新增“不喜欢歌曲”功能&新增“收藏歌曲”、“取消收藏”、“不喜欢该歌曲”快捷键设置

This commit is contained in:
lyswhut
2023-09-04 14:13:47 +08:00
parent 3ca8f09971
commit baf69e397a
40 changed files with 861 additions and 26 deletions
+4
View File
@@ -1,5 +1,9 @@
export const URL_SCHEME_RXP = /^lxmusic:\/\//
export const SPLIT_CHAR = {
DISLIKE_NAME: '@',
DISLIKE_NAME_ALIAS: '#',
} as const
export const STORE_NAMES = {
APP_SETTINGS: 'config_v2',
+15
View File
@@ -66,6 +66,21 @@ const hotKey = {
action: 'volume_mute',
type: '',
},
music_love: {
name: 'music_love',
action: 'music_love',
type: '',
},
music_unlove: {
name: 'music_unlove',
action: 'music_unlove',
type: '',
},
music_dislike: {
name: 'music_dislike',
action: 'music_dislike',
type: '',
},
},
desktop_lyric: {
toggle_visible: {
+4
View File
@@ -126,6 +126,10 @@ const modules = {
clear_music_url: 'clear_music_url',
get_music_url_count: 'get_music_url_count',
get_dislike_music_infos: 'get_dislike_music_infos',
add_dislike_music_infos: 'add_dislike_music_infos',
overwrite_dislike_music_infos: 'overwrite_dislike_music_infos',
sync_action: 'sync_action',
sync_get_server_devices: 'sync_get_server_devices',
sync_remove_server_device: 'sync_remove_server_device',
+35
View File
@@ -0,0 +1,35 @@
declare namespace LX {
namespace Dislike {
// interface ListItemMusicText {
// id?: string
// // type: 'music'
// name: string | null
// singer: string | null
// }
// interface ListItemMusic {
// id?: number
// type: 'musicId'
// musicId: string
// meta: LX.Music.MusicInfo
// }
// type ListItem = ListItemMusicText
// type ListItem = string
// type ListItem = ListItemMusic | ListItemMusicText
interface DislikeMusicInfo {
name: string
singer: string
}
interface DislikeInfo {
// musicIds: Set<string>
names: Set<string>
musicNames: Set<string>
singerNames: Set<string>
// list: LX.Dislike.ListItem[]
rules: string
}
}
}
+10
View File
@@ -81,6 +81,7 @@
"list__add_to": "Add to ...",
"list__collect": "Collect",
"list__copy_name": "Copy name",
"list__dislike": "Dislike",
"list__download": "Download",
"list__export_part_desc": "Choose where to save the list file",
"list__file": "Locate the file",
@@ -382,6 +383,9 @@
"setting__desktop_lyric_shadow_color": "Shadow color",
"setting__desktop_lyric_show_taskbar": "Display lyrics progress on the taskbar (this setting is used as a workaround when the screen recording software cannot capture the lyrics window)",
"setting__desktop_lyric_unplay_color": "Color not playing",
"setting__dislike_list_save_btn": "Save",
"setting__dislike_list_tips": "1. If there is a \"@\" symbol in the song or singer's name, you need to replace it with \"#\"\n2. Specify a song of a singer: <Name>@<Singer>\n3. Specify a song: <Name>\n4. Specify a certain singer:@<Singer>",
"setting__dislike_list_title": "List of Disliked Song Rules",
"setting__download": "Download",
"setting__download_data_embed": "Whether to embed the following content in the audio file",
"setting__download_embed_lyric": "Embedding lyric",
@@ -426,6 +430,9 @@
"setting__hot_key_player_toggle_play": "Play/Pause Control",
"setting__hot_key_player_volume_down": "Reduce Volume",
"setting__hot_key_player_volume_mute": "Mute Switch",
"setting__hot_key_player_music_love": "Favorites Song",
"setting__hot_key_player_music_unlove": "Cancel collection",
"setting__hot_key_player_music_dislike": "Dislike the song",
"setting__hot_key_player_volume_up": "Increase Volume",
"setting__hot_key_tip_input": "Please enter a new key",
"setting__hot_key_unset_input": "Not Set",
@@ -449,6 +456,9 @@
"setting__odc_clear_search_input": "Clear the search box when you are not searching",
"setting__odc_clear_search_list": "Clear the search list when you are not searching",
"setting__other": "Extras",
"setting__other_dislike_list": "dislike song rule",
"setting__other_dislike_list_label": "Number of rules:",
"setting__other_dislike_list_show_btn": "Edit dislike song rules",
"setting__other_listdata": "List Data Cleanup",
"setting__other_listdata_clear_btn": "Clear my list data",
"setting__other_listdata_clear_tip_confirm": "This will clear all lists you have created and all songs in your favourites, do you really want to continue?",
+10
View File
@@ -81,6 +81,7 @@
"list__add_to": "添加到...",
"list__collect": "收藏",
"list__copy_name": "复制歌曲名",
"list__dislike": "不喜欢",
"list__download": "下载",
"list__export_part_desc": "选择列表文件保存位置",
"list__file": "定位文件",
@@ -381,6 +382,9 @@
"setting__desktop_lyric_shadow_color": "阴影颜色",
"setting__desktop_lyric_show_taskbar": "在任务栏显示歌词进程(此设置用于在录屏软件无法捕获歌词窗口时的变通解决方法)",
"setting__desktop_lyric_unplay_color": "未播放颜色",
"setting__dislike_list_save_btn": "保存",
"setting__dislike_list_tips": "1. 每条一行,若歌曲或者歌手名字中存在“@”符号,需要将其替换成“#”\n2. 指定某歌手的某首歌:<歌曲名>@<歌手名>\n3. 指定某首歌:<歌曲名>\n4. 指定某歌手:@<歌手名>",
"setting__dislike_list_title": "不喜欢的歌曲规则列表",
"setting__download": "下载设置",
"setting__download_data_embed": "是否将以下内容嵌入到音频文件中",
"setting__download_embed_lyric": "歌词嵌入",
@@ -425,6 +429,9 @@
"setting__hot_key_player_toggle_play": "播放/暂停控制",
"setting__hot_key_player_volume_down": "减少音量",
"setting__hot_key_player_volume_mute": "静音切换",
"setting__hot_key_player_music_love": "收藏歌曲",
"setting__hot_key_player_music_unlove": "取消收藏",
"setting__hot_key_player_music_dislike": "不喜欢该歌曲",
"setting__hot_key_player_volume_up": "增加音量",
"setting__hot_key_tip_input": "请输入新的按键",
"setting__hot_key_unset_input": "未设置",
@@ -448,6 +455,9 @@
"setting__odc_clear_search_input": "离开搜索界面时清空搜索框",
"setting__odc_clear_search_list": "离开搜索界面时清空搜索列表",
"setting__other": "其他",
"setting__other_dislike_list": "不喜欢的歌曲规则",
"setting__other_dislike_list_label": "规则数量:",
"setting__other_dislike_list_show_btn": "编辑不喜欢歌曲规则",
"setting__other_listdata": "列表数据清理",
"setting__other_listdata_clear_btn": "清空我的列表数据",
"setting__other_listdata_clear_tip_confirm": "这将清理你创建的 所有列表 及收藏的 所有歌曲,是否真的要继续?",
+10
View File
@@ -81,6 +81,7 @@
"list__add_to": "添加到...",
"list__collect": "收藏",
"list__copy_name": "複製歌曲名",
"list__dislike": "不喜歡",
"list__download": "下載",
"list__export_part_desc": "選擇列表文件保存位置",
"list__file": "定位文件",
@@ -382,6 +383,9 @@
"setting__desktop_lyric_shadow_color": "陰影顏色",
"setting__desktop_lyric_show_taskbar": "在任務欄顯示歌詞進程(此設置用於在錄屏軟件無法捕獲歌詞窗口時的變通解決方法)",
"setting__desktop_lyric_unplay_color": "未播放顏色",
"setting__dislike_list_save_btn": "保存",
"setting__dislike_list_tips": "1. 每條一行,若歌曲或者歌手名字中存在“@”符號,需要將其替換成“#”\n2. 指定某歌手的某首歌:<歌曲名>@<歌手名>\n3. 指定某首歌:<歌曲名>\n4. 指定某歌手:@<歌手名>",
"setting__dislike_list_title": "不喜歡的歌曲規則列表",
"setting__download": "下載設置",
"setting__download_data_embed": "是否將以下內容嵌入到音頻文件中",
"setting__download_embed_lyric": "歌詞嵌入",
@@ -426,6 +430,9 @@
"setting__hot_key_player_toggle_play": "播放/暫停控制​​",
"setting__hot_key_player_volume_down": "減少音量",
"setting__hot_key_player_volume_mute": "靜音切換",
"setting__hot_key_player_music_love": "收藏歌曲",
"setting__hot_key_player_music_unlove": "取消收藏",
"setting__hot_key_player_music_dislike": "不喜歡該歌曲",
"setting__hot_key_player_volume_up": "增加音量",
"setting__hot_key_tip_input": "請輸入新的按鍵",
"setting__hot_key_unset_input": "未設置",
@@ -449,6 +456,9 @@
"setting__odc_clear_search_input": "離開搜索界面時清空搜索框",
"setting__odc_clear_search_list": "離開搜索界面時清空搜索列表",
"setting__other": "其他",
"setting__other_dislike_list": "不喜歡的歌曲規則",
"setting__other_dislike_list_label": "規則數量:",
"setting__other_dislike_list_show_btn": "編輯不喜歡歌曲規則",
"setting__other_listdata": "列表數據清理",
"setting__other_listdata_clear_btn": "清空我的列表數據",
"setting__other_listdata_clear_tip_confirm": "這將清理你創建的 所有列表 及收藏的 所有歌曲,是否真的要繼續?",
@@ -70,6 +70,23 @@ export default () => {
return global.lx.worker.dbService.musicInfoOtherSourceCount()
})
// =========================不喜欢的歌曲=========================
mainHandle<LX.Dislike.DislikeInfo>(WIN_MAIN_RENDERER_EVENT_NAME.get_dislike_music_infos, async() => {
return global.lx.worker.dbService.getDislikeListInfo()
})
mainHandle<LX.Dislike.DislikeMusicInfo[]>(WIN_MAIN_RENDERER_EVENT_NAME.add_dislike_music_infos, async({ params: infos }) => {
await global.lx.worker.dbService.dislikeInfoAdd(infos)
})
mainHandle<string>(WIN_MAIN_RENDERER_EVENT_NAME.overwrite_dislike_music_infos, async({ params: rules }) => {
await global.lx.worker.dbService.dislikeInfoOverwrite(rules)
})
// mainHandle<string[]>(WIN_MAIN_RENDERER_EVENT_NAME.remove_dislike_music_infos, async({ params: ids }) => {
// await global.lx.worker.dbService.dislikeInfoRemove(ids)
// })
// mainHandle(WIN_MAIN_RENDERER_EVENT_NAME.clear_dislike_music_infos, async() => {
// await global.lx.worker.dbService.dislikeInfoClear()
// })
// =========================我的列表=========================
// mainHandle<boolean>(WIN_MAIN_RENDERER_EVENT_NAME.get_playlist, async({ params: isIgnoredError = false }) => {
+1
View File
@@ -12,3 +12,4 @@ import '@common/types/desktop_lyric'
import '@common/types/theme'
import '@common/types/ipc_main'
import '@common/types/sound_effect'
import '@common/types/dislike_list'
+6
View File
@@ -74,6 +74,12 @@ declare namespace LX {
position: number
}
interface DislikeInfo {
// type: 'music'
content: string
// meta: string | null
}
interface MusicInfoOtherSource extends Omit<MusicInfoOnline, 'listId'> {
source_id: string
}
+2 -2
View File
@@ -2,7 +2,7 @@ import Database from 'better-sqlite3'
import path from 'path'
import tables from './tables'
import verifyDB from './verifyDB'
// import migrateData from './migrate'
import migrateData from './migrate'
let db: Database.Database
@@ -37,7 +37,7 @@ export const init = (lxDataPath: string): boolean | null => {
dbFileExists = false
}
// if (dbFileExists) migrateData(db)
if (dbFileExists) migrateData(db)
// https://www.sqlite.org/pragma.html#pragma_optimize
if (dbFileExists) db.exec('PRAGMA optimize;')
+3 -2
View File
@@ -1,13 +1,13 @@
import { init } from './db'
import { exposeWorker } from '../utils/worker'
import { list, lyric, music_url, music_other_source, download } from './modules/index'
import { list, lyric, music_url, music_other_source, download, dislike_list } from './modules/index'
const common = {
init,
}
exposeWorker(Object.assign(common, list, lyric, music_url, music_other_source, download))
exposeWorker(Object.assign(common, list, lyric, music_url, music_other_source, download, dislike_list))
export type workerDBSeriveTypes = typeof common
& typeof list
@@ -15,3 +15,4 @@ export type workerDBSeriveTypes = typeof common
& typeof music_url
& typeof music_other_source
& typeof download
& typeof dislike_list
+29 -17
View File
@@ -1,24 +1,36 @@
import type Database from 'better-sqlite3'
// const migrateV1 = (db: Database.Database) => {
// const sql = `
// DROP TABLE "main"."download_list";
// CREATE TABLE "download_list" (
// "id" TEXT NOT NULL,
// "isComplate" INTEGER NOT NULL,
// "status" TEXT NOT NULL,
// "statusText" TEXT NOT NULL,
// "progress_downloaded" INTEGER NOT NULL,
// "progress_total" INTEGER NOT NULL,
// "url" TEXT,
// "quality" TEXT NOT NULL,
// "ext" TEXT NOT NULL,
// "fileName" TEXT NOT NULL,
// "filePath" TEXT NOT NULL,
// "musicInfo" TEXT NOT NULL,
// "position" INTEGER NOT NULL,
// PRIMARY KEY("id")
// );
// `
// db.exec(sql)
// db.prepare('UPDATE "main"."db_info" SET "field_value"=@value WHERE "field_name"=@name').run({ name: 'version', value: '2' })
// }
const migrateV1 = (db: Database.Database) => {
const sql = `
DROP TABLE "main"."download_list";
CREATE TABLE "download_list" (
"id" TEXT NOT NULL,
"isComplate" INTEGER NOT NULL,
"status" TEXT NOT NULL,
"statusText" TEXT NOT NULL,
"progress_downloaded" INTEGER NOT NULL,
"progress_total" INTEGER NOT NULL,
"url" TEXT,
"quality" TEXT NOT NULL,
"ext" TEXT NOT NULL,
"fileName" TEXT NOT NULL,
"filePath" TEXT NOT NULL,
"musicInfo" TEXT NOT NULL,
"position" INTEGER NOT NULL,
PRIMARY KEY("id")
CREATE TABLE "dislike_list" (
"type" TEXT NOT NULL,
"content" TEXT NOT NULL,
"meta" TEXT
);
`
db.exec(sql)
@@ -0,0 +1,76 @@
// import type Database from 'better-sqlite3'
import { getDB } from '../../db'
import {
createQueryStatement,
createInsertStatement,
// createDeleteStatement,
// createUpdateStatement,
createClearStatement,
} from './statements'
/**
* 查询不喜欢歌曲列表
*/
export const queryDislikeList = () => {
const queryStatement = createQueryStatement()
return queryStatement.all() as LX.DBService.DislikeInfo[]
}
/**
* 批量插入不喜欢歌曲并刷新顺序
* @param infos 列表
*/
export const inertDislikeList = async(infos: LX.DBService.DislikeInfo[]) => {
const db = getDB()
const insertStatement = createInsertStatement()
db.transaction((infos: LX.DBService.DislikeInfo[]) => {
for (const info of infos) insertStatement.run(info)
})(infos)
}
/**
* 覆盖并批量插入不喜欢歌曲并刷新顺序
* @param infos 列表
*/
export const overwirteDislikeList = async(infos: LX.DBService.DislikeInfo[]) => {
const db = getDB()
const clearStatement = createClearStatement()
const insertStatement = createInsertStatement()
db.transaction((infos: LX.DBService.DislikeInfo[]) => {
clearStatement.run()
for (const info of infos) insertStatement.run(info)
})(infos)
}
// /**
// * 批量删除不喜欢歌曲
// * @param ids 列表
// */
// export const deleteDislikeList = (ids: string[]) => {
// const db = getDB()
// const deleteStatement = createDeleteStatement()
// db.transaction((ids: string[]) => {
// for (const id of ids) deleteStatement.run(BigInt(id))
// })(ids)
// }
// /**
// * 批量更新不喜欢歌曲
// * @param urlInfo 列表
// */
// export const updateDislikeList = async(infos: LX.DBService.DislikeInfo[]) => {
// const db = getDB()
// const updateStatement = createUpdateStatement()
// db.transaction((infos: LX.DBService.DislikeInfo[]) => {
// for (const info of infos) updateStatement.run(info)
// })(infos)
// }
// /**
// * 清空不喜欢歌曲列表
// */
// export const clearDislikeList = () => {
// const clearStatement = createClearStatement()
// clearStatement.run()
// }
@@ -0,0 +1,100 @@
import { SPLIT_CHAR } from '@common/constants'
import {
queryDislikeList,
inertDislikeList,
overwirteDislikeList,
// updateDislikeList,
// deleteDislikeList,
// clearDislikeList,
} from './dbHelper'
// let dislikeInfo: LX.Dislike.DislikeInfo
const toDBDislikeInfo = (musicInfos: string[]): LX.DBService.DislikeInfo[] => {
const list: LX.DBService.DislikeInfo[] = []
for (const item of musicInfos) {
if (!item.trim()) continue
list.push({
content: item,
})
}
return list
}
const initDislikeList = () => {
const dislikeInfo: LX.Dislike.DislikeInfo = {
// musicIds: new Set<string>(),
names: new Set<string>(),
singerNames: new Set<string>(),
musicNames: new Set<string>(),
rules: '',
}
const list: string[] = []
for (const item of queryDislikeList()) {
if (!item) continue
let [name, singer] = item.content.split(SPLIT_CHAR.DISLIKE_NAME)
if (name) {
name = name.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
if (singer) {
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
const rule = `${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`
dislikeInfo.names.add(rule)
list.push(rule)
} else {
dislikeInfo.musicNames.add(name)
list.push(name)
}
} else if (singer) {
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
dislikeInfo.singerNames.add(singer)
list.push(`${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
}
}
dislikeInfo.rules = list.join('\n') + '\n'
return dislikeInfo
}
/**
* 获取不喜欢列表信息
* @returns 不喜欢列表信息
*/
export const getDislikeListInfo = (): LX.Dislike.DislikeInfo => {
// if (!dislikeInfo) initDislikeList()
return initDislikeList()
}
/**
* 添加信息
* @param lists 列表信息
*/
export const dislikeInfoAdd = async(lists: LX.Dislike.DislikeMusicInfo[]) => {
await inertDislikeList(lists.map(info => ({ content: `${info.name}${SPLIT_CHAR.DISLIKE_NAME}${info.singer}` })))
}
/**
* 覆盖列表信息
* @param rules 规则信息
*/
export const dislikeInfoOverwrite = async(rules: string) => {
await overwirteDislikeList(toDBDislikeInfo(rules.split('\n')))
}
// /**
// * 删除不喜欢列表
// * @param ids 歌曲id
// */
// export const dislikeInfoRemove = (ids: string[]) => {
// deleteDislikeList(ids)
// }
// /**
// * 清空不喜欢列表
// */
// export const dislikeInfoClear = () => {
// clearDislikeList()
// }
@@ -0,0 +1,62 @@
import { getDB } from '../../db'
/**
* 创建不喜欢列表查询语句
* @returns 查询语句
*/
export const createQueryStatement = () => {
const db = getDB()
return db.prepare<[]>(`
SELECT "content"
FROM dislike_list
WHERE "type"='music'
`)
}
/**
* 创建不喜欢记录插入语句
* @returns 插入语句
*/
export const createInsertStatement = () => {
const db = getDB()
return db.prepare<[LX.DBService.DislikeInfo]>(`
INSERT INTO "main"."dislike_list" ("type", "content")
VALUES ('music', @content)`)
}
/**
* 创建不喜欢记录清空语句
* @returns 清空语句
*/
export const createClearStatement = () => {
const db = getDB()
return db.prepare<[]>(`
DELETE FROM "main"."dislike_list"
`)
}
// /**
// * 创建不喜欢记录删除语句
// * @returns 删除语句
// */
// export const createDeleteStatement = () => {
// const db = getDB()
// return db.prepare<[bigint]>(`
// DELETE FROM "main"."dislike_list"
// WHERE "id"=?
// `)
// }
// /**
// * 创建不喜欢记录更新语句
// * @returns 更新语句
// */
// export const createUpdateStatement = () => {
// const db = getDB()
// return db.prepare<[LX.DBService.DislikeInfo]>(`
// UPDATE "main"."dislike_list"
// SET "name"=@name, "singer"=@singer
// WHERE "id"=@id
// `)
// }
@@ -4,3 +4,4 @@ export * as lyric from './lyric'
export * as music_url from './music_url'
export * as music_other_source from './music_other_source'
export * as download from './download'
export * as dislike_list from './dislike_list'
+7
View File
@@ -205,5 +205,12 @@ tables.set('download_list', `
PRIMARY KEY("id")
);
`)
tables.set('dislike_list', `
CREATE TABLE "dislike_list" (
"type" TEXT NOT NULL,
"content" TEXT NOT NULL,
"meta" TEXT
);
`)
export default tables
@@ -60,6 +60,10 @@ export default {
type: String,
default: 'auto',
},
height: {
type: String,
default: 'auto',
},
},
emits: ['after-enter', 'after-leave', 'close'],
data() {
@@ -147,6 +151,7 @@ export default {
maxWidth: this.maxWidth,
minWidth: this.minWidth,
width: this.width,
height: this.height,
maxHeight: this.maxHeight,
}
},
@@ -180,6 +180,7 @@ export default {
const {
handleSearch,
handleOpenMusicDetail,
handleDislikeMusic,
} = useMusicActions({ props })
const {
@@ -199,6 +200,7 @@ export default {
handleSearch,
handleShowMusicAddModal,
handleOpenMusicDetail,
handleDislikeMusic,
})
const handleListItemClick = (event, index) => {
@@ -1,6 +1,7 @@
import { computed, ref, reactive, nextTick } from '@common/utils/vueTools'
import musicSdk from '@renderer/utils/musicSdk'
import { useI18n } from '@renderer/plugins/i18n'
import { hasDislike } from '@renderer/core/dislikeList'
export default ({
props,
@@ -13,6 +14,7 @@ export default ({
handleSearch,
handleShowMusicAddModal,
handleOpenMusicDetail,
handleDislikeMusic,
}) => {
const itemMenuControl = reactive({
play: true,
@@ -21,6 +23,7 @@ export default ({
download: true,
search: true,
sourceDetail: true,
dislike: true,
})
const t = useI18n()
const menuLocation = reactive({ x: 0, y: 0 })
@@ -58,6 +61,11 @@ export default ({
action: 'sourceDetail',
disabled: !itemMenuControl.sourceDetail,
},
{
name: t('list__dislike'),
action: 'dislike',
disabled: !itemMenuControl.dislike,
},
]
})
@@ -67,6 +75,8 @@ export default ({
// this.listMenu.itemMenuControl.playLater =
itemMenuControl.download = assertApiSupport(musicInfo.source)
itemMenuControl.dislike = !hasDislike(musicInfo)
if (props.checkApiSource) {
itemMenuControl.playLater =
itemMenuControl.play =
@@ -110,6 +120,9 @@ export default ({
break
case 'sourceDetail':
handleOpenMusicDetail(index)
case 'dislike':
handleDislikeMusic(index)
break
}
}
@@ -2,6 +2,9 @@ import { useRouter } from '@common/utils/vueRouter'
import musicSdk from '@renderer/utils/musicSdk'
import { openUrl } from '@common/utils/electron'
import { toOldMusicInfo } from '@renderer/utils'
import { addDislikeInfo, hasDislike } from '@renderer/core/dislikeList'
import { playNext } from '@renderer/core/player'
import { playMusicInfo } from '@renderer/store/player/state'
export default ({ props }) => {
@@ -24,8 +27,18 @@ export default ({ props }) => {
openUrl(url)
}
const handleDislikeMusic = async(index) => {
const minfo = props.list[index]
await addDislikeInfo([{ name: minfo.name, singer: minfo.singer }])
if (!playMusicInfo.isTempPlay && hasDislike(playMusicInfo.musicInfo)) {
playNext(true)
}
}
return {
handleSearch,
handleOpenMusicDetail,
handleDislikeMusic,
}
}
+48
View File
@@ -0,0 +1,48 @@
// import { toRaw } from '@common/utils/vueTools'
import { action } from '@renderer/store/dislikeList'
import {
getDislikeListInfo,
addDislikeInfo as addDislikeInfoRemote,
overwirteDislikeInfo as overwirteDislikeInfoRemote,
// updateDislikeInfo as updateDislikeInfoRemote,
// removeDislikeInfo as removeDislikeInfoRemote,
// clearDislikeInfo as clearDislikeInfoRemote,
} from '@renderer/utils/ipc'
export const initDislikeInfo = async() => {
action.initDislikeInfo(await getDislikeListInfo())
}
export const addDislikeInfo = async(infos: LX.Dislike.DislikeMusicInfo[]) => {
await addDislikeInfoRemote(infos)
return action.addDislikeInfo(infos)
}
export const overwirteDislikeInfo = async(rules: string) => {
await overwirteDislikeInfoRemote(rules)
return action.overwirteDislikeInfo(rules)
}
// export const updateDislikeInfo = async(info: LX.Dislike.ListItem) => {
// await updateDislikeInfoRemote([toRaw(info)])
// action.updateDislikeInfo(info)
// }
// export const removeDislikeInfo = async(ids: string[]) => {
// await removeDislikeInfoRemote(toRaw(ids))
// action.removeDislikeInfo(ids)
// }
// export const clearDislikeInfo = async() => {
// await clearDislikeInfoRemote()
// action.clearDislikeInfo()
// }
export const hasDislike = (info: LX.Music.MusicInfo | null) => {
if (!info) return false
return action.hasDislike(info)
}
+2
View File
@@ -299,6 +299,7 @@ export const playNext = async(isAutoToggle = false): Promise<void> => {
list: currentList,
playedList,
playerMusicInfo: currentList[playInfo.playerPlayIndex],
isNext: true,
})
if (!filteredList.length) {
@@ -398,6 +399,7 @@ export const playPrev = async(isAutoToggle = false): Promise<void> => {
list: currentList,
playedList,
playerMusicInfo: currentList[playInfo.playerPlayIndex],
isNext: false,
})
if (!filteredList.length) {
handleToggleStop()
+5 -1
View File
@@ -2,6 +2,7 @@ import { toRaw, markRawList } from '@common/utils/vueTools'
import { qualityList } from '@renderer/store'
import { clearPlayedList } from '@renderer/store/player/action'
import { appSetting } from '@renderer/store/setting'
import { dislikeInfo } from '@renderer/store/dislikeList'
export const getPlayType = (highQuality: boolean, musicInfo: LX.Music.MusicInfo | LX.Download.ListItem): LX.Quality | null => {
if ('progress' in musicInfo || musicInfo.source == 'local') return null
@@ -14,11 +15,12 @@ export const getPlayType = (highQuality: boolean, musicInfo: LX.Music.MusicInfo
/**
* 过滤列表中已播放的歌曲
*/
export const filterList = async({ playedList, listId, list, playerMusicInfo }: {
export const filterList = async({ playedList, listId, list, playerMusicInfo, isNext }: {
playedList: LX.Player.PlayMusicInfo[]
listId: string
list: Array<LX.Music.MusicInfo | LX.Download.ListItem>
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
isNext: boolean
}) => {
// if (this.list.listName === null) return
// console.log(isCheckFile)
@@ -28,6 +30,8 @@ export const filterList = async({ playedList, listId, list, playerMusicInfo }: {
playedList: toRaw(playedList),
savePath: appSetting['download.savePath'],
playerMusicInfo: toRaw(playerMusicInfo),
dislikeInfo: { names: toRaw(dislikeInfo.names), musicNames: toRaw(dislikeInfo.musicNames), singerNames: toRaw(dislikeInfo.singerNames) },
isNext,
})
if (!filteredList.length && playedList.length) {
+2
View File
@@ -9,6 +9,7 @@ import { play, playList } from '@renderer/core/player'
import { onBeforeUnmount } from '@common/utils/vueTools'
import { appSetting } from '@renderer/store/setting'
import { playMusicInfo } from '@renderer/store/player/state'
import { initDislikeInfo } from '@renderer/core/dislikeList'
const initPrevPlayInfo = async() => {
const info = await getPlayInfo()
@@ -48,6 +49,7 @@ export default () => {
window.app_event.myListUpdate(ids)
})
window.lxData.userLists = await getUserLists() // 获取用户列表
await initDislikeInfo() // 获取不喜欢列表
await initPrevPlayInfo().catch(err => {
log.error(err)
}) // 初始化上次的歌曲播放信息
@@ -32,6 +32,9 @@ import { HOTKEY_PLAYER } from '@common/hotKey'
import { playNext, pause, playPrev, togglePlay } from '@renderer/core/player'
import usePlaybackRate from './usePlaybackRate'
import useSoundEffect from './useSoundEffect'
import { addListMusics, removeListMusics } from '@renderer/store/list/action'
import { loveList } from '@renderer/store/list/state'
import { addDislikeInfo } from '@renderer/core/dislikeList'
export default () => {
@@ -90,6 +93,23 @@ export default () => {
setStop()
}
const collectMusic = () => {
if (!playMusicInfo.musicInfo) return
void addListMusics(loveList.id, ['progress' in playMusicInfo.musicInfo ? playMusicInfo.musicInfo.metadata.musicInfo : playMusicInfo.musicInfo])
}
const unCollectMusic = () => {
if (!playMusicInfo.musicInfo) return
void removeListMusics({ listId: loveList.id, ids: ['progress' in playMusicInfo.musicInfo ? playMusicInfo.musicInfo.metadata.musicInfo.id : playMusicInfo.musicInfo.id] })
}
const dislikeMusic = async() => {
if (!playMusicInfo.musicInfo) return
const minfo = 'progress' in playMusicInfo.musicInfo ? playMusicInfo.musicInfo.metadata.musicInfo : playMusicInfo.musicInfo
await addDislikeInfo([{ name: minfo.name, singer: minfo.singer }])
if (!playMusicInfo.isTempPlay) {
playNext(true)
}
}
watch(() => appSetting['player.togglePlayMethod'], newValue => {
// setLoopPlay(newValue == 'singleLoop')
if (playedList.length) clearPlayedList()
@@ -102,6 +122,9 @@ export default () => {
window.key_event.on(HOTKEY_PLAYER.next.action, handlePlayNext)
window.key_event.on(HOTKEY_PLAYER.prev.action, handlePlayPrev)
window.key_event.on(HOTKEY_PLAYER.toggle_play.action, togglePlay)
window.key_event.on(HOTKEY_PLAYER.music_love.action, collectMusic)
window.key_event.on(HOTKEY_PLAYER.music_unlove.action, unCollectMusic)
window.key_event.on(HOTKEY_PLAYER.music_dislike.action, dislikeMusic)
window.app_event.on('play', setPlayStatus)
window.app_event.on('pause', setPauseStatus)
@@ -119,6 +142,10 @@ export default () => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
window.key_event.off(HOTKEY_PLAYER.prev.action, handlePlayPrev)
window.key_event.off(HOTKEY_PLAYER.toggle_play.action, togglePlay)
window.key_event.off(HOTKEY_PLAYER.music_love.action, collectMusic)
window.key_event.off(HOTKEY_PLAYER.music_unlove.action, unCollectMusic)
window.key_event.off(HOTKEY_PLAYER.music_dislike.action, dislikeMusic)
window.app_event.off('play', setPlayStatus)
window.app_event.off('pause', setPauseStatus)
+83
View File
@@ -0,0 +1,83 @@
import { markRaw } from '@common/utils/vueTools'
import { dislikeInfo } from './state'
import { SPLIT_CHAR } from '@common/constants'
export const hasDislike = (info: LX.Music.MusicInfo) => {
const name = info.name?.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim() ?? ''
const singer = info.singer?.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim() ?? ''
return dislikeInfo.musicNames.has(name) || dislikeInfo.singerNames.has(singer) ||
dislikeInfo.names.has(`${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
}
export const initDislikeInfo = ({ musicNames, rules, names, singerNames }: LX.Dislike.DislikeInfo) => {
dislikeInfo.names = markRaw(names)
dislikeInfo.singerNames = markRaw(singerNames)
dislikeInfo.musicNames = markRaw(musicNames)
dislikeInfo.rules = rules
}
const initNameSet = () => {
dislikeInfo.names.clear()
dislikeInfo.musicNames.clear()
dislikeInfo.singerNames.clear()
const list: string[] = []
for (const item of dislikeInfo.rules.split('\n')) {
if (!item) continue
let [name, singer] = item.split(SPLIT_CHAR.DISLIKE_NAME)
if (name) {
name = name.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
if (singer) {
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
const rule = `${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`
dislikeInfo.names.add(rule)
list.push(rule)
} else {
dislikeInfo.musicNames.add(name)
list.push(name)
}
} else if (singer) {
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
dislikeInfo.singerNames.add(singer)
list.push(`${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
}
}
dislikeInfo.rules = list.join('\n') + '\n'
}
export const addDislikeInfo = (infos: LX.Dislike.DislikeMusicInfo[]) => {
dislikeInfo.rules += '\n' + infos.map(info => `${info.name ?? ''}${SPLIT_CHAR.DISLIKE_NAME}${info.singer ?? ''}`).join('\n')
initNameSet()
return dislikeInfo.rules
}
export const overwirteDislikeInfo = (rules: string) => {
dislikeInfo.rules = rules
initNameSet()
return dislikeInfo.rules
}
// export const updateDislikeInfo = (info: LX.Dislike.ListItem) => {
// const targetInfo = dislikeInfo.list.find(i => i.id == info.id)
// if (!targetInfo) return
// targetInfo.name = info.name
// targetInfo.singer = info.singer
// initNameSet()
// }
// export const removeDislikeInfo = (ids: string[]) => {
// for (const id of ids) {
// dislikeInfo.list.splice(dislikeInfo.list.findIndex(info => info.id == id), 1)
// }
// initNameSet()
// }
// export const clearDislikeInfo = () => {
// dislikeInfo.rules = ''
// initNameSet()
// }
+3
View File
@@ -0,0 +1,3 @@
export * as action from './action'
export * from './state'
+11
View File
@@ -0,0 +1,11 @@
import { markRaw } from '@common/utils/vueTools'
// import { deduplicationList } from '@common/utils/renderer'
export const dislikeInfo: LX.Dislike.DislikeInfo = markRaw({
names: markRaw(new Set()),
musicNames: markRaw(new Set()),
singerNames: markRaw(new Set()),
rules: '',
})
+1 -1
View File
@@ -73,7 +73,7 @@ export const setPlayListId = (listId: string | null) => {
playInfo.playerListId = listId
}
export const getList = (listId: string | null): LX.Music.MusicInfo[] | LX.Download.ListItem[] => {
export const getList = (listId: string | null): Array<LX.Music.MusicInfo | LX.Download.ListItem> => {
return listId == LIST_IDS.DOWNLOAD ? downloadList : getListMusicsFromCache(listId)
}
+1
View File
@@ -15,3 +15,4 @@ import '@common/types/ipc_renderer'
import '@common/types/config_files'
import '@common/types/music_metadata'
import '@common/types/sound_effect'
import '@common/types/dislike_list'
+38
View File
@@ -40,6 +40,24 @@ export const getOtherSourceCount = async() => {
return rendererInvoke<number>(WIN_MAIN_RENDERER_EVENT_NAME.get_other_source_count)
}
export const getDislikeListInfo = async(): Promise<LX.Dislike.DislikeInfo> => {
return rendererInvoke<LX.Dislike.DislikeInfo>(WIN_MAIN_RENDERER_EVENT_NAME.get_dislike_music_infos)
}
export const addDislikeInfo = async(dislikeInfo: LX.Dislike.DislikeMusicInfo[]) => {
return rendererInvoke<LX.Dislike.DislikeMusicInfo[]>(WIN_MAIN_RENDERER_EVENT_NAME.add_dislike_music_infos, dislikeInfo)
}
export const overwirteDislikeInfo = async(dislikeInfo: string) => {
return rendererInvoke<string>(WIN_MAIN_RENDERER_EVENT_NAME.overwrite_dislike_music_infos, dislikeInfo)
}
// export const updateDislikeInfo = async(dislikeInfo: LX.Dislike.ListItem[]) => {
// await rendererInvoke<LX.Dislike.ListItem[]>(WIN_MAIN_RENDERER_EVENT_NAME.update_dislike_music_infos, dislikeInfo)
// }
// export const removeDislikeInfo = async(ids: string[]) => {
// await rendererInvoke<string[]>(WIN_MAIN_RENDERER_EVENT_NAME.remove_dislike_music_infos, ids)
// }
// export const clearDislikeInfo = async() => {
// await rendererInvoke(WIN_MAIN_RENDERER_EVENT_NAME.clear_dislike_music_infos)
// }
export const getHotKeyConfig = async() => {
return rendererInvoke<LX.HotKeyConfigAll>(WIN_MAIN_RENDERER_EVENT_NAME.get_hot_key)
@@ -332,6 +350,11 @@ export const allHotKeys = markRaw({
action: hotKeys.HOTKEY_PLAYER.next.action,
type: APP_EVENT_NAMES.winMainName,
},
{
name: hotKeys.HOTKEY_PLAYER.music_dislike.name,
action: hotKeys.HOTKEY_PLAYER.music_dislike.action,
type: APP_EVENT_NAMES.winMainName,
},
{
name: hotKeys.HOTKEY_COMMON.focusSearchInput.name,
action: hotKeys.HOTKEY_COMMON.focusSearchInput.action,
@@ -394,6 +417,21 @@ export const allHotKeys = markRaw({
action: hotKeys.HOTKEY_PLAYER.volume_mute.action,
type: APP_EVENT_NAMES.winMainName,
},
{
name: hotKeys.HOTKEY_PLAYER.music_love.name,
action: hotKeys.HOTKEY_PLAYER.music_love.action,
type: APP_EVENT_NAMES.winMainName,
},
{
name: hotKeys.HOTKEY_PLAYER.music_unlove.name,
action: hotKeys.HOTKEY_PLAYER.music_unlove.action,
type: APP_EVENT_NAMES.winMainName,
},
{
name: hotKeys.HOTKEY_PLAYER.music_dislike.name,
action: hotKeys.HOTKEY_PLAYER.music_dislike.action,
type: APP_EVENT_NAMES.winMainName,
},
{
name: hotKeys.HOTKEY_DESKTOP_LYRIC.toggle_visible.name,
action: hotKeys.HOTKEY_DESKTOP_LYRIC.toggle_visible.action,
@@ -201,6 +201,7 @@ export default {
handleSearch,
handleOpenMusicDetail,
handleCopyName,
handleDislikeMusic,
handleRemoveMusic,
} = useMusicActions({ props, list, removeAllSelect, selectedList })
@@ -223,6 +224,7 @@ export default {
handleShowSortModal,
handleOpenMusicDetail,
handleCopyName,
handleDislikeMusic,
handleRemoveMusic,
})
@@ -1,6 +1,7 @@
import { computed, ref, shallowReactive, reactive, nextTick } from '@common/utils/vueTools'
import musicSdk from '@renderer/utils/musicSdk'
import { useI18n } from '@renderer/plugins/i18n'
import { hasDislike } from '@renderer/core/dislikeList'
export default ({
assertApiSupport,
@@ -15,6 +16,7 @@ export default ({
handleShowSortModal,
handleOpenMusicDetail,
handleCopyName,
handleDislikeMusic,
handleRemoveMusic,
}) => {
const itemMenuControl = reactive({
@@ -26,6 +28,7 @@ export default ({
sort: true,
download: true,
search: true,
dislike: true,
remove: true,
sourceDetail: true,
})
@@ -80,6 +83,11 @@ export default ({
action: 'search',
disabled: !itemMenuControl.search,
},
{
name: t('list__dislike'),
action: 'dislike',
disabled: !itemMenuControl.dislike,
},
{
name: t('list__remove'),
action: 'remove',
@@ -94,6 +102,8 @@ export default ({
// itemMenuControl.playLater =
itemMenuControl.download = assertApiSupport(musicInfo.source) && musicInfo.source != 'local'
itemMenuControl.dislike = !hasDislike(musicInfo)
menuLocation.x = event.pageX
menuLocation.y = event.pageY
@@ -138,6 +148,9 @@ export default ({
case 'search':
handleSearch(index)
break
case 'dislike':
handleDislikeMusic(index)
break
case 'remove':
handleRemoveMusic(index)
break
@@ -6,6 +6,9 @@ import { useI18n } from '@renderer/plugins/i18n'
import { removeListMusics } from '@renderer/store/list/action'
import { appSetting } from '@renderer/store/setting'
import { toOldMusicInfo } from '@renderer/utils/index'
import { addDislikeInfo, hasDislike } from '@renderer/core/dislikeList'
import { playNext } from '@renderer/core/player'
import { playMusicInfo } from '@renderer/store/player/state'
export default ({ props, list, selectedList, removeAllSelect }) => {
@@ -34,6 +37,14 @@ export default ({ props, list, selectedList, removeAllSelect }) => {
clipboardWriteText(appSetting['download.fileName'].replace('歌名', minfo.name).replace('歌手', minfo.singer))
}
const handleDislikeMusic = async(index) => {
const minfo = list.value[index]
await addDislikeInfo([{ name: minfo.name, singer: minfo.singer }])
if (!playMusicInfo.isTempPlay && hasDislike(playMusicInfo.musicInfo)) {
playNext(true)
}
}
const handleRemoveMusic = async(index, single) => {
if (selectedList.value.length && !single) {
const confirm = await (selectedList.value.length > 1
@@ -55,6 +66,7 @@ export default ({ props, list, selectedList, removeAllSelect }) => {
handleSearch,
handleOpenMusicDetail,
handleCopyName,
handleDislikeMusic,
handleRemoveMusic,
}
}
@@ -0,0 +1,112 @@
<template lang="pug">
material-modal(:show="modelValue" teleport="#view" height="80%" width="80%" @close="$emit('update:modelValue', false)")
main(:class="$style.main")
h2 {{ $t('setting__dislike_list_title') }}
div(:class="$style.content")
textarea(v-model="rules" :class="$style.textarea")
div(:class="$style.footer")
div(:class="$style.tips") {{ $t('setting__dislike_list_tips') }}
base-btn(:class="$style.btn" @click="handleSave") {{ $t('setting__dislike_list_save_btn') }}
</template>
<script>
import { watch, ref } from '@common/utils/vueTools'
import { overwirteDislikeInfo } from '@renderer/core/dislikeList'
import { dislikeInfo } from '@renderer/store/dislikeList'
export default {
props: {
modelValue: {
type: Boolean,
default: false,
},
},
emits: ['update:modelValue', 'onRuleUpdate'],
setup(props, { emit }) {
const rules = ref('')
const handleSave = async() => {
await overwirteDislikeInfo(rules.value)
emit('onRuleUpdate')
emit('update:modelValue', false)
}
watch(() => props.modelValue, (visible) => {
if (!visible) return
rules.value = dislikeInfo.rules
})
return {
rules,
handleSave,
}
},
}
</script>
<style lang="less" module>
@import '@renderer/assets/styles/layout.less';
.main {
// padding: 15px;
// max-width: 400px;
// min-width: 460px;
// min-height: 200px;
// width: ;
flex: auto;
display: flex;
flex-flow: column nowrap;
justify-content: center;
// min-height: 0;
// max-height: 100%;
// overflow: hidden;
h2 {
margin: 20px;
font-size: 16px;
color: var(--color-font);
line-height: 1.3;
text-align: center;
}
}
.content {
flex: auto;
// min-height: 100px;
max-height: 100%;
display: flex;
padding: 0 15px;
}
.textarea {
width: 100%;
height: 100%;
border: none;
outline: none;
border-radius: 4px;
background-color: var(--color-primary-light-200-alpha-900);
box-sizing: border-box;
font-family: inherit;
resize: none;
}
.footer {
box-sizing: border-box;
flex: none;
// width: @width;
padding: 15px 15px;
// padding: 2px 0;
display: flex;
justify-content: space-between;
align-items: center;
}
.tips {
// padding: 10px 15px;
font-size: 12px;
line-height: 1.25;
color: var(--color-550);
white-space: pre-wrap;
}
.btn {
min-width: 80px;
}
</style>
@@ -34,6 +34,16 @@ dd
base-btn.btn(min :disabled="isDisabledMusicUrlCacheClear" @click="handleClearMusicUrlCache") {{ $t('setting__other_music_url_clear_btn') }}
base-btn.btn(min :disabled="isDisabledLyricRawCacheClear" @click="handleClearLyricRawCache") {{ $t('setting__other_lyric_raw_clear_btn') }}
dd
h3#other_lyric_edited {{ $t('setting__other_dislike_list') }}
div
.p
| {{ $t('setting__other_dislike_list_label') }}
span.auto-hidden {{ dislikeRuleCount }}
.p
base-btn.btn(min @click="isShowDislikeList = true") {{ $t('setting__other_dislike_list_show_btn') }}
DislikeListModal(v-model="isShowDislikeList" @on-rule-update="handleCountRules")
dd
h3#other_lyric_edited {{ $t('setting__other_lyric_edited_cache') }}
div
@@ -65,9 +75,14 @@ import { dialog } from '@renderer/plugins/Dialog'
import { useI18n } from '@renderer/plugins/i18n'
import { appSetting, updateSetting } from '@renderer/store/setting'
import { overwriteListFull } from '@renderer/store/list/listManage'
import { dislikeInfo } from '@renderer/store/dislikeList'
import DislikeListModal from './DislikeListModal.vue'
export default {
name: 'SettingOther',
components: {
DislikeListModal,
},
setup() {
const t = useI18n()
@@ -135,6 +150,11 @@ export default {
}
refreshMusicUrlCount()
const dislikeRuleCount = ref(dislikeInfo.musicNames.size + dislikeInfo.singerNames.size + dislikeInfo.names.size)
const isShowDislikeList = ref(false)
const handleCountRules = () => {
dislikeRuleCount.value = dislikeInfo.musicNames.size + dislikeInfo.singerNames.size + dislikeInfo.names.size
}
const lyricRawCount = ref(0)
const isDisabledLyricRawCacheClear = ref(false)
@@ -204,6 +224,10 @@ export default {
isDisabledMusicUrlCacheClear,
handleClearMusicUrlCache,
dislikeRuleCount,
isShowDislikeList,
handleCountRules,
lyricRawCount,
isDisabledLyricRawCacheClear,
handleClearLyricRawCache,
+50 -3
View File
@@ -1,5 +1,6 @@
// import { throttle } from '@common/utils'
import { SPLIT_CHAR } from '@common/constants'
import { filterFileName, sortInsert, similar, arrPushByPosition, arrShuffle } from '@common/utils/common'
import { joinPath, saveStrToFile } from '@common/utils/nodejs'
import { createLocalMusicInfo } from '@renderer/utils/music'
@@ -8,7 +9,7 @@ import { createLocalMusicInfo } from '@renderer/utils/music'
/**
* 过滤列表中已播放的歌曲
*/
export const filterMusicList = async({ playedList, listId, list, savePath, playerMusicInfo }: {
export const filterMusicList = async({ playedList, listId, list, savePath, playerMusicInfo, dislikeInfo, isNext }: {
/**
* 已播放列表
*/
@@ -29,15 +30,34 @@ export const filterMusicList = async({ playedList, listId, list, savePath, playe
* 播放器内当前歌曲(`playInfo.playerPlayIndex`指向的歌曲)
*/
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
/**
* 不喜欢的歌曲名字列表
*/
dislikeInfo: Omit<LX.Dislike.DislikeInfo, 'rules'>
isNext: boolean
}) => {
let playerIndex = -1
let canPlayList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = []
const filteredPlayedList = playedList.filter(pmInfo => pmInfo.listId == listId && !pmInfo.isTempPlay).map(({ musicInfo }) => musicInfo)
const hasDislike = (info: LX.Music.MusicInfo) => {
const name = info.name?.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim() ?? ''
const singer = info.singer?.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim() ?? ''
return dislikeInfo.musicNames.has(name) || dislikeInfo.singerNames.has(singer) ||
dislikeInfo.names.has(`${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
}
let isDislike = false
const filteredList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = list.filter(s => {
// if (!assertApiSupport(s.source)) return false
if ('progress' in s && !s.isComplate) return false
if ('progress' in s) {
if (!s.isComplate) return false
} else if (hasDislike(s)) {
if (s.id != playerMusicInfo?.id) return false
isDislike = true
}
canPlayList.push(s)
@@ -49,7 +69,34 @@ export const filterMusicList = async({ playedList, listId, list, savePath, playe
return true
})
if (playerMusicInfo) {
playerIndex = (filteredList.length ? filteredList : canPlayList).findIndex(m => m.id == playerMusicInfo.id)
if (isDislike) {
if (filteredList.length <= 1) {
filteredList.splice(0, 1)
if (canPlayList.length > 1) {
let currentMusicIndex = canPlayList.findIndex(m => m.id == playerMusicInfo.id)
if (isNext) {
playerIndex = currentMusicIndex - 1
if (playerIndex < 0 && canPlayList.length > 1) playerIndex = canPlayList.length - 2
} else {
playerIndex = currentMusicIndex
if (canPlayList.length <= 1) playerIndex = -1
}
canPlayList.splice(currentMusicIndex, 1)
} else canPlayList.splice(0, 1)
} else {
let currentMusicIndex = filteredList.findIndex(m => m.id == playerMusicInfo.id)
if (isNext) {
playerIndex = currentMusicIndex - 1
if (playerIndex < 0 && filteredList.length > 1) playerIndex = filteredList.length - 2
} else {
playerIndex = currentMusicIndex
if (filteredList.length <= 1) playerIndex = -1
}
filteredList.splice(currentMusicIndex, 1)
}
} else {
playerIndex = (filteredList.length ? filteredList : canPlayList).findIndex(m => m.id == playerMusicInfo.id)
}
}
return {
filteredList,