diff --git a/src/i18n/zh_TW.jsonc b/src/i18n/zh_TW.jsonc index d66c4f73..b53162a9 100644 --- a/src/i18n/zh_TW.jsonc +++ b/src/i18n/zh_TW.jsonc @@ -108,6 +108,7 @@ "term.fullscreenView": "全螢幕顯示", "term.defaultView": "預設顯示", "term.audioSettings": "音訊設定", + "term.audioControls": "音訊控制", "term.spacializedAudioSetting": "空間音訊設定", "term.clearAll": "清空", "term.recentStations": "最近收聽的廣播", @@ -209,6 +210,7 @@ "action.copy": "複製", "action.newpreset": "新增預設", // Equalizer Preset "action.deletepreset": "刪除預設", // Equalizer Preset + "action.open": "開啟", // Settings - General "settings.header.general": "一般", @@ -230,7 +232,7 @@ "settings.header.audio": "音訊", "settings.header.audio.description": "調整 Cider 的音訊設定", "settings.option.audio.volumeStep": "音量改變量", - "settings.option.audio.maxVolume": "最高音量", + "settings.option.audio.maxVolume": "最大音量", "settings.option.audio.quality": "音訊品質", // Dropdown "settings.header.audio.quality.hireslossless": "高品質無損壓縮", "settings.header.audio.quality.hireslossless.description": "(高達 24-bit/192 kHz)", @@ -314,13 +316,17 @@ "settings.option.connectivity.lastfmScrobble.filterLoop": "不記錄單曲循環 (LastFM)", // Refer to term.connect for the connect button + // Settings - Debug + "settings.header.debug": "除錯", + "settings.option.debug.copy_log": "複製執行紀錄檔至剪貼簿", + "settings.option.debug.openAppData": "打開 Cider 資料夾", + // Settings - Experimental "settings.header.experimental": "實驗性功能", "settings.header.experimental.description": "調整 Cider 的實驗性功能", "settings.option.experimental.compactUI": "使用緊密的介面設計", // Toggle "settings.option.experimental.closeButtonBehaviour": "關閉按鈕操作", // Dropdown "settings.option.experimental.close_button_hide": "關閉按鈕將 Cider 隱藏至系統列", - "settings.option.experimental.copy_log": "複製執行紀錄檔至剪貼簿", "settings.option.experimental.inline_playlists": "將播放列表做為行内元素顯示", // Refer to term.disabled & term.enabled diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index 22010f45..d15a92d1 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -91,14 +91,15 @@ export class BrowserWindow { minHeight: 390, frame: false, title: "Cider", - vibrancy: "fullscreen-ui", + vibrancy: "dark", transparent: process.platform === "darwin", - hasShadow: false, + hasShadow: true, show: false, - backgroundColor: "#1E1E1E", + // backgroundColor: "#1E1E1E", titleBarStyle: 'hidden', trafficLightPosition: {x: 15, y: 20}, webPreferences: { + experimentalFeatures: true, nodeIntegration: true, sandbox: true, allowRunningInsecureContent: true, @@ -129,8 +130,12 @@ export class BrowserWindow { switch(process.platform) { default: + break; + case "win32": + this.options.backgroundColor = "#1E1E1E"; break; case "linux": + this.options.backgroundColor = "#1E1E1E"; this.options.autoHideMenuBar = true this.options.frame = true break; diff --git a/src/main/base/plugins.ts b/src/main/base/plugins.ts index 3dc77b0f..ccb7f2e4 100644 --- a/src/main/base/plugins.ts +++ b/src/main/base/plugins.ts @@ -32,6 +32,7 @@ export class Plugins { if (fs.existsSync(this.userPluginsPath)) { fs.readdirSync(this.userPluginsPath).forEach(file => { + // Plugins V1 if (file.endsWith('.ts') || file.endsWith('.js')) { if (!electron.app.isPackaged) { const plugin = require(path.join(this.userPluginsPath, file)).default; @@ -50,7 +51,24 @@ export class Plugins { plugins[file] = new plugin(electron.app, utils.getStore()); } } - + } + // Plugins V2 + else if (fs.lstatSync(path.join(this.userPluginsPath, file)).isDirectory()) { + const pluginPath = path.join(this.userPluginsPath, file); + if (fs.existsSync(path.join(pluginPath, 'package.json'))) { + const plugin = require(path.join(pluginPath, "index.js")); + if (plugins[plugin.name] || plugin.name in plugins) { + console.log(`[${plugin.name}] Plugin already loaded / Duplicate Class Name`); + } else { + const pluginEnv = { + app: electron.app, + store: utils.getStore(), + utils: utils, + dir: pluginPath + } + plugins[plugin.name] = new plugin(pluginEnv); + } + } } }); } diff --git a/src/main/base/wsapi.ts b/src/main/base/wsapi.ts index 619a0ac6..bb48d86a 100644 --- a/src/main/base/wsapi.ts +++ b/src/main/base/wsapi.ts @@ -183,7 +183,10 @@ export class wsapi { break; case "next": this._win.webContents.executeJavaScript(`if (MusicKit.getInstance().queue.nextPlayableItemIndex != -1 && MusicKit.getInstance().queue.nextPlayableItemIndex != null) { - MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex);}`); + try { + app.prevButtonBackIndicator = false; + } catch (e) { } + MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex);}`); response.message = "Next"; break; case "previous": diff --git a/src/preload/cider-preload.js b/src/preload/cider-preload.js index 243b7951..84a55e91 100644 --- a/src/preload/cider-preload.js +++ b/src/preload/cider-preload.js @@ -136,6 +136,9 @@ const MusicKitInterop = { }, next: () => { + try { + app.prevButtonBackIndicator = false; + } catch (e) { } if (MusicKit.getInstance().queue.nextPlayableItemIndex != -1 && MusicKit.getInstance().queue.nextPlayableItemIndex != null) MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex); // MusicKit.getInstance().skipToNextItem().then(r => console.log(`[MusicKitInterop.next] Skipping to Next ${r}`)); diff --git a/src/renderer/index.js b/src/renderer/index.js index e4700d7d..fa9cc246 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -250,7 +250,8 @@ const app = new Vue({ items: {}, headerItems: {} } - } + }, + pauseButtonTimer : null }, watch: { cfg: { @@ -452,7 +453,7 @@ const app = new Vue({ history.forward() }, getHTMLStyle() { - document.querySelector("html").style.background = "#222"; + // document.querySelector("html").style.background = "#222"; document.querySelector("body").classList.add("notransparency") }, resetState() { @@ -813,6 +814,8 @@ const app = new Vue({ this.page = "home" } + this.mediaKeyFixes() + setTimeout(() => { this.getSocialBadges() this.getBrowsePage(); @@ -1319,6 +1322,14 @@ const app = new Vue({ extend: "offers,editorialVideo", "views": "appears-on,more-by-artist,related-videos,other-versions,you-might-also-like,video-extras,audio-extras", } + if (kind.includes("playlist")){ + params["include"] = "tracks"; + } + if (kind.includes("album")){ + params["include[albums]"] = "artists" + params["fields[artists]"] = "name,url" + params["fields[albums]"] = "artistName,artistUrl,artwork,contentRating,editorialArtwork,name,playParams,releaseDate,url" + } if (this.cfg.advanced.experiments.includes('inline-playlists')) { let showModal = kind.toString().includes("album") || kind.toString().includes("playlist") @@ -1347,8 +1358,11 @@ const app = new Vue({ prevButton() { if (!app.prevButtonBackIndicator && app.mk.nowPlayingItem && app.mk.currentPlaybackTime > 2) { app.prevButtonBackIndicator = true; + try{clearTimeout(app.pauseButtonTimer)} catch (e){ } app.mk.seekToTime(0); + app.pauseButtonTimer = setTimeout(() => {app.prevButtonBackIndicator = false},3000); } else { + try{clearTimeout(app.pauseButtonTimer)} catch (e){ } app.prevButtonBackIndicator = false; app.skipToPreviousItem() } @@ -3245,8 +3259,8 @@ const app = new Vue({ }, async getRating(item) { let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" - let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id - if (item.id.startsWith("i.")) { + let id = item.attributes?.playParams?.catalogId ? item.attributes.playParams.catalogId : (item.attributes?.playParams?.id ?? item.id) + if (item.id != null && (item.id.toString()).startsWith("i.")) { if (!type.startsWith("library-")) { type = "library-" + type } @@ -3262,8 +3276,8 @@ const app = new Vue({ }, love(item) { let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" - let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id - if (item.id.startsWith("i.")) { + let id = item.attributes?.playParams?.catalogId ? item.attributes.playParams.catalogId : (item.attributes?.playParams?.id ?? item.id) + if (item.id != null && (item.id.toString()).startsWith("i.")) { if (!type.startsWith("library-")) { type = "library-" + type } @@ -3283,8 +3297,8 @@ const app = new Vue({ }, dislike(item) { let type = item.type.slice(-1) === "s" ? item.type : item.type + "s" - let id = item.attributes.playParams.catalogId ? item.attributes.playParams.catalogId : item.id - if (item.id.startsWith("i.")) { + let id = item.attributes?.playParams?.catalogId ? item.attributes.playParams.catalogId : (item.attributes?.playParams?.id ?? item.id) + if (item.id != null && (item.id.toString()).startsWith("i.")) { if (!type.startsWith("library-")) { type = "library-" + type } @@ -3732,6 +3746,7 @@ const app = new Vue({ } }, skipToNextItem(){ + app.prevButtonBackIndicator = false; // app.mk.skipToNextItem() is buggy somehow so use this if (this.mk.queue.nextPlayableItemIndex != -1 && this.mk.queue.nextPlayableItemIndex != null) this.mk.changeToMediaAtIndex(this.mk.queue.nextPlayableItemIndex); @@ -3740,6 +3755,10 @@ const app = new Vue({ // app.mk.skipToPreviousItem() is buggy somehow so use this if (this.mk.queue.previousPlayableItemIndex != -1 && this.mk.queue.previousPlayableItemIndex != null) this.mk.changeToMediaAtIndex(this.mk.queue.previousPlayableItemIndex); + }, + mediaKeyFixes(){ + navigator.mediaSession.setActionHandler('previoustrack', function() { app.prevButton() }); + navigator.mediaSession.setActionHandler('nexttrack', function() { app.skipToNextItem() }); } } }) @@ -3849,7 +3868,7 @@ function fallbackinitMusicKit() { }, sourceType: 24, suppressErrorDialog: true - }); + }) setTimeout(() => { app.init() }, 1000) diff --git a/src/renderer/less/macos.less b/src/renderer/less/macos.less new file mode 100644 index 00000000..af21338b --- /dev/null +++ b/src/renderer/less/macos.less @@ -0,0 +1,17 @@ +body[platform="darwin"] { + html { + background: transparent!important; + } + + &.notransparency::before { + display: none; + } + #app { + &.simplebg { + background: transparent; + } + &::before { + display: none; + } + } +} \ No newline at end of file diff --git a/src/renderer/less/pages.less b/src/renderer/less/pages.less index ee7ba294..561433a8 100644 --- a/src/renderer/less/pages.less +++ b/src/renderer/less/pages.less @@ -924,6 +924,30 @@ } } + .replay-playlist-container { + .cd-mediaitem-square { + height: 230px; + width: 230px; + .info-rect { + display: none; + } + } + } + + .replay-video { + max-height: 300px; + max-width: 800px; + margin: 0 auto; + + .mediaitem-artwork { + max-height: 300px; + max-width: 800px; + } + + .mediaitem-artwork .animatedartwork-view-box .animated video { + object-fit: cover; + } + } .top-genres-container { .genre-name { diff --git a/src/renderer/style.less b/src/renderer/style.less index 08813883..6ae9c835 100644 --- a/src/renderer/style.less +++ b/src/renderer/style.less @@ -3110,5 +3110,6 @@ body[platform='darwin'] { } +@import url("less/macos.less"); @import url("less/linux.less"); @import url("less/compact.less"); diff --git a/src/renderer/views/components/mediaitem-list-item.ejs b/src/renderer/views/components/mediaitem-list-item.ejs index 44288389..a3c4f621 100644 --- a/src/renderer/views/components/mediaitem-list-item.ejs +++ b/src/renderer/views/components/mediaitem-list-item.ejs @@ -474,7 +474,7 @@ menus.normal.headerItems.find(x => x.id == 'dislike').hidden = true } } catch (err) { - + console.log(err) } }, visibilityChanged: function (isVisible, entry) { diff --git a/src/renderer/views/components/mediaitem-square.ejs b/src/renderer/views/components/mediaitem-square.ejs index 4248f1b7..6be015b1 100644 --- a/src/renderer/views/components/mediaitem-square.ejs +++ b/src/renderer/views/components/mediaitem-square.ejs @@ -12,6 +12,7 @@ :size="size" shadow="subtle" :bgcolor="getBgColor()" + :video-priority="forceVideo" :type="item.type">