新增同步功能对“不喜欢歌曲”列表的同步
parent
fc03cd77fc
commit
b1f9e525ab
|
@ -10,6 +10,7 @@
|
|||
- 新增我的列表名右键菜单-排序歌曲-随机乱序功能,使用它可以对选中列表内歌曲进行随机重排(#1440)
|
||||
- 新增数据同步服务端模式已认证设备列表管理,该功能位置:设置-数据同步-服务端模式-已认证设备列表
|
||||
- 新增“不喜欢歌曲”功能,可以在我的列表或者在线列表内歌曲的右击菜单使用,还可以去“设置-其他”手动编辑不喜欢规则,注:“上一曲”、“下一曲”功能将跳过符合“不喜欢歌曲”规则的歌曲,但你仍可以手动播放这些歌曲
|
||||
- 新增同步功能对“不喜欢歌曲”列表的同步
|
||||
- 新增软件内快捷键“不喜欢该歌曲”设置,全局快捷键“收藏歌曲”、“取消收藏”、“不喜欢该歌曲”设置
|
||||
- 新增设置-播放设置-点击相同列表内的歌曲切歌时是否清空已播放列表(随机模式下列表内所有歌曲会重新参与随机)选项,默认关闭
|
||||
|
||||
|
|
|
@ -61,10 +61,14 @@ export const File = {
|
|||
listDir: 'list',
|
||||
listSnapshotDir: 'snapshot',
|
||||
listSnapshotInfoJSON: 'snapshotInfo.json',
|
||||
dislikeDir: 'dislike',
|
||||
dislikeSnapshotDir: 'snapshot',
|
||||
dislikeSnapshotInfoJSON: 'snapshotInfo.json',
|
||||
|
||||
syncAuthKeysJSON: 'syncAuthKey.json',
|
||||
} as const
|
||||
|
||||
export const FeaturesList = [
|
||||
'list',
|
||||
'dislike',
|
||||
] as const
|
||||
|
|
|
@ -36,6 +36,12 @@ const modules = {
|
|||
list_music_check_exist: 'list_music_check_exist',
|
||||
list_music_get_list_ids: 'list_music_get_list_ids',
|
||||
},
|
||||
dislike: {
|
||||
get_dislike_music_infos: 'get_dislike_music_infos',
|
||||
add_dislike_music_infos: 'add_dislike_music_infos',
|
||||
overwrite_dislike_music_infos: 'overwrite_dislike_music_infos',
|
||||
clear_dislike_music_infos: 'clear_dislike_music_infos',
|
||||
},
|
||||
winMain: {
|
||||
focus: 'focus',
|
||||
close: 'close',
|
||||
|
@ -126,10 +132,6 @@ 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',
|
||||
|
@ -186,6 +188,7 @@ for (const moduleName of Object.keys(modules) as Array<keyof typeof modules>) {
|
|||
|
||||
export const CMMON_EVENT_NAME = modules.common
|
||||
export const PLAYER_EVENT_NAME = modules.player
|
||||
export const DISLIKE_EVENT_NAME = modules.dislike
|
||||
export const WIN_MAIN_RENDERER_EVENT_NAME = modules.winMain
|
||||
export const WIN_LYRIC_RENDERER_EVENT_NAME = modules.winLyric
|
||||
export const HOTKEY_RENDERER_EVENT_NAME = modules.hotKey
|
||||
|
|
|
@ -23,13 +23,15 @@ declare namespace LX {
|
|||
singer: string
|
||||
}
|
||||
|
||||
type DislikeRules = string
|
||||
|
||||
interface DislikeInfo {
|
||||
// musicIds: Set<string>
|
||||
names: Set<string>
|
||||
musicNames: Set<string>
|
||||
singerNames: Set<string>
|
||||
// list: LX.Dislike.ListItem[]
|
||||
rules: string
|
||||
rules: DislikeRules
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
declare namespace LX {
|
||||
|
||||
namespace Sync {
|
||||
namespace Dislike {
|
||||
interface ListInfo {
|
||||
lastSyncDate?: number
|
||||
snapshotKey: string
|
||||
}
|
||||
|
||||
interface SyncActionBase <A> {
|
||||
action: A
|
||||
}
|
||||
interface SyncActionData<A, D> extends SyncActionBase<A> {
|
||||
data: D
|
||||
}
|
||||
type SyncAction<A, D = undefined> = D extends undefined ? SyncActionBase<A> : SyncActionData<A, D>
|
||||
type ActionList = SyncAction<'dislike_data_overwrite', LX.Dislike.DislikeRules>
|
||||
| SyncAction<'dislike_music_add', LX.Dislike.DislikeMusicInfo[]>
|
||||
| SyncAction<'dislike_music_clear'>
|
||||
|
||||
type SyncMode = 'merge_local_remote'
|
||||
| 'merge_remote_local'
|
||||
| 'overwrite_local_remote'
|
||||
| 'overwrite_remote_local'
|
||||
// | 'none'
|
||||
| 'cancel'
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -19,12 +19,20 @@ declare namespace LX {
|
|||
}
|
||||
type SyncAction<A, D = undefined> = D extends undefined ? SyncActionBase<A> : SyncActionData<A, D>
|
||||
|
||||
type SyncMainWindowActions = SyncAction<'select_mode', string>
|
||||
|
||||
interface ModeTypes {
|
||||
list: LX.Sync.List.SyncMode
|
||||
dislike: LX.Sync.Dislike.SyncMode
|
||||
}
|
||||
|
||||
type ModeType = { [K in keyof ModeTypes]: { type: K, mode: ModeTypes[K] } }[keyof ModeTypes]
|
||||
|
||||
type SyncMainWindowActions = SyncAction<'select_mode', { deviceName: string, type: keyof ModeTypes }>
|
||||
| SyncAction<'close_select_mode'>
|
||||
| SyncAction<'client_status', ClientStatus>
|
||||
| SyncAction<'server_status', ServerStatus>
|
||||
|
||||
type SyncServiceActions = SyncAction<'select_mode', LX.Sync.List.SyncMode>
|
||||
type SyncServiceActions = SyncAction<'select_mode', ModeType>
|
||||
| SyncAction<'get_server_status'>
|
||||
| SyncAction<'get_client_status'>
|
||||
| SyncAction<'generate_code'>
|
||||
|
@ -64,6 +72,7 @@ declare namespace LX {
|
|||
type ServerType = 'desktop-app' | 'server'
|
||||
interface EnabledFeatures {
|
||||
list: boolean
|
||||
dislike: boolean
|
||||
}
|
||||
type SupportedFeatures = Partial<{ [k in keyof EnabledFeatures]: number }>
|
||||
}
|
||||
|
|
|
@ -383,8 +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_input_tip": "song name@artist name\nSong name\n@ singer name",
|
||||
"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_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",
|
||||
|
@ -588,14 +589,20 @@
|
|||
"source_xm": "Xiami",
|
||||
"sync__auth_code_input_tip": "Please enter the connection code",
|
||||
"sync__auth_code_title": "Need to enter the connection code",
|
||||
"sync__dislike_merge_tip_desc": "Merge the content of the two lists and remove the duplicates",
|
||||
"sync__dislike_other_tip_desc": "\"Cancel sync\" will not use the dislike list sync feature",
|
||||
"sync__dislike_overwrite_tip_desc": "The list of overriddens will be replaced with the list of overriders",
|
||||
"sync__dislike_title": "Choose how to sync with {name}'s dislike list",
|
||||
"sync__list_merge_tip_desc": "Merge the two lists together, the same song will be removed (the song of the merged person is removed), and different songs will be added.",
|
||||
"sync__list_other_tip_desc": "\"Cancel Sync\" will not use list sync.",
|
||||
"sync__list_overwrite_tip_desc": "The list with the same ID of the covered person and the covered list will be deleted and replaced with the list of the covered person (lists with different list IDs will be merged together). If you check Complete coverage, all lists of the covered person will be moved. \nDivide, and then replace with a list of overriders.",
|
||||
"sync__list_title": "Choose how to synchronize the list with {name}",
|
||||
"sync__merge_btn_local_remote": "Local list merge remote list",
|
||||
"sync__merge_btn_remote_local": "Remote list merge local list",
|
||||
"sync__merge_label": "Merge",
|
||||
"sync__merge_tip": "Merge:",
|
||||
"sync__merge_tip_desc": "Merge the two lists together, the same song will be removed (the song of the merged person is removed), and different songs will be added.",
|
||||
"sync__other_label": "Other",
|
||||
"sync__other_tip": "Other: ",
|
||||
"sync__other_tip_desc": "\"Cancel Sync\" will not use list sync.",
|
||||
"sync__overwrite": "Full coverage",
|
||||
"sync__overwrite_btn_cancel": "Cancel sync",
|
||||
"sync__overwrite_btn_local_remote": "Local list Overwrite remote list",
|
||||
|
@ -603,8 +610,6 @@
|
|||
"sync__overwrite_btn_remote_local": "Remote list Overwrite local list",
|
||||
"sync__overwrite_label": "Cover",
|
||||
"sync__overwrite_tip": "Over: ",
|
||||
"sync__overwrite_tip_desc": "The list with the same ID of the covered person and the covered list will be deleted and replaced with the list of the covered person (lists with different list IDs will be merged together). If you check Complete coverage, all lists of the covered person will be moved. \nDivide, and then replace with a list of overriders.",
|
||||
"sync__title": "Choose how to synchronize the list with {name}",
|
||||
"sync_status_disabled": "not connected",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
|
|
|
@ -382,8 +382,9 @@
|
|||
"setting__desktop_lyric_shadow_color": "阴影颜色",
|
||||
"setting__desktop_lyric_show_taskbar": "在任务栏显示歌词进程(此设置用于在录屏软件无法捕获歌词窗口时的变通解决方法)",
|
||||
"setting__desktop_lyric_unplay_color": "未播放颜色",
|
||||
"setting__dislike_list_input_tip": "歌曲名@歌手名\n歌曲名\n@歌手名",
|
||||
"setting__dislike_list_save_btn": "保存",
|
||||
"setting__dislike_list_tips": "1. 每条一行,若歌曲或者歌手名字中存在“@”符号,需要将其替换成“#”\n2. 指定某歌手的某首歌:<歌曲名>@<歌手名>\n3. 指定某首歌:<歌曲名>\n4. 指定某歌手:@<歌手名>",
|
||||
"setting__dislike_list_tips": "1. 每条一行,若歌曲或者歌手名字中存在“@”符号,需要将其替换成“#”\n2. 指定某歌手的某首歌:歌曲名@歌手名\n3. 指定某首歌:歌曲名\n4. 指定某歌手:@歌手名",
|
||||
"setting__dislike_list_title": "不喜欢的歌曲规则列表",
|
||||
"setting__download": "下载设置",
|
||||
"setting__download_data_embed": "是否将以下内容嵌入到音频文件中",
|
||||
|
@ -587,14 +588,20 @@
|
|||
"source_xm": "虾米音乐",
|
||||
"sync__auth_code_input_tip": "请输入连接码",
|
||||
"sync__auth_code_title": "需要输入连接码",
|
||||
"sync__dislike_merge_tip_desc": "合并两边列表内容并去重",
|
||||
"sync__dislike_other_tip_desc": "“取消同步”将不使用不喜欢列表同步功能",
|
||||
"sync__dislike_overwrite_tip_desc": "被覆盖者的列表将被替换成覆盖者的列表",
|
||||
"sync__dislike_title": "选择与 {name} 的不喜欢列表同步方式",
|
||||
"sync__list_merge_tip_desc": "将两边的列表合并到一起,相同的歌曲将被去掉(去掉的是被合并者的歌曲),不同的歌曲将被添加。",
|
||||
"sync__list_other_tip_desc": "“取消同步”将不使用列表同步功能。",
|
||||
"sync__list_overwrite_tip_desc": "被覆盖者与覆盖者列表ID相同的列表将被删除后替换成覆盖者的列表(列表ID不同的列表将被合并到一起),若勾选完全覆盖,则被覆盖者的所有列表将被移除,然后替换成覆盖者的列表。",
|
||||
"sync__list_title": "选择与 {name} 的列表同步方式",
|
||||
"sync__merge_btn_local_remote": "本机列表 合并 远程列表",
|
||||
"sync__merge_btn_remote_local": "远程列表 合并 本机列表",
|
||||
"sync__merge_label": "合并",
|
||||
"sync__merge_tip": "合并:",
|
||||
"sync__merge_tip_desc": "将两边的列表合并到一起,相同的歌曲将被去掉(去掉的是被合并者的歌曲),不同的歌曲将被添加。",
|
||||
"sync__other_label": "其他",
|
||||
"sync__other_tip": "其他:",
|
||||
"sync__other_tip_desc": "“取消同步”将不使用列表同步功能。",
|
||||
"sync__overwrite": "完全覆盖",
|
||||
"sync__overwrite_btn_cancel": "取消同步",
|
||||
"sync__overwrite_btn_local_remote": "本机列表 覆盖 远程列表",
|
||||
|
@ -602,8 +609,6 @@
|
|||
"sync__overwrite_btn_remote_local": "远程列表 覆盖 本机列表",
|
||||
"sync__overwrite_label": "覆盖",
|
||||
"sync__overwrite_tip": "覆盖:",
|
||||
"sync__overwrite_tip_desc": "被覆盖者与覆盖者列表ID相同的列表将被删除后替换成覆盖者的列表(列表ID不同的列表将被合并到一起),若勾选完全覆盖,则被覆盖者的所有列表将被移除,然后替换成覆盖者的列表。",
|
||||
"sync__title": "选择与 {name} 的列表同步方式",
|
||||
"sync_status_disabled": "未连接",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
|
|
|
@ -383,8 +383,9 @@
|
|||
"setting__desktop_lyric_shadow_color": "陰影顏色",
|
||||
"setting__desktop_lyric_show_taskbar": "在任務欄顯示歌詞進程(此設置用於在錄屏軟件無法捕獲歌詞窗口時的變通解決方法)",
|
||||
"setting__desktop_lyric_unplay_color": "未播放顏色",
|
||||
"setting__dislike_list_input_tip": "歌曲名@歌手名\n歌曲名\n@歌手名",
|
||||
"setting__dislike_list_save_btn": "保存",
|
||||
"setting__dislike_list_tips": "1. 每條一行,若歌曲或者歌手名字中存在“@”符號,需要將其替換成“#”\n2. 指定某歌手的某首歌:<歌曲名>@<歌手名>\n3. 指定某首歌:<歌曲名>\n4. 指定某歌手:@<歌手名>",
|
||||
"setting__dislike_list_tips": "1. 每條一行,若歌曲或者歌手名字中存在“@”符號,需要將其替換成“#”\n2. 指定某歌手的某首歌:歌曲名@歌手名\n3. 指定某首歌:歌曲名\n4. 指定某歌手:@歌手名",
|
||||
"setting__dislike_list_title": "不喜歡的歌曲規則列表",
|
||||
"setting__download": "下載設置",
|
||||
"setting__download_data_embed": "是否將以下內容嵌入到音頻文件中",
|
||||
|
@ -587,14 +588,20 @@
|
|||
"source_xm": "蝦米音樂",
|
||||
"sync__auth_code_input_tip": "請輸入連接碼",
|
||||
"sync__auth_code_title": "需要輸入連接碼",
|
||||
"sync__dislike_merge_tip_desc": "合併兩邊列表內容並去重",
|
||||
"sync__dislike_other_tip_desc": "“取消同步”將不使用不喜歡列表同步功能",
|
||||
"sync__dislike_overwrite_tip_desc": "被覆蓋者的列表將被替換成覆蓋者的列表",
|
||||
"sync__dislike_title": "選擇與 {name} 的不喜歡列表同步方式",
|
||||
"sync__list_merge_tip_desc": "將兩邊的列表合併到一起,相同的歌曲將被去掉(去掉的是被合併者的歌曲),不同的歌曲將被添加。",
|
||||
"sync__list_other_tip_desc": "“取消同步”將不使用列表同步功能。",
|
||||
"sync__list_overwrite_tip_desc": "被覆蓋者與覆蓋者列表ID相同的列表將被刪除後替換成覆蓋者的列表(列表ID不同的列表將被合併到一起),若勾選完全覆蓋,則被覆蓋者的所有列表將被移除,然後替換成覆蓋者的列表。",
|
||||
"sync__list_title": "選擇與 {name} 的列表同步方式",
|
||||
"sync__merge_btn_local_remote": "本機列表 合併 遠程列表",
|
||||
"sync__merge_btn_remote_local": "遠程列表 合併 本機列表",
|
||||
"sync__merge_label": "合併",
|
||||
"sync__merge_tip": "合併:",
|
||||
"sync__merge_tip_desc": "將兩邊的列表合併到一起,相同的歌曲將被去掉(去掉的是被合併者的歌曲),不同的歌曲將被添加。",
|
||||
"sync__other_label": "其他",
|
||||
"sync__other_tip": "其他:",
|
||||
"sync__other_tip_desc": "“取消同步”將不使用列表同步功能。",
|
||||
"sync__overwrite": "完全覆蓋",
|
||||
"sync__overwrite_btn_cancel": "取消同步",
|
||||
"sync__overwrite_btn_local_remote": "本機列表 覆蓋 遠程列表",
|
||||
|
@ -602,8 +609,6 @@
|
|||
"sync__overwrite_btn_remote_local": "遠程列表 覆蓋 本機列表",
|
||||
"sync__overwrite_label": "覆蓋",
|
||||
"sync__overwrite_tip": "覆蓋:",
|
||||
"sync__overwrite_tip_desc": "被覆蓋者與覆蓋者列表ID相同的列表將被刪除後替換成覆蓋者的列表(列表ID不同的列表將被合併到一起),若勾選完全覆蓋,則被覆蓋者的所有列表將被移除,然後替換成覆蓋者的列表。",
|
||||
"sync__title": "選擇與 {name} 的列表同步方式",
|
||||
"sync_status_disabled": "未連接",
|
||||
"tag__high_quality": "HQ",
|
||||
"tag__lossless": "SQ",
|
||||
|
|
|
@ -6,7 +6,7 @@ import { getTheme, initHotKey, initSetting, parseEnvParams } from './utils'
|
|||
import { navigationUrlWhiteList } from '@common/config'
|
||||
import defaultSetting from '@common/defaultSetting'
|
||||
import { closeWindow, isExistWindow as isExistMainWindow, showWindow as showMainWindow } from './modules/winMain'
|
||||
import { createAppEvent, createListEvent } from '@main/event'
|
||||
import { createAppEvent, createDislikeEvent, createListEvent } from '@main/event'
|
||||
import { isMac, log } from '@common/utils'
|
||||
import createWorkers from './worker'
|
||||
import { migrateDBData } from './utils/migrate'
|
||||
|
@ -212,6 +212,7 @@ export const initAppSetting = async() => {
|
|||
// mainWindowClosed: true,
|
||||
event_app: createAppEvent(),
|
||||
event_list: createListEvent(),
|
||||
event_dislike: createDislikeEvent(),
|
||||
appSetting: defaultSetting,
|
||||
worker: createWorkers(),
|
||||
hotKey: {
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import { EventEmitter } from 'events'
|
||||
|
||||
|
||||
export class Event extends EventEmitter {
|
||||
dislike_changed() {
|
||||
this.emit('dislike_changed')
|
||||
}
|
||||
|
||||
/**
|
||||
* 覆盖整个列表数据
|
||||
* @param dislikeData 列表数据
|
||||
* @param isRemote 是否属于远程操作
|
||||
*/
|
||||
async dislike_data_overwrite(dislikeData: LX.Dislike.DislikeRules, isRemote: boolean = false) {
|
||||
await global.lx.worker.dbService.dislikeInfoOverwrite(dislikeData)
|
||||
this.emit('dislike_data_overwrite', dislikeData, isRemote)
|
||||
this.dislike_changed()
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量添加歌曲到列表
|
||||
* @param dislikeId 列表id
|
||||
* @param musicInfos 添加的歌曲信息
|
||||
* @param addMusicLocationType 添加在到列表的位置
|
||||
* @param isRemote 是否属于远程操作
|
||||
*/
|
||||
async dislike_music_add(musicInfo: LX.Dislike.DislikeMusicInfo[], isRemote: boolean = false) {
|
||||
// const changedIds =
|
||||
await global.lx.worker.dbService.dislikeInfoAdd(musicInfo)
|
||||
// await checkUpdateDislike(changedIds)
|
||||
this.emit('dislike_music_add', musicInfo, isRemote)
|
||||
this.dislike_changed()
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空列表内的歌曲
|
||||
* @param ids 列表Id
|
||||
* @param isRemote 是否属于远程操作
|
||||
*/
|
||||
async dislike_music_clear(isRemote: boolean = false) {
|
||||
// const changedIds =
|
||||
await global.lx.worker.dbService.dislikeInfoOverwrite('')
|
||||
// await checkUpdateDislike(changedIds)
|
||||
this.emit('dislike_music_clear', isRemote)
|
||||
this.dislike_changed()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type EventMethods = Omit<EventType, keyof EventEmitter>
|
||||
declare class EventType extends Event {
|
||||
on<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): this
|
||||
once<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): this
|
||||
off<K extends keyof EventMethods>(event: K, listener: EventMethods[K]): this
|
||||
}
|
||||
export type Type = Omit<EventType, keyof Omit<EventEmitter, 'on' | 'off' | 'once'>>
|
|
@ -1,9 +1,11 @@
|
|||
import { Event as App, type Type as AppType } from './AppEvent'
|
||||
import { Event as List, type Type as ListType } from './ListEvent'
|
||||
import { Event as Dislike, type Type as DislikeType } from './DislikeEvent'
|
||||
|
||||
export type {
|
||||
AppType,
|
||||
ListType,
|
||||
DislikeType,
|
||||
}
|
||||
|
||||
export const createAppEvent = (): AppType => {
|
||||
|
@ -14,3 +16,7 @@ export const createListEvent = (): ListType => {
|
|||
return new List()
|
||||
}
|
||||
|
||||
export const createDislikeEvent = (): DislikeType => {
|
||||
return new Dislike()
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export { registerRendererEvents } from './winRendererEvent'
|
||||
|
||||
export { default } from './rendererEvent'
|
|
@ -0,0 +1,18 @@
|
|||
import { mainHandle } from '@common/mainIpc'
|
||||
import { DISLIKE_EVENT_NAME } from '@common/ipcNames'
|
||||
|
||||
// 列表操作事件(公共,只注册一次)
|
||||
export default () => {
|
||||
mainHandle<LX.Dislike.DislikeInfo>(DISLIKE_EVENT_NAME.get_dislike_music_infos, async() => {
|
||||
return global.lx.worker.dbService.getDislikeListInfo()
|
||||
})
|
||||
mainHandle<LX.Dislike.DislikeMusicInfo[]>(DISLIKE_EVENT_NAME.add_dislike_music_infos, async({ params: listData }) => {
|
||||
await global.lx.event_dislike.dislike_music_add(listData, false)
|
||||
})
|
||||
mainHandle<LX.Dislike.DislikeRules>(DISLIKE_EVENT_NAME.overwrite_dislike_music_infos, async({ params: rules }) => {
|
||||
await global.lx.event_dislike.dislike_data_overwrite(rules, false)
|
||||
})
|
||||
mainHandle(DISLIKE_EVENT_NAME.clear_dislike_music_infos, async() => {
|
||||
await global.lx.event_dislike.dislike_music_clear(false)
|
||||
})
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
import { DISLIKE_EVENT_NAME } from '@common/ipcNames'
|
||||
|
||||
// 发送列表操作事件到渲染进程的注册方法
|
||||
// 哪个渲染进程需要接收则引入此方法注册
|
||||
export const registerRendererEvents = (sendEvent: <T = any>(name: string, params?: T | undefined) => void) => {
|
||||
const dislike_music_add = async(listData: LX.Dislike.DislikeMusicInfo[]) => {
|
||||
sendEvent<LX.Dislike.DislikeMusicInfo[]>(DISLIKE_EVENT_NAME.add_dislike_music_infos, listData)
|
||||
}
|
||||
const dislike_data_overwrite = async(rules: LX.Dislike.DislikeRules) => {
|
||||
sendEvent<LX.Dislike.DislikeRules>(DISLIKE_EVENT_NAME.overwrite_dislike_music_infos, rules)
|
||||
}
|
||||
const dislike_music_clear = async() => {
|
||||
sendEvent(DISLIKE_EVENT_NAME.clear_dislike_music_infos)
|
||||
}
|
||||
global.lx.event_dislike.on('dislike_music_add', dislike_music_add)
|
||||
global.lx.event_dislike.on('dislike_data_overwrite', dislike_data_overwrite)
|
||||
global.lx.event_dislike.on('dislike_music_clear', dislike_music_clear)
|
||||
|
||||
return () => {
|
||||
global.lx.event_dislike.off('dislike_music_add', dislike_music_add)
|
||||
global.lx.event_dislike.off('dislike_data_overwrite', dislike_data_overwrite)
|
||||
global.lx.event_dislike.off('dislike_music_clear', dislike_music_clear)
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
import common from './common'
|
||||
import list from './list'
|
||||
import dislike from './dislike'
|
||||
|
||||
export default () => {
|
||||
common()
|
||||
list()
|
||||
dislike()
|
||||
}
|
||||
|
|
|
@ -200,6 +200,7 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
|||
|
||||
client.remote = message2read.remote
|
||||
client.remoteQueueList = message2read.createQueueRemote('list')
|
||||
client.remoteQueueDislike = message2read.createQueueRemote('dislike')
|
||||
|
||||
client.addEventListener('message', ({ data }) => {
|
||||
if (data == 'ping') return
|
||||
|
@ -235,6 +236,7 @@ export const connect = (urlInfo: LX.Sync.Client.UrlInfo, keyInfo: LX.Sync.Client
|
|||
client!.isReady = false
|
||||
client!.moduleReadys = {
|
||||
list: false,
|
||||
dislike: false,
|
||||
}
|
||||
disconnected = false
|
||||
sendSyncStatus({
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
// 这个文件导出的方法将暴露给服务端调用,第一个参数固定为当前 socket 对象
|
||||
import { handleRemoteDislikeAction, getLocalDislikeData, setLocalDislikeData } from '@main/modules/sync/dislikeEvent'
|
||||
import { toMD5 } from '@common/utils/nodejs'
|
||||
import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain'
|
||||
import log from '@main/modules/sync/log'
|
||||
import { registerEvent, unregisterEvent } from './localEvent'
|
||||
|
||||
const logInfo = (eventName: string, success = false) => {
|
||||
log.info(`[${eventName}]${eventName.replace('dislike:sync:dislike_sync_', '').replaceAll('_', ' ')}${success ? ' success' : ''}`)
|
||||
}
|
||||
// const logError = (eventName: string, err: Error) => {
|
||||
// log.error(`[${eventName}]${eventName.replace('dislike:sync:dislike_sync_', '').replaceAll('_', ' ')} error: ${err.message}`)
|
||||
// }
|
||||
const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.Dislike.SyncMode> => new Promise((resolve, reject) => {
|
||||
const handleDisconnect = (err: Error) => {
|
||||
sendCloseSelectMode()
|
||||
removeSelectModeListener()
|
||||
reject(err)
|
||||
}
|
||||
let removeEventClose = socket.onClose(handleDisconnect)
|
||||
sendSelectMode(socket.data.keyInfo.serverName, 'dislike', (mode) => {
|
||||
if (mode == null) {
|
||||
reject(new Error('cancel'))
|
||||
return
|
||||
}
|
||||
resolve(mode)
|
||||
removeSelectModeListener()
|
||||
removeEventClose()
|
||||
})
|
||||
})
|
||||
const handler: LX.Sync.ClientSyncHandlerDislikeActions<LX.Sync.Client.Socket> = {
|
||||
async onDislikeSyncAction(socket, action) {
|
||||
if (!socket.moduleReadys?.dislike) return
|
||||
await handleRemoteDislikeAction(action)
|
||||
},
|
||||
|
||||
async dislike_sync_get_md5(socket) {
|
||||
logInfo('dislike:sync:dislike_sync_get_md5')
|
||||
return toMD5((await getLocalDislikeData()).trim())
|
||||
},
|
||||
|
||||
|
||||
async dislike_sync_get_sync_mode(socket) {
|
||||
return getSyncMode(socket)
|
||||
},
|
||||
|
||||
async dislike_sync_get_list_data(socket) {
|
||||
logInfo('dislike:sync:dislike_sync_get_list_data')
|
||||
return getLocalDislikeData()
|
||||
},
|
||||
|
||||
async dislike_sync_set_list_data(socket, data) {
|
||||
logInfo('dislike:sync:dislike_sync_set_list_data')
|
||||
await setLocalDislikeData(data)
|
||||
},
|
||||
|
||||
async dislike_sync_finished(socket) {
|
||||
logInfo('dislike:sync:finished')
|
||||
socket.moduleReadys.dislike = true
|
||||
registerEvent(socket)
|
||||
socket.onClose(() => {
|
||||
unregisterEvent()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
export { default as handler } from './handler'
|
||||
|
||||
export * from './localEvent'
|
|
@ -0,0 +1,21 @@
|
|||
import { registerDislikeActionEvent } from '@main/modules/sync/dislikeEvent'
|
||||
|
||||
let unregisterLocalListAction: (() => void) | null
|
||||
|
||||
export const registerEvent = (socket: LX.Sync.Client.Socket) => {
|
||||
// socket = _socket
|
||||
// socket.onClose(() => {
|
||||
// unregisterLocalListAction?.()
|
||||
// unregisterLocalListAction = null
|
||||
// })
|
||||
unregisterEvent()
|
||||
unregisterLocalListAction = registerDislikeActionEvent((action) => {
|
||||
if (!socket.moduleReadys?.dislike) return
|
||||
void socket.remoteQueueDislike.onDislikeSyncAction(action)
|
||||
})
|
||||
}
|
||||
|
||||
export const unregisterEvent = () => {
|
||||
unregisterLocalListAction?.()
|
||||
unregisterLocalListAction = null
|
||||
}
|
|
@ -1,14 +1,20 @@
|
|||
import * as list from './list'
|
||||
import * as dislike from './dislike'
|
||||
// export * as theme from './theme'
|
||||
|
||||
|
||||
export const callObj = Object.assign({}, list.handler)
|
||||
export const callObj = Object.assign({},
|
||||
list.handler,
|
||||
dislike.handler,
|
||||
)
|
||||
|
||||
|
||||
export const modules = {
|
||||
list,
|
||||
dislike,
|
||||
}
|
||||
|
||||
export const featureVersion = {
|
||||
list: 1,
|
||||
dislike: 1,
|
||||
} as const
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
// 这个文件导出的方法将暴露给服务端调用,第一个参数固定为当前 socket 对象
|
||||
import { handleRemoteListAction } from '@main/modules/sync/utils'
|
||||
import { getLocalListData, setLocalListData } from '../../../utils'
|
||||
import {
|
||||
handleRemoteListAction,
|
||||
getLocalListData,
|
||||
setLocalListData,
|
||||
} from '@main/modules/sync/listEvent'
|
||||
import { toMD5 } from '@common/utils/nodejs'
|
||||
import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain'
|
||||
import log from '@main/modules/sync/log'
|
||||
|
@ -12,17 +15,6 @@ const logInfo = (eventName: string, success = false) => {
|
|||
// const logError = (eventName: string, err: Error) => {
|
||||
// log.error(`[${eventName}]${eventName.replace('list:sync:list_sync_', '').replaceAll('_', ' ')} error: ${err.message}`)
|
||||
// }
|
||||
|
||||
export const onListSyncAction = async(socket: LX.Sync.Client.Socket, action: LX.Sync.List.ActionList) => {
|
||||
if (!socket.moduleReadys?.list) return
|
||||
await handleRemoteListAction(action)
|
||||
}
|
||||
|
||||
export const list_sync_get_md5 = async(socket: LX.Sync.Client.Socket) => {
|
||||
logInfo('list:sync:list_sync_get_md5')
|
||||
return toMD5(JSON.stringify(await getLocalListData()))
|
||||
}
|
||||
|
||||
const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.List.SyncMode> => new Promise((resolve, reject) => {
|
||||
const handleDisconnect = (err: Error) => {
|
||||
sendCloseSelectMode()
|
||||
|
@ -30,7 +22,7 @@ const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.List.S
|
|||
reject(err)
|
||||
}
|
||||
let removeEventClose = socket.onClose(handleDisconnect)
|
||||
sendSelectMode(socket.data.keyInfo.serverName, (mode) => {
|
||||
sendSelectMode(socket.data.keyInfo.serverName, 'list', (mode) => {
|
||||
if (mode == null) {
|
||||
reject(new Error('cancel'))
|
||||
return
|
||||
|
@ -40,26 +32,41 @@ const getSyncMode = async(socket: LX.Sync.Client.Socket): Promise<LX.Sync.List.S
|
|||
removeEventClose()
|
||||
})
|
||||
})
|
||||
export const list_sync_get_sync_mode = async(socket: LX.Sync.Client.Socket) => {
|
||||
return getSyncMode(socket)
|
||||
}
|
||||
|
||||
export const list_sync_get_list_data = async(socket: LX.Sync.Client.Socket) => {
|
||||
logInfo('list:sync:list_sync_get_list_data')
|
||||
return getLocalListData()
|
||||
}
|
||||
|
||||
export const list_sync_set_list_data = async(socket: LX.Sync.Client.Socket, data: LX.Sync.List.ListData) => {
|
||||
logInfo('list:sync:list_sync_set_list_data')
|
||||
await setLocalListData(data)
|
||||
}
|
||||
|
||||
export const list_sync_finished = async(socket: LX.Sync.Client.Socket) => {
|
||||
logInfo('list:sync:finished')
|
||||
socket.moduleReadys.list = true
|
||||
registerEvent(socket)
|
||||
socket.onClose(() => {
|
||||
unregisterEvent()
|
||||
})
|
||||
|
||||
const handler: LX.Sync.ClientSyncHandlerListActions<LX.Sync.Client.Socket> = {
|
||||
async onListSyncAction(socket, action) {
|
||||
if (!socket.moduleReadys?.list) return
|
||||
await handleRemoteListAction(action)
|
||||
},
|
||||
|
||||
async list_sync_get_md5(socket) {
|
||||
logInfo('list:sync:list_sync_get_md5')
|
||||
return toMD5(JSON.stringify(await getLocalListData()))
|
||||
},
|
||||
|
||||
|
||||
async list_sync_get_sync_mode(socket) {
|
||||
return getSyncMode(socket)
|
||||
},
|
||||
|
||||
async list_sync_get_list_data(socket) {
|
||||
logInfo('list:sync:list_sync_get_list_data')
|
||||
return getLocalListData()
|
||||
},
|
||||
|
||||
async list_sync_set_list_data(socket, data) {
|
||||
logInfo('list:sync:list_sync_set_list_data')
|
||||
await setLocalListData(data)
|
||||
},
|
||||
|
||||
async list_sync_finished(socket) {
|
||||
logInfo('list:sync:finished')
|
||||
socket.moduleReadys.list = true
|
||||
registerEvent(socket)
|
||||
socket.onClose(() => {
|
||||
unregisterEvent()
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
export * as handler from './handler'
|
||||
export { default as handler } from './handler'
|
||||
|
||||
export * from './localEvent'
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { registerListActionEvent } from '@main/modules/sync/utils'
|
||||
import { registerListActionEvent } from '@main/modules/sync/listEvent'
|
||||
|
||||
let unregisterLocalListAction: (() => void) | null
|
||||
|
||||
|
|
|
@ -12,11 +12,13 @@ export const getEnabledFeatures = async(socket: LX.Sync.Client.Socket, serverTyp
|
|||
case 'server':
|
||||
return {
|
||||
list: featureVersion.list == supportedFeatures.list,
|
||||
dislike: featureVersion.dislike == supportedFeatures.dislike,
|
||||
}
|
||||
case 'desktop-app':
|
||||
default:
|
||||
return {
|
||||
list: featureVersion.list == supportedFeatures.list,
|
||||
dislike: featureVersion.dislike == supportedFeatures.dislike,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
|
||||
export const getLocalDislikeData = async(): Promise<LX.Dislike.DislikeRules> => {
|
||||
return (await global.lx.worker.dbService.getDislikeListInfo()).rules
|
||||
}
|
||||
|
||||
export const setLocalDislikeData = async(listData: LX.Dislike.DislikeRules) => {
|
||||
await global.lx.event_dislike.dislike_data_overwrite(listData, true)
|
||||
}
|
||||
|
||||
export const registerDislikeActionEvent = (sendDislikeAction: (action: LX.Sync.Dislike.ActionList) => (void | Promise<void>)) => {
|
||||
const dislike_music_add = async(listData: LX.Dislike.DislikeMusicInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendDislikeAction({ action: 'dislike_music_add', data: listData })
|
||||
}
|
||||
const dislike_data_overwrite = async(listInfos: LX.Dislike.DislikeRules, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendDislikeAction({ action: 'dislike_data_overwrite', data: listInfos })
|
||||
}
|
||||
const dislike_music_clear = async(isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendDislikeAction({ action: 'dislike_music_clear' })
|
||||
}
|
||||
|
||||
global.lx.event_dislike.on('dislike_music_add', dislike_music_add)
|
||||
global.lx.event_dislike.on('dislike_data_overwrite', dislike_data_overwrite)
|
||||
global.lx.event_dislike.on('dislike_music_clear', dislike_music_clear)
|
||||
return () => {
|
||||
global.lx.event_dislike.off('dislike_music_add', dislike_music_add)
|
||||
global.lx.event_dislike.off('dislike_data_overwrite', dislike_data_overwrite)
|
||||
global.lx.event_dislike.off('dislike_music_clear', dislike_music_clear)
|
||||
}
|
||||
}
|
||||
|
||||
export const handleRemoteDislikeAction = async(event: LX.Sync.Dislike.ActionList) => {
|
||||
// console.log('handleRemoteDislikeAction', event)
|
||||
|
||||
switch (event.action) {
|
||||
case 'dislike_music_add':
|
||||
await global.lx.event_dislike.dislike_music_add(event.data, true)
|
||||
break
|
||||
case 'dislike_data_overwrite':
|
||||
await global.lx.event_dislike.dislike_data_overwrite(event.data, true)
|
||||
break
|
||||
case 'dislike_music_clear':
|
||||
await global.lx.event_dislike.dislike_music_clear(true)
|
||||
break
|
||||
default:
|
||||
throw new Error('unknown list sync action')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
import { LIST_IDS } from '@common/constants'
|
||||
|
||||
export const getLocalListData = async(): Promise<LX.Sync.List.ListData> => {
|
||||
const lists: LX.Sync.List.ListData = {
|
||||
defaultList: await global.lx.worker.dbService.getListMusics(LIST_IDS.DEFAULT),
|
||||
loveList: await global.lx.worker.dbService.getListMusics(LIST_IDS.LOVE),
|
||||
userList: [],
|
||||
}
|
||||
|
||||
const userListInfos = await global.lx.worker.dbService.getAllUserList()
|
||||
for await (const list of userListInfos) {
|
||||
lists.userList.push(await global.lx.worker.dbService.getListMusics(list.id)
|
||||
.then(musics => ({ ...list, list: musics })))
|
||||
}
|
||||
|
||||
return lists
|
||||
}
|
||||
|
||||
export const setLocalListData = async(listData: LX.Sync.List.ListData) => {
|
||||
await global.lx.event_list.list_data_overwrite(listData, true)
|
||||
}
|
||||
|
||||
|
||||
export const registerListActionEvent = (sendListAction: (action: LX.Sync.List.ActionList) => (void | Promise<void>)) => {
|
||||
const list_data_overwrite = async(listData: MakeOptional<LX.List.ListDataFull, 'tempList'>, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_data_overwrite', data: listData })
|
||||
}
|
||||
const list_create = async(position: number, listInfos: LX.List.UserListInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_create', data: { position, listInfos } })
|
||||
}
|
||||
const list_remove = async(ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_remove', data: ids })
|
||||
}
|
||||
const list_update = async(lists: LX.List.UserListInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_update', data: lists })
|
||||
}
|
||||
const list_update_position = async(position: number, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_update_position', data: { position, ids } })
|
||||
}
|
||||
const list_music_overwrite = async(listId: string, musicInfos: LX.Music.MusicInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_overwrite', data: { listId, musicInfos } })
|
||||
}
|
||||
const list_music_add = async(id: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_add', data: { id, musicInfos, addMusicLocationType } })
|
||||
}
|
||||
const list_music_move = async(fromId: string, toId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_move', data: { fromId, toId, musicInfos, addMusicLocationType } })
|
||||
}
|
||||
const list_music_remove = async(listId: string, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_remove', data: { listId, ids } })
|
||||
}
|
||||
const list_music_update = async(musicInfos: LX.List.ListActionMusicUpdate, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_update', data: musicInfos })
|
||||
}
|
||||
const list_music_clear = async(ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_clear', data: ids })
|
||||
}
|
||||
const list_music_update_position = async(listId: string, position: number, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_update_position', data: { listId, position, ids } })
|
||||
}
|
||||
global.lx.event_list.on('list_data_overwrite', list_data_overwrite)
|
||||
global.lx.event_list.on('list_create', list_create)
|
||||
global.lx.event_list.on('list_remove', list_remove)
|
||||
global.lx.event_list.on('list_update', list_update)
|
||||
global.lx.event_list.on('list_update_position', list_update_position)
|
||||
global.lx.event_list.on('list_music_overwrite', list_music_overwrite)
|
||||
global.lx.event_list.on('list_music_add', list_music_add)
|
||||
global.lx.event_list.on('list_music_move', list_music_move)
|
||||
global.lx.event_list.on('list_music_remove', list_music_remove)
|
||||
global.lx.event_list.on('list_music_update', list_music_update)
|
||||
global.lx.event_list.on('list_music_clear', list_music_clear)
|
||||
global.lx.event_list.on('list_music_update_position', list_music_update_position)
|
||||
return () => {
|
||||
global.lx.event_list.off('list_data_overwrite', list_data_overwrite)
|
||||
global.lx.event_list.off('list_create', list_create)
|
||||
global.lx.event_list.off('list_remove', list_remove)
|
||||
global.lx.event_list.off('list_update', list_update)
|
||||
global.lx.event_list.off('list_update_position', list_update_position)
|
||||
global.lx.event_list.off('list_music_overwrite', list_music_overwrite)
|
||||
global.lx.event_list.off('list_music_add', list_music_add)
|
||||
global.lx.event_list.off('list_music_move', list_music_move)
|
||||
global.lx.event_list.off('list_music_remove', list_music_remove)
|
||||
global.lx.event_list.off('list_music_update', list_music_update)
|
||||
global.lx.event_list.off('list_music_clear', list_music_clear)
|
||||
global.lx.event_list.off('list_music_update_position', list_music_update_position)
|
||||
}
|
||||
}
|
||||
|
||||
export const handleRemoteListAction = async({ action, data }: LX.Sync.List.ActionList) => {
|
||||
// console.log('handleRemoteListAction', action)
|
||||
|
||||
switch (action) {
|
||||
case 'list_data_overwrite':
|
||||
await global.lx.event_list.list_data_overwrite(data, true)
|
||||
break
|
||||
case 'list_create':
|
||||
await global.lx.event_list.list_create(data.position, data.listInfos, true)
|
||||
break
|
||||
case 'list_remove':
|
||||
await global.lx.event_list.list_remove(data, true)
|
||||
break
|
||||
case 'list_update':
|
||||
await global.lx.event_list.list_update(data, true)
|
||||
break
|
||||
case 'list_update_position':
|
||||
await global.lx.event_list.list_update_position(data.position, data.ids, true)
|
||||
break
|
||||
case 'list_music_add':
|
||||
await global.lx.event_list.list_music_add(data.id, data.musicInfos, data.addMusicLocationType, true)
|
||||
break
|
||||
case 'list_music_move':
|
||||
await global.lx.event_list.list_music_move(data.fromId, data.toId, data.musicInfos, data.addMusicLocationType, true)
|
||||
break
|
||||
case 'list_music_remove':
|
||||
await global.lx.event_list.list_music_remove(data.listId, data.ids, true)
|
||||
break
|
||||
case 'list_music_update':
|
||||
await global.lx.event_list.list_music_update(data, true)
|
||||
break
|
||||
case 'list_music_update_position':
|
||||
await global.lx.event_list.list_music_update_position(data.listId, data.position, data.ids, true)
|
||||
break
|
||||
case 'list_music_overwrite':
|
||||
await global.lx.event_list.list_music_overwrite(data.listId, data.musicInfos, true)
|
||||
break
|
||||
case 'list_music_clear':
|
||||
await global.lx.event_list.list_music_clear(data, true)
|
||||
break
|
||||
default:
|
||||
throw new Error('unknown list sync action')
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export * as sync from './sync'
|
||||
export { DislikeManage } from './manage'
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
import { type UserDataManage } from '../../user'
|
||||
import { SnapshotDataManage } from './snapshotDataManage'
|
||||
import { toMD5 } from '../../utils'
|
||||
import { getLocalDislikeData } from '@main/modules/sync/dislikeEvent'
|
||||
|
||||
export class DislikeManage {
|
||||
snapshotDataManage: SnapshotDataManage
|
||||
|
||||
constructor(userDataManage: UserDataManage) {
|
||||
this.snapshotDataManage = new SnapshotDataManage(userDataManage)
|
||||
}
|
||||
|
||||
createSnapshot = async() => {
|
||||
const listData = await this.getDislikeRules()
|
||||
const md5 = toMD5(listData.trim())
|
||||
const snapshotInfo = await this.snapshotDataManage.getSnapshotInfo()
|
||||
console.log(md5, snapshotInfo.latest)
|
||||
if (snapshotInfo.latest == md5) return md5
|
||||
if (snapshotInfo.list.includes(md5)) {
|
||||
snapshotInfo.list.splice(snapshotInfo.list.indexOf(md5), 1)
|
||||
} else await this.snapshotDataManage.saveSnapshot(md5, listData)
|
||||
if (snapshotInfo.latest) snapshotInfo.list.unshift(snapshotInfo.latest)
|
||||
snapshotInfo.latest = md5
|
||||
snapshotInfo.time = Date.now()
|
||||
this.snapshotDataManage.saveSnapshotInfo(snapshotInfo)
|
||||
return md5
|
||||
}
|
||||
|
||||
getCurrentListInfoKey = async() => {
|
||||
const snapshotInfo = await this.snapshotDataManage.getSnapshotInfo()
|
||||
if (snapshotInfo.latest) {
|
||||
return snapshotInfo.latest
|
||||
}
|
||||
snapshotInfo.latest = toMD5((await this.getDislikeRules()).trim())
|
||||
this.snapshotDataManage.saveSnapshotInfo(snapshotInfo)
|
||||
return snapshotInfo.latest
|
||||
}
|
||||
|
||||
getDeviceCurrentSnapshotKey = async(clientId: string) => {
|
||||
return this.snapshotDataManage.getDeviceCurrentSnapshotKey(clientId)
|
||||
}
|
||||
|
||||
updateDeviceSnapshotKey = async(clientId: string, key: string) => {
|
||||
await this.snapshotDataManage.updateDeviceSnapshotKey(clientId, key)
|
||||
}
|
||||
|
||||
removeDevice = async(clientId: string) => {
|
||||
this.snapshotDataManage.removeSnapshotInfo(clientId)
|
||||
}
|
||||
|
||||
getDislikeRules = async() => {
|
||||
return getLocalDislikeData()
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
import { throttle } from '@common/utils/common'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import syncLog from '../../../log'
|
||||
import { getUserConfig, type UserDataManage } from '../../user/data'
|
||||
import { File } from '../../../../../../common/constants_sync'
|
||||
import { checkAndCreateDirSync } from '../../utils'
|
||||
|
||||
|
||||
interface SnapshotInfo {
|
||||
latest: string | null
|
||||
time: number
|
||||
list: string[]
|
||||
clients: Record<string, LX.Sync.Dislike.ListInfo>
|
||||
}
|
||||
export class SnapshotDataManage {
|
||||
userDataManage: UserDataManage
|
||||
dislikeDir: string
|
||||
snapshotDir: string
|
||||
snapshotInfoFilePath: string
|
||||
snapshotInfo: SnapshotInfo
|
||||
clientSnapshotKeys: string[]
|
||||
private readonly saveSnapshotInfoThrottle: () => void
|
||||
|
||||
isIncluedsDevice = (key: string) => {
|
||||
return this.clientSnapshotKeys.includes(key)
|
||||
}
|
||||
|
||||
clearOldSnapshot = async() => {
|
||||
if (!this.snapshotInfo) return
|
||||
const snapshotList = this.snapshotInfo.list.filter(key => !this.isIncluedsDevice(key))
|
||||
// console.log(snapshotList.length, lx.config.maxSnapshotNum)
|
||||
const userMaxSnapshotNum = getUserConfig(this.userDataManage.userName).maxSnapshotNum
|
||||
let requiredSave = snapshotList.length > userMaxSnapshotNum
|
||||
while (snapshotList.length > userMaxSnapshotNum) {
|
||||
const name = snapshotList.pop()
|
||||
if (name) {
|
||||
await this.removeSnapshot(name)
|
||||
this.snapshotInfo.list.splice(this.snapshotInfo.list.indexOf(name), 1)
|
||||
} else break
|
||||
}
|
||||
if (requiredSave) this.saveSnapshotInfo(this.snapshotInfo)
|
||||
}
|
||||
|
||||
updateDeviceSnapshotKey = async(clientId: string, key: string) => {
|
||||
// console.log('updateDeviceSnapshotKey', key)
|
||||
let client = this.snapshotInfo.clients[clientId]
|
||||
if (!client) client = this.snapshotInfo.clients[clientId] = { snapshotKey: '', lastSyncDate: 0 }
|
||||
if (client.snapshotKey) this.clientSnapshotKeys.splice(this.clientSnapshotKeys.indexOf(client.snapshotKey), 1)
|
||||
client.snapshotKey = key
|
||||
client.lastSyncDate = Date.now()
|
||||
this.clientSnapshotKeys.push(key)
|
||||
this.saveSnapshotInfoThrottle()
|
||||
}
|
||||
|
||||
getDeviceCurrentSnapshotKey = async(clientId: string) => {
|
||||
// console.log('updateDeviceSnapshotKey', key)
|
||||
const client = this.snapshotInfo.clients[clientId]
|
||||
return client?.snapshotKey
|
||||
}
|
||||
|
||||
getSnapshotInfo = async(): Promise<SnapshotInfo> => {
|
||||
return this.snapshotInfo
|
||||
}
|
||||
|
||||
saveSnapshotInfo = (info: SnapshotInfo) => {
|
||||
this.snapshotInfo = info
|
||||
this.saveSnapshotInfoThrottle()
|
||||
}
|
||||
|
||||
removeSnapshotInfo = (clientId: string) => {
|
||||
let client = this.snapshotInfo.clients[clientId]
|
||||
if (!client) return
|
||||
if (client.snapshotKey) this.clientSnapshotKeys.splice(this.clientSnapshotKeys.indexOf(client.snapshotKey), 1)
|
||||
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
||||
delete this.snapshotInfo.clients[clientId]
|
||||
this.saveSnapshotInfoThrottle()
|
||||
}
|
||||
|
||||
getSnapshot = async(name: string) => {
|
||||
const filePath = path.join(this.snapshotDir, `snapshot_${name}`)
|
||||
let listData: LX.Dislike.DislikeRules
|
||||
try {
|
||||
listData = (await fs.promises.readFile(filePath)).toString('utf-8')
|
||||
} catch (err) {
|
||||
syncLog.warn(err)
|
||||
return null
|
||||
}
|
||||
return listData
|
||||
}
|
||||
|
||||
saveSnapshot = async(name: string, data: string) => {
|
||||
syncLog.info('saveSnapshot', this.userDataManage.userName, name)
|
||||
const filePath = path.join(this.snapshotDir, `snapshot_${name}`)
|
||||
try {
|
||||
fs.writeFileSync(filePath, data)
|
||||
} catch (err) {
|
||||
syncLog.error(err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
removeSnapshot = async(name: string) => {
|
||||
syncLog.info('removeSnapshot', this.userDataManage.userName, name)
|
||||
const filePath = path.join(this.snapshotDir, `snapshot_${name}`)
|
||||
try {
|
||||
fs.unlinkSync(filePath)
|
||||
} catch (err) {
|
||||
syncLog.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
constructor(userDataManage: UserDataManage) {
|
||||
this.userDataManage = userDataManage
|
||||
|
||||
this.dislikeDir = path.join(userDataManage.userDir, File.dislikeDir)
|
||||
checkAndCreateDirSync(this.dislikeDir)
|
||||
|
||||
this.snapshotDir = path.join(this.dislikeDir, File.dislikeSnapshotDir)
|
||||
checkAndCreateDirSync(this.snapshotDir)
|
||||
|
||||
this.snapshotInfoFilePath = path.join(this.dislikeDir, File.dislikeSnapshotInfoJSON)
|
||||
this.snapshotInfo = fs.existsSync(this.snapshotInfoFilePath)
|
||||
? JSON.parse(fs.readFileSync(this.snapshotInfoFilePath).toString())
|
||||
: { latest: null, time: 0, list: [], clients: {} }
|
||||
|
||||
this.saveSnapshotInfoThrottle = throttle(() => {
|
||||
fs.writeFile(this.snapshotInfoFilePath, JSON.stringify(this.snapshotInfo), 'utf8', (err) => {
|
||||
if (err) console.error(err)
|
||||
void this.clearOldSnapshot()
|
||||
})
|
||||
})
|
||||
|
||||
this.clientSnapshotKeys = Object.values(this.snapshotInfo.clients).map(device => device.snapshotKey).filter(k => k)
|
||||
}
|
||||
}
|
||||
// type UserDataManages = Map<string, UserDataManage>
|
||||
|
||||
// export const createUserDataManage = (user: LX.UserConfig) => {
|
||||
// const manage = Object.create(userDataManage) as typeof userDataManage
|
||||
// manage.userDir = user.dataPath
|
||||
// }
|
|
@ -0,0 +1,35 @@
|
|||
// 这个文件导出的方法将暴露给客户端调用,第一个参数固定为当前 socket 对象
|
||||
// import { throttle } from '@common/utils/common'
|
||||
// import { sendSyncActionList } from '@main/modules/winMain'
|
||||
// import { SYNC_CLOSE_CODE } from '@/constants'
|
||||
// import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { getUserSpace } from '@main/modules/sync/server/user'
|
||||
import { handleRemoteDislikeAction } from '@main/modules/sync/dislikeEvent'
|
||||
// import { encryptMsg } from '@/utils/tools'
|
||||
|
||||
|
||||
const handler: LX.Sync.ServerSyncHandlerDislikeActions<LX.Sync.Server.Socket> = {
|
||||
async onDislikeSyncAction(socket, action) {
|
||||
if (!socket.moduleReadys.dislike) return
|
||||
await handleRemoteDislikeAction(action)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const key = await userSpace.dislikeManage.createSnapshot()
|
||||
userSpace.dislikeManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
const currentUserName = socket.userInfo.name
|
||||
const currentId = socket.keyInfo.clientId
|
||||
socket.broadcast((client) => {
|
||||
if (client.keyInfo.clientId == currentId || !client.moduleReadys?.dislike || client.userInfo.name != currentUserName) return
|
||||
void client.remoteQueueDislike.onDislikeSyncAction(action).then(async() => {
|
||||
return userSpace.dislikeManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.dislike = false
|
||||
console.log(err.message)
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default handler
|
|
@ -0,0 +1,3 @@
|
|||
export { default as handler } from './handler'
|
||||
export { sync } from './sync'
|
||||
export * from './localEvent'
|
|
@ -0,0 +1,43 @@
|
|||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { registerDislikeActionEvent } from '../../../../dislikeEvent'
|
||||
import { getUserSpace } from '../../../user'
|
||||
|
||||
// let socket: LX.Sync.Server.Socket | null
|
||||
let unregisterLocalListAction: (() => void) | null
|
||||
|
||||
|
||||
const sendListAction = async(wss: LX.Sync.Server.SocketServer, action: LX.Sync.Dislike.ActionList) => {
|
||||
// console.log('sendListAction', action.action)
|
||||
const userSpace = getUserSpace()
|
||||
let key = ''
|
||||
for (const client of wss.clients) {
|
||||
if (!client.moduleReadys?.dislike) continue
|
||||
// eslint-disable-next-line require-atomic-updates
|
||||
if (!key) key = await userSpace.dislikeManage.createSnapshot()
|
||||
void client.remoteQueueDislike.onDislikeSyncAction(action).then(async() => {
|
||||
return userSpace.dislikeManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.dislike = false
|
||||
console.log(err.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const registerEvent = (wss: LX.Sync.Server.SocketServer) => {
|
||||
// socket = _socket
|
||||
// socket.onClose(() => {
|
||||
// unregisterLocalListAction?.()
|
||||
// unregisterLocalListAction = null
|
||||
// })
|
||||
unregisterEvent()
|
||||
unregisterLocalListAction = registerDislikeActionEvent((action) => {
|
||||
void sendListAction(wss, action)
|
||||
})
|
||||
}
|
||||
|
||||
export const unregisterEvent = () => {
|
||||
unregisterLocalListAction?.()
|
||||
unregisterLocalListAction = null
|
||||
}
|
|
@ -0,0 +1,232 @@
|
|||
// import { SYNC_CLOSE_CODE } from '../../../../constants'
|
||||
import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain'
|
||||
import { getUserSpace } from '../../../user'
|
||||
import { getLocalDislikeData, setLocalDislikeData } from '@main/modules/sync/dislikeEvent'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { filterRules } from '../utils'
|
||||
// import { LIST_IDS } from '@common/constants'
|
||||
|
||||
// type ListInfoType = LX.Dislike.UserListInfoFull | LX.Dislike.MyDefaultListInfoFull | LX.Dislike.MyLoveListInfoFull
|
||||
|
||||
// let wss: LX.Sync.Server.SocketServer | null
|
||||
let syncingId: string | null = null
|
||||
const wait = async(time = 1000) => await new Promise((resolve, reject) => setTimeout(resolve, time))
|
||||
|
||||
|
||||
const getRemoteListData = async(socket: LX.Sync.Server.Socket): Promise<LX.Dislike.DislikeRules> => {
|
||||
console.log('getRemoteListData')
|
||||
return (await socket.remoteQueueDislike.dislike_sync_get_list_data()) ?? ''
|
||||
}
|
||||
|
||||
const getRemoteDataMD5 = async(socket: LX.Sync.Server.Socket): Promise<string> => {
|
||||
return socket.remoteQueueDislike.dislike_sync_get_md5()
|
||||
}
|
||||
|
||||
// const getLocalDislikeData async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.Dislike.ListData> => {
|
||||
// return getUserSpace(socket.userInfo.name).listManage.getListData()
|
||||
// }
|
||||
const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.Dislike.SyncMode> => new Promise((resolve, reject) => {
|
||||
const handleDisconnect = (err: Error) => {
|
||||
sendCloseSelectMode()
|
||||
removeSelectModeListener()
|
||||
reject(err)
|
||||
}
|
||||
let removeEventClose = socket.onClose(handleDisconnect)
|
||||
sendSelectMode(socket.keyInfo.deviceName, 'dislike', (mode) => {
|
||||
if (mode == null) {
|
||||
reject(new Error('cancel'))
|
||||
return
|
||||
}
|
||||
resolve(mode)
|
||||
removeSelectModeListener()
|
||||
removeEventClose()
|
||||
})
|
||||
})
|
||||
// const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.Dislike.SyncMode> => {
|
||||
// return socket.remoteQueueDislike.list_sync_get_sync_mode()
|
||||
// }
|
||||
|
||||
const finishedSync = async(socket: LX.Sync.Server.Socket) => {
|
||||
await socket.remoteQueueDislike.dislike_sync_finished()
|
||||
}
|
||||
|
||||
|
||||
const setLocalList = async(socket: LX.Sync.Server.Socket, listData: LX.Dislike.DislikeRules) => {
|
||||
await setLocalDislikeData(listData)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
return userSpace.listManage.createSnapshot()
|
||||
}
|
||||
|
||||
const overwriteRemoteListData = async(socket: LX.Sync.Server.Socket, listData: LX.Dislike.DislikeRules, key: string, excludeIds: string[] = []) => {
|
||||
const action = { action: 'dislike_data_overwrite', data: listData } as const
|
||||
const tasks: Array<Promise<void>> = []
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
socket.broadcast((client) => {
|
||||
if (excludeIds.includes(client.keyInfo.clientId) || client.userInfo?.name != socket.userInfo.name || !client.moduleReadys?.dislike) return
|
||||
tasks.push(client.remoteQueueDislike.onDislikeSyncAction(action).then(async() => {
|
||||
return userSpace.dislikeManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.list = false
|
||||
console.log(err.message)
|
||||
}))
|
||||
})
|
||||
if (!tasks.length) return
|
||||
await Promise.all(tasks)
|
||||
}
|
||||
const setRemotelList = async(socket: LX.Sync.Server.Socket, listData: LX.Dislike.DislikeRules, key: string): Promise<void> => {
|
||||
await socket.remoteQueueDislike.dislike_sync_set_list_data(listData)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
await userSpace.dislikeManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
}
|
||||
|
||||
|
||||
const mergeList = (socket: LX.Sync.Server.Socket, sourceListData: LX.Dislike.DislikeRules, targetListData: LX.Dislike.DislikeRules): LX.Dislike.DislikeRules => {
|
||||
return Array.from(filterRules(sourceListData + '\n' + targetListData)).join('\n')
|
||||
}
|
||||
|
||||
const handleMergeListData = async(socket: LX.Sync.Server.Socket): Promise<[LX.Dislike.DislikeRules, boolean, boolean]> => {
|
||||
const mode: LX.Sync.Dislike.SyncMode = await getSyncMode(socket)
|
||||
|
||||
if (mode == 'cancel') throw new Error('cancel')
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalDislikeData()])
|
||||
console.log('handleMergeListData', 'remoteListData, localListData')
|
||||
let listData: LX.Dislike.DislikeRules
|
||||
let requiredUpdateLocalListData = true
|
||||
let requiredUpdateRemoteListData = true
|
||||
switch (mode) {
|
||||
case 'merge_local_remote':
|
||||
listData = mergeList(socket, localListData, remoteListData)
|
||||
break
|
||||
case 'merge_remote_local':
|
||||
listData = mergeList(socket, remoteListData, localListData)
|
||||
break
|
||||
case 'overwrite_local_remote':
|
||||
listData = localListData
|
||||
requiredUpdateLocalListData = false
|
||||
break
|
||||
case 'overwrite_remote_local':
|
||||
listData = remoteListData
|
||||
requiredUpdateRemoteListData = false
|
||||
break
|
||||
// case 'none': return null
|
||||
// case 'cancel':
|
||||
default: throw new Error('cancel')
|
||||
}
|
||||
return [listData, requiredUpdateLocalListData, requiredUpdateRemoteListData]
|
||||
}
|
||||
|
||||
const handleSyncList = async(socket: LX.Sync.Server.Socket) => {
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalDislikeData()])
|
||||
console.log('handleSyncList', 'remoteListData, localListData')
|
||||
console.log('localListData', localListData.length)
|
||||
console.log('remoteListData', remoteListData.length)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const clientId = socket.keyInfo.clientId
|
||||
if (localListData.length) {
|
||||
if (remoteListData.length) {
|
||||
const [mergedList, requiredUpdateLocalListData, requiredUpdateRemoteListData] = await handleMergeListData(socket)
|
||||
console.log('handleMergeListData', 'mergedList', requiredUpdateLocalListData, requiredUpdateRemoteListData)
|
||||
let key
|
||||
if (requiredUpdateLocalListData) {
|
||||
key = await setLocalList(socket, mergedList)
|
||||
await overwriteRemoteListData(socket, mergedList, key, [clientId])
|
||||
if (!requiredUpdateRemoteListData) await userSpace.dislikeManage.updateDeviceSnapshotKey(clientId, key)
|
||||
}
|
||||
if (requiredUpdateRemoteListData) {
|
||||
if (!key) key = await userSpace.dislikeManage.getCurrentListInfoKey()
|
||||
await setRemotelList(socket, mergedList, key)
|
||||
}
|
||||
} else {
|
||||
await setRemotelList(socket, localListData, await userSpace.dislikeManage.getCurrentListInfoKey())
|
||||
}
|
||||
} else {
|
||||
let key: string
|
||||
if (remoteListData.length) {
|
||||
key = await setLocalList(socket, remoteListData)
|
||||
await overwriteRemoteListData(socket, remoteListData, key, [clientId])
|
||||
}
|
||||
key ??= await userSpace.dislikeManage.getCurrentListInfoKey()
|
||||
await userSpace.dislikeManage.updateDeviceSnapshotKey(clientId, key)
|
||||
}
|
||||
}
|
||||
|
||||
const mergeDataFromSnapshot = (
|
||||
sourceList: LX.Dislike.DislikeRules,
|
||||
targetList: LX.Dislike.DislikeRules,
|
||||
snapshotList: LX.Dislike.DislikeRules,
|
||||
): LX.Dislike.DislikeRules => {
|
||||
const removedRules = new Set<string>()
|
||||
const sourceRules = filterRules(sourceList)
|
||||
const targetRules = filterRules(targetList)
|
||||
|
||||
if (snapshotList) {
|
||||
const snapshotRules = filterRules(snapshotList)
|
||||
for (const m of snapshotRules.values()) {
|
||||
if (!sourceRules.has(m) || !targetRules.has(m)) removedRules.add(m)
|
||||
}
|
||||
}
|
||||
return Array.from(new Set(Array.from([...sourceRules, ...targetRules]).filter((rule) => {
|
||||
return !removedRules.has(rule)
|
||||
}))).join('\n')
|
||||
}
|
||||
const checkListLatest = async(socket: LX.Sync.Server.Socket) => {
|
||||
const remoteListMD5 = await getRemoteDataMD5(socket)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const userCurrentListInfoKey = await userSpace.dislikeManage.getDeviceCurrentSnapshotKey(socket.keyInfo.clientId)
|
||||
const currentListInfoKey = await userSpace.dislikeManage.getCurrentListInfoKey()
|
||||
const latest = remoteListMD5 == currentListInfoKey
|
||||
if (latest && userCurrentListInfoKey != currentListInfoKey) await userSpace.dislikeManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, currentListInfoKey)
|
||||
return latest
|
||||
}
|
||||
|
||||
const handleMergeListDataFromSnapshot = async(socket: LX.Sync.Server.Socket, snapshot: LX.Dislike.DislikeRules) => {
|
||||
if (await checkListLatest(socket)) return
|
||||
|
||||
const [remoteListData, localListData] = await Promise.all([getRemoteListData(socket), getLocalDislikeData()])
|
||||
const newDislikeData = mergeDataFromSnapshot(localListData, remoteListData, snapshot)
|
||||
|
||||
const key = await setLocalList(socket, newDislikeData)
|
||||
const err = await setRemotelList(socket, newDislikeData, key).catch(err => err)
|
||||
await overwriteRemoteListData(socket, newDislikeData, key, [socket.keyInfo.clientId])
|
||||
if (err) throw err
|
||||
}
|
||||
|
||||
const syncDislike = async(socket: LX.Sync.Server.Socket) => {
|
||||
// socket.data.snapshotFilePath = getSnapshotFilePath(socket.keyInfo)
|
||||
// console.log(socket.keyInfo)
|
||||
const user = getUserSpace(socket.userInfo.name)
|
||||
const userCurrentDislikeInfoKey = await user.dislikeManage.getDeviceCurrentSnapshotKey(socket.keyInfo.clientId)
|
||||
if (userCurrentDislikeInfoKey) {
|
||||
const listData = await user.dislikeManage.snapshotDataManage.getSnapshot(userCurrentDislikeInfoKey)
|
||||
if (listData) {
|
||||
console.log('handleMergeDislikeDataFromSnapshot')
|
||||
await handleMergeListDataFromSnapshot(socket, listData)
|
||||
return
|
||||
}
|
||||
}
|
||||
await handleSyncList(socket)
|
||||
}
|
||||
|
||||
export const sync = async(socket: LX.Sync.Server.Socket) => {
|
||||
let disconnected = false
|
||||
socket.onClose(() => {
|
||||
disconnected = true
|
||||
if (syncingId == socket.keyInfo.clientId) syncingId = null
|
||||
})
|
||||
|
||||
while (true) {
|
||||
if (disconnected) throw new Error('disconnected')
|
||||
if (!syncingId) break
|
||||
await wait()
|
||||
}
|
||||
|
||||
syncingId = socket.keyInfo.clientId
|
||||
await syncDislike(socket).then(async() => {
|
||||
await finishedSync(socket)
|
||||
socket.moduleReadys.dislike = true
|
||||
}).finally(() => {
|
||||
syncingId = null
|
||||
})
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import { SPLIT_CHAR } from '@common/constants'
|
||||
|
||||
|
||||
export const filterRules = (rules: string) => {
|
||||
const list: string[] = []
|
||||
for (const item of 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()
|
||||
list.push(`${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
|
||||
} else {
|
||||
list.push(name)
|
||||
}
|
||||
} else if (singer) {
|
||||
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
|
||||
list.push(`${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
|
||||
}
|
||||
}
|
||||
return new Set(list)
|
||||
}
|
|
@ -1,16 +1,22 @@
|
|||
import { sync } from './list'
|
||||
import { sync as listSync } from './list'
|
||||
import { sync as dislikeSync } from './dislike'
|
||||
|
||||
export const callObj = Object.assign({},
|
||||
sync.handler,
|
||||
listSync.handler,
|
||||
dislikeSync.handler,
|
||||
)
|
||||
|
||||
export const modules = {
|
||||
list: sync,
|
||||
list: listSync,
|
||||
dislike: dislikeSync,
|
||||
}
|
||||
|
||||
|
||||
export { ListManage } from './list'
|
||||
|
||||
export { DislikeManage } from './dislike'
|
||||
|
||||
export const featureVersion = {
|
||||
list: 1,
|
||||
dislike: 1,
|
||||
} as const
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { type UserDataManage } from '../../user'
|
||||
import { SnapshotDataManage } from './snapshotDataManage'
|
||||
import { toMD5 } from '../../utils'
|
||||
import { getLocalListData } from '@main/modules/sync/utils'
|
||||
import { getLocalListData } from '@main/modules/sync/listEvent'
|
||||
|
||||
export class ListManage {
|
||||
snapshotDataManage: SnapshotDataManage
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { getUserSpace } from '@main/modules/sync/server/user'
|
||||
import { handleRemoteListAction } from '@main/modules/sync/utils'
|
||||
import { handleRemoteListAction } from '@main/modules/sync/listEvent'
|
||||
// import { encryptMsg } from '@/utils/tools'
|
||||
|
||||
// let wss: LX.SocketServer | null
|
||||
|
@ -146,23 +146,27 @@ import { handleRemoteListAction } from '@main/modules/sync/utils'
|
|||
// // }
|
||||
// }
|
||||
|
||||
export const onListSyncAction = async(socket: LX.Sync.Server.Socket, action: LX.Sync.List.ActionList) => {
|
||||
if (!socket.moduleReadys.list) return
|
||||
await handleRemoteListAction(action)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const key = await userSpace.listManage.createSnapshot()
|
||||
userSpace.listManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
const currentUserName = socket.userInfo.name
|
||||
const currentId = socket.keyInfo.clientId
|
||||
socket.broadcast((client) => {
|
||||
if (client.keyInfo.clientId == currentId || !client.moduleReadys?.list || client.userInfo.name != currentUserName) return
|
||||
void client.remoteQueueList.onListSyncAction(action).then(async() => {
|
||||
return userSpace.listManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.list = false
|
||||
console.log(err.message)
|
||||
const handler: LX.Sync.ServerSyncHandlerListActions<LX.Sync.Server.Socket> = {
|
||||
async onListSyncAction(socket, action) {
|
||||
if (!socket.moduleReadys.list) return
|
||||
await handleRemoteListAction(action)
|
||||
const userSpace = getUserSpace(socket.userInfo.name)
|
||||
const key = await userSpace.listManage.createSnapshot()
|
||||
userSpace.listManage.updateDeviceSnapshotKey(socket.keyInfo.clientId, key)
|
||||
const currentUserName = socket.userInfo.name
|
||||
const currentId = socket.keyInfo.clientId
|
||||
socket.broadcast((client) => {
|
||||
if (client.keyInfo.clientId == currentId || !client.moduleReadys?.list || client.userInfo.name != currentUserName) return
|
||||
void client.remoteQueueList.onListSyncAction(action).then(async() => {
|
||||
return userSpace.listManage.updateDeviceSnapshotKey(client.keyInfo.clientId, key)
|
||||
}).catch(err => {
|
||||
// TODO send status
|
||||
client.close(SYNC_CLOSE_CODE.failed)
|
||||
// client.moduleReadys.list = false
|
||||
console.log(err.message)
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
|
||||
export default handler
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export * as handler from './handler'
|
||||
export { default as handler } from './handler'
|
||||
export { sync } from './sync'
|
||||
export * from './localEvent'
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
import { registerListActionEvent } from '../../../../utils'
|
||||
import { registerListActionEvent } from '../../../../listEvent'
|
||||
import { getUserSpace } from '../../../user'
|
||||
|
||||
// let socket: LX.Sync.Server.Socket | null
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
// import { SYNC_CLOSE_CODE } from '../../../../constants'
|
||||
import { removeSelectModeListener, sendCloseSelectMode, sendSelectMode } from '@main/modules/winMain'
|
||||
import { getUserSpace, getUserConfig } from '../../../user'
|
||||
import { getLocalListData, setLocalListData } from '@main/modules/sync/utils'
|
||||
import { getLocalListData, setLocalListData } from '@main/modules/sync/listEvent'
|
||||
import { SYNC_CLOSE_CODE } from '@common/constants_sync'
|
||||
// import { LIST_IDS } from '@common/constants'
|
||||
|
||||
|
@ -38,7 +38,7 @@ const getSyncMode = async(socket: LX.Sync.Server.Socket): Promise<LX.Sync.List.S
|
|||
reject(err)
|
||||
}
|
||||
let removeEventClose = socket.onClose(handleDisconnect)
|
||||
sendSelectMode(socket.keyInfo.deviceName, (mode) => {
|
||||
sendSelectMode(socket.keyInfo.deviceName, 'list', (mode) => {
|
||||
if (mode == null) {
|
||||
reject(new Error('cancel'))
|
||||
return
|
||||
|
|
|
@ -156,9 +156,11 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
socket.isReady = false
|
||||
socket.moduleReadys = {
|
||||
list: false,
|
||||
dislike: false,
|
||||
}
|
||||
socket.feature = {
|
||||
list: false,
|
||||
dislike: false,
|
||||
}
|
||||
socket.on('pong', () => {
|
||||
socket.isAlive = true
|
||||
|
@ -196,6 +198,7 @@ const handleStartServer = async(port = 9527, ip = '0.0.0.0') => await new Promis
|
|||
})
|
||||
socket.remote = msg2call.remote
|
||||
socket.remoteQueueList = msg2call.createQueueRemote('list')
|
||||
socket.remoteQueueDislike = msg2call.createQueueRemote('dislike')
|
||||
socket.addEventListener('message', ({ data }) => {
|
||||
if (typeof data != 'string') return
|
||||
void decryptMsg(socket.keyInfo, data).then((data) => {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import { UserDataManage } from './data'
|
||||
import {
|
||||
ListManage,
|
||||
DislikeManage,
|
||||
} from '../modules'
|
||||
|
||||
export interface UserSpace {
|
||||
dataManage: UserDataManage
|
||||
listManage: ListManage
|
||||
dislikeManage: DislikeManage
|
||||
getDecices: () => Promise<LX.Sync.ServerKeyInfo[]>
|
||||
removeDevice: (clientId: string) => Promise<void>
|
||||
}
|
||||
|
@ -34,9 +36,11 @@ export const getUserSpace = (userName = 'default') => {
|
|||
console.log('new user data manage:', userName)
|
||||
const dataManage = new UserDataManage(userName)
|
||||
const listManage = new ListManage(dataManage)
|
||||
const dislikeManage = new DislikeManage(dataManage)
|
||||
users.set(userName, user = {
|
||||
dataManage,
|
||||
listManage,
|
||||
dislikeManage,
|
||||
async getDecices() {
|
||||
return this.dataManage.getAllClientKeyInfo()
|
||||
},
|
||||
|
|
|
@ -2,7 +2,6 @@ import { createCipheriv, createDecipheriv, publicEncrypt, privateDecrypt, consta
|
|||
import os, { networkInterfaces } from 'node:os'
|
||||
import zlib from 'node:zlib'
|
||||
import cp from 'node:child_process'
|
||||
import { LIST_IDS } from '@common/constants'
|
||||
|
||||
|
||||
export const getAddress = (): string[] => {
|
||||
|
@ -89,146 +88,3 @@ export const rsaEncrypt = (buffer: Buffer, key: string): string => {
|
|||
export const rsaDecrypt = (buffer: Buffer, key: string): Buffer => {
|
||||
return privateDecrypt({ key, padding: constants.RSA_PKCS1_OAEP_PADDING }, buffer)
|
||||
}
|
||||
|
||||
export const getLocalListData = async(): Promise<LX.Sync.List.ListData> => {
|
||||
const lists: LX.Sync.List.ListData = {
|
||||
defaultList: await global.lx.worker.dbService.getListMusics(LIST_IDS.DEFAULT),
|
||||
loveList: await global.lx.worker.dbService.getListMusics(LIST_IDS.LOVE),
|
||||
userList: [],
|
||||
}
|
||||
|
||||
const userListInfos = await global.lx.worker.dbService.getAllUserList()
|
||||
for await (const list of userListInfos) {
|
||||
lists.userList.push(await global.lx.worker.dbService.getListMusics(list.id)
|
||||
.then(musics => ({ ...list, list: musics })))
|
||||
}
|
||||
|
||||
return lists
|
||||
}
|
||||
|
||||
export const setLocalListData = async(listData: LX.Sync.List.ListData) => {
|
||||
await global.lx.event_list.list_data_overwrite(listData, true)
|
||||
}
|
||||
|
||||
|
||||
export const registerListActionEvent = (sendListAction: (action: LX.Sync.List.ActionList) => (void | Promise<void>)) => {
|
||||
const list_data_overwrite = async(listData: MakeOptional<LX.List.ListDataFull, 'tempList'>, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_data_overwrite', data: listData })
|
||||
}
|
||||
const list_create = async(position: number, listInfos: LX.List.UserListInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_create', data: { position, listInfos } })
|
||||
}
|
||||
const list_remove = async(ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_remove', data: ids })
|
||||
}
|
||||
const list_update = async(lists: LX.List.UserListInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_update', data: lists })
|
||||
}
|
||||
const list_update_position = async(position: number, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_update_position', data: { position, ids } })
|
||||
}
|
||||
const list_music_overwrite = async(listId: string, musicInfos: LX.Music.MusicInfo[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_overwrite', data: { listId, musicInfos } })
|
||||
}
|
||||
const list_music_add = async(id: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_add', data: { id, musicInfos, addMusicLocationType } })
|
||||
}
|
||||
const list_music_move = async(fromId: string, toId: string, musicInfos: LX.Music.MusicInfo[], addMusicLocationType: LX.AddMusicLocationType, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_move', data: { fromId, toId, musicInfos, addMusicLocationType } })
|
||||
}
|
||||
const list_music_remove = async(listId: string, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_remove', data: { listId, ids } })
|
||||
}
|
||||
const list_music_update = async(musicInfos: LX.List.ListActionMusicUpdate, isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_update', data: musicInfos })
|
||||
}
|
||||
const list_music_clear = async(ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_clear', data: ids })
|
||||
}
|
||||
const list_music_update_position = async(listId: string, position: number, ids: string[], isRemote: boolean = false) => {
|
||||
if (isRemote) return
|
||||
await sendListAction({ action: 'list_music_update_position', data: { listId, position, ids } })
|
||||
}
|
||||
global.lx.event_list.on('list_data_overwrite', list_data_overwrite)
|
||||
global.lx.event_list.on('list_create', list_create)
|
||||
global.lx.event_list.on('list_remove', list_remove)
|
||||
global.lx.event_list.on('list_update', list_update)
|
||||
global.lx.event_list.on('list_update_position', list_update_position)
|
||||
global.lx.event_list.on('list_music_overwrite', list_music_overwrite)
|
||||
global.lx.event_list.on('list_music_add', list_music_add)
|
||||
global.lx.event_list.on('list_music_move', list_music_move)
|
||||
global.lx.event_list.on('list_music_remove', list_music_remove)
|
||||
global.lx.event_list.on('list_music_update', list_music_update)
|
||||
global.lx.event_list.on('list_music_clear', list_music_clear)
|
||||
global.lx.event_list.on('list_music_update_position', list_music_update_position)
|
||||
return () => {
|
||||
global.lx.event_list.off('list_data_overwrite', list_data_overwrite)
|
||||
global.lx.event_list.off('list_create', list_create)
|
||||
global.lx.event_list.off('list_remove', list_remove)
|
||||
global.lx.event_list.off('list_update', list_update)
|
||||
global.lx.event_list.off('list_update_position', list_update_position)
|
||||
global.lx.event_list.off('list_music_overwrite', list_music_overwrite)
|
||||
global.lx.event_list.off('list_music_add', list_music_add)
|
||||
global.lx.event_list.off('list_music_move', list_music_move)
|
||||
global.lx.event_list.off('list_music_remove', list_music_remove)
|
||||
global.lx.event_list.off('list_music_update', list_music_update)
|
||||
global.lx.event_list.off('list_music_clear', list_music_clear)
|
||||
global.lx.event_list.off('list_music_update_position', list_music_update_position)
|
||||
}
|
||||
}
|
||||
|
||||
export const handleRemoteListAction = async({ action, data }: LX.Sync.List.ActionList) => {
|
||||
// console.log('handleRemoteListAction', action)
|
||||
|
||||
switch (action) {
|
||||
case 'list_data_overwrite':
|
||||
await global.lx.event_list.list_data_overwrite(data, true)
|
||||
break
|
||||
case 'list_create':
|
||||
await global.lx.event_list.list_create(data.position, data.listInfos, true)
|
||||
break
|
||||
case 'list_remove':
|
||||
await global.lx.event_list.list_remove(data, true)
|
||||
break
|
||||
case 'list_update':
|
||||
await global.lx.event_list.list_update(data, true)
|
||||
break
|
||||
case 'list_update_position':
|
||||
await global.lx.event_list.list_update_position(data.position, data.ids, true)
|
||||
break
|
||||
case 'list_music_add':
|
||||
await global.lx.event_list.list_music_add(data.id, data.musicInfos, data.addMusicLocationType, true)
|
||||
break
|
||||
case 'list_music_move':
|
||||
await global.lx.event_list.list_music_move(data.fromId, data.toId, data.musicInfos, data.addMusicLocationType, true)
|
||||
break
|
||||
case 'list_music_remove':
|
||||
await global.lx.event_list.list_music_remove(data.listId, data.ids, true)
|
||||
break
|
||||
case 'list_music_update':
|
||||
await global.lx.event_list.list_music_update(data, true)
|
||||
break
|
||||
case 'list_music_update_position':
|
||||
await global.lx.event_list.list_music_update_position(data.listId, data.position, data.ids, true)
|
||||
break
|
||||
case 'list_music_overwrite':
|
||||
await global.lx.event_list.list_music_overwrite(data.listId, data.musicInfos, true)
|
||||
break
|
||||
case 'list_music_clear':
|
||||
await global.lx.event_list.list_music_clear(data, true)
|
||||
break
|
||||
default:
|
||||
throw new Error('unknown list sync action')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { registerRendererEvents as common } from '@main/modules/commonRenderers/common'
|
||||
import { registerRendererEvents as list } from '@main/modules/commonRenderers/list'
|
||||
import { registerRendererEvents as dislike } from '@main/modules/commonRenderers/dislike'
|
||||
import app, { sendConfigChange } from './app'
|
||||
import hotKey from './hotKey'
|
||||
import kw_decodeLyric from './kw_decodeLyric'
|
||||
|
@ -25,6 +26,7 @@ export default () => {
|
|||
|
||||
common(sendEvent)
|
||||
list(sendEvent)
|
||||
dislike(sendEvent)
|
||||
app()
|
||||
hotKey()
|
||||
kw_decodeLyric()
|
||||
|
|
|
@ -70,16 +70,6 @@ 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)
|
||||
// })
|
||||
|
|
|
@ -13,7 +13,8 @@ import {
|
|||
} from '@main/modules/sync'
|
||||
import { sendEvent } from '../main'
|
||||
|
||||
let selectModeListenr: ((mode: LX.Sync.List.SyncMode | null) => void) | null = null
|
||||
|
||||
let selectModeListenr: ((mode: LX.Sync.ModeTypes[keyof LX.Sync.ModeTypes] | null) => void) | null = null
|
||||
|
||||
export default () => {
|
||||
mainHandle<LX.Sync.SyncServiceActions, any>(WIN_MAIN_RENDERER_EVENT_NAME.sync_action, async({ params: data }) => {
|
||||
|
@ -29,7 +30,7 @@ export default () => {
|
|||
case 'generate_code': return generateCode()
|
||||
case 'select_mode':
|
||||
if (selectModeListenr) {
|
||||
selectModeListenr(data.data)
|
||||
selectModeListenr(data.data.mode)
|
||||
selectModeListenr = null
|
||||
}
|
||||
break
|
||||
|
@ -62,9 +63,9 @@ export const sendServerStatus = (status: LX.Sync.ServerStatus) => {
|
|||
data: status,
|
||||
})
|
||||
}
|
||||
export const sendSelectMode = (deviceName: string, listener: (mode: LX.Sync.List.SyncMode | null) => void) => {
|
||||
selectModeListenr = listener
|
||||
sendSyncAction({ action: 'select_mode', data: deviceName })
|
||||
export const sendSelectMode = <T extends keyof LX.Sync.ModeTypes>(deviceName: string, type: T, listener: (mode: LX.Sync.ModeTypes[T] | null) => void) => {
|
||||
selectModeListenr = listener as typeof selectModeListenr
|
||||
sendSyncAction({ action: 'select_mode', data: { deviceName, type } })
|
||||
}
|
||||
export const removeSelectModeListener = () => {
|
||||
if (selectModeListenr) selectModeListenr(null)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable no-var */
|
||||
// import { Event as WinMainEvent } from '@main/modules/winMain/event'
|
||||
// import { Event as WinLyricEvent } from '@main/modules/winLyric/event'
|
||||
import { type AppType, type ListType } from '@main/event'
|
||||
import { type DislikeType, type AppType, type ListType } from '@main/event'
|
||||
import { type DBSeriveTypes } from '@main/worker/utils'
|
||||
|
||||
interface Lx {
|
||||
|
@ -25,6 +25,7 @@ interface Lx {
|
|||
// mainWindowClosed: boolean
|
||||
event_app: AppType
|
||||
event_list: ListType
|
||||
event_dislike: DislikeType
|
||||
worker: {
|
||||
dbService: DBSeriveTypes
|
||||
}
|
||||
|
|
|
@ -13,3 +13,4 @@ import '@common/types/theme'
|
|||
import '@common/types/ipc_main'
|
||||
import '@common/types/sound_effect'
|
||||
import '@common/types/dislike_list'
|
||||
import '@common/types/dislike_list_sync'
|
||||
|
|
|
@ -15,11 +15,13 @@ declare global {
|
|||
}
|
||||
moduleReadys: {
|
||||
list: boolean
|
||||
dislike: boolean
|
||||
}
|
||||
|
||||
onClose: (handler: (err: Error) => (void | Promise<void>)) => () => void
|
||||
remote: LX.Sync.ServerSyncActions
|
||||
remoteQueueList: LX.Sync.ServerSyncListActions
|
||||
remoteQueueDislike: LX.Sync.ServerSyncDislikeActions
|
||||
}
|
||||
|
||||
interface UrlInfo {
|
||||
|
@ -38,6 +40,7 @@ declare global {
|
|||
feature: LX.Sync.EnabledFeatures
|
||||
moduleReadys: {
|
||||
list: boolean
|
||||
dislike: boolean
|
||||
}
|
||||
|
||||
onClose: (handler: (err: Error) => (void | Promise<void>)) => () => void
|
||||
|
@ -45,6 +48,7 @@ declare global {
|
|||
|
||||
remote: LX.Sync.ClientSyncActions
|
||||
remoteQueueList: LX.Sync.ClientSyncListActions
|
||||
remoteQueueDislike: LX.Sync.ClientSyncDislikeActions
|
||||
}
|
||||
type SocketServer = WS.Server<Socket>
|
||||
}
|
||||
|
|
|
@ -1,16 +1,30 @@
|
|||
type WarpSyncHandlerActions<Socket, Actions> = {
|
||||
[K in keyof Actions]: (...args: [Socket, ...Parameters<Actions[K]>]) => ReturnType<Actions[K]>
|
||||
}
|
||||
|
||||
declare namespace LX {
|
||||
namespace Sync {
|
||||
type ServerSyncActions = WarpPromiseRecord<{
|
||||
onFeatureChanged: (feature: EnabledFeatures) => void
|
||||
}>
|
||||
type ServerSyncHandlerActions<Socket> = WarpSyncHandlerActions<Socket, ServerSyncActions>
|
||||
|
||||
type ServerSyncListActions = WarpPromiseRecord<{
|
||||
onListSyncAction: (action: LX.Sync.List.ActionList) => void
|
||||
}>
|
||||
type ServerSyncHandlerListActions<Socket> = WarpSyncHandlerActions<Socket, ServerSyncListActions>
|
||||
|
||||
type ServerSyncDislikeActions = WarpPromiseRecord<{
|
||||
onDislikeSyncAction: (action: LX.Sync.Dislike.ActionList) => void
|
||||
}>
|
||||
type ServerSyncHandlerDislikeActions<Socket> = WarpSyncHandlerActions<Socket, ServerSyncDislikeActions>
|
||||
|
||||
type ClientSyncActions = WarpPromiseRecord<{
|
||||
getEnabledFeatures: (serverType: ServerType, supportedFeatures: SupportedFeatures) => EnabledFeatures
|
||||
finished: () => void
|
||||
}>
|
||||
type ClientSyncHandlerActions<Socket> = WarpSyncHandlerActions<Socket, ClientSyncActions>
|
||||
|
||||
type ClientSyncListActions = WarpPromiseRecord<{
|
||||
onListSyncAction: (action: LX.Sync.List.ActionList) => void
|
||||
list_sync_get_md5: () => string
|
||||
|
@ -19,6 +33,17 @@ declare namespace LX {
|
|||
list_sync_set_list_data: (data: LX.Sync.List.ListData) => void
|
||||
list_sync_finished: () => void
|
||||
}>
|
||||
type ClientSyncHandlerListActions<Socket> = WarpSyncHandlerActions<Socket, ClientSyncListActions>
|
||||
|
||||
type ClientSyncDislikeActions = WarpPromiseRecord<{
|
||||
onDislikeSyncAction: (action: LX.Sync.Dislike.ActionList) => void
|
||||
dislike_sync_get_md5: () => string
|
||||
dislike_sync_get_sync_mode: () => LX.Sync.Dislike.SyncMode
|
||||
dislike_sync_get_list_data: () => LX.Dislike.DislikeRules
|
||||
dislike_sync_set_list_data: (data: LX.Dislike.DislikeRules) => void
|
||||
dislike_sync_finished: () => void
|
||||
}>
|
||||
type ClientSyncHandlerDislikeActions<Socket> = WarpSyncHandlerActions<Socket, ClientSyncDislikeActions>
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ const initDislikeList = () => {
|
|||
}
|
||||
}
|
||||
|
||||
dislikeInfo.rules = Array.from(new Set(list)).join('\n') + '\n'
|
||||
dislikeInfo.rules = Array.from(new Set(list)).join('\n')
|
||||
|
||||
return dislikeInfo
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<material-modal :show="sync.isShowSyncMode" :bg-close="false" :close-btn="false" @close="handleClose(false)">
|
||||
<main :class="$style.main">
|
||||
<h2>{{ $t('sync__title', { name: sync.deviceName }) }}</h2>
|
||||
<main v-if="sync.type == 'list'" :class="$style.main">
|
||||
<h2>{{ $t('sync__list_title', { name: sync.deviceName }) }}</h2>
|
||||
<div class="scroll" :class="$style.content">
|
||||
<dl :class="$style.btnGroup">
|
||||
<dt :class="$style.label">{{ $t('sync__merge_label') }}</dt>
|
||||
|
@ -31,15 +31,57 @@
|
|||
<dd>
|
||||
<section :class="$style.tipGroup">
|
||||
<h3 :class="$style.title">{{ $t('sync__merge_tip') }}</h3>
|
||||
<p :class="$style.tip">{{ $t('sync__merge_tip_desc') }}</p>
|
||||
<p :class="$style.tip">{{ $t('sync__list_merge_tip_desc') }}</p>
|
||||
</section>
|
||||
<section :class="$style.tipGroup">
|
||||
<h3 :class="$style.title">{{ $t('sync__overwrite_tip') }}</h3>
|
||||
<p :class="$style.tip">{{ $t('sync__overwrite_tip_desc') }}</p>
|
||||
<p :class="$style.tip">{{ $t('sync__list_overwrite_tip_desc') }}</p>
|
||||
</section>
|
||||
<section :class="$style.tipGroup">
|
||||
<h3 :class="$style.title">{{ $t('sync__other_tip') }}</h3>
|
||||
<p :class="$style.tip">{{ $t('sync__other_tip_desc') }}</p>
|
||||
<p :class="$style.tip">{{ $t('sync__list_other_tip_desc') }}</p>
|
||||
</section>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</main>
|
||||
<main v-else-if="sync.type == 'dislike'" :class="$style.main">
|
||||
<h2>{{ $t('sync__dislike_title', { name: sync.deviceName }) }}</h2>
|
||||
<div class="scroll" :class="$style.content">
|
||||
<dl :class="$style.btnGroup">
|
||||
<dt :class="$style.label">{{ $t('sync__merge_label') }}</dt>
|
||||
<dd :class="$style.btns">
|
||||
<base-btn :class="$style.btn" @click="handleSelectMode('merge_local_remote')">{{ $t('sync__merge_btn_local_remote') }}</base-btn>
|
||||
<base-btn :class="$style.btn" @click="handleSelectMode('merge_remote_local')">{{ $t('sync__merge_btn_remote_local') }}</base-btn>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl :class="$style.btnGroup">
|
||||
<dt :class="$style.label">{{ $t('sync__overwrite_label') }}</dt>
|
||||
<dd :class="$style.btns">
|
||||
<base-btn :class="$style.btn" @click="handleSelectMode('overwrite_local_remote')">{{ $t('sync__overwrite_btn_local_remote') }}</base-btn>
|
||||
<base-btn :class="$style.btn" @click="handleSelectMode('overwrite_remote_local')">{{ $t('sync__overwrite_btn_remote_local') }}</base-btn>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl :class="$style.btnGroup">
|
||||
<dt :class="$style.label">{{ $t('sync__other_label') }}</dt>
|
||||
<dd :class="$style.btns">
|
||||
<!-- <base-btn :class="$style.btn" @click="handleSelectMode('none')">{{ $t('sync__overwrite_btn_none') }}</base-btn> -->
|
||||
<base-btn :class="$style.btn" @click="handleSelectMode('cancel')">{{ $t('sync__overwrite_btn_cancel') }}</base-btn>
|
||||
</dd>
|
||||
</dl>
|
||||
<dl :class="$style.btnGroup">
|
||||
<dd>
|
||||
<section :class="$style.tipGroup">
|
||||
<h3 :class="$style.title">{{ $t('sync__merge_tip') }}</h3>
|
||||
<p :class="$style.tip">{{ $t('sync__dislike_merge_tip_desc') }}</p>
|
||||
</section>
|
||||
<section :class="$style.tipGroup">
|
||||
<h3 :class="$style.title">{{ $t('sync__overwrite_tip') }}</h3>
|
||||
<p :class="$style.tip">{{ $t('sync__dislike_overwrite_tip_desc') }}</p>
|
||||
</section>
|
||||
<section :class="$style.tipGroup">
|
||||
<h3 :class="$style.title">{{ $t('sync__other_tip') }}</h3>
|
||||
<p :class="$style.tip">{{ $t('sync__dislike_other_tip_desc') }}</p>
|
||||
</section>
|
||||
</dd>
|
||||
</dl>
|
||||
|
@ -60,8 +102,10 @@ export default {
|
|||
sync.isShowSyncMode = false
|
||||
}
|
||||
const handleSelectMode = (mode) => {
|
||||
if (mode.startsWith('overwrite') && isOverwrite.value) mode += '_full'
|
||||
void sendSyncAction({ action: 'select_mode', data: mode })
|
||||
if (sync.type == 'list') {
|
||||
if (mode.startsWith('overwrite') && isOverwrite.value) mode += '_full'
|
||||
}
|
||||
void sendSyncAction({ action: 'select_mode', data: { type: sync.type, mode } })
|
||||
handleClose()
|
||||
}
|
||||
return {
|
||||
|
|
|
@ -1,48 +1,51 @@
|
|||
// import { toRaw } from '@common/utils/vueTools'
|
||||
import { DISLIKE_EVENT_NAME } from '@common/ipcNames'
|
||||
import { rendererInvoke, rendererOff, rendererOn } from '@common/rendererIpc'
|
||||
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())
|
||||
action.initDislikeInfo(await rendererInvoke<LX.Dislike.DislikeInfo>(DISLIKE_EVENT_NAME.get_dislike_music_infos))
|
||||
}
|
||||
|
||||
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 | LX.Download.ListItem | null) => {
|
||||
if (!info) return false
|
||||
return action.hasDislike(info)
|
||||
}
|
||||
|
||||
export const addDislikeInfo = async(infos: LX.Dislike.DislikeMusicInfo[]) => {
|
||||
await rendererInvoke<LX.Dislike.DislikeMusicInfo[]>(DISLIKE_EVENT_NAME.add_dislike_music_infos, infos)
|
||||
}
|
||||
|
||||
export const overwirteDislikeInfo = async(rules: string) => {
|
||||
await rendererInvoke<string>(DISLIKE_EVENT_NAME.overwrite_dislike_music_infos, rules)
|
||||
}
|
||||
|
||||
export const clearDislikeInfo = async() => {
|
||||
await rendererInvoke(DISLIKE_EVENT_NAME.clear_dislike_music_infos)
|
||||
}
|
||||
|
||||
|
||||
const noop = () => {}
|
||||
|
||||
export const registerRemoteDislikeAction = (onListChanged: (listIds: string[]) => void = noop) => {
|
||||
const add_dislike_music_infos = ({ params: datas }: LX.IpcRendererEventParams<LX.Dislike.DislikeMusicInfo[]>) => {
|
||||
action.addDislikeInfo(datas)
|
||||
}
|
||||
const overwrite_dislike_music_infos = ({ params: datas }: LX.IpcRendererEventParams<LX.Dislike.DislikeRules>) => {
|
||||
action.overwirteDislikeInfo(datas)
|
||||
}
|
||||
const clear_dislike_music_infos = () => {
|
||||
return action.clearDislikeInfo()
|
||||
}
|
||||
|
||||
rendererOn(DISLIKE_EVENT_NAME.add_dislike_music_infos, add_dislike_music_infos)
|
||||
rendererOn(DISLIKE_EVENT_NAME.overwrite_dislike_music_infos, overwrite_dislike_music_infos)
|
||||
rendererOn(DISLIKE_EVENT_NAME.clear_dislike_music_infos, clear_dislike_music_infos)
|
||||
|
||||
return () => {
|
||||
rendererOff(DISLIKE_EVENT_NAME.add_dislike_music_infos, add_dislike_music_infos)
|
||||
rendererOff(DISLIKE_EVENT_NAME.overwrite_dislike_music_infos, overwrite_dislike_music_infos)
|
||||
rendererOff(DISLIKE_EVENT_NAME.clear_dislike_music_infos, clear_dislike_music_infos)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +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'
|
||||
import { initDislikeInfo, registerRemoteDislikeAction } from '@renderer/core/dislikeList'
|
||||
|
||||
const initPrevPlayInfo = async() => {
|
||||
const info = await getPlayInfo()
|
||||
|
@ -33,9 +33,11 @@ export default () => {
|
|||
const initUserApi = useInitUserApi()
|
||||
|
||||
let unregister: null | (() => void) = null
|
||||
let unregisterDislikeEvent: null | (() => void) = null
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (unregister) unregister()
|
||||
if (unregisterDislikeEvent) unregisterDislikeEvent()
|
||||
})
|
||||
|
||||
return async() => {
|
||||
|
@ -49,6 +51,7 @@ export default () => {
|
|||
window.app_event.myListUpdate(ids)
|
||||
})
|
||||
window.lxData.userLists = await getUserLists() // 获取用户列表
|
||||
unregisterDislikeEvent = registerRemoteDislikeAction()
|
||||
await initDislikeInfo() // 获取不喜欢列表
|
||||
await initPrevPlayInfo().catch(err => {
|
||||
log.error(err)
|
||||
|
|
|
@ -9,7 +9,8 @@ export default () => {
|
|||
// console.log(event)
|
||||
switch (event.action) {
|
||||
case 'select_mode':
|
||||
sync.deviceName = event.data
|
||||
sync.deviceName = event.data.deviceName
|
||||
sync.type = event.data.type
|
||||
sync.isShowSyncMode = true
|
||||
break
|
||||
case 'close_select_mode':
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { markRaw } from '@common/utils/vueTools'
|
||||
|
||||
|
||||
import { dislikeInfo } from './state'
|
||||
import { dislikeInfo, dislikeRuleCount } from './state'
|
||||
import { SPLIT_CHAR } from '@common/constants'
|
||||
|
||||
|
||||
|
@ -19,6 +19,7 @@ export const initDislikeInfo = ({ musicNames, rules, names, singerNames }: LX.Di
|
|||
dislikeInfo.singerNames = markRaw(singerNames)
|
||||
dislikeInfo.musicNames = markRaw(musicNames)
|
||||
dislikeInfo.rules = rules
|
||||
dislikeRuleCount.value = dislikeInfo.musicNames.size + dislikeInfo.singerNames.size + dislikeInfo.names.size
|
||||
}
|
||||
|
||||
const initNameSet = () => {
|
||||
|
@ -46,7 +47,8 @@ const initNameSet = () => {
|
|||
list.push(`${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
|
||||
}
|
||||
}
|
||||
dislikeInfo.rules = Array.from(new Set(list)).join('\n') + '\n'
|
||||
dislikeInfo.rules = Array.from(new Set(list)).join('\n')
|
||||
dislikeRuleCount.value = dislikeInfo.musicNames.size + dislikeInfo.singerNames.size + dislikeInfo.names.size
|
||||
}
|
||||
|
||||
export const addDislikeInfo = (infos: LX.Dislike.DislikeMusicInfo[]) => {
|
||||
|
@ -61,6 +63,12 @@ export const overwirteDislikeInfo = (rules: string) => {
|
|||
return dislikeInfo.rules
|
||||
}
|
||||
|
||||
export const clearDislikeInfo = () => {
|
||||
dislikeInfo.rules = ''
|
||||
initNameSet()
|
||||
return dislikeInfo.rules
|
||||
}
|
||||
|
||||
|
||||
// export const updateDislikeInfo = (info: LX.Dislike.ListItem) => {
|
||||
// const targetInfo = dislikeInfo.list.find(i => i.id == info.id)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { markRaw } from '@common/utils/vueTools'
|
||||
import { markRaw, ref } from '@common/utils/vueTools'
|
||||
|
||||
// import { deduplicationList } from '@common/utils/renderer'
|
||||
|
||||
|
@ -9,3 +9,5 @@ export const dislikeInfo: LX.Dislike.DislikeInfo = markRaw({
|
|||
singerNames: markRaw(new Set()),
|
||||
rules: '',
|
||||
})
|
||||
|
||||
export const dislikeRuleCount = ref(0)
|
||||
|
|
|
@ -31,6 +31,7 @@ export const sync: {
|
|||
isShowSyncMode: boolean
|
||||
isShowAuthCodeModal: boolean
|
||||
deviceName: string
|
||||
type: keyof LX.Sync.ModeTypes
|
||||
server: {
|
||||
port: string
|
||||
status: {
|
||||
|
@ -55,6 +56,7 @@ export const sync: {
|
|||
isShowSyncMode: false,
|
||||
isShowAuthCodeModal: false,
|
||||
deviceName: '',
|
||||
type: 'list',
|
||||
server: {
|
||||
port: '',
|
||||
status: {
|
||||
|
|
|
@ -40,15 +40,6 @@ 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)
|
||||
// }
|
||||
|
|
|
@ -3,7 +3,7 @@ material-modal(:show="modelValue" teleport="#view" height="80%" width="80%" @clo
|
|||
main(:class="$style.main")
|
||||
h2 {{ $t('setting__dislike_list_title') }}
|
||||
div(:class="$style.content")
|
||||
textarea(v-model="rules" :class="$style.textarea")
|
||||
textarea(v-model="rules" :class="$style.textarea" :placeholder="$t('setting__dislike_list_input_tip')")
|
||||
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') }}
|
||||
|
@ -21,21 +21,20 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'onRuleUpdate'],
|
||||
emits: ['update:modelValue'],
|
||||
setup(props, { emit }) {
|
||||
const rules = ref('')
|
||||
|
||||
const handleSave = async() => {
|
||||
if (rules.value.trim() != dislikeInfo.rules.trim()) {
|
||||
await overwirteDislikeInfo(rules.value)
|
||||
emit('onRuleUpdate')
|
||||
}
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, (visible) => {
|
||||
if (!visible) return
|
||||
rules.value = dislikeInfo.rules
|
||||
rules.value = dislikeInfo.rules.length ? dislikeInfo.rules + '\n' : dislikeInfo.rules
|
||||
})
|
||||
|
||||
return {
|
||||
|
@ -84,6 +83,7 @@ export default {
|
|||
border: none;
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
background-color: var(--color-primary-light-200-alpha-900);
|
||||
box-sizing: border-box;
|
||||
font-family: inherit;
|
||||
|
|
|
@ -42,7 +42,7 @@ dd
|
|||
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")
|
||||
DislikeListModal(v-model="isShowDislikeList")
|
||||
|
||||
dd
|
||||
h3#other_lyric_edited {{ $t('setting__other_lyric_edited_cache') }}
|
||||
|
@ -75,7 +75,7 @@ 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 { dislikeRuleCount } from '@renderer/store/dislikeList'
|
||||
import DislikeListModal from './DislikeListModal.vue'
|
||||
|
||||
export default {
|
||||
|
@ -150,11 +150,7 @@ 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)
|
||||
|
@ -226,7 +222,6 @@ export default {
|
|||
|
||||
dislikeRuleCount,
|
||||
isShowDislikeList,
|
||||
handleCountRules,
|
||||
|
||||
lyricRawCount,
|
||||
isDisabledLyricRawCacheClear,
|
||||
|
|
Loading…
Reference in New Issue