Skip to content

Commit

Permalink
feat: 自动换源
Browse files Browse the repository at this point in the history
  • Loading branch information
maotoumao committed Mar 26, 2024
1 parent 5b5a8d7 commit 3991724
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 5 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "MusicFree",
"version": "0.2.1",
"version": "0.3.0",
"license": "GPL",
"private": true,
"author": {
Expand Down
2 changes: 2 additions & 0 deletions src/core/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ interface IConfig {
showExitOnNotification: boolean;
// 本地歌单添加歌曲顺序
musicOrderInLocalSheet: 'start' | 'end';
// 自动换源
tryChangeSourceWhenPlayFail: boolean;
};
/** 歌词 */
lyric: {
Expand Down
44 changes: 40 additions & 4 deletions src/core/trackPlayer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {musicIsPaused} from '@/utils/trackUtils';
import {trace} from '@/utils/log';
import PersistStatus from '../persistStatus';
import {getCurrentDialog, showDialog} from '@/components/dialogs/useDialog';
import getSimilarMusic from '@/utils/getSimilarMusic';

/** 当前播放 */
const currentMusicStore = new GlobalState<IMusic.IMusicItem | null>(null);
Expand Down Expand Up @@ -335,7 +336,7 @@ const addNext = (musicItem: IMusic.IMusicItem | IMusic.IMusicItem[]) => {
}
};

const isCurrentMusic = (musicItem: IMusic.IMusicItem) => {
const isCurrentMusic = (musicItem: IMusic.IMusicItem | null | undefined) => {
return isSameMediaItem(musicItem, currentMusicStore.getValue()) ?? false;
};

Expand Down Expand Up @@ -581,7 +582,6 @@ const play = async (
if (!isCurrentMusic(musicItem)) {
return;
}

if (!source) {
// 如果有source
if (musicItem.source) {
Expand All @@ -594,10 +594,46 @@ const play = async (
}
}
}

// 5.4 没有返回源
if (!source && !musicItem.url) {
throw new Error(PlayFailReason.INVALID_SOURCE);
// 插件失效的情况
if (Config.get('setting.basic.tryChangeSourceWhenPlayFail')) {
// 重试
const similarMusic = await getSimilarMusic(
musicItem,
'music',
() => !isCurrentMusic(musicItem),
);

if (similarMusic) {
const similarMusicPlugin =
PluginManager.getByMedia(similarMusic);

for (let quality of qualityOrder) {
if (isCurrentMusic(musicItem)) {
source =
(await similarMusicPlugin?.methods?.getMediaSource(
similarMusic,
quality,
)) ?? null;
// 5.4.1 获取到真实源
if (source) {
setQuality(quality);
break;
}
} else {
// 5.4.2 已经切换到其他歌曲了,
return;
}
}
}

if (!source) {
throw new Error(PlayFailReason.INVALID_SOURCE);
}
} else {
throw new Error(PlayFailReason.INVALID_SOURCE);
}
} else {
source = {
url: musicItem.url,
Expand Down
5 changes: 5 additions & 0 deletions src/pages/setting/settingTypes/basicSetting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,11 @@ export default function BasicSetting() {
'setting.basic.autoPlayWhenAppStart',
basicSetting?.autoPlayWhenAppStart ?? false,
),
createSwitch(
'播放失败时尝试更换音源',
'setting.basic.tryChangeSourceWhenPlayFail',
basicSetting?.tryChangeSourceWhenPlayFail ?? false,
),
createSwitch(
'播放失败时自动暂停',
'setting.basic.autoStopWhenError',
Expand Down
67 changes: 67 additions & 0 deletions src/utils/getSimilarMusic.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import PluginManager from '@/core/pluginManager';
import minDistance from './minDistance';

/**
*
* @param musicItem 音乐类型
* @param type 媒体类型
* @param abortFunction 如果函数为true,则中断
* @returns
*/
export default async function <T extends ICommon.SupportMediaType>(
musicItem: IMusic.IMusicItem,
type: T = 'music' as T,
abortFunction?: () => boolean,
): Promise<ICommon.SupportMediaItemBase[T] | null> {
const keyword = musicItem.alias || musicItem.title;
const plugins = PluginManager.getSearchablePlugins(type);

let distance = Infinity;
let minDistanceMusicItem;
let targetPlugin;

const startTime = Date.now();

for (let plugin of plugins) {
// 超时时间:10s
if (abortFunction?.() || Date.now() - startTime > 8000) {
break;
}
if (plugin.name === musicItem.platform) {
continue;
}
const results = await plugin.methods
.search(keyword, 1, type)
.catch(() => null);

// 取前两个
const firstTwo = results?.data?.slice(0, 2) || [];

for (let item of firstTwo) {
if (item.title === keyword && item.artist === musicItem.artist) {
distance = 0;
minDistanceMusicItem = item;
targetPlugin = plugin;
break;
} else {
const dist =
minDistance(keyword, musicItem.title) +
minDistance(item.artist, musicItem.artist);
if (dist < distance) {
distance = dist;
minDistanceMusicItem = item;
targetPlugin = plugin;
}
}
}

if (distance === 0) {
break;
}
}
if (minDistanceMusicItem && targetPlugin) {
return minDistanceMusicItem as ICommon.SupportMediaItemBase[T];
}

return null;
}

0 comments on commit 3991724

Please sign in to comment.