新增“不喜欢歌曲”功能&新增“收藏歌曲”、“取消收藏”、“不喜欢该歌曲”快捷键设置
This commit is contained in:
@@ -60,6 +60,10 @@ export default {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: 'auto',
|
||||
},
|
||||
},
|
||||
emits: ['after-enter', 'after-leave', 'close'],
|
||||
data() {
|
||||
@@ -147,6 +151,7 @@ export default {
|
||||
maxWidth: this.maxWidth,
|
||||
minWidth: this.minWidth,
|
||||
width: this.width,
|
||||
height: this.height,
|
||||
maxHeight: this.maxHeight,
|
||||
}
|
||||
},
|
||||
|
||||
@@ -180,6 +180,7 @@ export default {
|
||||
const {
|
||||
handleSearch,
|
||||
handleOpenMusicDetail,
|
||||
handleDislikeMusic,
|
||||
} = useMusicActions({ props })
|
||||
|
||||
const {
|
||||
@@ -199,6 +200,7 @@ export default {
|
||||
handleSearch,
|
||||
handleShowMusicAddModal,
|
||||
handleOpenMusicDetail,
|
||||
handleDislikeMusic,
|
||||
})
|
||||
|
||||
const handleListItemClick = (event, index) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { computed, ref, reactive, nextTick } from '@common/utils/vueTools'
|
||||
import musicSdk from '@renderer/utils/musicSdk'
|
||||
import { useI18n } from '@renderer/plugins/i18n'
|
||||
import { hasDislike } from '@renderer/core/dislikeList'
|
||||
|
||||
export default ({
|
||||
props,
|
||||
@@ -13,6 +14,7 @@ export default ({
|
||||
handleSearch,
|
||||
handleShowMusicAddModal,
|
||||
handleOpenMusicDetail,
|
||||
handleDislikeMusic,
|
||||
}) => {
|
||||
const itemMenuControl = reactive({
|
||||
play: true,
|
||||
@@ -21,6 +23,7 @@ export default ({
|
||||
download: true,
|
||||
search: true,
|
||||
sourceDetail: true,
|
||||
dislike: true,
|
||||
})
|
||||
const t = useI18n()
|
||||
const menuLocation = reactive({ x: 0, y: 0 })
|
||||
@@ -58,6 +61,11 @@ export default ({
|
||||
action: 'sourceDetail',
|
||||
disabled: !itemMenuControl.sourceDetail,
|
||||
},
|
||||
{
|
||||
name: t('list__dislike'),
|
||||
action: 'dislike',
|
||||
disabled: !itemMenuControl.dislike,
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
@@ -67,6 +75,8 @@ export default ({
|
||||
// this.listMenu.itemMenuControl.playLater =
|
||||
itemMenuControl.download = assertApiSupport(musicInfo.source)
|
||||
|
||||
itemMenuControl.dislike = !hasDislike(musicInfo)
|
||||
|
||||
if (props.checkApiSource) {
|
||||
itemMenuControl.playLater =
|
||||
itemMenuControl.play =
|
||||
@@ -110,6 +120,9 @@ export default ({
|
||||
break
|
||||
case 'sourceDetail':
|
||||
handleOpenMusicDetail(index)
|
||||
case 'dislike':
|
||||
handleDislikeMusic(index)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@ import { useRouter } from '@common/utils/vueRouter'
|
||||
import musicSdk from '@renderer/utils/musicSdk'
|
||||
import { openUrl } from '@common/utils/electron'
|
||||
import { toOldMusicInfo } from '@renderer/utils'
|
||||
import { addDislikeInfo, hasDislike } from '@renderer/core/dislikeList'
|
||||
import { playNext } from '@renderer/core/player'
|
||||
import { playMusicInfo } from '@renderer/store/player/state'
|
||||
|
||||
|
||||
export default ({ props }) => {
|
||||
@@ -24,8 +27,18 @@ export default ({ props }) => {
|
||||
openUrl(url)
|
||||
}
|
||||
|
||||
const handleDislikeMusic = async(index) => {
|
||||
const minfo = props.list[index]
|
||||
await addDislikeInfo([{ name: minfo.name, singer: minfo.singer }])
|
||||
if (!playMusicInfo.isTempPlay && hasDislike(playMusicInfo.musicInfo)) {
|
||||
playNext(true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
handleSearch,
|
||||
handleOpenMusicDetail,
|
||||
handleDislikeMusic,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
// import { toRaw } from '@common/utils/vueTools'
|
||||
import { action } from '@renderer/store/dislikeList'
|
||||
import {
|
||||
getDislikeListInfo,
|
||||
addDislikeInfo as addDislikeInfoRemote,
|
||||
overwirteDislikeInfo as overwirteDislikeInfoRemote,
|
||||
// updateDislikeInfo as updateDislikeInfoRemote,
|
||||
// removeDislikeInfo as removeDislikeInfoRemote,
|
||||
// clearDislikeInfo as clearDislikeInfoRemote,
|
||||
} from '@renderer/utils/ipc'
|
||||
|
||||
|
||||
export const initDislikeInfo = async() => {
|
||||
action.initDislikeInfo(await getDislikeListInfo())
|
||||
}
|
||||
|
||||
export const addDislikeInfo = async(infos: LX.Dislike.DislikeMusicInfo[]) => {
|
||||
await addDislikeInfoRemote(infos)
|
||||
return action.addDislikeInfo(infos)
|
||||
}
|
||||
|
||||
export const overwirteDislikeInfo = async(rules: string) => {
|
||||
await overwirteDislikeInfoRemote(rules)
|
||||
return action.overwirteDislikeInfo(rules)
|
||||
}
|
||||
|
||||
// export const updateDislikeInfo = async(info: LX.Dislike.ListItem) => {
|
||||
// await updateDislikeInfoRemote([toRaw(info)])
|
||||
// action.updateDislikeInfo(info)
|
||||
// }
|
||||
|
||||
// export const removeDislikeInfo = async(ids: string[]) => {
|
||||
// await removeDislikeInfoRemote(toRaw(ids))
|
||||
// action.removeDislikeInfo(ids)
|
||||
// }
|
||||
|
||||
|
||||
// export const clearDislikeInfo = async() => {
|
||||
// await clearDislikeInfoRemote()
|
||||
// action.clearDislikeInfo()
|
||||
// }
|
||||
|
||||
|
||||
export const hasDislike = (info: LX.Music.MusicInfo | null) => {
|
||||
if (!info) return false
|
||||
return action.hasDislike(info)
|
||||
}
|
||||
|
||||
@@ -299,6 +299,7 @@ export const playNext = async(isAutoToggle = false): Promise<void> => {
|
||||
list: currentList,
|
||||
playedList,
|
||||
playerMusicInfo: currentList[playInfo.playerPlayIndex],
|
||||
isNext: true,
|
||||
})
|
||||
|
||||
if (!filteredList.length) {
|
||||
@@ -398,6 +399,7 @@ export const playPrev = async(isAutoToggle = false): Promise<void> => {
|
||||
list: currentList,
|
||||
playedList,
|
||||
playerMusicInfo: currentList[playInfo.playerPlayIndex],
|
||||
isNext: false,
|
||||
})
|
||||
if (!filteredList.length) {
|
||||
handleToggleStop()
|
||||
|
||||
@@ -2,6 +2,7 @@ import { toRaw, markRawList } from '@common/utils/vueTools'
|
||||
import { qualityList } from '@renderer/store'
|
||||
import { clearPlayedList } from '@renderer/store/player/action'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { dislikeInfo } from '@renderer/store/dislikeList'
|
||||
|
||||
export const getPlayType = (highQuality: boolean, musicInfo: LX.Music.MusicInfo | LX.Download.ListItem): LX.Quality | null => {
|
||||
if ('progress' in musicInfo || musicInfo.source == 'local') return null
|
||||
@@ -14,11 +15,12 @@ export const getPlayType = (highQuality: boolean, musicInfo: LX.Music.MusicInfo
|
||||
/**
|
||||
* 过滤列表中已播放的歌曲
|
||||
*/
|
||||
export const filterList = async({ playedList, listId, list, playerMusicInfo }: {
|
||||
export const filterList = async({ playedList, listId, list, playerMusicInfo, isNext }: {
|
||||
playedList: LX.Player.PlayMusicInfo[]
|
||||
listId: string
|
||||
list: Array<LX.Music.MusicInfo | LX.Download.ListItem>
|
||||
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
|
||||
isNext: boolean
|
||||
}) => {
|
||||
// if (this.list.listName === null) return
|
||||
// console.log(isCheckFile)
|
||||
@@ -28,6 +30,8 @@ export const filterList = async({ playedList, listId, list, playerMusicInfo }: {
|
||||
playedList: toRaw(playedList),
|
||||
savePath: appSetting['download.savePath'],
|
||||
playerMusicInfo: toRaw(playerMusicInfo),
|
||||
dislikeInfo: { names: toRaw(dislikeInfo.names), musicNames: toRaw(dislikeInfo.musicNames), singerNames: toRaw(dislikeInfo.singerNames) },
|
||||
isNext,
|
||||
})
|
||||
|
||||
if (!filteredList.length && playedList.length) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import { play, playList } from '@renderer/core/player'
|
||||
import { onBeforeUnmount } from '@common/utils/vueTools'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { playMusicInfo } from '@renderer/store/player/state'
|
||||
import { initDislikeInfo } from '@renderer/core/dislikeList'
|
||||
|
||||
const initPrevPlayInfo = async() => {
|
||||
const info = await getPlayInfo()
|
||||
@@ -48,6 +49,7 @@ export default () => {
|
||||
window.app_event.myListUpdate(ids)
|
||||
})
|
||||
window.lxData.userLists = await getUserLists() // 获取用户列表
|
||||
await initDislikeInfo() // 获取不喜欢列表
|
||||
await initPrevPlayInfo().catch(err => {
|
||||
log.error(err)
|
||||
}) // 初始化上次的歌曲播放信息
|
||||
|
||||
@@ -32,6 +32,9 @@ import { HOTKEY_PLAYER } from '@common/hotKey'
|
||||
import { playNext, pause, playPrev, togglePlay } from '@renderer/core/player'
|
||||
import usePlaybackRate from './usePlaybackRate'
|
||||
import useSoundEffect from './useSoundEffect'
|
||||
import { addListMusics, removeListMusics } from '@renderer/store/list/action'
|
||||
import { loveList } from '@renderer/store/list/state'
|
||||
import { addDislikeInfo } from '@renderer/core/dislikeList'
|
||||
|
||||
|
||||
export default () => {
|
||||
@@ -90,6 +93,23 @@ export default () => {
|
||||
setStop()
|
||||
}
|
||||
|
||||
const collectMusic = () => {
|
||||
if (!playMusicInfo.musicInfo) return
|
||||
void addListMusics(loveList.id, ['progress' in playMusicInfo.musicInfo ? playMusicInfo.musicInfo.metadata.musicInfo : playMusicInfo.musicInfo])
|
||||
}
|
||||
const unCollectMusic = () => {
|
||||
if (!playMusicInfo.musicInfo) return
|
||||
void removeListMusics({ listId: loveList.id, ids: ['progress' in playMusicInfo.musicInfo ? playMusicInfo.musicInfo.metadata.musicInfo.id : playMusicInfo.musicInfo.id] })
|
||||
}
|
||||
const dislikeMusic = async() => {
|
||||
if (!playMusicInfo.musicInfo) return
|
||||
const minfo = 'progress' in playMusicInfo.musicInfo ? playMusicInfo.musicInfo.metadata.musicInfo : playMusicInfo.musicInfo
|
||||
await addDislikeInfo([{ name: minfo.name, singer: minfo.singer }])
|
||||
if (!playMusicInfo.isTempPlay) {
|
||||
playNext(true)
|
||||
}
|
||||
}
|
||||
|
||||
watch(() => appSetting['player.togglePlayMethod'], newValue => {
|
||||
// setLoopPlay(newValue == 'singleLoop')
|
||||
if (playedList.length) clearPlayedList()
|
||||
@@ -102,6 +122,9 @@ export default () => {
|
||||
window.key_event.on(HOTKEY_PLAYER.next.action, handlePlayNext)
|
||||
window.key_event.on(HOTKEY_PLAYER.prev.action, handlePlayPrev)
|
||||
window.key_event.on(HOTKEY_PLAYER.toggle_play.action, togglePlay)
|
||||
window.key_event.on(HOTKEY_PLAYER.music_love.action, collectMusic)
|
||||
window.key_event.on(HOTKEY_PLAYER.music_unlove.action, unCollectMusic)
|
||||
window.key_event.on(HOTKEY_PLAYER.music_dislike.action, dislikeMusic)
|
||||
|
||||
window.app_event.on('play', setPlayStatus)
|
||||
window.app_event.on('pause', setPauseStatus)
|
||||
@@ -119,6 +142,10 @@ export default () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
window.key_event.off(HOTKEY_PLAYER.prev.action, handlePlayPrev)
|
||||
window.key_event.off(HOTKEY_PLAYER.toggle_play.action, togglePlay)
|
||||
window.key_event.off(HOTKEY_PLAYER.music_love.action, collectMusic)
|
||||
window.key_event.off(HOTKEY_PLAYER.music_unlove.action, unCollectMusic)
|
||||
window.key_event.off(HOTKEY_PLAYER.music_dislike.action, dislikeMusic)
|
||||
|
||||
|
||||
window.app_event.off('play', setPlayStatus)
|
||||
window.app_event.off('pause', setPauseStatus)
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
import { markRaw } from '@common/utils/vueTools'
|
||||
|
||||
|
||||
import { dislikeInfo } from './state'
|
||||
import { SPLIT_CHAR } from '@common/constants'
|
||||
|
||||
|
||||
export const hasDislike = (info: LX.Music.MusicInfo) => {
|
||||
const name = info.name?.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim() ?? ''
|
||||
const singer = info.singer?.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim() ?? ''
|
||||
|
||||
return dislikeInfo.musicNames.has(name) || dislikeInfo.singerNames.has(singer) ||
|
||||
dislikeInfo.names.has(`${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
|
||||
}
|
||||
|
||||
export const initDislikeInfo = ({ musicNames, rules, names, singerNames }: LX.Dislike.DislikeInfo) => {
|
||||
dislikeInfo.names = markRaw(names)
|
||||
dislikeInfo.singerNames = markRaw(singerNames)
|
||||
dislikeInfo.musicNames = markRaw(musicNames)
|
||||
dislikeInfo.rules = rules
|
||||
}
|
||||
|
||||
const initNameSet = () => {
|
||||
dislikeInfo.names.clear()
|
||||
dislikeInfo.musicNames.clear()
|
||||
dislikeInfo.singerNames.clear()
|
||||
const list: string[] = []
|
||||
for (const item of dislikeInfo.rules.split('\n')) {
|
||||
if (!item) continue
|
||||
let [name, singer] = item.split(SPLIT_CHAR.DISLIKE_NAME)
|
||||
if (name) {
|
||||
name = name.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
|
||||
if (singer) {
|
||||
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
|
||||
const rule = `${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`
|
||||
dislikeInfo.names.add(rule)
|
||||
list.push(rule)
|
||||
} else {
|
||||
dislikeInfo.musicNames.add(name)
|
||||
list.push(name)
|
||||
}
|
||||
} else if (singer) {
|
||||
singer = singer.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim()
|
||||
dislikeInfo.singerNames.add(singer)
|
||||
list.push(`${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
|
||||
}
|
||||
}
|
||||
dislikeInfo.rules = list.join('\n') + '\n'
|
||||
}
|
||||
|
||||
export const addDislikeInfo = (infos: LX.Dislike.DislikeMusicInfo[]) => {
|
||||
dislikeInfo.rules += '\n' + infos.map(info => `${info.name ?? ''}${SPLIT_CHAR.DISLIKE_NAME}${info.singer ?? ''}`).join('\n')
|
||||
initNameSet()
|
||||
return dislikeInfo.rules
|
||||
}
|
||||
|
||||
export const overwirteDislikeInfo = (rules: string) => {
|
||||
dislikeInfo.rules = rules
|
||||
initNameSet()
|
||||
return dislikeInfo.rules
|
||||
}
|
||||
|
||||
|
||||
// export const updateDislikeInfo = (info: LX.Dislike.ListItem) => {
|
||||
// const targetInfo = dislikeInfo.list.find(i => i.id == info.id)
|
||||
// if (!targetInfo) return
|
||||
// targetInfo.name = info.name
|
||||
// targetInfo.singer = info.singer
|
||||
// initNameSet()
|
||||
// }
|
||||
|
||||
// export const removeDislikeInfo = (ids: string[]) => {
|
||||
// for (const id of ids) {
|
||||
// dislikeInfo.list.splice(dislikeInfo.list.findIndex(info => info.id == id), 1)
|
||||
// }
|
||||
// initNameSet()
|
||||
// }
|
||||
|
||||
// export const clearDislikeInfo = () => {
|
||||
// dislikeInfo.rules = ''
|
||||
// initNameSet()
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
export * as action from './action'
|
||||
export * from './state'
|
||||
@@ -0,0 +1,11 @@
|
||||
import { markRaw } from '@common/utils/vueTools'
|
||||
|
||||
// import { deduplicationList } from '@common/utils/renderer'
|
||||
|
||||
|
||||
export const dislikeInfo: LX.Dislike.DislikeInfo = markRaw({
|
||||
names: markRaw(new Set()),
|
||||
musicNames: markRaw(new Set()),
|
||||
singerNames: markRaw(new Set()),
|
||||
rules: '',
|
||||
})
|
||||
@@ -73,7 +73,7 @@ export const setPlayListId = (listId: string | null) => {
|
||||
playInfo.playerListId = listId
|
||||
}
|
||||
|
||||
export const getList = (listId: string | null): LX.Music.MusicInfo[] | LX.Download.ListItem[] => {
|
||||
export const getList = (listId: string | null): Array<LX.Music.MusicInfo | LX.Download.ListItem> => {
|
||||
return listId == LIST_IDS.DOWNLOAD ? downloadList : getListMusicsFromCache(listId)
|
||||
}
|
||||
|
||||
|
||||
Vendored
+1
@@ -15,3 +15,4 @@ import '@common/types/ipc_renderer'
|
||||
import '@common/types/config_files'
|
||||
import '@common/types/music_metadata'
|
||||
import '@common/types/sound_effect'
|
||||
import '@common/types/dislike_list'
|
||||
|
||||
@@ -40,6 +40,24 @@ export const getOtherSourceCount = async() => {
|
||||
return rendererInvoke<number>(WIN_MAIN_RENDERER_EVENT_NAME.get_other_source_count)
|
||||
}
|
||||
|
||||
export const getDislikeListInfo = async(): Promise<LX.Dislike.DislikeInfo> => {
|
||||
return rendererInvoke<LX.Dislike.DislikeInfo>(WIN_MAIN_RENDERER_EVENT_NAME.get_dislike_music_infos)
|
||||
}
|
||||
export const addDislikeInfo = async(dislikeInfo: LX.Dislike.DislikeMusicInfo[]) => {
|
||||
return rendererInvoke<LX.Dislike.DislikeMusicInfo[]>(WIN_MAIN_RENDERER_EVENT_NAME.add_dislike_music_infos, dislikeInfo)
|
||||
}
|
||||
export const overwirteDislikeInfo = async(dislikeInfo: string) => {
|
||||
return rendererInvoke<string>(WIN_MAIN_RENDERER_EVENT_NAME.overwrite_dislike_music_infos, dislikeInfo)
|
||||
}
|
||||
// export const updateDislikeInfo = async(dislikeInfo: LX.Dislike.ListItem[]) => {
|
||||
// await rendererInvoke<LX.Dislike.ListItem[]>(WIN_MAIN_RENDERER_EVENT_NAME.update_dislike_music_infos, dislikeInfo)
|
||||
// }
|
||||
// export const removeDislikeInfo = async(ids: string[]) => {
|
||||
// await rendererInvoke<string[]>(WIN_MAIN_RENDERER_EVENT_NAME.remove_dislike_music_infos, ids)
|
||||
// }
|
||||
// export const clearDislikeInfo = async() => {
|
||||
// await rendererInvoke(WIN_MAIN_RENDERER_EVENT_NAME.clear_dislike_music_infos)
|
||||
// }
|
||||
|
||||
export const getHotKeyConfig = async() => {
|
||||
return rendererInvoke<LX.HotKeyConfigAll>(WIN_MAIN_RENDERER_EVENT_NAME.get_hot_key)
|
||||
@@ -332,6 +350,11 @@ export const allHotKeys = markRaw({
|
||||
action: hotKeys.HOTKEY_PLAYER.next.action,
|
||||
type: APP_EVENT_NAMES.winMainName,
|
||||
},
|
||||
{
|
||||
name: hotKeys.HOTKEY_PLAYER.music_dislike.name,
|
||||
action: hotKeys.HOTKEY_PLAYER.music_dislike.action,
|
||||
type: APP_EVENT_NAMES.winMainName,
|
||||
},
|
||||
{
|
||||
name: hotKeys.HOTKEY_COMMON.focusSearchInput.name,
|
||||
action: hotKeys.HOTKEY_COMMON.focusSearchInput.action,
|
||||
@@ -394,6 +417,21 @@ export const allHotKeys = markRaw({
|
||||
action: hotKeys.HOTKEY_PLAYER.volume_mute.action,
|
||||
type: APP_EVENT_NAMES.winMainName,
|
||||
},
|
||||
{
|
||||
name: hotKeys.HOTKEY_PLAYER.music_love.name,
|
||||
action: hotKeys.HOTKEY_PLAYER.music_love.action,
|
||||
type: APP_EVENT_NAMES.winMainName,
|
||||
},
|
||||
{
|
||||
name: hotKeys.HOTKEY_PLAYER.music_unlove.name,
|
||||
action: hotKeys.HOTKEY_PLAYER.music_unlove.action,
|
||||
type: APP_EVENT_NAMES.winMainName,
|
||||
},
|
||||
{
|
||||
name: hotKeys.HOTKEY_PLAYER.music_dislike.name,
|
||||
action: hotKeys.HOTKEY_PLAYER.music_dislike.action,
|
||||
type: APP_EVENT_NAMES.winMainName,
|
||||
},
|
||||
{
|
||||
name: hotKeys.HOTKEY_DESKTOP_LYRIC.toggle_visible.name,
|
||||
action: hotKeys.HOTKEY_DESKTOP_LYRIC.toggle_visible.action,
|
||||
|
||||
@@ -201,6 +201,7 @@ export default {
|
||||
handleSearch,
|
||||
handleOpenMusicDetail,
|
||||
handleCopyName,
|
||||
handleDislikeMusic,
|
||||
handleRemoveMusic,
|
||||
} = useMusicActions({ props, list, removeAllSelect, selectedList })
|
||||
|
||||
@@ -223,6 +224,7 @@ export default {
|
||||
handleShowSortModal,
|
||||
handleOpenMusicDetail,
|
||||
handleCopyName,
|
||||
handleDislikeMusic,
|
||||
handleRemoveMusic,
|
||||
})
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { computed, ref, shallowReactive, reactive, nextTick } from '@common/utils/vueTools'
|
||||
import musicSdk from '@renderer/utils/musicSdk'
|
||||
import { useI18n } from '@renderer/plugins/i18n'
|
||||
import { hasDislike } from '@renderer/core/dislikeList'
|
||||
|
||||
export default ({
|
||||
assertApiSupport,
|
||||
@@ -15,6 +16,7 @@ export default ({
|
||||
handleShowSortModal,
|
||||
handleOpenMusicDetail,
|
||||
handleCopyName,
|
||||
handleDislikeMusic,
|
||||
handleRemoveMusic,
|
||||
}) => {
|
||||
const itemMenuControl = reactive({
|
||||
@@ -26,6 +28,7 @@ export default ({
|
||||
sort: true,
|
||||
download: true,
|
||||
search: true,
|
||||
dislike: true,
|
||||
remove: true,
|
||||
sourceDetail: true,
|
||||
})
|
||||
@@ -80,6 +83,11 @@ export default ({
|
||||
action: 'search',
|
||||
disabled: !itemMenuControl.search,
|
||||
},
|
||||
{
|
||||
name: t('list__dislike'),
|
||||
action: 'dislike',
|
||||
disabled: !itemMenuControl.dislike,
|
||||
},
|
||||
{
|
||||
name: t('list__remove'),
|
||||
action: 'remove',
|
||||
@@ -94,6 +102,8 @@ export default ({
|
||||
// itemMenuControl.playLater =
|
||||
itemMenuControl.download = assertApiSupport(musicInfo.source) && musicInfo.source != 'local'
|
||||
|
||||
itemMenuControl.dislike = !hasDislike(musicInfo)
|
||||
|
||||
menuLocation.x = event.pageX
|
||||
menuLocation.y = event.pageY
|
||||
|
||||
@@ -138,6 +148,9 @@ export default ({
|
||||
case 'search':
|
||||
handleSearch(index)
|
||||
break
|
||||
case 'dislike':
|
||||
handleDislikeMusic(index)
|
||||
break
|
||||
case 'remove':
|
||||
handleRemoveMusic(index)
|
||||
break
|
||||
|
||||
@@ -6,6 +6,9 @@ import { useI18n } from '@renderer/plugins/i18n'
|
||||
import { removeListMusics } from '@renderer/store/list/action'
|
||||
import { appSetting } from '@renderer/store/setting'
|
||||
import { toOldMusicInfo } from '@renderer/utils/index'
|
||||
import { addDislikeInfo, hasDislike } from '@renderer/core/dislikeList'
|
||||
import { playNext } from '@renderer/core/player'
|
||||
import { playMusicInfo } from '@renderer/store/player/state'
|
||||
|
||||
|
||||
export default ({ props, list, selectedList, removeAllSelect }) => {
|
||||
@@ -34,6 +37,14 @@ export default ({ props, list, selectedList, removeAllSelect }) => {
|
||||
clipboardWriteText(appSetting['download.fileName'].replace('歌名', minfo.name).replace('歌手', minfo.singer))
|
||||
}
|
||||
|
||||
const handleDislikeMusic = async(index) => {
|
||||
const minfo = list.value[index]
|
||||
await addDislikeInfo([{ name: minfo.name, singer: minfo.singer }])
|
||||
if (!playMusicInfo.isTempPlay && hasDislike(playMusicInfo.musicInfo)) {
|
||||
playNext(true)
|
||||
}
|
||||
}
|
||||
|
||||
const handleRemoveMusic = async(index, single) => {
|
||||
if (selectedList.value.length && !single) {
|
||||
const confirm = await (selectedList.value.length > 1
|
||||
@@ -55,6 +66,7 @@ export default ({ props, list, selectedList, removeAllSelect }) => {
|
||||
handleSearch,
|
||||
handleOpenMusicDetail,
|
||||
handleCopyName,
|
||||
handleDislikeMusic,
|
||||
handleRemoveMusic,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
<template lang="pug">
|
||||
material-modal(:show="modelValue" teleport="#view" height="80%" width="80%" @close="$emit('update:modelValue', false)")
|
||||
main(:class="$style.main")
|
||||
h2 {{ $t('setting__dislike_list_title') }}
|
||||
div(:class="$style.content")
|
||||
textarea(v-model="rules" :class="$style.textarea")
|
||||
div(:class="$style.footer")
|
||||
div(:class="$style.tips") {{ $t('setting__dislike_list_tips') }}
|
||||
base-btn(:class="$style.btn" @click="handleSave") {{ $t('setting__dislike_list_save_btn') }}
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { watch, ref } from '@common/utils/vueTools'
|
||||
import { overwirteDislikeInfo } from '@renderer/core/dislikeList'
|
||||
import { dislikeInfo } from '@renderer/store/dislikeList'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: ['update:modelValue', 'onRuleUpdate'],
|
||||
setup(props, { emit }) {
|
||||
const rules = ref('')
|
||||
|
||||
const handleSave = async() => {
|
||||
await overwirteDislikeInfo(rules.value)
|
||||
emit('onRuleUpdate')
|
||||
emit('update:modelValue', false)
|
||||
}
|
||||
|
||||
watch(() => props.modelValue, (visible) => {
|
||||
if (!visible) return
|
||||
rules.value = dislikeInfo.rules
|
||||
})
|
||||
|
||||
return {
|
||||
rules,
|
||||
handleSave,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" module>
|
||||
@import '@renderer/assets/styles/layout.less';
|
||||
|
||||
.main {
|
||||
// padding: 15px;
|
||||
// max-width: 400px;
|
||||
// min-width: 460px;
|
||||
// min-height: 200px;
|
||||
// width: ;
|
||||
flex: auto;
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: center;
|
||||
// min-height: 0;
|
||||
// max-height: 100%;
|
||||
// overflow: hidden;
|
||||
h2 {
|
||||
margin: 20px;
|
||||
font-size: 16px;
|
||||
color: var(--color-font);
|
||||
line-height: 1.3;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
flex: auto;
|
||||
// min-height: 100px;
|
||||
max-height: 100%;
|
||||
display: flex;
|
||||
padding: 0 15px;
|
||||
}
|
||||
.textarea {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 4px;
|
||||
background-color: var(--color-primary-light-200-alpha-900);
|
||||
box-sizing: border-box;
|
||||
font-family: inherit;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.footer {
|
||||
box-sizing: border-box;
|
||||
flex: none;
|
||||
// width: @width;
|
||||
padding: 15px 15px;
|
||||
// padding: 2px 0;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
.tips {
|
||||
// padding: 10px 15px;
|
||||
font-size: 12px;
|
||||
line-height: 1.25;
|
||||
color: var(--color-550);
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.btn {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -34,6 +34,16 @@ dd
|
||||
base-btn.btn(min :disabled="isDisabledMusicUrlCacheClear" @click="handleClearMusicUrlCache") {{ $t('setting__other_music_url_clear_btn') }}
|
||||
base-btn.btn(min :disabled="isDisabledLyricRawCacheClear" @click="handleClearLyricRawCache") {{ $t('setting__other_lyric_raw_clear_btn') }}
|
||||
|
||||
dd
|
||||
h3#other_lyric_edited {{ $t('setting__other_dislike_list') }}
|
||||
div
|
||||
.p
|
||||
| {{ $t('setting__other_dislike_list_label') }}
|
||||
span.auto-hidden {{ dislikeRuleCount }}
|
||||
.p
|
||||
base-btn.btn(min @click="isShowDislikeList = true") {{ $t('setting__other_dislike_list_show_btn') }}
|
||||
DislikeListModal(v-model="isShowDislikeList" @on-rule-update="handleCountRules")
|
||||
|
||||
dd
|
||||
h3#other_lyric_edited {{ $t('setting__other_lyric_edited_cache') }}
|
||||
div
|
||||
@@ -65,9 +75,14 @@ import { dialog } from '@renderer/plugins/Dialog'
|
||||
import { useI18n } from '@renderer/plugins/i18n'
|
||||
import { appSetting, updateSetting } from '@renderer/store/setting'
|
||||
import { overwriteListFull } from '@renderer/store/list/listManage'
|
||||
import { dislikeInfo } from '@renderer/store/dislikeList'
|
||||
import DislikeListModal from './DislikeListModal.vue'
|
||||
|
||||
export default {
|
||||
name: 'SettingOther',
|
||||
components: {
|
||||
DislikeListModal,
|
||||
},
|
||||
setup() {
|
||||
const t = useI18n()
|
||||
|
||||
@@ -135,6 +150,11 @@ export default {
|
||||
}
|
||||
refreshMusicUrlCount()
|
||||
|
||||
const dislikeRuleCount = ref(dislikeInfo.musicNames.size + dislikeInfo.singerNames.size + dislikeInfo.names.size)
|
||||
const isShowDislikeList = ref(false)
|
||||
const handleCountRules = () => {
|
||||
dislikeRuleCount.value = dislikeInfo.musicNames.size + dislikeInfo.singerNames.size + dislikeInfo.names.size
|
||||
}
|
||||
|
||||
const lyricRawCount = ref(0)
|
||||
const isDisabledLyricRawCacheClear = ref(false)
|
||||
@@ -204,6 +224,10 @@ export default {
|
||||
isDisabledMusicUrlCacheClear,
|
||||
handleClearMusicUrlCache,
|
||||
|
||||
dislikeRuleCount,
|
||||
isShowDislikeList,
|
||||
handleCountRules,
|
||||
|
||||
lyricRawCount,
|
||||
isDisabledLyricRawCacheClear,
|
||||
handleClearLyricRawCache,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// import { throttle } from '@common/utils'
|
||||
|
||||
import { SPLIT_CHAR } from '@common/constants'
|
||||
import { filterFileName, sortInsert, similar, arrPushByPosition, arrShuffle } from '@common/utils/common'
|
||||
import { joinPath, saveStrToFile } from '@common/utils/nodejs'
|
||||
import { createLocalMusicInfo } from '@renderer/utils/music'
|
||||
@@ -8,7 +9,7 @@ import { createLocalMusicInfo } from '@renderer/utils/music'
|
||||
/**
|
||||
* 过滤列表中已播放的歌曲
|
||||
*/
|
||||
export const filterMusicList = async({ playedList, listId, list, savePath, playerMusicInfo }: {
|
||||
export const filterMusicList = async({ playedList, listId, list, savePath, playerMusicInfo, dislikeInfo, isNext }: {
|
||||
/**
|
||||
* 已播放列表
|
||||
*/
|
||||
@@ -29,15 +30,34 @@ export const filterMusicList = async({ playedList, listId, list, savePath, playe
|
||||
* 播放器内当前歌曲(`playInfo.playerPlayIndex`指向的歌曲)
|
||||
*/
|
||||
playerMusicInfo?: LX.Music.MusicInfo | LX.Download.ListItem
|
||||
/**
|
||||
* 不喜欢的歌曲名字列表
|
||||
*/
|
||||
dislikeInfo: Omit<LX.Dislike.DislikeInfo, 'rules'>
|
||||
|
||||
isNext: boolean
|
||||
}) => {
|
||||
let playerIndex = -1
|
||||
|
||||
let canPlayList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = []
|
||||
const filteredPlayedList = playedList.filter(pmInfo => pmInfo.listId == listId && !pmInfo.isTempPlay).map(({ musicInfo }) => musicInfo)
|
||||
const hasDislike = (info: LX.Music.MusicInfo) => {
|
||||
const name = info.name?.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim() ?? ''
|
||||
const singer = info.singer?.replaceAll(SPLIT_CHAR.DISLIKE_NAME, SPLIT_CHAR.DISLIKE_NAME_ALIAS).toLocaleLowerCase().trim() ?? ''
|
||||
|
||||
return dislikeInfo.musicNames.has(name) || dislikeInfo.singerNames.has(singer) ||
|
||||
dislikeInfo.names.has(`${name}${SPLIT_CHAR.DISLIKE_NAME}${singer}`)
|
||||
}
|
||||
|
||||
let isDislike = false
|
||||
const filteredList: Array<LX.Music.MusicInfo | LX.Download.ListItem> = list.filter(s => {
|
||||
// if (!assertApiSupport(s.source)) return false
|
||||
if ('progress' in s && !s.isComplate) return false
|
||||
if ('progress' in s) {
|
||||
if (!s.isComplate) return false
|
||||
} else if (hasDislike(s)) {
|
||||
if (s.id != playerMusicInfo?.id) return false
|
||||
isDislike = true
|
||||
}
|
||||
|
||||
canPlayList.push(s)
|
||||
|
||||
@@ -49,7 +69,34 @@ export const filterMusicList = async({ playedList, listId, list, savePath, playe
|
||||
return true
|
||||
})
|
||||
if (playerMusicInfo) {
|
||||
playerIndex = (filteredList.length ? filteredList : canPlayList).findIndex(m => m.id == playerMusicInfo.id)
|
||||
if (isDislike) {
|
||||
if (filteredList.length <= 1) {
|
||||
filteredList.splice(0, 1)
|
||||
if (canPlayList.length > 1) {
|
||||
let currentMusicIndex = canPlayList.findIndex(m => m.id == playerMusicInfo.id)
|
||||
if (isNext) {
|
||||
playerIndex = currentMusicIndex - 1
|
||||
if (playerIndex < 0 && canPlayList.length > 1) playerIndex = canPlayList.length - 2
|
||||
} else {
|
||||
playerIndex = currentMusicIndex
|
||||
if (canPlayList.length <= 1) playerIndex = -1
|
||||
}
|
||||
canPlayList.splice(currentMusicIndex, 1)
|
||||
} else canPlayList.splice(0, 1)
|
||||
} else {
|
||||
let currentMusicIndex = filteredList.findIndex(m => m.id == playerMusicInfo.id)
|
||||
if (isNext) {
|
||||
playerIndex = currentMusicIndex - 1
|
||||
if (playerIndex < 0 && filteredList.length > 1) playerIndex = filteredList.length - 2
|
||||
} else {
|
||||
playerIndex = currentMusicIndex
|
||||
if (filteredList.length <= 1) playerIndex = -1
|
||||
}
|
||||
filteredList.splice(currentMusicIndex, 1)
|
||||
}
|
||||
} else {
|
||||
playerIndex = (filteredList.length ? filteredList : canPlayList).findIndex(m => m.id == playerMusicInfo.id)
|
||||
}
|
||||
}
|
||||
return {
|
||||
filteredList,
|
||||
|
||||
Reference in New Issue
Block a user