新增“不喜欢歌曲”功能&新增“收藏歌曲”、“取消收藏”、“不喜欢该歌曲”快捷键设置
parent
3ca8f09971
commit
baf69e397a
|
@ -9,6 +9,8 @@
|
||||||
|
|
||||||
- 新增我的列表名右键菜单-排序歌曲-随机乱序功能,使用它可以对选中列表内歌曲进行随机重排(#1440)
|
- 新增我的列表名右键菜单-排序歌曲-随机乱序功能,使用它可以对选中列表内歌曲进行随机重排(#1440)
|
||||||
- 新增数据同步服务端模式已认证设备列表管理,该功能位置:设置-数据同步-服务端模式-已认证设备列表
|
- 新增数据同步服务端模式已认证设备列表管理,该功能位置:设置-数据同步-服务端模式-已认证设备列表
|
||||||
|
- 新增“不喜欢歌曲”功能,可以在我的列表或者在线列表内歌曲的右击菜单使用,还可以去“设置-其他”手动编辑不喜欢规则,注:“上一曲”、“下一曲”功能将跳过符合“不喜欢歌曲”规则的歌曲,但你仍可以手动播放这些歌曲
|
||||||
|
- 新增软件内快捷键“不喜欢该歌曲”设置,全局快捷键“收藏歌曲”、“取消收藏”、“不喜欢该歌曲”设置
|
||||||
|
|
||||||
### 优化
|
### 优化
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
export const URL_SCHEME_RXP = /^lxmusic:\/\//
|
export const URL_SCHEME_RXP = /^lxmusic:\/\//
|
||||||
|
|
||||||
|
export const SPLIT_CHAR = {
|
||||||
|
DISLIKE_NAME: '@',
|
||||||
|
DISLIKE_NAME_ALIAS: '#',
|
||||||
|
} as const
|
||||||
|
|
||||||
export const STORE_NAMES = {
|
export const STORE_NAMES = {
|
||||||
APP_SETTINGS: 'config_v2',
|
APP_SETTINGS: 'config_v2',
|
||||||
|
|
|
@ -66,6 +66,21 @@ const hotKey = {
|
||||||
action: 'volume_mute',
|
action: 'volume_mute',
|
||||||
type: '',
|
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: {
|
desktop_lyric: {
|
||||||
toggle_visible: {
|
toggle_visible: {
|
||||||
|
|
|
@ -126,6 +126,10 @@ const modules = {
|
||||||
clear_music_url: 'clear_music_url',
|
clear_music_url: 'clear_music_url',
|
||||||
get_music_url_count: 'get_music_url_count',
|
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_action: 'sync_action',
|
||||||
sync_get_server_devices: 'sync_get_server_devices',
|
sync_get_server_devices: 'sync_get_server_devices',
|
||||||
sync_remove_server_device: 'sync_remove_server_device',
|
sync_remove_server_device: 'sync_remove_server_device',
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,6 +81,7 @@
|
||||||
"list__add_to": "Add to ...",
|
"list__add_to": "Add to ...",
|
||||||
"list__collect": "Collect",
|
"list__collect": "Collect",
|
||||||
"list__copy_name": "Copy name",
|
"list__copy_name": "Copy name",
|
||||||
|
"list__dislike": "Dislike",
|
||||||
"list__download": "Download",
|
"list__download": "Download",
|
||||||
"list__export_part_desc": "Choose where to save the list file",
|
"list__export_part_desc": "Choose where to save the list file",
|
||||||
"list__file": "Locate the file",
|
"list__file": "Locate the file",
|
||||||
|
@ -382,6 +383,9 @@
|
||||||
"setting__desktop_lyric_shadow_color": "Shadow color",
|
"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_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__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": "Download",
|
||||||
"setting__download_data_embed": "Whether to embed the following content in the audio file",
|
"setting__download_data_embed": "Whether to embed the following content in the audio file",
|
||||||
"setting__download_embed_lyric": "Embedding lyric",
|
"setting__download_embed_lyric": "Embedding lyric",
|
||||||
|
@ -426,6 +430,9 @@
|
||||||
"setting__hot_key_player_toggle_play": "Play/Pause Control",
|
"setting__hot_key_player_toggle_play": "Play/Pause Control",
|
||||||
"setting__hot_key_player_volume_down": "Reduce Volume",
|
"setting__hot_key_player_volume_down": "Reduce Volume",
|
||||||
"setting__hot_key_player_volume_mute": "Mute Switch",
|
"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_player_volume_up": "Increase Volume",
|
||||||
"setting__hot_key_tip_input": "Please enter a new key",
|
"setting__hot_key_tip_input": "Please enter a new key",
|
||||||
"setting__hot_key_unset_input": "Not Set",
|
"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_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__odc_clear_search_list": "Clear the search list when you are not searching",
|
||||||
"setting__other": "Extras",
|
"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": "List Data Cleanup",
|
||||||
"setting__other_listdata_clear_btn": "Clear my list data",
|
"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?",
|
"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?",
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
"list__add_to": "添加到...",
|
"list__add_to": "添加到...",
|
||||||
"list__collect": "收藏",
|
"list__collect": "收藏",
|
||||||
"list__copy_name": "复制歌曲名",
|
"list__copy_name": "复制歌曲名",
|
||||||
|
"list__dislike": "不喜欢",
|
||||||
"list__download": "下载",
|
"list__download": "下载",
|
||||||
"list__export_part_desc": "选择列表文件保存位置",
|
"list__export_part_desc": "选择列表文件保存位置",
|
||||||
"list__file": "定位文件",
|
"list__file": "定位文件",
|
||||||
|
@ -381,6 +382,9 @@
|
||||||
"setting__desktop_lyric_shadow_color": "阴影颜色",
|
"setting__desktop_lyric_shadow_color": "阴影颜色",
|
||||||
"setting__desktop_lyric_show_taskbar": "在任务栏显示歌词进程(此设置用于在录屏软件无法捕获歌词窗口时的变通解决方法)",
|
"setting__desktop_lyric_show_taskbar": "在任务栏显示歌词进程(此设置用于在录屏软件无法捕获歌词窗口时的变通解决方法)",
|
||||||
"setting__desktop_lyric_unplay_color": "未播放颜色",
|
"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": "下载设置",
|
||||||
"setting__download_data_embed": "是否将以下内容嵌入到音频文件中",
|
"setting__download_data_embed": "是否将以下内容嵌入到音频文件中",
|
||||||
"setting__download_embed_lyric": "歌词嵌入",
|
"setting__download_embed_lyric": "歌词嵌入",
|
||||||
|
@ -425,6 +429,9 @@
|
||||||
"setting__hot_key_player_toggle_play": "播放/暂停控制",
|
"setting__hot_key_player_toggle_play": "播放/暂停控制",
|
||||||
"setting__hot_key_player_volume_down": "减少音量",
|
"setting__hot_key_player_volume_down": "减少音量",
|
||||||
"setting__hot_key_player_volume_mute": "静音切换",
|
"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_player_volume_up": "增加音量",
|
||||||
"setting__hot_key_tip_input": "请输入新的按键",
|
"setting__hot_key_tip_input": "请输入新的按键",
|
||||||
"setting__hot_key_unset_input": "未设置",
|
"setting__hot_key_unset_input": "未设置",
|
||||||
|
@ -448,6 +455,9 @@
|
||||||
"setting__odc_clear_search_input": "离开搜索界面时清空搜索框",
|
"setting__odc_clear_search_input": "离开搜索界面时清空搜索框",
|
||||||
"setting__odc_clear_search_list": "离开搜索界面时清空搜索列表",
|
"setting__odc_clear_search_list": "离开搜索界面时清空搜索列表",
|
||||||
"setting__other": "其他",
|
"setting__other": "其他",
|
||||||
|
"setting__other_dislike_list": "不喜欢的歌曲规则",
|
||||||
|
"setting__other_dislike_list_label": "规则数量:",
|
||||||
|
"setting__other_dislike_list_show_btn": "编辑不喜欢歌曲规则",
|
||||||
"setting__other_listdata": "列表数据清理",
|
"setting__other_listdata": "列表数据清理",
|
||||||
"setting__other_listdata_clear_btn": "清空我的列表数据",
|
"setting__other_listdata_clear_btn": "清空我的列表数据",
|
||||||
"setting__other_listdata_clear_tip_confirm": "这将清理你创建的 所有列表 及收藏的 所有歌曲,是否真的要继续?",
|
"setting__other_listdata_clear_tip_confirm": "这将清理你创建的 所有列表 及收藏的 所有歌曲,是否真的要继续?",
|
||||||
|
|
|
@ -81,6 +81,7 @@
|
||||||
"list__add_to": "添加到...",
|
"list__add_to": "添加到...",
|
||||||
"list__collect": "收藏",
|
"list__collect": "收藏",
|
||||||
"list__copy_name": "複製歌曲名",
|
"list__copy_name": "複製歌曲名",
|
||||||
|
"list__dislike": "不喜歡",
|
||||||
"list__download": "下載",
|
"list__download": "下載",
|
||||||
"list__export_part_desc": "選擇列表文件保存位置",
|
"list__export_part_desc": "選擇列表文件保存位置",
|
||||||
"list__file": "定位文件",
|
"list__file": "定位文件",
|
||||||
|
@ -382,6 +383,9 @@
|
||||||
"setting__desktop_lyric_shadow_color": "陰影顏色",
|
"setting__desktop_lyric_shadow_color": "陰影顏色",
|
||||||
"setting__desktop_lyric_show_taskbar": "在任務欄顯示歌詞進程(此設置用於在錄屏軟件無法捕獲歌詞窗口時的變通解決方法)",
|
"setting__desktop_lyric_show_taskbar": "在任務欄顯示歌詞進程(此設置用於在錄屏軟件無法捕獲歌詞窗口時的變通解決方法)",
|
||||||
"setting__desktop_lyric_unplay_color": "未播放顏色",
|
"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": "下載設置",
|
||||||
"setting__download_data_embed": "是否將以下內容嵌入到音頻文件中",
|
"setting__download_data_embed": "是否將以下內容嵌入到音頻文件中",
|
||||||
"setting__download_embed_lyric": "歌詞嵌入",
|
"setting__download_embed_lyric": "歌詞嵌入",
|
||||||
|
@ -426,6 +430,9 @@
|
||||||
"setting__hot_key_player_toggle_play": "播放/暫停控制",
|
"setting__hot_key_player_toggle_play": "播放/暫停控制",
|
||||||
"setting__hot_key_player_volume_down": "減少音量",
|
"setting__hot_key_player_volume_down": "減少音量",
|
||||||
"setting__hot_key_player_volume_mute": "靜音切換",
|
"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_player_volume_up": "增加音量",
|
||||||
"setting__hot_key_tip_input": "請輸入新的按鍵",
|
"setting__hot_key_tip_input": "請輸入新的按鍵",
|
||||||
"setting__hot_key_unset_input": "未設置",
|
"setting__hot_key_unset_input": "未設置",
|
||||||
|
@ -449,6 +456,9 @@
|
||||||
"setting__odc_clear_search_input": "離開搜索界面時清空搜索框",
|
"setting__odc_clear_search_input": "離開搜索界面時清空搜索框",
|
||||||
"setting__odc_clear_search_list": "離開搜索界面時清空搜索列表",
|
"setting__odc_clear_search_list": "離開搜索界面時清空搜索列表",
|
||||||
"setting__other": "其他",
|
"setting__other": "其他",
|
||||||
|
"setting__other_dislike_list": "不喜歡的歌曲規則",
|
||||||
|
"setting__other_dislike_list_label": "規則數量:",
|
||||||
|
"setting__other_dislike_list_show_btn": "編輯不喜歡歌曲規則",
|
||||||
"setting__other_listdata": "列表數據清理",
|
"setting__other_listdata": "列表數據清理",
|
||||||
"setting__other_listdata_clear_btn": "清空我的列表數據",
|
"setting__other_listdata_clear_btn": "清空我的列表數據",
|
||||||
"setting__other_listdata_clear_tip_confirm": "這將清理你創建的 所有列表 及收藏的 所有歌曲,是否真的要繼續?",
|
"setting__other_listdata_clear_tip_confirm": "這將清理你創建的 所有列表 及收藏的 所有歌曲,是否真的要繼續?",
|
||||||
|
|
|
@ -70,6 +70,23 @@ export default () => {
|
||||||
return global.lx.worker.dbService.musicInfoOtherSourceCount()
|
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 }) => {
|
// mainHandle<boolean>(WIN_MAIN_RENDERER_EVENT_NAME.get_playlist, async({ params: isIgnoredError = false }) => {
|
||||||
|
|
|
@ -12,3 +12,4 @@ import '@common/types/desktop_lyric'
|
||||||
import '@common/types/theme'
|
import '@common/types/theme'
|
||||||
import '@common/types/ipc_main'
|
import '@common/types/ipc_main'
|
||||||
import '@common/types/sound_effect'
|
import '@common/types/sound_effect'
|
||||||
|
import '@common/types/dislike_list'
|
||||||
|
|
|
@ -74,6 +74,12 @@ declare namespace LX {
|
||||||
position: number
|
position: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface DislikeInfo {
|
||||||
|
// type: 'music'
|
||||||
|
content: string
|
||||||
|
// meta: string | null
|
||||||
|
}
|
||||||
|
|
||||||
interface MusicInfoOtherSource extends Omit<MusicInfoOnline, 'listId'> {
|
interface MusicInfoOtherSource extends Omit<MusicInfoOnline, 'listId'> {
|
||||||
source_id: string
|
source_id: string
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Database from 'better-sqlite3'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import tables from './tables'
|
import tables from './tables'
|
||||||
import verifyDB from './verifyDB'
|
import verifyDB from './verifyDB'
|
||||||
// import migrateData from './migrate'
|
import migrateData from './migrate'
|
||||||
|
|
||||||
let db: Database.Database
|
let db: Database.Database
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ export const init = (lxDataPath: string): boolean | null => {
|
||||||
dbFileExists = false
|
dbFileExists = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (dbFileExists) migrateData(db)
|
if (dbFileExists) migrateData(db)
|
||||||
|
|
||||||
// https://www.sqlite.org/pragma.html#pragma_optimize
|
// https://www.sqlite.org/pragma.html#pragma_optimize
|
||||||
if (dbFileExists) db.exec('PRAGMA optimize;')
|
if (dbFileExists) db.exec('PRAGMA optimize;')
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import { init } from './db'
|
import { init } from './db'
|
||||||
import { exposeWorker } from '../utils/worker'
|
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 = {
|
const common = {
|
||||||
init,
|
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
|
export type workerDBSeriveTypes = typeof common
|
||||||
& typeof list
|
& typeof list
|
||||||
|
@ -15,3 +15,4 @@ export type workerDBSeriveTypes = typeof common
|
||||||
& typeof music_url
|
& typeof music_url
|
||||||
& typeof music_other_source
|
& typeof music_other_source
|
||||||
& typeof download
|
& typeof download
|
||||||
|
& typeof dislike_list
|
||||||
|
|
|
@ -1,24 +1,36 @@
|
||||||
import type Database from 'better-sqlite3'
|
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 migrateV1 = (db: Database.Database) => {
|
||||||
const sql = `
|
const sql = `
|
||||||
DROP TABLE "main"."download_list";
|
CREATE TABLE "dislike_list" (
|
||||||
|
"type" TEXT NOT NULL,
|
||||||
CREATE TABLE "download_list" (
|
"content" TEXT NOT NULL,
|
||||||
"id" TEXT NOT NULL,
|
"meta" TEXT
|
||||||
"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.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_url from './music_url'
|
||||||
export * as music_other_source from './music_other_source'
|
export * as music_other_source from './music_other_source'
|
||||||
export * as download from './download'
|
export * as download from './download'
|
||||||
|
export * as dislike_list from './dislike_list'
|
||||||
|
|
|
@ -205,5 +205,12 @@ tables.set('download_list', `
|
||||||
PRIMARY KEY("id")
|
PRIMARY KEY("id")
|
||||||
);
|
);
|
||||||
`)
|
`)
|
||||||
|
tables.set('dislike_list', `
|
||||||
|
CREATE TABLE "dislike_list" (
|
||||||
|
"type" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"meta" TEXT
|
||||||
|
);
|
||||||
|
`)
|
||||||
|
|
||||||
export default tables
|
export default tables
|
||||||
|
|
|
@ -60,6 +60,10 @@ export default {
|
||||||
type: String,
|
type: String,
|
||||||
default: 'auto',
|
default: 'auto',
|
||||||
},
|
},
|
||||||
|
height: {
|
||||||
|
type: String,
|
||||||
|
default: 'auto',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
emits: ['after-enter', 'after-leave', 'close'],
|
emits: ['after-enter', 'after-leave', 'close'],
|
||||||
data() {
|
data() {
|
||||||
|
@ -147,6 +151,7 @@ export default {
|
||||||
maxWidth: this.maxWidth,
|
maxWidth: this.maxWidth,
|
||||||
minWidth: this.minWidth,
|
minWidth: this.minWidth,
|
||||||
width: this.width,
|
width: this.width,
|
||||||
|
height: this.height,
|
||||||
maxHeight: this.maxHeight,
|
maxHeight: this.maxHeight,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -180,6 +180,7 @@ export default {
|
||||||
const {
|
const {
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleOpenMusicDetail,
|
handleOpenMusicDetail,
|
||||||
|
handleDislikeMusic,
|
||||||
} = useMusicActions({ props })
|
} = useMusicActions({ props })
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
@ -199,6 +200,7 @@ export default {
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleShowMusicAddModal,
|
handleShowMusicAddModal,
|
||||||
handleOpenMusicDetail,
|
handleOpenMusicDetail,
|
||||||
|
handleDislikeMusic,
|
||||||
})
|
})
|
||||||
|
|
||||||
const handleListItemClick = (event, index) => {
|
const handleListItemClick = (event, index) => {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { computed, ref, reactive, nextTick } from '@common/utils/vueTools'
|
import { computed, ref, reactive, nextTick } from '@common/utils/vueTools'
|
||||||
import musicSdk from '@renderer/utils/musicSdk'
|
import musicSdk from '@renderer/utils/musicSdk'
|
||||||
import { useI18n } from '@renderer/plugins/i18n'
|
import { useI18n } from '@renderer/plugins/i18n'
|
||||||
|
import { hasDislike } from '@renderer/core/dislikeList'
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
props,
|
props,
|
||||||
|
@ -13,6 +14,7 @@ export default ({
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleShowMusicAddModal,
|
handleShowMusicAddModal,
|
||||||
handleOpenMusicDetail,
|
handleOpenMusicDetail,
|
||||||
|
handleDislikeMusic,
|
||||||
}) => {
|
}) => {
|
||||||
const itemMenuControl = reactive({
|
const itemMenuControl = reactive({
|
||||||
play: true,
|
play: true,
|
||||||
|
@ -21,6 +23,7 @@ export default ({
|
||||||
download: true,
|
download: true,
|
||||||
search: true,
|
search: true,
|
||||||
sourceDetail: true,
|
sourceDetail: true,
|
||||||
|
dislike: true,
|
||||||
})
|
})
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
const menuLocation = reactive({ x: 0, y: 0 })
|
const menuLocation = reactive({ x: 0, y: 0 })
|
||||||
|
@ -58,6 +61,11 @@ export default ({
|
||||||
action: 'sourceDetail',
|
action: 'sourceDetail',
|
||||||
disabled: !itemMenuControl.sourceDetail,
|
disabled: !itemMenuControl.sourceDetail,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: t('list__dislike'),
|
||||||
|
action: 'dislike',
|
||||||
|
disabled: !itemMenuControl.dislike,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -67,6 +75,8 @@ export default ({
|
||||||
// this.listMenu.itemMenuControl.playLater =
|
// this.listMenu.itemMenuControl.playLater =
|
||||||
itemMenuControl.download = assertApiSupport(musicInfo.source)
|
itemMenuControl.download = assertApiSupport(musicInfo.source)
|
||||||
|
|
||||||
|
itemMenuControl.dislike = !hasDislike(musicInfo)
|
||||||
|
|
||||||
if (props.checkApiSource) {
|
if (props.checkApiSource) {
|
||||||
itemMenuControl.playLater =
|
itemMenuControl.playLater =
|
||||||
itemMenuControl.play =
|
itemMenuControl.play =
|
||||||
|
@ -110,6 +120,9 @@ export default ({
|
||||||
break
|
break
|
||||||
case 'sourceDetail':
|
case 'sourceDetail':
|
||||||
handleOpenMusicDetail(index)
|
handleOpenMusicDetail(index)
|
||||||
|
case 'dislike':
|
||||||
|
handleDislikeMusic(index)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,9 @@ import { useRouter } from '@common/utils/vueRouter'
|
||||||
import musicSdk from '@renderer/utils/musicSdk'
|
import musicSdk from '@renderer/utils/musicSdk'
|
||||||
import { openUrl } from '@common/utils/electron'
|
import { openUrl } from '@common/utils/electron'
|
||||||
import { toOldMusicInfo } from '@renderer/utils'
|
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 }) => {
|
export default ({ props }) => {
|
||||||
|
@ -24,8 +27,18 @@ export default ({ props }) => {
|
||||||
openUrl(url)
|
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 {
|
return {
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleOpenMusicDetail,
|
handleOpenMusicDetail,
|
||||||
|
handleDislikeMusic,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
|
@ -299,6 +299,7 @@ export const playNext = async(isAutoToggle = false): Promise<void> => {
|
||||||
list: currentList,
|
list: currentList,
|
||||||
playedList,
|
playedList,
|
||||||
playerMusicInfo: currentList[playInfo.playerPlayIndex],
|
playerMusicInfo: currentList[playInfo.playerPlayIndex],
|
||||||
|
isNext: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!filteredList.length) {
|
if (!filteredList.length) {
|
||||||
|
@ -398,6 +399,7 @@ export const playPrev = async(isAutoToggle = false): Promise<void> => {
|
||||||
list: currentList,
|
list: currentList,
|
||||||
playedList,
|
playedList,
|
||||||
playerMusicInfo: currentList[playInfo.playerPlayIndex],
|
playerMusicInfo: currentList[playInfo.playerPlayIndex],
|
||||||
|
isNext: false,
|
||||||
})
|
})
|
||||||
if (!filteredList.length) {
|
if (!filteredList.length) {
|
||||||
handleToggleStop()
|
handleToggleStop()
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { toRaw, markRawList } from '@common/utils/vueTools'
|
||||||
import { qualityList } from '@renderer/store'
|
import { qualityList } from '@renderer/store'
|
||||||
import { clearPlayedList } from '@renderer/store/player/action'
|
import { clearPlayedList } from '@renderer/store/player/action'
|
||||||
import { appSetting } from '@renderer/store/setting'
|
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 => {
|
export const getPlayType = (highQuality: boolean, musicInfo: LX.Music.MusicInfo | LX.Download.ListItem): LX.Quality | null => {
|
||||||
if ('progress' in musicInfo || musicInfo.source == 'local') return 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[]
|
playedList: LX.Player.PlayMusicInfo[]
|
||||||
listId: string
|
listId: string
|
||||||
list: Array<LX.Music.MusicInfo | LX.Download.ListItem>
|
list: Array<LX.Music.MusicInfo | LX.Download.ListItem>
|
||||||
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
|
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
|
||||||
|
isNext: boolean
|
||||||
}) => {
|
}) => {
|
||||||
// if (this.list.listName === null) return
|
// if (this.list.listName === null) return
|
||||||
// console.log(isCheckFile)
|
// console.log(isCheckFile)
|
||||||
|
@ -28,6 +30,8 @@ export const filterList = async({ playedList, listId, list, playerMusicInfo }: {
|
||||||
playedList: toRaw(playedList),
|
playedList: toRaw(playedList),
|
||||||
savePath: appSetting['download.savePath'],
|
savePath: appSetting['download.savePath'],
|
||||||
playerMusicInfo: toRaw(playerMusicInfo),
|
playerMusicInfo: toRaw(playerMusicInfo),
|
||||||
|
dislikeInfo: { names: toRaw(dislikeInfo.names), musicNames: toRaw(dislikeInfo.musicNames), singerNames: toRaw(dislikeInfo.singerNames) },
|
||||||
|
isNext,
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!filteredList.length && playedList.length) {
|
if (!filteredList.length && playedList.length) {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { play, playList } from '@renderer/core/player'
|
||||||
import { onBeforeUnmount } from '@common/utils/vueTools'
|
import { onBeforeUnmount } from '@common/utils/vueTools'
|
||||||
import { appSetting } from '@renderer/store/setting'
|
import { appSetting } from '@renderer/store/setting'
|
||||||
import { playMusicInfo } from '@renderer/store/player/state'
|
import { playMusicInfo } from '@renderer/store/player/state'
|
||||||
|
import { initDislikeInfo } from '@renderer/core/dislikeList'
|
||||||
|
|
||||||
const initPrevPlayInfo = async() => {
|
const initPrevPlayInfo = async() => {
|
||||||
const info = await getPlayInfo()
|
const info = await getPlayInfo()
|
||||||
|
@ -48,6 +49,7 @@ export default () => {
|
||||||
window.app_event.myListUpdate(ids)
|
window.app_event.myListUpdate(ids)
|
||||||
})
|
})
|
||||||
window.lxData.userLists = await getUserLists() // 获取用户列表
|
window.lxData.userLists = await getUserLists() // 获取用户列表
|
||||||
|
await initDislikeInfo() // 获取不喜欢列表
|
||||||
await initPrevPlayInfo().catch(err => {
|
await initPrevPlayInfo().catch(err => {
|
||||||
log.error(err)
|
log.error(err)
|
||||||
}) // 初始化上次的歌曲播放信息
|
}) // 初始化上次的歌曲播放信息
|
||||||
|
|
|
@ -32,6 +32,9 @@ import { HOTKEY_PLAYER } from '@common/hotKey'
|
||||||
import { playNext, pause, playPrev, togglePlay } from '@renderer/core/player'
|
import { playNext, pause, playPrev, togglePlay } from '@renderer/core/player'
|
||||||
import usePlaybackRate from './usePlaybackRate'
|
import usePlaybackRate from './usePlaybackRate'
|
||||||
import useSoundEffect from './useSoundEffect'
|
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 () => {
|
export default () => {
|
||||||
|
@ -90,6 +93,23 @@ export default () => {
|
||||||
setStop()
|
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 => {
|
watch(() => appSetting['player.togglePlayMethod'], newValue => {
|
||||||
// setLoopPlay(newValue == 'singleLoop')
|
// setLoopPlay(newValue == 'singleLoop')
|
||||||
if (playedList.length) clearPlayedList()
|
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.next.action, handlePlayNext)
|
||||||
window.key_event.on(HOTKEY_PLAYER.prev.action, handlePlayPrev)
|
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.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('play', setPlayStatus)
|
||||||
window.app_event.on('pause', setPauseStatus)
|
window.app_event.on('pause', setPauseStatus)
|
||||||
|
@ -119,6 +142,10 @@ export default () => {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||||
window.key_event.off(HOTKEY_PLAYER.prev.action, handlePlayPrev)
|
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.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('play', setPlayStatus)
|
||||||
window.app_event.off('pause', setPauseStatus)
|
window.app_event.off('pause', setPauseStatus)
|
||||||
|
|
|
@ -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()
|
||||||
|
// }
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
|
||||||
|
export * as action from './action'
|
||||||
|
export * from './state'
|
|
@ -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: '',
|
||||||
|
})
|
|
@ -73,7 +73,7 @@ export const setPlayListId = (listId: string | null) => {
|
||||||
playInfo.playerListId = listId
|
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)
|
return listId == LIST_IDS.DOWNLOAD ? downloadList : getListMusicsFromCache(listId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,3 +15,4 @@ import '@common/types/ipc_renderer'
|
||||||
import '@common/types/config_files'
|
import '@common/types/config_files'
|
||||||
import '@common/types/music_metadata'
|
import '@common/types/music_metadata'
|
||||||
import '@common/types/sound_effect'
|
import '@common/types/sound_effect'
|
||||||
|
import '@common/types/dislike_list'
|
||||||
|
|
|
@ -40,6 +40,24 @@ export const getOtherSourceCount = async() => {
|
||||||
return rendererInvoke<number>(WIN_MAIN_RENDERER_EVENT_NAME.get_other_source_count)
|
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() => {
|
export const getHotKeyConfig = async() => {
|
||||||
return rendererInvoke<LX.HotKeyConfigAll>(WIN_MAIN_RENDERER_EVENT_NAME.get_hot_key)
|
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,
|
action: hotKeys.HOTKEY_PLAYER.next.action,
|
||||||
type: APP_EVENT_NAMES.winMainName,
|
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,
|
name: hotKeys.HOTKEY_COMMON.focusSearchInput.name,
|
||||||
action: hotKeys.HOTKEY_COMMON.focusSearchInput.action,
|
action: hotKeys.HOTKEY_COMMON.focusSearchInput.action,
|
||||||
|
@ -394,6 +417,21 @@ export const allHotKeys = markRaw({
|
||||||
action: hotKeys.HOTKEY_PLAYER.volume_mute.action,
|
action: hotKeys.HOTKEY_PLAYER.volume_mute.action,
|
||||||
type: APP_EVENT_NAMES.winMainName,
|
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,
|
name: hotKeys.HOTKEY_DESKTOP_LYRIC.toggle_visible.name,
|
||||||
action: hotKeys.HOTKEY_DESKTOP_LYRIC.toggle_visible.action,
|
action: hotKeys.HOTKEY_DESKTOP_LYRIC.toggle_visible.action,
|
||||||
|
|
|
@ -201,6 +201,7 @@ export default {
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleOpenMusicDetail,
|
handleOpenMusicDetail,
|
||||||
handleCopyName,
|
handleCopyName,
|
||||||
|
handleDislikeMusic,
|
||||||
handleRemoveMusic,
|
handleRemoveMusic,
|
||||||
} = useMusicActions({ props, list, removeAllSelect, selectedList })
|
} = useMusicActions({ props, list, removeAllSelect, selectedList })
|
||||||
|
|
||||||
|
@ -223,6 +224,7 @@ export default {
|
||||||
handleShowSortModal,
|
handleShowSortModal,
|
||||||
handleOpenMusicDetail,
|
handleOpenMusicDetail,
|
||||||
handleCopyName,
|
handleCopyName,
|
||||||
|
handleDislikeMusic,
|
||||||
handleRemoveMusic,
|
handleRemoveMusic,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { computed, ref, shallowReactive, reactive, nextTick } from '@common/utils/vueTools'
|
import { computed, ref, shallowReactive, reactive, nextTick } from '@common/utils/vueTools'
|
||||||
import musicSdk from '@renderer/utils/musicSdk'
|
import musicSdk from '@renderer/utils/musicSdk'
|
||||||
import { useI18n } from '@renderer/plugins/i18n'
|
import { useI18n } from '@renderer/plugins/i18n'
|
||||||
|
import { hasDislike } from '@renderer/core/dislikeList'
|
||||||
|
|
||||||
export default ({
|
export default ({
|
||||||
assertApiSupport,
|
assertApiSupport,
|
||||||
|
@ -15,6 +16,7 @@ export default ({
|
||||||
handleShowSortModal,
|
handleShowSortModal,
|
||||||
handleOpenMusicDetail,
|
handleOpenMusicDetail,
|
||||||
handleCopyName,
|
handleCopyName,
|
||||||
|
handleDislikeMusic,
|
||||||
handleRemoveMusic,
|
handleRemoveMusic,
|
||||||
}) => {
|
}) => {
|
||||||
const itemMenuControl = reactive({
|
const itemMenuControl = reactive({
|
||||||
|
@ -26,6 +28,7 @@ export default ({
|
||||||
sort: true,
|
sort: true,
|
||||||
download: true,
|
download: true,
|
||||||
search: true,
|
search: true,
|
||||||
|
dislike: true,
|
||||||
remove: true,
|
remove: true,
|
||||||
sourceDetail: true,
|
sourceDetail: true,
|
||||||
})
|
})
|
||||||
|
@ -80,6 +83,11 @@ export default ({
|
||||||
action: 'search',
|
action: 'search',
|
||||||
disabled: !itemMenuControl.search,
|
disabled: !itemMenuControl.search,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: t('list__dislike'),
|
||||||
|
action: 'dislike',
|
||||||
|
disabled: !itemMenuControl.dislike,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: t('list__remove'),
|
name: t('list__remove'),
|
||||||
action: 'remove',
|
action: 'remove',
|
||||||
|
@ -94,6 +102,8 @@ export default ({
|
||||||
// itemMenuControl.playLater =
|
// itemMenuControl.playLater =
|
||||||
itemMenuControl.download = assertApiSupport(musicInfo.source) && musicInfo.source != 'local'
|
itemMenuControl.download = assertApiSupport(musicInfo.source) && musicInfo.source != 'local'
|
||||||
|
|
||||||
|
itemMenuControl.dislike = !hasDislike(musicInfo)
|
||||||
|
|
||||||
menuLocation.x = event.pageX
|
menuLocation.x = event.pageX
|
||||||
menuLocation.y = event.pageY
|
menuLocation.y = event.pageY
|
||||||
|
|
||||||
|
@ -138,6 +148,9 @@ export default ({
|
||||||
case 'search':
|
case 'search':
|
||||||
handleSearch(index)
|
handleSearch(index)
|
||||||
break
|
break
|
||||||
|
case 'dislike':
|
||||||
|
handleDislikeMusic(index)
|
||||||
|
break
|
||||||
case 'remove':
|
case 'remove':
|
||||||
handleRemoveMusic(index)
|
handleRemoveMusic(index)
|
||||||
break
|
break
|
||||||
|
|
|
@ -6,6 +6,9 @@ import { useI18n } from '@renderer/plugins/i18n'
|
||||||
import { removeListMusics } from '@renderer/store/list/action'
|
import { removeListMusics } from '@renderer/store/list/action'
|
||||||
import { appSetting } from '@renderer/store/setting'
|
import { appSetting } from '@renderer/store/setting'
|
||||||
import { toOldMusicInfo } from '@renderer/utils/index'
|
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 }) => {
|
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))
|
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) => {
|
const handleRemoveMusic = async(index, single) => {
|
||||||
if (selectedList.value.length && !single) {
|
if (selectedList.value.length && !single) {
|
||||||
const confirm = await (selectedList.value.length > 1
|
const confirm = await (selectedList.value.length > 1
|
||||||
|
@ -55,6 +66,7 @@ export default ({ props, list, selectedList, removeAllSelect }) => {
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleOpenMusicDetail,
|
handleOpenMusicDetail,
|
||||||
handleCopyName,
|
handleCopyName,
|
||||||
|
handleDislikeMusic,
|
||||||
handleRemoveMusic,
|
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="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') }}
|
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
|
dd
|
||||||
h3#other_lyric_edited {{ $t('setting__other_lyric_edited_cache') }}
|
h3#other_lyric_edited {{ $t('setting__other_lyric_edited_cache') }}
|
||||||
div
|
div
|
||||||
|
@ -65,9 +75,14 @@ import { dialog } from '@renderer/plugins/Dialog'
|
||||||
import { useI18n } from '@renderer/plugins/i18n'
|
import { useI18n } from '@renderer/plugins/i18n'
|
||||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||||
import { overwriteListFull } from '@renderer/store/list/listManage'
|
import { overwriteListFull } from '@renderer/store/list/listManage'
|
||||||
|
import { dislikeInfo } from '@renderer/store/dislikeList'
|
||||||
|
import DislikeListModal from './DislikeListModal.vue'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'SettingOther',
|
name: 'SettingOther',
|
||||||
|
components: {
|
||||||
|
DislikeListModal,
|
||||||
|
},
|
||||||
setup() {
|
setup() {
|
||||||
const t = useI18n()
|
const t = useI18n()
|
||||||
|
|
||||||
|
@ -135,6 +150,11 @@ export default {
|
||||||
}
|
}
|
||||||
refreshMusicUrlCount()
|
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 lyricRawCount = ref(0)
|
||||||
const isDisabledLyricRawCacheClear = ref(false)
|
const isDisabledLyricRawCacheClear = ref(false)
|
||||||
|
@ -204,6 +224,10 @@ export default {
|
||||||
isDisabledMusicUrlCacheClear,
|
isDisabledMusicUrlCacheClear,
|
||||||
handleClearMusicUrlCache,
|
handleClearMusicUrlCache,
|
||||||
|
|
||||||
|
dislikeRuleCount,
|
||||||
|
isShowDislikeList,
|
||||||
|
handleCountRules,
|
||||||
|
|
||||||
lyricRawCount,
|
lyricRawCount,
|
||||||
isDisabledLyricRawCacheClear,
|
isDisabledLyricRawCacheClear,
|
||||||
handleClearLyricRawCache,
|
handleClearLyricRawCache,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
// import { throttle } from '@common/utils'
|
// import { throttle } from '@common/utils'
|
||||||
|
|
||||||
|
import { SPLIT_CHAR } from '@common/constants'
|
||||||
import { filterFileName, sortInsert, similar, arrPushByPosition, arrShuffle } from '@common/utils/common'
|
import { filterFileName, sortInsert, similar, arrPushByPosition, arrShuffle } from '@common/utils/common'
|
||||||
import { joinPath, saveStrToFile } from '@common/utils/nodejs'
|
import { joinPath, saveStrToFile } from '@common/utils/nodejs'
|
||||||
import { createLocalMusicInfo } from '@renderer/utils/music'
|
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`指向的歌曲)
|
* 播放器内当前歌曲(`playInfo.playerPlayIndex`指向的歌曲)
|
||||||
*/
|
*/
|
||||||
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
|
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
|
||||||
|
/**
|
||||||
|
* 不喜欢的歌曲名字列表
|
||||||
|
*/
|
||||||
|
dislikeInfo: Omit<LX.Dislike.DislikeInfo, 'rules'>
|
||||||
|
|
||||||
|
isNext: boolean
|
||||||
}) => {
|
}) => {
|
||||||
let playerIndex = -1
|
let playerIndex = -1
|
||||||
|
|
||||||
let canPlayList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = []
|
let canPlayList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = []
|
||||||
const filteredPlayedList = playedList.filter(pmInfo => pmInfo.listId == listId && !pmInfo.isTempPlay).map(({ musicInfo }) => musicInfo)
|
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 => {
|
const filteredList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = list.filter(s => {
|
||||||
// if (!assertApiSupport(s.source)) return false
|
// 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)
|
canPlayList.push(s)
|
||||||
|
|
||||||
|
@ -49,8 +69,35 @@ export const filterMusicList = async({ playedList, listId, list, savePath, playe
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
if (playerMusicInfo) {
|
if (playerMusicInfo) {
|
||||||
|
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)
|
playerIndex = (filteredList.length ? filteredList : canPlayList).findIndex(m => m.id == playerMusicInfo.id)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
filteredList,
|
filteredList,
|
||||||
canPlayList,
|
canPlayList,
|
||||||
|
|
Loading…
Reference in New Issue