新增下载的歌曲按列表名分组的功能(#2145)
parent
63b2c2fb2f
commit
6f74003e14
|
@ -5,6 +5,7 @@ Linux 系统至少需要 GLIBC_2.29 版本才能运行,
|
||||||
|
|
||||||
### 新增
|
### 新增
|
||||||
|
|
||||||
|
- 新增下载的歌曲按列表名分组的功能,默认关闭,可以到 设置-下载设置-将文件保存到以对应列表命名的子目录中 启用(#2145)
|
||||||
- 新增托盘图标颜色 跟随系统亮暗模式 设置,可以在 设置-其他 启用 (#2016)
|
- 新增托盘图标颜色 跟随系统亮暗模式 设置,可以在 设置-其他 启用 (#2016)
|
||||||
- 支持本地同名 `krc` 格式歌词文件的读取(#2053)
|
- 支持本地同名 `krc` 格式歌词文件的读取(#2053)
|
||||||
- Open API 新增播放器播放/暂停、切歌、收藏当前播放歌曲调用,详情看开放API文档 (原始 PR #2077)
|
- Open API 新增播放器播放/暂停、切歌、收藏当前播放歌曲调用,详情看开放API文档 (原始 PR #2077)
|
||||||
|
|
|
@ -107,6 +107,7 @@ const defaultSetting: LX.AppSetting = {
|
||||||
'list.actionButtonsVisible': false,
|
'list.actionButtonsVisible': false,
|
||||||
|
|
||||||
'download.enable': false,
|
'download.enable': false,
|
||||||
|
'download.isSavePathGroupByListName': false,
|
||||||
'download.savePath': path.join(os.homedir(), 'Desktop'),
|
'download.savePath': path.join(os.homedir(), 'Desktop'),
|
||||||
'download.fileName': '歌名 - 歌手',
|
'download.fileName': '歌名 - 歌手',
|
||||||
'download.maxDownloadNum': 3,
|
'download.maxDownloadNum': 3,
|
||||||
|
|
|
@ -485,6 +485,11 @@ declare global {
|
||||||
*/
|
*/
|
||||||
'download.enable': boolean
|
'download.enable': boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按列表名分组保存
|
||||||
|
*/
|
||||||
|
'download.isSavePathGroupByListName': boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 下载路径
|
* 下载路径
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -59,6 +59,7 @@ declare global {
|
||||||
ext: FileExt
|
ext: FileExt
|
||||||
fileName: string
|
fileName: string
|
||||||
filePath: string
|
filePath: string
|
||||||
|
listId?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,25 @@ export const checkPath = async(path: string): Promise<boolean> => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查路径并创建目录
|
||||||
|
* @param path
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const checkAndCreateDir = async(path: string) => {
|
||||||
|
return fs.promises.access(path, fs.constants.F_OK | fs.constants.W_OK)
|
||||||
|
.catch(async(err: NodeJS.ErrnoException) => {
|
||||||
|
if (err.code != 'ENOENT') throw err as Error
|
||||||
|
return fs.promises.mkdir(path, { recursive: true })
|
||||||
|
})
|
||||||
|
.then(() => true)
|
||||||
|
.catch((err) => {
|
||||||
|
console.error(err)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export const getFileStats = async(path: string): Promise<fs.Stats | null> => {
|
export const getFileStats = async(path: string): Promise<fs.Stats | null> => {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
|
|
|
@ -130,3 +130,21 @@ export const filterMusicList = <T extends LX.Music.MusicInfo>(list: T[]): T[] =>
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const MAX_NAME_LENGTH = 80
|
||||||
|
const MAX_FILE_NAME_LENGTH = 150
|
||||||
|
export const clipNameLength = (name: string) => {
|
||||||
|
if (name.length <= MAX_NAME_LENGTH || !name.includes('、')) return name
|
||||||
|
const names = name.split('、')
|
||||||
|
let newName = names.shift()!
|
||||||
|
for (const name of names) {
|
||||||
|
if (newName.length + name.length > MAX_NAME_LENGTH) break
|
||||||
|
newName = newName + '、' + name
|
||||||
|
}
|
||||||
|
return newName
|
||||||
|
}
|
||||||
|
export const clipFileNameLength = (name: string) => {
|
||||||
|
return name.length > MAX_FILE_NAME_LENGTH ? name.substring(0, MAX_FILE_NAME_LENGTH) : name
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -586,6 +586,7 @@
|
||||||
"setting__update_try_auto_update": "Attempt to download updates automatically when a new version is found",
|
"setting__update_try_auto_update": "Attempt to download updates automatically when a new version is found",
|
||||||
"setting__update_unknown": "Unknown",
|
"setting__update_unknown": "Unknown",
|
||||||
"setting__update_unknown_tip": "❓ Failed to obtain the latest version information, it is recommended to go to the About interface to open the project release address to check whether the current version is the latest",
|
"setting__update_unknown_tip": "❓ Failed to obtain the latest version information, it is recommended to go to the About interface to open the project release address to check whether the current version is the latest",
|
||||||
|
"setting_download_save_group_list_name": "Save files to a subdirectory named after the corresponding list",
|
||||||
"setting_sync_status_enabled": "connected",
|
"setting_sync_status_enabled": "connected",
|
||||||
"song_list": "Playlists",
|
"song_list": "Playlists",
|
||||||
"songlist__import_input_btn_confirm": "Open",
|
"songlist__import_input_btn_confirm": "Open",
|
||||||
|
|
|
@ -586,6 +586,7 @@
|
||||||
"setting__update_try_auto_update": "发现新版本时尝试自动下载更新",
|
"setting__update_try_auto_update": "发现新版本时尝试自动下载更新",
|
||||||
"setting__update_unknown": "未知",
|
"setting__update_unknown": "未知",
|
||||||
"setting__update_unknown_tip": "❓ 获取最新版本信息失败,建议去「关于」页面打开项目发布地址查看当前版本是否最新",
|
"setting__update_unknown_tip": "❓ 获取最新版本信息失败,建议去「关于」页面打开项目发布地址查看当前版本是否最新",
|
||||||
|
"setting_download_save_group_list_name": "将文件保存到以对应列表命名的子目录中",
|
||||||
"setting_sync_status_enabled": "已连接",
|
"setting_sync_status_enabled": "已连接",
|
||||||
"song_list": "歌单",
|
"song_list": "歌单",
|
||||||
"songlist__import_input_btn_confirm": "打开",
|
"songlist__import_input_btn_confirm": "打开",
|
||||||
|
|
|
@ -586,6 +586,7 @@
|
||||||
"setting__update_try_auto_update": "發現新版本時嘗試自動下載更新",
|
"setting__update_try_auto_update": "發現新版本時嘗試自動下載更新",
|
||||||
"setting__update_unknown": "未知",
|
"setting__update_unknown": "未知",
|
||||||
"setting__update_unknown_tip": "❓ 取得最新版本資訊失敗,建議去關於介面開啟專案發佈位址查看目前版本是否最新",
|
"setting__update_unknown_tip": "❓ 取得最新版本資訊失敗,建議去關於介面開啟專案發佈位址查看目前版本是否最新",
|
||||||
|
"setting_download_save_group_list_name": "將檔案儲存到以對應清單命名的子目錄中",
|
||||||
"setting_sync_status_enabled": "已連接",
|
"setting_sync_status_enabled": "已連接",
|
||||||
"song_list": "歌單",
|
"song_list": "歌單",
|
||||||
"songlist__import_input_btn_confirm": "打開",
|
"songlist__import_input_btn_confirm": "打開",
|
||||||
|
|
|
@ -23,6 +23,10 @@ export default {
|
||||||
type: [Object, null],
|
type: [Object, null],
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
listId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
bgClose: {
|
bgClose: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
|
@ -51,7 +55,7 @@ export default {
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleClick(quality) {
|
handleClick(quality) {
|
||||||
void createDownloadTasks([this.musicInfo], quality)
|
void createDownloadTasks([this.musicInfo], quality, this.listId)
|
||||||
this.handleClose()
|
this.handleClose()
|
||||||
},
|
},
|
||||||
handleClose() {
|
handleClose() {
|
||||||
|
|
|
@ -23,6 +23,10 @@ export default {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
},
|
},
|
||||||
|
listId: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
list: {
|
list: {
|
||||||
type: Array,
|
type: Array,
|
||||||
default() {
|
default() {
|
||||||
|
@ -37,7 +41,7 @@ export default {
|
||||||
emits: ['update:show', 'confirm'],
|
emits: ['update:show', 'confirm'],
|
||||||
methods: {
|
methods: {
|
||||||
handleClick(quality) {
|
handleClick(quality) {
|
||||||
void createDownloadTasks(this.list.filter(item => item.source != 'local'), quality)
|
void createDownloadTasks(this.list.filter(item => item.source != 'local'), quality, this.listId)
|
||||||
this.handleClose()
|
this.handleClose()
|
||||||
this.$emit('confirm')
|
this.$emit('confirm')
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { appSetting } from '@renderer/store/setting'
|
|
||||||
import { getDownloadFilePath } from '@renderer/utils/music'
|
import { getDownloadFilePath } from '@renderer/utils/music'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -7,6 +6,7 @@ import {
|
||||||
getLyricInfo as getOnlineLyricInfo,
|
getLyricInfo as getOnlineLyricInfo,
|
||||||
} from './online'
|
} from './online'
|
||||||
import { buildLyricInfo, getCachedLyricInfo } from './utils'
|
import { buildLyricInfo, getCachedLyricInfo } from './utils'
|
||||||
|
import { buildSavePath } from '@renderer/store/download/utils'
|
||||||
|
|
||||||
export const getMusicUrl = async({ musicInfo, isRefresh, allowToggleSource = true, onToggleSource = () => {} }: {
|
export const getMusicUrl = async({ musicInfo, isRefresh, allowToggleSource = true, onToggleSource = () => {} }: {
|
||||||
musicInfo: LX.Download.ListItem
|
musicInfo: LX.Download.ListItem
|
||||||
|
@ -15,7 +15,7 @@ export const getMusicUrl = async({ musicInfo, isRefresh, allowToggleSource = tru
|
||||||
allowToggleSource?: boolean
|
allowToggleSource?: boolean
|
||||||
}): Promise<string> => {
|
}): Promise<string> => {
|
||||||
if (!isRefresh) {
|
if (!isRefresh) {
|
||||||
const path = await getDownloadFilePath(musicInfo, appSetting['download.savePath'])
|
const path = await getDownloadFilePath(musicInfo, buildSavePath(musicInfo))
|
||||||
if (path) return path
|
if (path) return path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ export const getPicUrl = async({ musicInfo, isRefresh, listId, onToggleSource =
|
||||||
onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void
|
onToggleSource?: (musicInfo?: LX.Music.MusicInfoOnline) => void
|
||||||
}): Promise<string> => {
|
}): Promise<string> => {
|
||||||
if (!isRefresh) {
|
if (!isRefresh) {
|
||||||
const path = await getDownloadFilePath(musicInfo, appSetting['download.savePath'])
|
const path = await getDownloadFilePath(musicInfo, buildSavePath(musicInfo))
|
||||||
if (path) {
|
if (path) {
|
||||||
const pic = await window.lx.worker.main.getMusicFilePic(path)
|
const pic = await window.lx.worker.main.getMusicFilePic(path)
|
||||||
if (pic) return pic
|
if (pic) return pic
|
||||||
|
@ -62,7 +62,7 @@ export const getLyricInfo = async({ musicInfo, isRefresh, onToggleSource = () =>
|
||||||
onToggleSource,
|
onToggleSource,
|
||||||
}).catch(async() => {
|
}).catch(async() => {
|
||||||
// 尝试读取文件内歌词
|
// 尝试读取文件内歌词
|
||||||
const path = await getDownloadFilePath(musicInfo, appSetting['download.savePath'])
|
const path = await getDownloadFilePath(musicInfo, buildSavePath(musicInfo))
|
||||||
if (path) {
|
if (path) {
|
||||||
const rawlrcInfo = await window.lx.worker.main.getMusicFileLyric(path)
|
const rawlrcInfo = await window.lx.worker.main.getMusicFileLyric(path)
|
||||||
if (rawlrcInfo) return buildLyricInfo(rawlrcInfo)
|
if (rawlrcInfo) return buildLyricInfo(rawlrcInfo)
|
||||||
|
|
|
@ -29,7 +29,7 @@ export const filterList = async({ playedList, listId, list, playerMusicInfo, isN
|
||||||
listId,
|
listId,
|
||||||
list: list.map(m => toRaw(m)),
|
list: list.map(m => toRaw(m)),
|
||||||
playedList: toRaw(playedList),
|
playedList: toRaw(playedList),
|
||||||
savePath: appSetting['download.savePath'],
|
// savePath: appSetting['download.savePath'],
|
||||||
playerMusicInfo: toRaw(playerMusicInfo),
|
playerMusicInfo: toRaw(playerMusicInfo),
|
||||||
dislikeInfo: { names: toRaw(dislikeInfo.names), musicNames: toRaw(dislikeInfo.musicNames), singerNames: toRaw(dislikeInfo.singerNames) },
|
dislikeInfo: { names: toRaw(dislikeInfo.names), musicNames: toRaw(dislikeInfo.musicNames), singerNames: toRaw(dislikeInfo.singerNames) },
|
||||||
isNext,
|
isNext,
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { proxyCallback } from '@renderer/worker/utils'
|
||||||
import { arrPush, arrUnshift, joinPath } from '@renderer/utils'
|
import { arrPush, arrUnshift, joinPath } from '@renderer/utils'
|
||||||
import { DOWNLOAD_STATUS } from '@common/constants'
|
import { DOWNLOAD_STATUS } from '@common/constants'
|
||||||
import { proxy } from '../index'
|
import { proxy } from '../index'
|
||||||
|
import { buildSavePath } from './utils'
|
||||||
|
|
||||||
const waitingUpdateTasks = new Map<string, LX.Download.ListItem>()
|
const waitingUpdateTasks = new Map<string, LX.Download.ListItem>()
|
||||||
let timer: NodeJS.Timeout | null = null
|
let timer: NodeJS.Timeout | null = null
|
||||||
|
@ -271,12 +272,13 @@ const handleStartTask = async(downloadInfo: LX.Download.ListItem) => {
|
||||||
if (downloadInfo.status != DOWNLOAD_STATUS.RUN) return
|
if (downloadInfo.status != DOWNLOAD_STATUS.RUN) return
|
||||||
}
|
}
|
||||||
|
|
||||||
const filePath = joinPath(appSetting['download.savePath'], downloadInfo.metadata.fileName)
|
const savePath = buildSavePath(downloadInfo)
|
||||||
|
const filePath = joinPath(savePath, downloadInfo.metadata.fileName)
|
||||||
if (downloadInfo.metadata.filePath != filePath) updateFilePath(downloadInfo, filePath)
|
if (downloadInfo.metadata.filePath != filePath) updateFilePath(downloadInfo, filePath)
|
||||||
|
|
||||||
setStatusText(downloadInfo, window.i18n.t('download_status_start'))
|
setStatusText(downloadInfo, window.i18n.t('download_status_start'))
|
||||||
|
|
||||||
await window.lx.worker.download.startTask(toRaw(downloadInfo), appSetting['download.savePath'], appSetting['download.skipExistFile'], proxyCallback((event: LX.Download.DownloadTaskActions) => {
|
await window.lx.worker.download.startTask(toRaw(downloadInfo), savePath, appSetting['download.skipExistFile'], proxyCallback((event: LX.Download.DownloadTaskActions) => {
|
||||||
// console.log(event)
|
// console.log(event)
|
||||||
switch (event.action) {
|
switch (event.action) {
|
||||||
case 'start':
|
case 'start':
|
||||||
|
@ -357,12 +359,11 @@ const filterTask = (list: LX.Download.ListItem[]) => {
|
||||||
* @param list 要下载的歌曲
|
* @param list 要下载的歌曲
|
||||||
* @param quality 下载音质
|
* @param quality 下载音质
|
||||||
*/
|
*/
|
||||||
export const createDownloadTasks = async(list: LX.Music.MusicInfoOnline[], quality: LX.Quality) => {
|
export const createDownloadTasks = async(list: LX.Music.MusicInfoOnline[], quality: LX.Quality, listId?: string) => {
|
||||||
if (!list.length) return
|
if (!list.length) return
|
||||||
const tasks = filterTask(await window.lx.worker.download.createDownloadTasks(list, quality,
|
const tasks = filterTask(await window.lx.worker.download.createDownloadTasks(list, quality,
|
||||||
appSetting['download.savePath'],
|
|
||||||
appSetting['download.fileName'],
|
appSetting['download.fileName'],
|
||||||
toRaw(qualityList.value)),
|
toRaw(qualityList.value), listId),
|
||||||
)
|
)
|
||||||
|
|
||||||
if (tasks.length) await addTasks(tasks)
|
if (tasks.length) await addTasks(tasks)
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { appSetting } from '@renderer/store/setting'
|
||||||
|
import { defaultList, loveList, userLists } from '@renderer/store/list/listManage'
|
||||||
|
import { filterFileName } from '@common/utils/common'
|
||||||
|
import { clipFileNameLength } from '@common/utils/tools'
|
||||||
|
import { joinPath } from '@common/utils/nodejs'
|
||||||
|
|
||||||
|
export const buildSavePath = (musicInfo: LX.Download.ListItem) => {
|
||||||
|
let savePath = appSetting['download.savePath']
|
||||||
|
if (appSetting['download.isSavePathGroupByListName']) {
|
||||||
|
let dirName: string | undefined
|
||||||
|
const listId = musicInfo.metadata.listId
|
||||||
|
switch (listId) {
|
||||||
|
case defaultList.id:
|
||||||
|
dirName = window.i18n.t(defaultList.name)
|
||||||
|
break
|
||||||
|
case loveList.id:
|
||||||
|
dirName = window.i18n.t(loveList.name)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
dirName = userLists.find(list => list.id === listId)?.name
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (dirName) dirName = filterFileName(dirName)
|
||||||
|
savePath = joinPath(savePath, clipFileNameLength(dirName ?? window.i18n.t(defaultList.name)))
|
||||||
|
}
|
||||||
|
return savePath
|
||||||
|
}
|
|
@ -94,8 +94,8 @@
|
||||||
v-model:show="isShowListAddMultiple" :from-list-id="listId"
|
v-model:show="isShowListAddMultiple" :from-list-id="listId"
|
||||||
:is-move="isMoveMultiple" :music-list="selectedList" :exclude-list-id="excludeListIds" teleport="#view" @confirm="removeAllSelect"
|
:is-move="isMoveMultiple" :music-list="selectedList" :exclude-list-id="excludeListIds" teleport="#view" @confirm="removeAllSelect"
|
||||||
/>
|
/>
|
||||||
<common-download-modal v-model:show="isShowDownload" :music-info="selectedDownloadMusicInfo" teleport="#view" />
|
<common-download-modal v-model:show="isShowDownload" :music-info="selectedDownloadMusicInfo" teleport="#view" :list-id="listId" />
|
||||||
<common-download-multiple-modal v-model:show="isShowDownloadMultiple" :list="selectedList" teleport="#view" @confirm="removeAllSelect" />
|
<common-download-multiple-modal v-model:show="isShowDownloadMultiple" :list="selectedList" teleport="#view" :list-id="listId" @confirm="removeAllSelect" />
|
||||||
<search-list :list="list" :visible="isShowSearchBar" @action="handleMusicSearchAction" />
|
<search-list :list="list" :visible="isShowSearchBar" @action="handleMusicSearchAction" />
|
||||||
<music-sort-modal v-model:show="isShowMusicSortModal" :music-info="selectedSortMusicInfo" :selected-num="selectedNum" @confirm="sortMusic" />
|
<music-sort-modal v-model:show="isShowMusicSortModal" :music-info="selectedSortMusicInfo" :selected-num="selectedNum" @confirm="sortMusic" />
|
||||||
<music-toggle-modal v-model:show="isShowMusicToggleModal" :music-info="selectedToggleMusicInfo" @toggle="toggleSource" />
|
<music-toggle-modal v-model:show="isShowMusicToggleModal" :music-info="selectedToggleMusicInfo" @toggle="toggleSource" />
|
||||||
|
|
|
@ -5,6 +5,8 @@ dd
|
||||||
base-checkbox(id="setting_download_enable" :model-value="appSetting['download.enable']" :label="$t('setting__download_enable')" @update:model-value="updateSetting({'download.enable': $event})")
|
base-checkbox(id="setting_download_enable" :model-value="appSetting['download.enable']" :label="$t('setting__download_enable')" @update:model-value="updateSetting({'download.enable': $event})")
|
||||||
.gap-top
|
.gap-top
|
||||||
base-checkbox(id="setting_download_skip_exist_file" :model-value="appSetting['download.skipExistFile']" :label="$t('setting__download_skip_exist_file')" @update:model-value="updateSetting({'download.skipExistFile': $event})")
|
base-checkbox(id="setting_download_skip_exist_file" :model-value="appSetting['download.skipExistFile']" :label="$t('setting__download_skip_exist_file')" @update:model-value="updateSetting({'download.skipExistFile': $event})")
|
||||||
|
.gap-top
|
||||||
|
base-checkbox(id="setting_download_save_group_list_name" :model-value="appSetting['download.isSavePathGroupByListName']" :label="$t('setting_download_save_group_list_name')" @update:model-value="updateSetting({'download.isSavePathGroupByListName': $event})")
|
||||||
dd(:aria-label="$t('setting__download_path_title')")
|
dd(:aria-label="$t('setting__download_path_title')")
|
||||||
h3#download_path {{ $t('setting__download_path') }}
|
h3#download_path {{ $t('setting__download_path') }}
|
||||||
div
|
div
|
||||||
|
|
|
@ -8,7 +8,7 @@ import { createDownloadInfo } from './utils'
|
||||||
// assertApiSupport,
|
// assertApiSupport,
|
||||||
// getExt,
|
// getExt,
|
||||||
// } from '..'
|
// } from '..'
|
||||||
import { checkPath, getFileStats, removeFile } from '@common/utils/nodejs'
|
import { checkAndCreateDir, checkPath, getFileStats, removeFile } from '@common/utils/nodejs'
|
||||||
import { DOWNLOAD_STATUS } from '@common/constants'
|
import { DOWNLOAD_STATUS } from '@common/constants'
|
||||||
// import { download as eventDownloadNames } from '@renderer/event/names'
|
// import { download as eventDownloadNames } from '@renderer/event/names'
|
||||||
|
|
||||||
|
@ -40,12 +40,12 @@ const sendAction = (id: string, action: LX.Download.DownloadTaskActions) => {
|
||||||
export const createDownloadTasks = (
|
export const createDownloadTasks = (
|
||||||
list: LX.Music.MusicInfoOnline[],
|
list: LX.Music.MusicInfoOnline[],
|
||||||
quality: LX.Quality,
|
quality: LX.Quality,
|
||||||
savePath: string,
|
|
||||||
fileNameFormat: string,
|
fileNameFormat: string,
|
||||||
qualityList: LX.QualityList,
|
qualityList: LX.QualityList,
|
||||||
|
listId?: string,
|
||||||
): LX.Download.ListItem[] => {
|
): LX.Download.ListItem[] => {
|
||||||
return list.map(musicInfo => {
|
return list.map(musicInfo => {
|
||||||
return createDownloadInfo(musicInfo, quality, fileNameFormat, savePath, qualityList)
|
return createDownloadInfo(musicInfo, quality, fileNameFormat, qualityList, listId)
|
||||||
}).filter(task => task)
|
}).filter(task => task)
|
||||||
// commit('addTasks', { list: taskList, addMusicLocationType: rootState.setting.list.addMusicLocationType })
|
// commit('addTasks', { list: taskList, addMusicLocationType: rootState.setting.list.addMusicLocationType })
|
||||||
// let result = getStartTask(downloadList, DOWNLOAD_STATUS, rootState.setting.download.maxDownloadNum)
|
// let result = getStartTask(downloadList, DOWNLOAD_STATUS, rootState.setting.download.maxDownloadNum)
|
||||||
|
@ -60,7 +60,7 @@ const createTask = async(downloadInfo: LX.Download.ListItem, savePath: string, s
|
||||||
// 开始任务
|
// 开始任务
|
||||||
/* commit('onStart', downloadInfo)
|
/* commit('onStart', downloadInfo)
|
||||||
commit('setStatusText', { downloadInfo, text: '任务初始化中' }) */
|
commit('setStatusText', { downloadInfo, text: '任务初始化中' }) */
|
||||||
if (!await checkPath(savePath)) {
|
if (!await checkAndCreateDir(savePath)) {
|
||||||
sendAction(downloadInfo.id, {
|
sendAction(downloadInfo.id, {
|
||||||
action: 'error',
|
action: 'error',
|
||||||
data: {
|
data: {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { DOWNLOAD_STATUS, QUALITYS } from '@common/constants'
|
import { DOWNLOAD_STATUS, QUALITYS } from '@common/constants'
|
||||||
import { filterFileName } from '@common/utils/common'
|
import { filterFileName } from '@common/utils/common'
|
||||||
import { joinPath } from '@common/utils/nodejs'
|
|
||||||
import { mergeLyrics } from './lrcTool'
|
import { mergeLyrics } from './lrcTool'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import { clipFileNameLength, clipNameLength } from '@common/utils/tools'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存歌词文件
|
* 保存歌词文件
|
||||||
|
@ -65,22 +65,8 @@ export const getMusicType = (musicInfo: LX.Music.MusicInfoOnline, type: LX.Quali
|
||||||
// const checkExistList = (list: LX.Download.ListItem[], musicInfo: LX.Music.MusicInfo, type: LX.Quality, ext: string): boolean => {
|
// const checkExistList = (list: LX.Download.ListItem[], musicInfo: LX.Music.MusicInfo, type: LX.Quality, ext: string): boolean => {
|
||||||
// return list.some(s => s.id === musicInfo.id && (s.metadata.type === type || s.metadata.ext === ext))
|
// return list.some(s => s.id === musicInfo.id && (s.metadata.type === type || s.metadata.ext === ext))
|
||||||
// }
|
// }
|
||||||
const MAX_NAME_LENGTH = 80
|
|
||||||
const MAX_FILE_NAME_LENGTH = 150
|
export const createDownloadInfo = (musicInfo: LX.Music.MusicInfoOnline, type: LX.Quality, fileName: string, qualityList: LX.QualityList, listId?: string) => {
|
||||||
const clipNameLength = (name: string) => {
|
|
||||||
if (name.length <= MAX_NAME_LENGTH || !name.includes('、')) return name
|
|
||||||
const names = name.split('、')
|
|
||||||
let newName = names.shift()!
|
|
||||||
for (const name of names) {
|
|
||||||
if (newName.length + name.length > MAX_NAME_LENGTH) break
|
|
||||||
newName = newName + '、' + name
|
|
||||||
}
|
|
||||||
return newName
|
|
||||||
}
|
|
||||||
const clipFileNameLength = (name: string) => {
|
|
||||||
return name.length > MAX_FILE_NAME_LENGTH ? name.substring(0, MAX_FILE_NAME_LENGTH) : name
|
|
||||||
}
|
|
||||||
export const createDownloadInfo = (musicInfo: LX.Music.MusicInfoOnline, type: LX.Quality, fileName: string, savePath: string, qualityList: LX.QualityList) => {
|
|
||||||
type = getMusicType(musicInfo, type, qualityList)
|
type = getMusicType(musicInfo, type, qualityList)
|
||||||
let ext = getExt(type)
|
let ext = getExt(type)
|
||||||
const key = `${musicInfo.id}_${type}_${ext}`
|
const key = `${musicInfo.id}_${type}_${ext}`
|
||||||
|
@ -101,12 +87,13 @@ export const createDownloadInfo = (musicInfo: LX.Music.MusicInfoOnline, type: LX
|
||||||
quality: type,
|
quality: type,
|
||||||
ext,
|
ext,
|
||||||
filePath: '',
|
filePath: '',
|
||||||
|
listId,
|
||||||
fileName: filterFileName(`${clipFileNameLength(fileName
|
fileName: filterFileName(`${clipFileNameLength(fileName
|
||||||
.replace('歌名', musicInfo.name)
|
.replace('歌名', musicInfo.name)
|
||||||
.replace('歌手', clipNameLength(musicInfo.singer)))}.${ext}`),
|
.replace('歌手', clipNameLength(musicInfo.singer)))}.${ext}`),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
downloadInfo.metadata.filePath = joinPath(savePath, downloadInfo.metadata.fileName)
|
// downloadInfo.metadata.filePath = joinPath(savePath, downloadInfo.metadata.fileName)
|
||||||
// commit('addTask', downloadInfo)
|
// commit('addTask', downloadInfo)
|
||||||
|
|
||||||
// 删除同路径下的同名文件
|
// 删除同路径下的同名文件
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { createLocalMusicInfo } from '@renderer/utils/music'
|
||||||
/**
|
/**
|
||||||
* 过滤列表中已播放的歌曲
|
* 过滤列表中已播放的歌曲
|
||||||
*/
|
*/
|
||||||
export const filterMusicList = async({ playedList, listId, list, savePath, playerMusicInfo, dislikeInfo, isNext }: {
|
export const filterMusicList = async({ playedList, listId, list, playerMusicInfo, dislikeInfo, isNext }: {
|
||||||
/**
|
/**
|
||||||
* 已播放列表
|
* 已播放列表
|
||||||
*/
|
*/
|
||||||
|
@ -25,7 +25,7 @@ export const filterMusicList = async({ playedList, listId, list, savePath, playe
|
||||||
/**
|
/**
|
||||||
* 下载目录
|
* 下载目录
|
||||||
*/
|
*/
|
||||||
savePath: string
|
// savePath: string
|
||||||
/**
|
/**
|
||||||
* 播放器内当前歌曲(`playInfo.playerPlayIndex`指向的歌曲)
|
* 播放器内当前歌曲(`playInfo.playerPlayIndex`指向的歌曲)
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue