mirror of
https://github.com/ikun0014/lx-music-mobile.git
synced 2025-05-23 22:37:41 +08:00
将 LX Music 设置为“音乐应用”分类,添加在程序外使用LX Music打开歌曲文件、js
、json
、lxmc
文件的支持
This commit is contained in:
parent
d1348b2aba
commit
80e39555ca
@ -31,12 +31,64 @@
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
<intent-filter android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="lxmusic" android:host="*" />
|
||||
</intent-filter>
|
||||
<intent-filter android:priority="80">
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.OPENABLE"/>
|
||||
|
||||
<data android:scheme="file"/>
|
||||
<data android:scheme="content" />
|
||||
<data android:mimeType="audio/*" />
|
||||
<data android:mimeType="vnd.android.cursor.dir/audio"/>
|
||||
<data android:mimeType="application/ogg"/>
|
||||
<data android:mimeType="application/x-ogg"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.APP_MUSIC" />
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="com.cyanogenmod.eleven.AUDIO_PLAYER"/>
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
|
||||
<intent-filter android:priority="80">
|
||||
<!-- <action android:name="android.intent.action.PICK"/> -->
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
<category android:name="android.intent.category.OPENABLE"/>
|
||||
|
||||
<data android:scheme="file"/>
|
||||
<data android:scheme="content" />
|
||||
<data android:host="*"/>
|
||||
<data android:mimeType="application/octet-stream"/>
|
||||
|
||||
<data android:mimeType="text/javascript"/>
|
||||
<data android:mimeType="application/x-javascript"/>
|
||||
<data android:mimeType="application/javascript"/>
|
||||
<!-- https://stackoverflow.com/a/66402243 -->
|
||||
<data android:pathPattern=".*\\.js" />
|
||||
<data android:pathPattern=".*\\..*\\.js" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.js" />
|
||||
<data android:pathSuffix=".js" tools:targetApi="s" />
|
||||
|
||||
<data android:mimeType="application/json"/>
|
||||
<data android:pathPattern=".*\\.json" />
|
||||
<data android:pathPattern=".*\\..*\\.json" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.json" />
|
||||
<data android:pathSuffix=".json" tools:targetApi="s" />
|
||||
|
||||
<data android:pathPattern=".*\\.lxmc" />
|
||||
<data android:pathPattern=".*\\..*\\.lxmc" />
|
||||
<data android:pathPattern=".*\\..*\\..*\\.lxmc" />
|
||||
<data android:pathSuffix=".lxmc" tools:targetApi="s" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Define a FileProvider for API24+ -->
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
- 新增蓝牙歌词支持,可以通过「设置 → 播放设置 → 显示蓝牙歌词」启用(#615)
|
||||
- 新增繁体中文语言(#659, @3gf8jv4dv)
|
||||
- 将 LX Music 设置为“音乐应用”分类,允许将 LX Music 设置为系统默认音乐播放器
|
||||
- 添加在程序外使用LX Music打开歌曲文件、`js`、`json`、`lxmc`文件的支持
|
||||
|
||||
### 优化
|
||||
|
||||
|
36
src/core/init/deeplink/fileAction.ts
Normal file
36
src/core/init/deeplink/fileAction.ts
Normal file
@ -0,0 +1,36 @@
|
||||
import { readMetadata } from '@/utils/localMediaMetadata'
|
||||
import { handleImportList } from '@/screens/Home/Views/Setting/settings/Backup/actions'
|
||||
import { handleImportLocalFile } from '@/screens/Home/Views/Setting/settings/Basic/UserApiEditModal/action'
|
||||
import { type FileType } from '@/utils/fs'
|
||||
import { confirmDialog } from '@/utils/tools'
|
||||
import playerState from '@/store/player/state'
|
||||
import { addTempPlayList } from '@/core/player/tempPlayList'
|
||||
import { LIST_IDS } from '@/config/constant'
|
||||
import { playNext } from '@/core/player/player'
|
||||
import { buildLocalMusicInfo, buildLocalMusicInfoByFilePath } from '@/screens/Home/Views/Mylist/MyList/listAction'
|
||||
|
||||
|
||||
export const handleFileLXMCAction = async(file: FileType) => {
|
||||
if (!(await confirmDialog({
|
||||
message: global.i18n.t('deep_link_file_lxmc_confirm_tip', { name: file.name }),
|
||||
}))) return
|
||||
|
||||
handleImportList(file.path)
|
||||
}
|
||||
|
||||
export const handleFileMusicAction = async(file: FileType) => {
|
||||
const info = await readMetadata(file.path)
|
||||
const isPlaying = !!playerState.playMusicInfo.musicInfo
|
||||
const musicInfo = info ? buildLocalMusicInfo(file.path, info) : buildLocalMusicInfoByFilePath(file)
|
||||
console.log(musicInfo)
|
||||
addTempPlayList([{ listId: LIST_IDS.PLAY_LATER, musicInfo, isTop: true }])
|
||||
if (isPlaying) void playNext()
|
||||
}
|
||||
|
||||
export const handleFileJSAction = async(file: FileType) => {
|
||||
if (!(await confirmDialog({
|
||||
message: global.i18n.t('deep_link_file_js_confirm_tip', { name: file.name }),
|
||||
}))) return
|
||||
|
||||
handleImportLocalFile(file.path)
|
||||
}
|
@ -3,6 +3,8 @@ import { errorDialog } from './utils'
|
||||
import { handleMusicAction } from './musicAction'
|
||||
import { handlePlayerAction, type PlayerAction } from './playerAction'
|
||||
import { handleSonglistAction } from './songlistAction'
|
||||
import { extname, stat } from '@/utils/fs'
|
||||
import { handleFileMusicAction, handleFileJSAction, handleFileLXMCAction } from './fileAction'
|
||||
|
||||
|
||||
const handleLinkAction = async(link: string) => {
|
||||
@ -38,16 +40,61 @@ const handleLinkAction = async(link: string) => {
|
||||
// default: throw new Error('Unknown type: ' + type)
|
||||
}
|
||||
}
|
||||
const runLinkAction = async(link: string) => {
|
||||
if (!link.startsWith('lxmusic://')) return
|
||||
try {
|
||||
await handleLinkAction(link)
|
||||
} catch (err: any) {
|
||||
errorDialog(err.message)
|
||||
// focusWindow()
|
||||
|
||||
const handleFileAction = async(link: string) => {
|
||||
const file = await stat(link)
|
||||
// console.log(file)
|
||||
switch (extname(file.name)) {
|
||||
case 'json':
|
||||
case 'lxmc':
|
||||
await handleFileLXMCAction(file)
|
||||
break
|
||||
case 'js':
|
||||
await handleFileJSAction(file)
|
||||
break
|
||||
case 'ogg':
|
||||
case 'flac':
|
||||
case 'wav':
|
||||
case 'mp3':
|
||||
await handleFileMusicAction(file)
|
||||
break
|
||||
default:
|
||||
if (!file.mimeType?.startsWith('audio/')) throw new Error('Unknown file type')
|
||||
await handleFileMusicAction(file)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// const handleHttpAction = async(link: string) => {
|
||||
// }
|
||||
|
||||
|
||||
const runLinkAction = async(link: string) => {
|
||||
if (link.startsWith('lxmusic://')) {
|
||||
try {
|
||||
await handleLinkAction(link)
|
||||
} catch (err: any) {
|
||||
errorDialog(err.message)
|
||||
// focusWindow()
|
||||
}
|
||||
} else if (link.startsWith('file://') || link.startsWith('content://')) {
|
||||
try {
|
||||
await handleFileAction(link)
|
||||
} catch (err: any) {
|
||||
errorDialog(err.message)
|
||||
// focusWindow()
|
||||
}
|
||||
}
|
||||
// else if (/^https?:\/\//.test(link)) {
|
||||
// try {
|
||||
// await handleHttpAction(link)
|
||||
// } catch (err: any) {
|
||||
// errorDialog(err.message)
|
||||
// // focusWindow()
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
export const initDeeplink = async() => {
|
||||
Linking.addEventListener('url', ({ url }) => {
|
||||
void runLinkAction(url)
|
||||
|
@ -37,6 +37,8 @@
|
||||
"date_format_minute": "{num} minutes ago",
|
||||
"date_format_second": "{num} seconds ago",
|
||||
"deep_link__handle_error_tip": "Call failed: {message}",
|
||||
"deep_link_file_js_confirm_tip": "Are you sure you want to import this ({name}) custom source file?",
|
||||
"deep_link_file_lxmc_confirm_tip": "Are you sure you want to import this ({name}) list file?",
|
||||
"delete": "Remove",
|
||||
"dialog_cancel": "No",
|
||||
"dialog_confirm": "OK",
|
||||
@ -49,8 +51,6 @@
|
||||
"ignoring_battery_optimization_check_tip": "LX Music is \"Restricted\" or \"Optimized\" in \"App battery usage\", which may cause LX Music to be prevented by the system when playing music in the background. Do you need to set LX Music to \"Unrestricted\"?",
|
||||
"ignoring_battery_optimization_check_title": "Background Running Permission Reminder",
|
||||
"input_error": "Don't type indiscriminately 😡",
|
||||
"list_name_default": "Default",
|
||||
"list_name_love": "Loved",
|
||||
"list_add_btn_title": "Add the song(s) to \"{name}\"",
|
||||
"list_add_tip_exists": "This song already exists in the list, don't click me again~😡",
|
||||
"list_add_title_first_add": "Add",
|
||||
@ -84,6 +84,9 @@
|
||||
"list_multi_add_title_first_add": "Add the selected",
|
||||
"list_multi_add_title_first_move": "Move the selected",
|
||||
"list_multi_add_title_last": "songs to ...",
|
||||
"list_name_default": "Default",
|
||||
"list_name_love": "Loved",
|
||||
"list_name_temp": "Temp List",
|
||||
"list_remove": "Remove",
|
||||
"list_remove_music_multi_tip": "Do you really want to remove the selected {num} songs?",
|
||||
"list_remove_tip": "Do you really want to remove \"{name}\"?",
|
||||
@ -96,7 +99,6 @@
|
||||
"list_select_local_file_desc": "Choose local song folder",
|
||||
"list_select_local_file_empty_tip": "No songs found in current folder",
|
||||
"list_select_local_file_result_failed_tip": "Found {total} song(s), successfully added {success} song(s), failed to add {failed} song(s). View the error log for details.",
|
||||
|
||||
"list_select_local_file_result_tip": "Found {Total} song(s), all added!",
|
||||
"list_select_local_file_temp_add_tip": "Found {total} matching files, quickly added to the current list, will now start the file metadata reading process. Please do not exit the app!",
|
||||
"list_select_range": "Range",
|
||||
@ -115,7 +117,6 @@
|
||||
"list_sort_modal_by_up": "Ascending",
|
||||
"list_sync": "Update",
|
||||
"list_sync_confirm_tip": "This will replace the songs in \"{name}\" with the songs in the online list, are you sure you want to update?",
|
||||
"list_name_temp": "Temp List",
|
||||
"list_update_error": "Failed to update \"{name}\"",
|
||||
"list_update_success": "Successfully updated \"{name}\"",
|
||||
"list_updating": "Updating",
|
||||
@ -303,11 +304,11 @@
|
||||
"setting_list_click_action": "Automatically switch to current list when clicking a song in the list (Only valid for \"Playlists\" and \"Charts\" page)",
|
||||
"setting_list_show interval": "Show song length",
|
||||
"setting_list_show_album_name": "Show song album name",
|
||||
"setting_lyric_desktop_permission_tip": "To use this feature, you need to grant LX Music the permission to display hover windows in the system permission settings.\n\nDo you go to the relevant page to grant this permission?",
|
||||
"setting_lyric_desktop": "Desktop Lyric",
|
||||
"setting_lyric_desktop_enable": "Show lyric window",
|
||||
"setting_lyric_desktop_lock": "Lock lyric window",
|
||||
"setting_lyric_desktop_maxlineNum": "Maximum Number of Lines",
|
||||
"setting_lyric_desktop_permission_tip": "To use this feature, you need to grant LX Music the permission to display hover windows in the system permission settings.\n\nDo you go to the relevant page to grant this permission?",
|
||||
"setting_lyric_desktop_single_line": "Do not wrap lyrics",
|
||||
"setting_lyric_desktop_text_opacity": "Lyric Font Transparency",
|
||||
"setting_lyric_desktop_text_size": "Lyric Font Size",
|
||||
|
@ -37,6 +37,8 @@
|
||||
"date_format_minute": "{num} 分钟前",
|
||||
"date_format_second": "{num} 秒前",
|
||||
"deep_link__handle_error_tip": "调用失败:{message}",
|
||||
"deep_link_file_js_confirm_tip": "确认要导入这个({name})自定义源文件吗?",
|
||||
"deep_link_file_lxmc_confirm_tip": "确认要导入这个({name})列表文件吗?",
|
||||
"delete": "移除",
|
||||
"dialog_cancel": "我不",
|
||||
"dialog_confirm": "好的",
|
||||
@ -49,8 +51,6 @@
|
||||
"ignoring_battery_optimization_check_tip": "LX Music 没有在「忽略电池优化」的白名单中,这可能会导致在后台播放音乐时被系统暂停。是否将 LX Music 加入该白名单中?",
|
||||
"ignoring_battery_optimization_check_title": "后台运行权限设置提醒",
|
||||
"input_error": "不要乱输好吧😡",
|
||||
"list_name_default": "试听列表",
|
||||
"list_name_love": "我的收藏",
|
||||
"list_add_btn_title": "把该歌曲添加到「{name}」",
|
||||
"list_add_tip_exists": "列表已经存在这首歌啦,不要再点我啦~😡",
|
||||
"list_add_title_first_add": "添加",
|
||||
@ -84,6 +84,9 @@
|
||||
"list_multi_add_title_first_add": "添加已选的",
|
||||
"list_multi_add_title_first_move": "移动已选的",
|
||||
"list_multi_add_title_last": "首歌曲到...",
|
||||
"list_name_default": "试听列表",
|
||||
"list_name_love": "我的收藏",
|
||||
"list_name_temp": "临时列表",
|
||||
"list_remove": "移除",
|
||||
"list_remove_music_multi_tip": "你真的想要移除所选的 {num} 首歌曲吗?",
|
||||
"list_remove_tip": "你真的想要移除「{name}」吗?",
|
||||
@ -114,7 +117,6 @@
|
||||
"list_sort_modal_by_up": "升序",
|
||||
"list_sync": "更新",
|
||||
"list_sync_confirm_tip": "这将会把「{name}」内的歌曲替换成在线列表的歌曲,你确认要更新吗?",
|
||||
"list_name_temp": "临时列表",
|
||||
"list_update_error": "「{name}」更新失败",
|
||||
"list_update_success": "「{name}」更新成功",
|
||||
"list_updating": "更新中",
|
||||
@ -302,11 +304,11 @@
|
||||
"setting_list_click_action": "点击列表里的歌曲时自动切换到当前列表播放(仅对歌单、排行榜有效)",
|
||||
"setting_list_show interval": "显示歌曲时长",
|
||||
"setting_list_show_album_name": "显示歌曲专辑名",
|
||||
"setting_lyric_desktop_permission_tip": "桌面歌词功能需要在系统权限设置中授予 LX Music 显示悬浮窗口的权限才能使用,是否去相关界面授予该权限?",
|
||||
"setting_lyric_desktop": "桌面歌词",
|
||||
"setting_lyric_desktop_enable": "显示歌词",
|
||||
"setting_lyric_desktop_lock": "锁定歌词",
|
||||
"setting_lyric_desktop_maxlineNum": "最大行数",
|
||||
"setting_lyric_desktop_permission_tip": "桌面歌词功能需要在系统权限设置中授予 LX Music 显示悬浮窗口的权限才能使用,是否去相关界面授予该权限?",
|
||||
"setting_lyric_desktop_single_line": "使用单行歌词",
|
||||
"setting_lyric_desktop_text_opacity": "歌词字体透明度",
|
||||
"setting_lyric_desktop_text_size": "歌词字体大小",
|
||||
|
@ -37,6 +37,8 @@
|
||||
"date_format_minute": "{num} 分鐘前",
|
||||
"date_format_second": "{num} 秒前",
|
||||
"deep_link__handle_error_tip": "呼叫失敗:{message}",
|
||||
"deep_link_file_js_confirm_tip": "確認要匯入這個({name})自訂原始檔嗎?",
|
||||
"deep_link_file_lxmc_confirm_tip": "確認要匯入這個({name})清單檔案嗎?",
|
||||
"delete": "移除",
|
||||
"dialog_cancel": "我不",
|
||||
"dialog_confirm": "好的",
|
||||
|
@ -92,7 +92,7 @@ export const handleSync = (listInfo: LX.List.UserListInfo) => {
|
||||
})
|
||||
}
|
||||
|
||||
const buildLocalMusicInfoByFilePath = (file: FileType): LX.Music.MusicInfoLocal => {
|
||||
export const buildLocalMusicInfoByFilePath = (file: FileType): LX.Music.MusicInfoLocal => {
|
||||
const index = file.name.lastIndexOf('.')
|
||||
return {
|
||||
id: file.path,
|
||||
@ -109,7 +109,7 @@ const buildLocalMusicInfoByFilePath = (file: FileType): LX.Music.MusicInfoLocal
|
||||
},
|
||||
}
|
||||
}
|
||||
const buildLocalMusicInfo = (filePath: string, metadata: MusicMetadataFull): LX.Music.MusicInfoLocal => {
|
||||
export const buildLocalMusicInfo = (filePath: string, metadata: MusicMetadataFull): LX.Music.MusicInfoLocal => {
|
||||
return {
|
||||
id: filePath,
|
||||
name: metadata.name,
|
||||
|
@ -81,7 +81,7 @@ export default {
|
||||
global.state_event.playPlayedListChanged({ ...state.playedList })
|
||||
},
|
||||
addTempPlayList(list: LX.Player.TempPlayListItem[]) {
|
||||
const topList: Array<{ listId: string, musicInfo: LX.Music.MusicInfo | LX.Download.ListItem }> = []
|
||||
const topList: Array<{ listId: string | null, musicInfo: LX.Music.MusicInfo | LX.Download.ListItem }> = []
|
||||
const bottomList = list.filter(({ isTop, ...musicInfo }) => {
|
||||
if (isTop) {
|
||||
topList.push(musicInfo)
|
||||
|
2
src/types/player.d.ts
vendored
2
src/types/player.d.ts
vendored
@ -57,7 +57,7 @@ declare global {
|
||||
/**
|
||||
* 播放列表id
|
||||
*/
|
||||
listId: string
|
||||
listId: string | null
|
||||
/**
|
||||
* 歌曲信息
|
||||
*/
|
||||
|
@ -15,6 +15,8 @@ export type {
|
||||
|
||||
// export const externalDirectoryPath = RNFS.ExternalDirectoryPath
|
||||
|
||||
export const extname = (name: string) => name.lastIndexOf('.') > 0 ? name.substring(name.lastIndexOf('.') + 1) : ''
|
||||
|
||||
export const temporaryDirectoryPath = Dirs.CacheDir
|
||||
export const externalStorageDirectoryPath = Dirs.SDCardDir
|
||||
export const privateStorageDirectoryPath = Dirs.DocumentDir
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { temporaryDirectoryPath, readDir, unlink } from '@/utils/fs'
|
||||
import { temporaryDirectoryPath, readDir, unlink, extname } from '@/utils/fs'
|
||||
import { readPic as _readPic } from 'react-native-local-media-metadata'
|
||||
export {
|
||||
type MusicMetadata,
|
||||
@ -15,7 +15,11 @@ const picCachePath = temporaryDirectoryPath + '/local-media-metadata'
|
||||
|
||||
export const scanAudioFiles = async(dirPath: string) => {
|
||||
const files = await readDir(dirPath)
|
||||
return files.filter(file => file.mimeType?.startsWith('audio/')).map(file => file)
|
||||
return files.filter(file => {
|
||||
if (file.mimeType?.startsWith('audio/')) return true
|
||||
if (extname(file?.name ?? '') === 'ogg') return true
|
||||
return false
|
||||
}).map(file => file)
|
||||
}
|
||||
|
||||
const clearPicCache = async() => {
|
||||
|
@ -2,5 +2,7 @@ import { existsFile } from './fs'
|
||||
|
||||
|
||||
export const getLocalFilePath = async(musicInfo: LX.Music.MusicInfoLocal): Promise<string> => {
|
||||
return (await existsFile(musicInfo.meta.filePath)) ? musicInfo.meta.filePath : ''
|
||||
if (await existsFile(musicInfo.meta.filePath)) return musicInfo.meta.filePath
|
||||
// 直接从应用外 intent 调用打开的文件,ogg等类型无法判断文件是否存在,但这类文件路径为纯数字
|
||||
return /\/\d+$/.test(musicInfo.meta.filePath) ? musicInfo.meta.filePath : ''
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user