diff --git a/.gitignore b/.gitignore index a7130433..f2383b33 100644 --- a/.gitignore +++ b/.gitignore @@ -319,3 +319,8 @@ keys.sh package-lock.json yarn.lock resources/b64.txt + + +savedconfig/cider-config.json +savedconfig/config.json +savedconfig/session.json diff --git a/src/i18n/zh_CN.jsonc b/src/i18n/zh_CN.jsonc index 75ea8e2d..f5f8b35b 100644 --- a/src/i18n/zh_CN.jsonc +++ b/src/i18n/zh_CN.jsonc @@ -4,7 +4,7 @@ "i18n.languageName": "简体中文(中国)", // name of language in native language "i18n.languageNameEnglish": "Simp. Chinese (China)", // name of language in English "i18n.category": "main", // main = real language, fun = fun community languages - "i18n.authors": "@maikirakiwi", // Authors, if you contribute to this file feel free to add your name seperated with a space + "i18n.authors": "@maikirakiwi @BillKerman", // Authors, if you contribute to this file feel free to add your name seperated with a space // App info "app.name": "Cider", @@ -21,6 +21,7 @@ "notification.updatingLibraryArtists": "正在更新资料库的艺人信息...", // Terms + "term.appleInc": "Apple Inc.", "term.appleMusic": "Apple Music", // Follows brand term "term.applePodcasts": "Apple Podcasts", // Follows brand term "term.itunes": "iTunes", // Follows brand term @@ -45,6 +46,11 @@ "term.podcasts": "播客", "term.playlists": "播放列表", "term.playlist": "播放列表", + "term.newPlaylist": "新播放列表", + "term.newPlaylistFolder": "新播放列表文件夹", + "term.createNewPlaylist": "新建播放列表", + "term.createNewPlaylistFolder": "新建播放列表文件夹", + "term.deletePlaylist": "您确定要删除该播放列表吗?", "term.play": "播放", "term.pause": "暂停", "term.previous": "上一首", @@ -55,6 +61,7 @@ "term.mute": "静音", "term.unmute": "解除静音", "term.share": "分享", + "term.share.success": "已复制到剪贴板", "term.settings": "设置", "term.seeAll": "查看全部", "term.sortBy": "排序", @@ -104,7 +111,7 @@ "term.clearAll": "清空", "term.recentStations": "最近播放的频道", "term.language": "语言", - "term.noLyrics": "加载中。。/ 搜索无结果 / 纯音乐", + "term.noLyrics": "加载中... / 搜索无结果 / 纯音乐", "term.copyright": "版权所有", "term.rightsReserved": "保留所有权利。", "term.sponsor": "赞助", @@ -119,13 +126,14 @@ "term.menu": "菜单", "term.check": "检查", "term.aboutArtist": "关于{{artistName}}", // e.g. 'About Doja Cat' + "term.updateCider": "更新 Cider", // Home "home.title": "主页", "home.recentlyPlayed": "最近播放", "home.recentlyAdded": "最近添加", "home.artistsFeed": "艺人推荐", - "home.artistsFeed.noArtist": "追踪您喜爱的艺人后便可查看他们的最新发行。", + "home.artistsFeed.noArtist": "关注您喜爱的艺人后便可查看他们的最新发行歌曲。", "home.madeForYou": "专属推荐", "home.friendsListeningTo": "朋友正在听", "home.followedArtists": "关注的艺人", @@ -137,8 +145,8 @@ "error.noResults.description": "尝试更改搜索条件。", // Podcasts - "podcast.followOnCider": "在 Cider 中追踪", - "podcast.followedOnCider": "已追踪", + "podcast.followOnCider": "在 Cider 中关注", + "podcast.followedOnCider": "已关注", "podcast.subscribeOnItunes": "在 iTunes 上订阅", "podcast.subscribedOnItunes": "已订阅", "podcast.itunesStore": "iTunes Store", // Follow brand term @@ -152,12 +160,12 @@ "action.addToLibrary.error": "加入资料库的过程发生了错误", "action.removeFromLibrary": "从资料库中移除", "action.removeFromLibrary.success": "已从资料库中移除", - "action.addToQueue": "加入队列", - "action.addToQueue.success": "成功加入队列", - "action.addToQueue.error": "加入队列的过程发生了错误", - "action.removeFromQueue": "从队列中移除", - "action.removeFromQueue.success": "已从队列中移除", - "action.removeFromQueue.error": "从队列中移除的过程发生了错误", + "action.addToQueue": "加入待播清单", + "action.addToQueue.success": "成功加入加入待播清单", + "action.addToQueue.error": "加入加入待播清单的过程发生了错误", + "action.removeFromQueue": "从加入待播清单中移除", + "action.removeFromQueue.success": "已从加入待播清单中移除", + "action.removeFromQueue.error": "从加入待播清单中移除的过程发生了错误", "action.addToPlaylist": "加入播放列表", "action.removeFromPlaylist": "从播放列表中移除", "action.addToFavorites": "加至收藏", @@ -167,7 +175,7 @@ "action.unfollow": "取消关注", "action.unfollow.success": "已取消关注", "action.unfollow.error": "尝试取消关注的过程发生了错误", - "action.playNext": "下一首播放", + "action.playNext": "插播", "action.playLater": "最后播放", "action.startRadio": "开始电台", "action.goToArtist": "前往艺人", @@ -178,7 +186,7 @@ "action.love": "喜欢", "action.unlove": "踩", "action.dislike": "减少此类建议", - "action.undoDislike": "增加此类建议", + "action.undoDislike": "撤销减少此类建议", "action.showWebRemoteQR": "显示远程控制的二维码", "action.playTracksNext": "插播 ${app.selectedMediaItems.length} 首歌曲", "action.playTracksLater": "最后播放 ${app.selectedMediaItems.length} 首歌曲", @@ -245,6 +253,8 @@ "settings.header.visual.hardwareAcceleration.webGPU": "WebGPU", // Settings - Visual - Theme name + "settings.option.visual.theme.default": "默认", + "settings.option.visual.theme.dark": "午夜黑", // Refer to term.disabled for the disabled option "settings.option.visual.showPersonalInfo": "显示个人资料", // Toggle @@ -261,14 +271,16 @@ "settings.header.connectivity": "外部连接", "settings.header.connectivity.description": "调整Cider与外部应用的交互设置", "settings.option.connectivity.discordRPC": "Discord 动态", // Dropdown + "settings.option.connectivity.playbackNotifications": "歌曲播放通知", // Toggle // Refer to term.disabled for the disabled option - "settings.header.connectivity.discordRPC.cider": "显示正在玩 'Cider'", - "settings.header.connectivity.discordRPC.appleMusic": "显示正在玩 'Apple Music'", - "settings.option.connectivity.discordRPC.clearOnPause": "暂停时清除Discord 动态", // Toggle + "settings.header.connectivity.discordRPC.cider": "显示正在使用 'Cider'", + "settings.header.connectivity.discordRPC.appleMusic": "显示正在使用 'Apple Music'", + "settings.option.connectivity.discordRPC.clearOnPause": "暂停时清除 Discord 动态", // Toggle "settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling 记录", // Option to Connect "settings.option.connectivity.lastfmScrobble.delay": "LastFM Scrobble 延迟 (%)", "settings.option.connectivity.lastfmScrobble.nowPlaying": "启用 LastFM 正在播放", - "settings.option.connectivity.lastfmScrobble.removeFeatured": "从歌名里去除艺人推荐 (LastFM)", + "settings.option.connectivity.lastfmScrobble.removeFeatured": "从歌名里去除合作者 (LastFM)", + "settings.option.connectivity.lastfmScrobble.filterLoop": "不记录单曲循环 (LastFM)", // Refer to term.connect for the connect button // Settings - Experimental @@ -279,6 +291,7 @@ // Refer to term.disabled & term.enabled // Spatialization Menu + "spatial.notTurnedOn": "请在设定中开启空间音频。", "spatial.spatialProperties": "空间属性", "spatial.width": "宽度", "spatial.height": "高度", diff --git a/src/i18n/zh_HK.jsonc b/src/i18n/zh_HK.jsonc index 516ff4b6..c6aa902f 100644 --- a/src/i18n/zh_HK.jsonc +++ b/src/i18n/zh_HK.jsonc @@ -4,7 +4,7 @@ "i18n.languageName": "繁體中文(香港)", // name of language in native language "i18n.languageNameEnglish": "Trad. Chinese (Hong Kong)", // name of language in English "i18n.category": "main", // main = real language, fun = fun community languages - "i18n.authors": "@kyw504100 @maikirakiwi", // Authors, if you contribute to this file feel free to add your name seperated with a space + "i18n.authors": "@kyw504100 @maikirakiwi @BillKerman", // Authors, if you contribute to this file feel free to add your name seperated with a space // App info "app.name": "Cider", @@ -48,9 +48,9 @@ "term.playlists": "播放列表", "term.playlist": "播放列表", "term.newPlaylist": "新播放列表", - "term.newPlaylistFolder": "新資料夾", + "term.newPlaylistFolder": "新播放列表資料夾", "term.createNewPlaylist": "新增播放列表", - "term.createNewPlaylistFolder": "新增資料夾", + "term.createNewPlaylistFolder": "新增播放列表資料夾", "term.deletePlaylist": "你確認要刪除這個播放列表?", "term.play": "播放", "term.pause": "暫停", @@ -317,8 +317,8 @@ "settings.option.connectivity.lastfmScrobble": "Last.fm Scrobbling 記錄", // Option to Connect "settings.option.connectivity.lastfmScrobble.delay": "Last.fm Scrobble 延遲 (%)", "settings.option.connectivity.lastfmScrobble.nowPlaying": "啟用 Last.fm 正在播放", - "settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除藝人推薦 (Last.fm)", - //"settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", + "settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除客串藝人 (LastFM)", + "settings.option.connectivity.lastfmScrobble.filterLoop": "不記錄單曲循環 (LastFM)", // Refer to term.connect for the connect button // Settings - Experimental diff --git a/src/i18n/zh_TW.jsonc b/src/i18n/zh_TW.jsonc index aa238675..86572ce4 100644 --- a/src/i18n/zh_TW.jsonc +++ b/src/i18n/zh_TW.jsonc @@ -4,7 +4,7 @@ "i18n.languageName": "繁體中文(台灣)", // name of language in native language "i18n.languageNameEnglish": "Trad. Chinese (Taiwan)", // name of language in English "i18n.category": "main", // main = real language, fun = fun community languages - "i18n.authors": "@maikirakiwi @jay900604 @kyw504100", // Authors, if you contribute to this file feel free to add your name seperated with a space + "i18n.authors": "@maikirakiwi @jay900604 @kyw504100 @BillKerman", // Authors, if you contribute to this file feel free to add your name seperated with a space // App info "app.name": "Cider", @@ -45,6 +45,11 @@ "term.podcasts": "Podcasts", "term.playlists": "播放列表", "term.playlist": "播放列表", + "term.newPlaylist": "新播放列表", + "term.newPlaylistFolder": "新播放列表資料夾", + "term.createNewPlaylist": "新增播放列表", + "term.createNewPlaylistFolder": "新增播放列表資料夾", + "term.deletePlaylist": "您確認要删除该播放列表吗?", "term.play": "播放", "term.pause": "暫停", "term.previous": "上一首", @@ -105,7 +110,7 @@ "term.clearAll": "清空", "term.recentStations": "最近收聽的廣播", "term.language": "語言", - "term.noLyrics": "正在載入。。/ 無歌詞結果 / 純音樂", + "term.noLyrics": "正在載入... / 無歌詞結果 / 純音樂", "term.copyright": "版權聲明", "term.rightsReserved": "保留所有權利。", "term.sponsor": "贊助我們", @@ -283,13 +288,14 @@ "settings.option.connectivity.discordRPC": "Discord 動態", // Dropdown "settings.option.connectivity.playbackNotifications": "歌曲播放通知", // Toggle // Refer to term.disabled for the disabled option - "settings.header.connectivity.discordRPC.cider": "顯示正在玩 'Cider'", - "settings.header.connectivity.discordRPC.appleMusic": "顯示正在玩 'Apple Music'", + "settings.header.connectivity.discordRPC.cider": "顯示正在使用 'Cider'", + "settings.header.connectivity.discordRPC.appleMusic": "顯示正在使用 'Apple Music'", "settings.option.connectivity.discordRPC.clearOnPause": "暫停時清除 Discord 動態", // Toggle "settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling 記錄", // Option to Connect "settings.option.connectivity.lastfmScrobble.delay": "LastFM Scrobble 延遲 (%)", "settings.option.connectivity.lastfmScrobble.nowPlaying": "啟用 LastFM 目前聆聽", // Toggle - "settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除藝人推薦 (LastFM)", + "settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除客串藝人 (LastFM)", + "settings.option.connectivity.lastfmScrobble.filterLoop": "不記錄單曲循環 (LastFM)", // Refer to term.connect for the connect button // Settings - Experimental diff --git a/src/main/plugins/menubar.ts b/src/main/plugins/menubar.ts index ec484b40..eb40f61e 100644 --- a/src/main/plugins/menubar.ts +++ b/src/main/plugins/menubar.ts @@ -101,7 +101,7 @@ export default class Thumbar { { label: 'Pause / Play', accelerator: 'Space', - click: () => this._win.webContents.executeJavaScript(`MusicKitInterop.playPause()`) + click: () => this._win.webContents.executeJavaScript(`app.SpacePause()`) }, { label: 'Next', diff --git a/src/main/plugins/webNowPlaying.ts b/src/main/plugins/webNowPlaying.ts index 2787e4c1..27b5af42 100644 --- a/src/main/plugins/webNowPlaying.ts +++ b/src/main/plugins/webNowPlaying.ts @@ -14,7 +14,7 @@ const pad = (number: number, length: number) => String(number).padStart(length, * @param {Number} timeInSeconds * @returns String */ - const convertTimeToString = (timeInSeconds: number) => { +const convertTimeToString = (timeInSeconds: number) => { const timeInMinutes = Math.floor(timeInSeconds / 60); if (timeInMinutes < 60) { return timeInMinutes + ":" + pad(Math.floor(timeInSeconds % 60), 2); @@ -28,13 +28,13 @@ export default class WebNowPlaying { */ public name: string = 'WebNowPlaying'; public description: string = 'Song info and playback control for the Rainmeter WebNowPlaying plugin.'; - public version: string = '1.0.0'; + public version: string = '1.0.1'; public author: string = 'Zennn '; private _win: any; - private ws: any = null; - private wsapiConn: any = null; - private playerName: string = 'Cider'/* Apple Music */; + private ws?: WebSocket; + private wsapiConn?: WebSocket; + private playerName: string = 'Cider'; constructor() { console.debug(`[Plugin][${this.name}] Loading Complete.`); @@ -47,9 +47,7 @@ export default class WebNowPlaying { */ private static windowsOnly(_target: any, _propertyKey: string, descriptor: PropertyDescriptor) { if (process.platform !== 'win32') { - descriptor.value = function () { - return - } + descriptor.value = () => void 0; } } @@ -92,22 +90,25 @@ export default class WebNowPlaying { value = attributes.shuffleMode; break; } - this.ws.send(`${field}:${value}`); + this.ws?.send(`${field}:${value}`); } catch (error) { - if (this.ws.readyState === WebSocket.OPEN) { + if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send(`Error:Error updating ${field} for ${this.playerName}`); this.ws.send(`ErrorD:${error}`); } } }); } - private fireEvent(evt: any) { + + private fireEvent(evt: WebSocket.MessageEvent) { if (!evt.data) return; - let value = ''; - if (evt.data.split(/ (.+)/).length > 1) { - value = evt.data.split(/ (.+)/)[1]; + const data = evt.data; + + let value: string = ''; + if (data.split(/ (.+)/).length > 1) { + value = data.split(/ (.+)/)[1]; } - const eventName = evt.data.split(' ')[0].toLowerCase(); + const eventName = data.split(' ')[0].toLowerCase(); try { switch (eventName) { @@ -144,7 +145,7 @@ export default class WebNowPlaying { } } catch (error) { console.debug(error); - if (this.ws.readyState === WebSocket.OPEN) { + if (this.ws?.readyState === WebSocket.OPEN) { this.ws.send(`Error:Error sending event to ${this.playerName}`); this.ws.send(`ErrorD:${error}`); } @@ -163,10 +164,10 @@ export default class WebNowPlaying { try { this.ws = new WebSocket('ws://127.0.0.1:8974/'); let retry: NodeJS.Timeout; - this.ws.onopen = (() => { + this.ws.onopen = () => { console.info('[WebNowPlaying] Connected to Rainmeter'); - this.ws.send(`PLAYER:${this.playerName}`); - }).bind(this); + this.ws?.send(`PLAYER:${this.playerName}`); + }; this.ws.onclose = () => { clearTimeout(retry); @@ -175,7 +176,7 @@ export default class WebNowPlaying { this.ws.onerror = () => { clearTimeout(retry); - this.ws.close(); + this.ws?.close(); }; this.ws.onmessage = this.fireEvent?.bind(this); @@ -194,8 +195,8 @@ export default class WebNowPlaying { console.info('[WebNowPlaying] Connected to wsapi'); }; - this.wsapiConn.onmessage = (evt: { data: string; }) => { - const response = JSON.parse(evt.data); + this.wsapiConn.onmessage = (evt: WebSocket.MessageEvent) => { + const response = JSON.parse(evt.data); if (response.type === 'playbackStateUpdate') { this.sendSongInfo(response.data); } @@ -214,8 +215,8 @@ export default class WebNowPlaying { public onBeforeQuit() { if (this.ws) { this.ws.send('STATE:0'); - this.ws.onclose = null; // disable onclose handler first to stop it from retrying - this.ws.close(); + this.ws.onclose = () => void 0; // disable onclose handler first to stop it from retrying + this.ws.close(); } if (this.wsapiConn) { this.wsapiConn.close(); @@ -227,7 +228,8 @@ export default class WebNowPlaying { * Runs on playback State Change * @param attributes Music Attributes (attributes.status = current state) */ - onPlaybackStateDidChange(attributes: any) { + @WebNowPlaying.windowsOnly + public onPlaybackStateDidChange(attributes: any) { this.sendSongInfo(attributes); } diff --git a/src/renderer/index.js b/src/renderer/index.js index 931bf60f..c3884705 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -3578,6 +3578,27 @@ const app = new Vue({ R.push(arr.slice(i, i + chunkSize)); } return R; + }, + SpacePause() { + const elems = document.querySelectorAll('input'); + for (elem of elems){ + if (elem === document.activeElement) { + return; + } + } + if (!this.isDev) // disable in dev mode to keep my sanity + MusicKitInterop.playPause(); + }, + MKJSLang(){ + let u = this.cfg.general.language; + let langcodes = ['af', 'sq', 'ar', 'eu', 'bg', 'be', 'ca', 'zh', 'zh-tw', 'zh-cn', 'zh-hk', 'zh-sg', 'hr', 'cs', 'da', 'nl', 'nl-be', 'en', 'en-us', 'en-eg', 'en-au', 'en-gb', 'en-ca', 'en-nz', 'en-ie', 'en-za', 'en-jm', 'en-bz', 'en-tt', 'en-001', 'et', 'fo', 'fa', 'fi', 'fr', 'fr-ca', 'gd', 'de', 'de-ch', 'el', 'he', 'hi', 'hu', 'is', 'id', 'it', 'ja', 'ko', 'lv', 'lt', 'mk', 'mt', 'no', 'nb', 'nn', 'pl', 'pt-br', 'pt', 'rm', 'ro', 'ru', 'sr', 'sk', 'sl', 'es', 'es-mx', 'es-419', 'sv', 'th', 'ts', 'tn', 'tr', 'uk', 'ur', 've', 'vi', 'xh', 'yi', 'zu', 'ms', 'iw', 'lo', 'tl', 'kk', 'ta', 'te', 'bn', 'ga', 'ht', 'la', 'pa', 'sa']; + let sellang = "en" + if (u && langcodes.includes(u.toLowerCase().replace('_', "-"))) { + sellang = ((u.toLowerCase()).replace('_', "-")) + } else if (u && u.includes('_') && langcodes.includes(((u.toLowerCase()).replace('_', "-")).split("-")[0])) { + sellang = ((u.toLowerCase()).replace('_', "-")).split("-")[0] + } + return sellang } } }) diff --git a/src/renderer/views/components/mediaitem-list-item.ejs b/src/renderer/views/components/mediaitem-list-item.ejs index 132d7b24..76487b1e 100644 --- a/src/renderer/views/components/mediaitem-list-item.ejs +++ b/src/renderer/views/components/mediaitem-list-item.ejs @@ -16,9 +16,12 @@