mirror of
https://github.com/jeffvli/feishin.git
synced 2026-05-08 04:50:12 +02:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| adfdf04240 | |||
| faa7281993 | |||
| 2d0f4e7881 | |||
| ce9183ffd6 | |||
| 3a5508653b | |||
| 7e4e28037c | |||
| d2d8ea8249 | |||
| ba835bec3e | |||
| 9850874dfd | |||
| 51a8285ba2 | |||
| e12150d026 | |||
| 54bc241984 | |||
| a698f83c45 |
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "feishin",
|
||||
"version": "1.4.0",
|
||||
"version": "1.4.2",
|
||||
"description": "A modern self-hosted music player.",
|
||||
"keywords": [
|
||||
"subsonic",
|
||||
@@ -30,7 +30,7 @@
|
||||
"dev:watch": "electron-vite dev --watch",
|
||||
"i18next": "i18next -c src/i18n/i18next-parser.config.js",
|
||||
"postinstall": "electron-builder install-app-deps",
|
||||
"lint": "pnpm run lint-code && pnpm run lint-styles",
|
||||
"lint": "pnpm run typecheck && pnpm run lint-code && pnpm run lint-styles",
|
||||
"lint-code": "eslint --max-warnings=0 --cache .",
|
||||
"lint-code:fix": "eslint --cache --fix .",
|
||||
"lint-styles": "stylelint --max-warnings=0 'src/**/*.{css,scss}'",
|
||||
|
||||
@@ -162,7 +162,8 @@
|
||||
"mood": "nastrój",
|
||||
"example": "przykład",
|
||||
"filter_multiple": "multi",
|
||||
"filter_single": "single"
|
||||
"filter_single": "single",
|
||||
"rename": "zmień nazwę"
|
||||
},
|
||||
"entity": {
|
||||
"genre_one": "gatunek",
|
||||
@@ -512,7 +513,8 @@
|
||||
"shared": "udostępniono $t(entity.playlist, {\"count\": 2})",
|
||||
"myLibrary": "Moja biblioteka",
|
||||
"favorites": "$t(entity.favorite, {\"count\": 2})",
|
||||
"radio": "$t(entity.radioStation, {\"count\": 2})"
|
||||
"radio": "$t(entity.radioStation, {\"count\": 2})",
|
||||
"collections": "kolekcje"
|
||||
},
|
||||
"home": {
|
||||
"mostPlayed": "najczęściej odtwarzane",
|
||||
@@ -601,6 +603,14 @@
|
||||
},
|
||||
"radioList": {
|
||||
"title": "stacje radiowe"
|
||||
},
|
||||
"windowBar": {
|
||||
"paused": "(Wstrzymane) ",
|
||||
"privateMode": "(Tryb prywatny)"
|
||||
},
|
||||
"collections": {
|
||||
"overrideExisting": "nadpisz istniejące",
|
||||
"saveAsCollection": "zapisz jako kolekcję"
|
||||
}
|
||||
},
|
||||
"player": {
|
||||
@@ -984,7 +994,10 @@
|
||||
"enableGridMultiSelect_description": "gdy włączone, pozwala na wybieranie wielu elementów w widokach siatki, gdy wyłączone, klikanie obrazów elementów siatki będzie przenosić na stronę elementu",
|
||||
"enableGridMultiSelect": "wybieranie wielu w siatce",
|
||||
"sidebarPlaylistSorting_description": "pozwala na ręczne sortowanie playlist w bocznym pasku używając przeciągania i upuszczania zamiast używania domyślnej kolejności serwera",
|
||||
"sidebarPlaylistSorting": "sortowanie playlist w bocznym pasku"
|
||||
"sidebarPlaylistSorting": "sortowanie playlist w bocznym pasku",
|
||||
"sidebarPlaylistListFilterRegex_description": "ukryj playlisty w pasku bocznym pasujące do wyrażenia regularnego",
|
||||
"sidebarPlaylistListFilterRegex_placeholder": "np. ^Miks codzienny.^",
|
||||
"sidebarPlaylistListFilterRegex": "filtr playlist regex"
|
||||
},
|
||||
"table": {
|
||||
"config": {
|
||||
|
||||
+182
-28
@@ -150,7 +150,12 @@
|
||||
"tableColumns": "表格列",
|
||||
"itemsMore": "{{count}} 更多",
|
||||
"countSelected": "已选择{{count}}项",
|
||||
"retry": "重试"
|
||||
"retry": "重试",
|
||||
"example": "示例",
|
||||
"filter_single": "单项",
|
||||
"mood": "氛围",
|
||||
"rename": "重命名",
|
||||
"filter_multiple": "多项"
|
||||
},
|
||||
"entity": {
|
||||
"albumArtist_other": "专辑艺术家",
|
||||
@@ -170,7 +175,9 @@
|
||||
"genreWithCount_other": "{{count}} 种流派",
|
||||
"trackWithCount_other": "{{count}} 首曲目",
|
||||
"play_other": "{{count}} 次播放",
|
||||
"song_other": "歌曲"
|
||||
"song_other": "歌曲",
|
||||
"radioStation_other": "广播电台",
|
||||
"radioStationWithCount_other": "{{count}} 个广播电台"
|
||||
},
|
||||
"player": {
|
||||
"repeat_all": "循环全部",
|
||||
@@ -187,7 +194,7 @@
|
||||
"shuffle": "播放(随机)",
|
||||
"playbackFetchNoResults": "未找到歌曲",
|
||||
"playbackFetchInProgress": "正在加载歌曲…",
|
||||
"addNext": "下一首播放",
|
||||
"addNext": "下一个",
|
||||
"playbackFetchCancel": "请稍等…关闭通知以取消操作",
|
||||
"play": "播放",
|
||||
"repeat_off": "循环关闭",
|
||||
@@ -197,7 +204,7 @@
|
||||
"queue_moveToTop": "将所选项移至底部",
|
||||
"queue_moveToBottom": "将所选项移至顶部",
|
||||
"shuffle_off": "禁用随机播放",
|
||||
"addLast": "上一曲",
|
||||
"addLast": "最后",
|
||||
"mute": "静音",
|
||||
"skip_forward": "向前跳过",
|
||||
"playbackSpeed": "播放速度",
|
||||
@@ -206,7 +213,12 @@
|
||||
"viewQueue": "查看播放队列",
|
||||
"saveQueueToServer": "将播放队列保存到服务器",
|
||||
"restoreQueueFromServer": "从服务器恢复播放队列",
|
||||
"lyrics": "歌词"
|
||||
"lyrics": "歌词",
|
||||
"addLastShuffled": "最后(随机)",
|
||||
"addNextShuffled": "下一个(随机)",
|
||||
"artistRadio": "艺术家电台",
|
||||
"holdToShuffle": "按住即可随机",
|
||||
"trackRadio": "追踪广播"
|
||||
},
|
||||
"setting": {
|
||||
"crossfadeStyle_description": "选择用于音频播放器的淡入淡出风格",
|
||||
@@ -333,7 +345,7 @@
|
||||
"useSystemTheme_description": "使用系统定义的浅色或深色主题",
|
||||
"playButtonBehavior_optionAddNext": "$t(player.addNext)",
|
||||
"lyricFetch_description": "从多个互联网源获取歌词",
|
||||
"lyricFetchProvider_description": "选择歌词源。 歌词源顺序与查询顺序一致",
|
||||
"lyricFetchProvider_description": "选择要从中获取歌词的提供商",
|
||||
"sidePlayQueueStyle_optionDetached": "不吸附",
|
||||
"hotkey_zoomOut": "缩小",
|
||||
"hotkey_unfavoriteCurrentSong": "取消收藏$t(common.currentSong)",
|
||||
@@ -454,7 +466,7 @@
|
||||
"releaseChannel": "发布通道",
|
||||
"releaseChannel_description": "选择稳定版本或测试版以进行自动更新",
|
||||
"mediaSession": "启用媒体会话",
|
||||
"mediaSession_description": "启用 Windows 媒体会话集成,在系统音量覆盖和锁定屏幕中显示媒体控件和元数据(仅限 Windows)",
|
||||
"mediaSession_description": "启用媒体会话集成,在系统音量叠加层和锁屏界面显示媒体控件和元数据",
|
||||
"exportImportSettings_control_description": "通过 JSON 导出和导入设置",
|
||||
"exportImportSettings_control_exportText": "导出设置",
|
||||
"exportImportSettings_control_importText": "导入设置",
|
||||
@@ -515,7 +527,43 @@
|
||||
"playerbarWaveformAlign": "波形对齐方式",
|
||||
"playerbarWaveformBarWidth": "波形宽度",
|
||||
"playerbarWaveformGap": "波形间距",
|
||||
"transcode": "启用转码功能"
|
||||
"transcode": "启用转码功能",
|
||||
"useThemeAccentColor_description": "使用所选主题中定义的主色,而不是自定义强调色",
|
||||
"homeFeatureStyle_optionSingle": "单项",
|
||||
"autoDJ": "自动DJ",
|
||||
"autoDJ_itemCount": "项目数量",
|
||||
"autoDJ_itemCount_description": "启用自动 DJ 功能后,尝试添加到队列中的项目数",
|
||||
"autoDJ_timing": "定时",
|
||||
"autoDJ_timing_description": "自动 DJ 触发前队列中剩余的歌曲数量",
|
||||
"crossfadeStyle": "交叉渐变风格",
|
||||
"discordRichPresence": "{{discord}} rich presence",
|
||||
"homeFeatureStyle_description": "控制首页特色轮播图的样式",
|
||||
"homeFeatureStyle": "首页特色旋转样式",
|
||||
"homeFeatureStyle_optionMultiple": "多样",
|
||||
"hotkey_listNavigateToPage": "列表导航至项目页面",
|
||||
"hotkey_listPlayDefault": "播放列表",
|
||||
"hotkey_listPlayLast": "播放列表最后",
|
||||
"hotkey_listPlayNext": "播放列表下一个",
|
||||
"hotkey_listPlayNow": "播放列表现在",
|
||||
"pathReplace": "文件路径替换",
|
||||
"pathReplace_description": "替换服务器的默认文件路径",
|
||||
"pathReplace_optionRemovePrefix": "移除前缀",
|
||||
"pathReplace_optionAddPrefix": "添加前缀",
|
||||
"playerFilters": "从队列中筛选歌曲",
|
||||
"playerFilters_description": "根据以下条件,忽略添加到队列中的歌曲",
|
||||
"artistRadioCount_description": "设置艺术家电台和曲目电台要获取的歌曲数量",
|
||||
"artistRadioCount": "艺术家/曲目电台数量",
|
||||
"imageResolution_optionItemCard": "项目卡",
|
||||
"playerbarWaveformRadius": "波形半径",
|
||||
"enableGridMultiSelect": "启用网格多选",
|
||||
"enableGridMultiSelect_description": "启用后,允许在网格视图中选择多个项目。禁用后,点击网格项目图像将跳转到项目页面",
|
||||
"sidebarPlaylistSorting_description": "允许在侧边栏中使用拖放操作手动对播放列表进行排序,而不是使用默认的服务器顺序",
|
||||
"sidebarPlaylistSorting": "侧边栏播放列表排序",
|
||||
"sidebarPlaylistListFilterRegex_description": "隐藏侧边栏中与此正则表达式匹配的播放列表",
|
||||
"sidebarPlaylistListFilterRegex_placeholder": "例如:^每日精选*",
|
||||
"sidebarPlaylistListFilterRegex": "播放列表筛选正则表达式",
|
||||
"queryBuilder": "查询构建器",
|
||||
"queryBuilderCustomFields": "自定义字段"
|
||||
},
|
||||
"error": {
|
||||
"remotePortWarning": "重启服务器使新端口生效",
|
||||
@@ -568,7 +616,7 @@
|
||||
"biography": "个人简介",
|
||||
"songCount": "歌曲数量",
|
||||
"random": "随机",
|
||||
"lastPlayed": "上次播放过",
|
||||
"lastPlayed": "最后播放",
|
||||
"toYear": "截止年份",
|
||||
"fromYear": "起始年份",
|
||||
"criticRating": "评论家评分",
|
||||
@@ -582,7 +630,7 @@
|
||||
"recentlyUpdated": "最近更新",
|
||||
"isRated": "已评分",
|
||||
"isRecentlyPlayed": "最近播放过",
|
||||
"channels": "$t(common.channel_other)",
|
||||
"channels": "$t(common.channel, {\"count\": 2})",
|
||||
"owner": "$t(common.owner)",
|
||||
"genre": "$t(entity.genre, {\"count\": 1})",
|
||||
"note": "注释",
|
||||
@@ -591,7 +639,8 @@
|
||||
"disc": "碟片",
|
||||
"duration": "时长",
|
||||
"album": "$t(entity.album, {\"count\": 1})",
|
||||
"explicitStatus": "$t(common.explicitStatus)"
|
||||
"explicitStatus": "$t(common.explicitStatus)",
|
||||
"sortName": "排序名称"
|
||||
},
|
||||
"page": {
|
||||
"sidebar": {
|
||||
@@ -609,7 +658,8 @@
|
||||
"shared": "共享$t(entity.playlist, {\"count\": 2})",
|
||||
"myLibrary": "我的媒体库",
|
||||
"favorites": "$t(entity.favorite, {\"count\": 2})",
|
||||
"radio": "$t(entity.radioStation, {\"count\": 2})"
|
||||
"radio": "$t(entity.radioStation, {\"count\": 2})",
|
||||
"collections": "合集"
|
||||
},
|
||||
"fullscreenPlayer": {
|
||||
"config": {
|
||||
@@ -649,7 +699,8 @@
|
||||
"privateModeOn": "开启私人模式",
|
||||
"multipleMusicFolders": "已选择{{count}}个媒体库",
|
||||
"noMusicFolder": "未选择任何音乐库",
|
||||
"selectMusicFolder": "选择媒体库"
|
||||
"selectMusicFolder": "选择媒体库",
|
||||
"commandPalette": "打开命令面板"
|
||||
},
|
||||
"home": {
|
||||
"mostPlayed": "最多播放",
|
||||
@@ -687,7 +738,8 @@
|
||||
"discord": "Discord",
|
||||
"logger": "日志记录器",
|
||||
"queryBuilder": "查询构建器",
|
||||
"lyricsDisplay": "歌词显示"
|
||||
"lyricsDisplay": "歌词显示",
|
||||
"playerFilters": "播放筛选器"
|
||||
},
|
||||
"globalSearch": {
|
||||
"commands": {
|
||||
@@ -756,7 +808,8 @@
|
||||
"about": "关于{{artist}}",
|
||||
"appearsOn": "出现在",
|
||||
"viewAll": "查看全部",
|
||||
"groupingTypeAll": "所有发行类型"
|
||||
"groupingTypeAll": "所有发行类型",
|
||||
"groupingTypePrimary": "首选发布类型"
|
||||
},
|
||||
"itemDetail": {
|
||||
"copyPath": "将路径复制到剪贴板",
|
||||
@@ -779,6 +832,17 @@
|
||||
},
|
||||
"folderList": {
|
||||
"title": "$t(entity.folder, {\"count\": 2})"
|
||||
},
|
||||
"radioList": {
|
||||
"title": "广播电台"
|
||||
},
|
||||
"windowBar": {
|
||||
"paused": "(暂停) ",
|
||||
"privateMode": "(私人模式)"
|
||||
},
|
||||
"collections": {
|
||||
"overrideExisting": "覆盖现有",
|
||||
"saveAsCollection": "保存为集合"
|
||||
}
|
||||
},
|
||||
"form": {
|
||||
@@ -801,9 +865,9 @@
|
||||
"input_url": "url",
|
||||
"input_preferInstantMixDescription": "仅使用即时混音来获取类似的歌曲。如果您有修改此行为的插件,则很有用",
|
||||
"input_preferInstantMix": "首选即时混音",
|
||||
"input_preferRemoteUrl": "首选公共 URL",
|
||||
"input_remoteUrl": "公共 URL",
|
||||
"input_remoteUrlPlaceholder": "可选:对外功能的公共 URL"
|
||||
"input_preferRemoteUrl": "首选公共 url",
|
||||
"input_remoteUrl": "公共 url",
|
||||
"input_remoteUrlPlaceholder": "可选:对外功能的公共 url"
|
||||
},
|
||||
"addToPlaylist": {
|
||||
"success": "添加$t(entity.trackWithCount, {\"count\": {{message}} })到$t(entity.playlistWithCount, {\"count\": {{numOfPlaylists}} })",
|
||||
@@ -865,7 +929,9 @@
|
||||
"createRadioStation": {
|
||||
"input_homepageUrl": "首页地址",
|
||||
"input_name": "名称",
|
||||
"input_streamUrl": "串流地址"
|
||||
"input_streamUrl": "串流地址",
|
||||
"success": "电台创建成功",
|
||||
"title": "创建广播电台"
|
||||
},
|
||||
"lyricsExport": {
|
||||
"export": "导出歌词",
|
||||
@@ -882,7 +948,9 @@
|
||||
"input_maxYear": "截止年份",
|
||||
"input_minYear": "起始年份",
|
||||
"input_played_optionUnplayed": "仅未播放的曲目",
|
||||
"input_played_optionPlayed": "仅已播放的曲目"
|
||||
"input_played_optionPlayed": "仅已播放的曲目",
|
||||
"input_limit": "有多少首歌?",
|
||||
"input_played": "播放筛选器"
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
@@ -916,7 +984,8 @@
|
||||
"advancedSettings": "高级设置",
|
||||
"autosize": "自动调整大小",
|
||||
"horizontalBorders": "行边框",
|
||||
"verticalBorders": "列边框"
|
||||
"verticalBorders": "列边框",
|
||||
"showHeader": "显示标题"
|
||||
},
|
||||
"view": {
|
||||
"table": "表格",
|
||||
@@ -940,10 +1009,10 @@
|
||||
"biography": "$t(common.biography)",
|
||||
"owner": "$t(common.owner)",
|
||||
"path": "$t(common.path)",
|
||||
"channels": "$t(common.channel_other)",
|
||||
"channels": "$t(common.channel, {\"count\": 2})",
|
||||
"playCount": "播放次数",
|
||||
"bitrate": "$t(common.bitrate)",
|
||||
"actions": "$t(common.action_other)",
|
||||
"actions": "$t(common.action, {\"count\": 2})",
|
||||
"genre": "$t(entity.genre, {\"count\": 1})",
|
||||
"discNumber": "碟片编号",
|
||||
"favorite": "$t(common.favorite)",
|
||||
@@ -956,7 +1025,9 @@
|
||||
"image": "图片",
|
||||
"bitDepth": "$t(common.bitDepth)",
|
||||
"sampleRate": "$t(common.sampleRate)",
|
||||
"genreBadge": "$t(entity.genre, {\"count\": 1})(徽章)"
|
||||
"genreBadge": "$t(entity.genre, {\"count\": 1})(徽章)",
|
||||
"composer": "作曲家",
|
||||
"titleArtist": "$t(common.title) (艺术家)"
|
||||
}
|
||||
},
|
||||
"column": {
|
||||
@@ -980,7 +1051,7 @@
|
||||
"genre": "$t(entity.genre, {\"count\": 1})",
|
||||
"albumArtist": "专辑艺术家",
|
||||
"path": "路径",
|
||||
"channels": "$t(common.channel_other)",
|
||||
"channels": "$t(common.channel, {\"count\": 2})",
|
||||
"discNumber": "碟片",
|
||||
"size": "$t(common.size)",
|
||||
"codec": "$t(common.codec)",
|
||||
@@ -1011,7 +1082,10 @@
|
||||
"mixtape": "混音专辑",
|
||||
"remix": "再混音(Remix)",
|
||||
"soundtrack": "原声带",
|
||||
"audioDrama": "广播剧"
|
||||
"audioDrama": "广播剧",
|
||||
"djMix": "DJ混音",
|
||||
"fieldRecording": "现场录制",
|
||||
"spokenWord": "访谈"
|
||||
}
|
||||
},
|
||||
"filterOperator": {
|
||||
@@ -1032,7 +1106,8 @@
|
||||
"notContains": "不包含",
|
||||
"startsWith": "以…开头",
|
||||
"inTheRangeDate": "在(日期)范围内",
|
||||
"notInPlaylist": "不在…中"
|
||||
"notInPlaylist": "不在…中",
|
||||
"notInTheLast": "不在最后"
|
||||
},
|
||||
"datetime": {
|
||||
"minuteShort": "分",
|
||||
@@ -1085,6 +1160,85 @@
|
||||
"builtIn": "内置",
|
||||
"colors": "颜色",
|
||||
"gradient": "渐变",
|
||||
"miscellaneousSettings": "杂项设置"
|
||||
"miscellaneousSettings": "杂项设置",
|
||||
"options": {
|
||||
"channelLayout": {
|
||||
"single": "单项"
|
||||
},
|
||||
"mode": {
|
||||
"0": "[0] 离散频率"
|
||||
},
|
||||
"colorMode": {
|
||||
"gradient": "渐变"
|
||||
},
|
||||
"gradient": {
|
||||
"classic": "经典",
|
||||
"prism": "棱镜",
|
||||
"rainbow": "彩虹"
|
||||
},
|
||||
"frequencyScale": {
|
||||
"none": "无"
|
||||
},
|
||||
"weightingFilter": {
|
||||
"none": "无",
|
||||
"a": "A",
|
||||
"b": "B",
|
||||
"c": "C",
|
||||
"d": "D",
|
||||
"z": "Z"
|
||||
}
|
||||
},
|
||||
"cyclePresets": "循环预设",
|
||||
"includeAllPresets": "包含所有预设",
|
||||
"ignoredPresets": "忽略预设",
|
||||
"selectedPresets": "已选预设",
|
||||
"randomizeNextPreset": "随机化下一个预设",
|
||||
"blendTime": "混合时间",
|
||||
"barSpace": "住间距",
|
||||
"colorStops": "颜色停止",
|
||||
"level": "等级",
|
||||
"colorMode": "颜色模式",
|
||||
"gradientLeft": "左侧渐变",
|
||||
"gradientRight": "右侧渐变",
|
||||
"fft": "FFT",
|
||||
"fftSize": "FFT 大小",
|
||||
"smoothing": "平滑",
|
||||
"frequencyRangeAndScaling": "频率范围和缩放",
|
||||
"minimumFrequency": "最低频率",
|
||||
"maximumFrequency": "最大频率",
|
||||
"frequencyScale": "频率尺度",
|
||||
"sensitivity": "灵敏度",
|
||||
"weightingFilter": "加权滤波器",
|
||||
"minimumDecibels": "最低分贝",
|
||||
"maximumDecibels": "最大分贝",
|
||||
"linearAmplitude": "线性振幅",
|
||||
"linearBoost": "线性增强",
|
||||
"peakBehavior": "峰值行为",
|
||||
"showPeaks": "显示峰值",
|
||||
"fadePeaks": "峰值淡出",
|
||||
"peakLine": "峰值线条",
|
||||
"gravity": "重力",
|
||||
"peakFadeTime": "峰值淡出时间(毫秒)",
|
||||
"peakHoldTime": "峰值保持时间(毫秒)",
|
||||
"radialSpectrum": "圆形频谱",
|
||||
"radial": "径向",
|
||||
"radialInvert": "径向反转",
|
||||
"spinSpeed": "旋转速度",
|
||||
"radius": "半径",
|
||||
"reflexMirror": "反射镜",
|
||||
"reflexFit": "反射贴合",
|
||||
"reflexRatio": "反射比率",
|
||||
"reflexAlpha": "反射Alpha",
|
||||
"reflexBrightness": "反射亮度",
|
||||
"mirror": "镜像",
|
||||
"lowResolution": "低分辨率",
|
||||
"splitGradient": "渐变分割",
|
||||
"showScaleX": "显示比例尺 X",
|
||||
"noteLabels": "笔记标签",
|
||||
"showScaleY": "显示比例尺 Y"
|
||||
},
|
||||
"queryBuilder": {
|
||||
"standardTags": "标准标签",
|
||||
"customTags": "自定义标签"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"ascending": "升冪",
|
||||
"disable": "禁用",
|
||||
"disc": "光碟",
|
||||
"dismiss": "忽略",
|
||||
"dismiss": "不再顯示",
|
||||
"duration": "時長",
|
||||
"edit": "編輯",
|
||||
"enable": "啟用",
|
||||
@@ -113,7 +113,9 @@
|
||||
"mood": "情緒",
|
||||
"view": "查看",
|
||||
"rename": "重新命名",
|
||||
"itemsMore": "{{count}} 更多"
|
||||
"itemsMore": "{{count}} 更多",
|
||||
"filter_single": "單選",
|
||||
"filter_multiple": "複選"
|
||||
},
|
||||
"error": {
|
||||
"endpointNotImplementedError": "{{serverType}} 尚未實現端點 {{endpoint}}",
|
||||
@@ -338,6 +340,9 @@
|
||||
},
|
||||
"radioList": {
|
||||
"title": "電台"
|
||||
},
|
||||
"windowBar": {
|
||||
"paused": "(暫停) "
|
||||
}
|
||||
},
|
||||
"player": {
|
||||
@@ -490,7 +495,7 @@
|
||||
"scrobble_description": "在你的媒體伺服器中記錄播放資訊",
|
||||
"showSkipButton": "顯示跳過按鈕",
|
||||
"showSkipButton_description": "在播放條上顯示/隱藏跳過按鈕",
|
||||
"sidebarPlaylistList": "側邊欄歌單清單",
|
||||
"sidebarPlaylistList": "側邊欄播放清單列表",
|
||||
"sidebarCollapsedNavigation": "側邊欄(已折疊)導航",
|
||||
"sidebarCollapsedNavigation_description": "在折疊的側邊欄中顯示或隱藏導航",
|
||||
"sidebarConfiguration": "側邊欄設定",
|
||||
@@ -709,7 +714,8 @@
|
||||
"pathReplace": "檔案路徑替換",
|
||||
"pathReplace_description": "替換您伺服器的預設檔案路徑",
|
||||
"pathReplace_optionRemovePrefix": "移除前綴",
|
||||
"pathReplace_optionAddPrefix": "增加前綴"
|
||||
"pathReplace_optionAddPrefix": "增加前綴",
|
||||
"sidebarPlaylistSorting": "側邊欄播放清單排序"
|
||||
},
|
||||
"table": {
|
||||
"config": {
|
||||
@@ -1049,7 +1055,8 @@
|
||||
"live": "Live",
|
||||
"mixtape": "混音帶",
|
||||
"remix": "Remix",
|
||||
"soundtrack": "原聲帶"
|
||||
"soundtrack": "原聲帶",
|
||||
"spokenWord": "訪談"
|
||||
}
|
||||
},
|
||||
"dragDropZone": {
|
||||
|
||||
@@ -109,6 +109,7 @@ export interface ItemListStateItem {
|
||||
_itemType: LibraryItem;
|
||||
_serverId: string;
|
||||
id: string;
|
||||
imageId: null | string;
|
||||
}
|
||||
|
||||
export type ItemListStateItemWithRequiredProperties = Record<string, unknown> & {
|
||||
|
||||
+2
-1
@@ -1,6 +1,7 @@
|
||||
import { useEffect, useImperativeHandle, useMemo } from 'react';
|
||||
|
||||
import { ItemListHandle, ItemListStateActions } from '/@/renderer/components/item-list/types';
|
||||
import { ItemListStateActions } from '/@/renderer/components/item-list/helpers/item-list-state';
|
||||
import { ItemListHandle } from '/@/renderer/components/item-list/types';
|
||||
|
||||
interface UseTableImperativeHandleProps {
|
||||
enableHeader: boolean;
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import { ListKey } from '/@/renderer/store';
|
||||
|
||||
export const AlbumListContext = createContext<{ id?: string; pageKey: ListKey }>({
|
||||
pageKey: 'album',
|
||||
});
|
||||
|
||||
export const useAlbumListContext = () => {
|
||||
const ctxValue = useContext(AlbumListContext);
|
||||
return ctxValue;
|
||||
};
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
LibraryHeader,
|
||||
LibraryHeaderMenu,
|
||||
} from '/@/renderer/features/shared/components/library-header';
|
||||
import { useSetFavorite } from '/@/renderer/features/shared/hooks/use-set-favorite';
|
||||
import { useSetRating } from '/@/renderer/features/shared/hooks/use-set-rating';
|
||||
import { AppRoute } from '/@/renderer/router/routes';
|
||||
import { useCurrentServer, useShowRatings } from '/@/renderer/store';
|
||||
import { usePlayButtonBehavior } from '/@/renderer/store/settings.store';
|
||||
@@ -65,7 +67,9 @@ export const AlbumArtistDetailHeader = forwardRef((_props, ref: Ref<HTMLDivEleme
|
||||
},
|
||||
];
|
||||
|
||||
const { addToQueueByFetch, setFavorite, setRating } = usePlayer();
|
||||
const { addToQueueByFetch } = usePlayer();
|
||||
const setFavorite = useSetFavorite();
|
||||
const setRating = useSetRating();
|
||||
const playButtonBehavior = usePlayButtonBehavior();
|
||||
|
||||
const handlePlay = useCallback(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 5100;
|
||||
z-index: 200;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 2rem;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 5100;
|
||||
z-index: 200;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
|
||||
@@ -53,5 +53,5 @@ export const PasswordSettings = memo(() => {
|
||||
},
|
||||
];
|
||||
|
||||
return <SettingsSection divider={false} options={updateOptions} />;
|
||||
return <SettingsSection options={updateOptions} />;
|
||||
});
|
||||
|
||||
@@ -8,6 +8,7 @@ import { SubsonicAlbumFilters } from '/@/renderer/features/albums/components/sub
|
||||
import { useAlbumListFilters } from '/@/renderer/features/albums/hooks/use-album-list-filters';
|
||||
import { ComponentErrorBoundary } from '/@/renderer/features/shared/components/component-error-boundary';
|
||||
import { FilterButton } from '/@/renderer/features/shared/components/filter-button';
|
||||
import { SaveAsCollectionButton } from '/@/renderer/features/shared/components/save-as-collection-button';
|
||||
import { JellyfinSongFilters } from '/@/renderer/features/songs/components/jellyfin-song-filters';
|
||||
import { NavidromeSongFilters } from '/@/renderer/features/songs/components/navidrome-song-filters';
|
||||
import { SubsonicSongFilters } from '/@/renderer/features/songs/components/subsonic-song-filters';
|
||||
@@ -18,6 +19,7 @@ import { Button } from '/@/shared/components/button/button';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Modal } from '/@/shared/components/modal/modal';
|
||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { useDisclosure } from '/@/shared/hooks/use-disclosure';
|
||||
import { LibraryItem, ServerType } from '/@/shared/types/domain-types';
|
||||
@@ -103,6 +105,12 @@ export const ListFiltersModal = ({ isActive, itemType }: ListFiltersProps) => {
|
||||
disableArtistFilter={disableArtistFilter}
|
||||
disableGenreFilter={disableGenreFilter}
|
||||
/>
|
||||
<Stack p="md">
|
||||
<SaveAsCollectionButton
|
||||
fullWidth
|
||||
itemType={itemType as LibraryItem.ALBUM | LibraryItem.SONG}
|
||||
/>
|
||||
</Stack>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -94,7 +94,7 @@ export const SaveAsCollectionButton = ({ fullWidth, itemType }: SaveAsCollection
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Popover onClose={handlers.close} opened={isOpen} position="bottom-start" width={320}>
|
||||
<Popover onClose={handlers.close} opened={isOpen} width="target">
|
||||
<Popover.Target>
|
||||
{fullWidth ? (
|
||||
<Button fullWidth onClick={handleOpen} variant="default">
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
max-height: 100%;
|
||||
margin: auto;
|
||||
overflow: hidden;
|
||||
background: #000;
|
||||
}
|
||||
|
||||
.icon-group {
|
||||
|
||||
@@ -479,7 +479,8 @@ const VisualizerInner = () => {
|
||||
};
|
||||
|
||||
const CurrentPresetDisplay = () => {
|
||||
const currentPreset = useSettingsStore.getState().visualizer.butterchurn.currentPreset;
|
||||
const currentPreset = useSettingsStore((store) => store.visualizer.butterchurn.currentPreset);
|
||||
|
||||
return (
|
||||
<Text className={styles['preset-overlay']} isNoSelect size="sm">
|
||||
{currentPreset}
|
||||
|
||||
@@ -2,42 +2,86 @@ import { closeAllModals, openModal } from '@mantine/modals';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import axios from 'axios';
|
||||
import DOMPurify from 'dompurify';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import packageJson from '../../package.json';
|
||||
|
||||
import { formatHrDateTime } from '/@/renderer/utils/format';
|
||||
import { Button } from '/@/shared/components/button/button';
|
||||
import { Center } from '/@/shared/components/center/center';
|
||||
import { Group } from '/@/shared/components/group/group';
|
||||
import { Icon } from '/@/shared/components/icon/icon';
|
||||
import { ScrollArea } from '/@/shared/components/scroll-area/scroll-area';
|
||||
import { Select } from '/@/shared/components/select/select';
|
||||
import { Spinner } from '/@/shared/components/spinner/spinner';
|
||||
import { Stack } from '/@/shared/components/stack/stack';
|
||||
import { Text } from '/@/shared/components/text/text';
|
||||
import { useLocalStorage } from '/@/shared/hooks/use-local-storage';
|
||||
|
||||
const GITHUB_RELEASES_URL = 'https://api.github.com/repos/jeffvli/feishin/releases';
|
||||
const RELEASES_TO_FETCH = 30;
|
||||
|
||||
interface GitHubRelease {
|
||||
body: null | string;
|
||||
name: null | string;
|
||||
published_at: string;
|
||||
tag_name: string;
|
||||
}
|
||||
|
||||
interface ReleaseNotesContentProps {
|
||||
onDismiss: () => void;
|
||||
version: string;
|
||||
}
|
||||
|
||||
function parseVersionFromTag(tagName: string): string {
|
||||
return tagName.startsWith('v') ? tagName.slice(1) : tagName;
|
||||
}
|
||||
|
||||
const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) => {
|
||||
const { t } = useTranslation();
|
||||
const [selectedVersion, setSelectedVersion] = useState(version);
|
||||
|
||||
// Fetch list of recent releases for the selector
|
||||
const { data: releasesList = [] } = useQuery({
|
||||
queryFn: async () => {
|
||||
const response = await axios.get<GitHubRelease[]>(GITHUB_RELEASES_URL, {
|
||||
params: { per_page: RELEASES_TO_FETCH },
|
||||
});
|
||||
return response.data;
|
||||
},
|
||||
queryKey: ['github-releases-list'],
|
||||
retry: 2,
|
||||
});
|
||||
|
||||
const releaseOptions = useMemo(() => {
|
||||
const options = releasesList.slice(0, RELEASES_TO_FETCH).map((r) => {
|
||||
const v = parseVersionFromTag(r.tag_name);
|
||||
const dateStr = formatHrDateTime(r.published_at);
|
||||
return {
|
||||
label: dateStr ? `${v} - ${dateStr}` : v,
|
||||
value: v,
|
||||
};
|
||||
});
|
||||
const versions = options.map((o) => o.value);
|
||||
if (!versions.includes(version)) {
|
||||
options.unshift({ label: version, value: version });
|
||||
}
|
||||
return options;
|
||||
}, [releasesList, version]);
|
||||
|
||||
// Fetch release notes from GitHub API
|
||||
const {
|
||||
data: releaseData,
|
||||
isError,
|
||||
isLoading,
|
||||
} = useQuery({
|
||||
queryFn: async () => {
|
||||
const response = await axios.get(
|
||||
`https://api.github.com/repos/jeffvli/feishin/releases/tags/v${version}`,
|
||||
const response = await axios.get<GitHubRelease>(
|
||||
`${GITHUB_RELEASES_URL}/tags/v${selectedVersion}`,
|
||||
);
|
||||
return response.data;
|
||||
},
|
||||
queryKey: ['github-release', version],
|
||||
queryKey: ['github-release', selectedVersion],
|
||||
retry: 2,
|
||||
});
|
||||
|
||||
@@ -49,7 +93,7 @@ const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) =
|
||||
'https://api.github.com/markdown',
|
||||
{
|
||||
mode: 'gfm',
|
||||
text: releaseData.body,
|
||||
text: releaseData?.body ?? '',
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
@@ -103,11 +147,18 @@ const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) =
|
||||
if (isError || !releaseData) {
|
||||
return (
|
||||
<Stack gap="md">
|
||||
{releaseOptions.length > 1 && (
|
||||
<Select
|
||||
data={releaseOptions}
|
||||
onChange={(v) => v && setSelectedVersion(v)}
|
||||
value={selectedVersion}
|
||||
/>
|
||||
)}
|
||||
<Text size="sm">{t('error.genericError', { postProcess: 'sentenceCase' })}</Text>
|
||||
<Group justify="flex-end">
|
||||
<Button
|
||||
component="a"
|
||||
href={`https://github.com/jeffvli/feishin/releases/tag/v${version}`}
|
||||
href={`https://github.com/jeffvli/feishin/releases/tag/v${selectedVersion}`}
|
||||
onClick={onDismiss}
|
||||
rightSection={<Icon icon="externalLink" />}
|
||||
target="_blank"
|
||||
@@ -125,6 +176,13 @@ const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) =
|
||||
|
||||
return (
|
||||
<Stack gap="md">
|
||||
{releaseOptions.length > 1 && (
|
||||
<Select
|
||||
data={releaseOptions}
|
||||
onChange={(v) => v && setSelectedVersion(v)}
|
||||
value={selectedVersion}
|
||||
/>
|
||||
)}
|
||||
<ScrollArea
|
||||
style={{
|
||||
height: '400px',
|
||||
@@ -140,7 +198,7 @@ const ReleaseNotesContent = ({ onDismiss, version }: ReleaseNotesContentProps) =
|
||||
<Group justify="flex-end">
|
||||
<Button
|
||||
component="a"
|
||||
href={`https://github.com/jeffvli/feishin/releases/tag/v${version}`}
|
||||
href={`https://github.com/jeffvli/feishin/releases/tag/v${selectedVersion}`}
|
||||
onClick={onDismiss}
|
||||
rightSection={<Icon icon="externalLink" />}
|
||||
target="_blank"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 5000;
|
||||
z-index: 195;
|
||||
height: 65px;
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
||||
@@ -101,6 +101,10 @@ export enum AuthState {
|
||||
}
|
||||
|
||||
export enum CrossfadeStyle {
|
||||
CONSTANT_POWER = 'constantPower',
|
||||
CONSTANT_POWER_SLOW_CUT = 'constantPowerSlowCut',
|
||||
CONSTANT_POWER_SLOW_FADE = 'constantPowerSlowFade',
|
||||
DIPPED = 'dipped',
|
||||
EQUAL_POWER = 'equalPower',
|
||||
EXPONENTIAL = 'exponential',
|
||||
LINEAR = 'linear',
|
||||
|
||||
Reference in New Issue
Block a user