diff --git a/package.json b/package.json index 5da3fef3..ca72e47e 100644 --- a/package.json +++ b/package.json @@ -134,6 +134,13 @@ "publisherDisplayName": "Cider Collective", "backgroundColor": "transparent", "setBuildNumber": true + }, + "nsis": { + "oneClick": false, + "perMachine": false, + "allowToChangeInstallationDirectory": true, + "license": "LICENSE", + "deleteAppDataOnUninstall": true }, "win": { "target": [ diff --git a/src/i18n/el_GR.jsonc b/src/i18n/el_GR.jsonc new file mode 100644 index 00000000..c1d91af3 --- /dev/null +++ b/src/i18n/el_GR.jsonc @@ -0,0 +1,95 @@ +{ + // App info + "app.name": "Cider", + // Dialogs + "dialog.cancel": "Ακύρωση", + "dialog.ok": "ΟΚ", + // Terms + "term.appleMusic": "Apple Music", + "term.applePodcasts": "Apple Podcasts", + "term.itunes": "iTunes", + "term.github": "GitHub", + "term.discord": "Discord", + "term.learnMore": "Μάθετε Περισσότερα", + "term.accountSettings": "Ρυθμίσεις Λογαριασμού", + "term.logout": "Αποσύνδεση", + "term.login": "Σύνδεση", + "term.about": "Σχετικά με", + "term.privateSession": "Ιδιωτική Περίοδος Λειτουργίας", + "term.queue": "Ουρά", + "term.search": "Εύρεση", + "term.library": "Βιβλιοθήκη", + "term.recentlyAdded": "Πρόσφατες Προσθήκες", + "term.songs": "Τραγούδια", + "term.albums": "Άλμπουμ", + "term.artists": "Καλλιτέχνες", + "term.podcasts": "Podcast", + "term.playlists": "Λίστες Αναπαραγωγής", + "term.playlist": "Λίστα Αναπαραγωγής", + "term.play": "Αναπαραγωγή", + "term.pause": "Παύση", + "term.previous": "Προηγούμενο", + "term.next": "Επόμενο", + "term.shuffle": "Τυχαία Σειρά", + "term.repeat": "Επανάληψη", + "term.volume": "Ένταση", + "term.mute": "Σίγαση", + "term.unmute": "Κατάργηση Σίγασης", + "term.share": "Κοινή Χρήση", + "term.settings": "Ρυθμίσεις", + "term.seeAll": "Προβολή Όλων", + // Home + "home.title": "Αρχική", + "home.recentlyPlayed": "Έπαιξαν Πρόσφατα", + "home.recentlyAdded": "Πρόσφατες Προσθήκες", + "home.artistsFeed": "Ροή των Καλλιτεχνών σου", + "home.madeForYou": "Δημιουργήθηκε Για Εσάς", + "home.friendsListeningTo": "Οι Φίλοι σου Ακούν", + "home.followedArtists": "Καλλιτέχνες που Ακολουθείτε", + // Errors + "error.appleMusicSubRequired": "Το Apple Music απαιτεί μια συνδρομή.", + // Actions + "action.addToLibrary": "Προσθήκη στη Βιβλιοθήκη", + "action.addToLibrary.success": "Προστέθηκε στη Βιβλιοθήκη", + "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.follow": "Ακολούθηση", + "action.follow.success": "Ακολουθήθηκε", + "action.follow.error": "Σφάλμα Ακολούθησης", + "action.unfollow": "Διακοπή Ακολούθησης", + "action.unfollow.success": "Έγινε Διακοπή Ακολούθησης", + "action.unfollow.error": "Σφάλμα Διακοπής Ακολούθησης ", + "action.playNext": "Αναπαραγωγή ως Επόμενου", + "action.playLater": "Αναπαραγωγή Αργότερα", + "action.startRadio": "Έναρξη Σταθμού", + "action.goToArtist": "Μετάβαση σε Καλλιτέχνη", + "action.goToAlbum": "Μετάβαση σε Άλμπουμ", + "action.share": "Κοινή Χρήση", + "action.love": "Μου αρέσει πολύ", + "action.unlove": "Αναίρεση \"Μου Αρέσει\"", + "action.dislike": "Δεν μου αρέσει", + "action.undoDislike": "Αναίρεση \"Δεν μου αρέσει\"", + // Settings + "settings.header.audio": "Ήχος", + "settings.header.audio.description": "Προσαρμογή ρυθμίσεων ήχου για το Cider.", + "settings.header.audio.quality.high": "Υψηλή", + "settings.header.audio.quality.low": "Χαμηλή", + "settings.header.audio.quality.auto": "Αυτόματη", + "settings.header.visual": "Οπτικά", + "settings.header.visual.description": "Προσαρμογή οπτικών ρυθμίσεων για το Cider.", + "settings.header.general": "Γενικά", + "settings.header.general.description": "Προσαρμογή γενικών ρυθμίσεων για το Cider.", + "settings.header.lyrics": "Στίχοι", + "settings.header.lyrics.description": "Προσαρμογή ρυθμίσεων στίχων για το Cider.", + "settings.header.connectivity": "Σύνδεση", + "settings.header.connectivity.description": "Προσαρμογή ρυθμίσεων σύνδεσης για το Cider.", + "settings.header.experimental": "Πειραματικές", + "settings.header.experimental.description": "Προσαρμογή πειραματικών ρυθμίσεων για το Cider." +} \ No newline at end of file diff --git a/src/i18n/ja_JP.jsonc b/src/i18n/ja_JP.jsonc new file mode 100644 index 00000000..da019992 --- /dev/null +++ b/src/i18n/ja_JP.jsonc @@ -0,0 +1,95 @@ +{ + // App info + "app.name": "Cider", + // Dialogs + "dialog.cancel": "キャンセル", + "dialog.ok": "OK", + // Terms + "term.appleMusic": "Apple Music", // Follows brand term + "term.applePodcasts": "Apple Podcasts", // Follows brand term + "term.itunes": "iTunes", // Follows brand term + "term.github": "GitHub", // Follows brand term + "term.discord": "Discord", // Follows brand term + "term.learnMore": "詳しい情報", + "term.accountSettings": "アカウント設定", + "term.logout": "サインアウト", + "term.login": "サインイン", + "term.about": "アプリについて", + "term.privateSession": "プライベートセッション", + "term.queue": "次はこちら", + "term.search": "検索", + "term.library": "ライブラリ", + "term.recentlyAdded": "最近追加した項目", + "term.songs": "曲", + "term.albums": "アルバム", + "term.artists": "アーティスト", + "term.podcasts": "Podcast", + "term.playlists": "プレイリスト", + "term.playlist": "プレイリスト", + "term.play": "再生", + "term.pause": "停止", + "term.previous": "戻る", + "term.next": "次へ", + "term.shuffle": "シャッフル", + "term.repeat": "リピート", + "term.volume": "音量", + "term.mute": "ミュート", + "term.unmute": "ミュート解除", + "term.share": "共有", + "term.settings": "設定", + "term.seeAll": "全部表示", + // Home + "home.title": "ホーム", + "home.recentlyPlayed": "最近の再生", + "home.recentlyAdded": "最近追加した項目", + "home.artistsFeed": "アーティストのフィード", + "home.madeForYou": "あなたにおすすめ", + "home.friendsListeningTo": "友達が聴いている", + "home.followedArtists": "フォローしているアーティスト", + // Errors + "error.appleMusicSubRequired": "Apple Musicのサブスクリプションが必要です。", + // Actions + "action.addToLibrary": "ライブラリに追加", + "action.addToLibrary.success": "ライブラリに追加されました", + "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.follow": "フォロー", + "action.follow.success": "フォロー中", + "action.follow.error": "操作を完了できませんでした", + "action.unfollow": "フォロー解除", + "action.unfollow.success": "フォローをやめました", + "action.unfollow.error": "操作を完了できませんでした", + "action.playNext": "次に再生", + "action.playLater": "最後に再生", + "action.startRadio": "ステーションを作成", + "action.goToArtist": "アーティストへ移動", + "action.goToAlbum": "アルバムへ移動", + "action.share": "曲を共有", + "action.love": "ラブ", + "action.unlove": "ラブを解除", + "action.dislike": "これに似たものをすすめない", + "action.undoDislike": "「これと似た曲のおすすめを減らす」を取り消す", + // Settings + "settings.header.audio": "オーディオ", + "settings.header.audio.description": "Ciderのオーディオ設定", + "settings.header.audio.quality.high": "高品質", + "settings.header.audio.quality.low": "高効率", + "settings.header.audio.quality.auto": "自動", + "settings.header.visual": "ビジュアル", + "settings.header.visual.description": "Ciderのビジュアル設定", + "settings.header.general": "一般", + "settings.header.general.description": "Ciderの一般設定", + "settings.header.lyrics": "歌詞", + "settings.header.lyrics.description": "歌詞の表示設定", + "settings.header.connectivity": "アプリと連携", + "settings.header.connectivity.description": "Ciderの連携設定", + "settings.header.experimental": "試験的な機能", + "settings.header.experimental.description": "Ciderの試験的な機能", +} \ No newline at end of file diff --git a/src/i18n/zh_CN.jsonc b/src/i18n/zh_CN.jsonc new file mode 100644 index 00000000..d37e463f --- /dev/null +++ b/src/i18n/zh_CN.jsonc @@ -0,0 +1,95 @@ +{ + // App info + "app.name": "Cider", + // Dialogs + "dialog.cancel": "取消", + "dialog.ok": "确定", + // Terms + "term.appleMusic": "Apple Music", // Follows brand term + "term.applePodcasts": "Apple Podcasts", // Follows brand term + "term.itunes": "iTunes", // Follows brand term + "term.github": "GitHub", // Follows brand term + "term.discord": "Discord", // Follows brand term + "term.learnMore": "更多信息", + "term.accountSettings": "账户设置", + "term.logout": "登出", + "term.login": "登录", + "term.about": "关于", + "term.privateSession": "私人聆听", + "term.queue": "队列", + "term.search": "搜索", + "term.library": "音乐库", + "term.recentlyAdded": "最近添加", + "term.songs": "歌曲", + "term.albums": "专辑", + "term.artists": "歌手", + "term.podcasts": "播客", + "term.playlists": "播放列表", + "term.playlist": "播放列表", + "term.play": "播放", + "term.pause": "暂停", + "term.previous": "上一首", + "term.next": "下一首", + "term.shuffle": "随机播放", + "term.repeat": "重复播放", + "term.volume": "音量", + "term.mute": "静音", + "term.unmute": "解除静音", + "term.share": "分享", + "term.settings": "设置", + "term.seeAll": "查看全部", + // Home + "home.title": "主页", + "home.recentlyPlayed": "最近播放", + "home.recentlyAdded": "最近添加", + "home.artistsFeed": "您的歌手推荐", + "home.madeForYou": "为您量身定制", + "home.friendsListeningTo": "朋友正在听", + "home.followedArtists": "关注的歌手", + // Errors + "error.appleMusicSubRequired": "需要订阅Apple Music以使用Cider", + // Actions + "action.addToLibrary": "加入音乐库", + "action.addToLibrary.success": "成功加入音乐库", + "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.follow": "关注", + "action.follow.success": "已关注", + "action.follow.error": "尝试关注的过程发生了错误", + "action.unfollow": "取消关注", + "action.unfollow.success": "已取消关注", + "action.unfollow.error": "尝试取消关注的过程发生了错误", + "action.playNext": "下一首播放", + "action.playLater": "最后播放", + "action.startRadio": "开始电台", + "action.goToArtist": "前往歌手", + "action.goToAlbum": "前往专辑", + "action.share": "分享歌曲", + "action.love": "喜欢", + "action.unlove": "取消喜欢", + "action.dislike": "减少此类建议", + "action.undoDislike": "撤销减少此类建议", + // Settings + "settings.header.audio": "音频", + "settings.header.audio.description": "调整Cider的音质", + "settings.header.audio.quality.high": "高音质", + "settings.header.audio.quality.low": "高效率", + "settings.header.audio.quality.auto": "自动", + "settings.header.visual": "外观", + "settings.header.visual.description": "调整Cider的外观", + "settings.header.general": "通用", + "settings.header.general.description": "调整Cider的通用设置", + "settings.header.lyrics": "歌词", + "settings.header.lyrics.description": "调整Cider的歌词设置", + "settings.header.connectivity": "外部连接", + "settings.header.connectivity.description": "调整Cider与外部的连接", + "settings.header.experimental": "实验性功能", + "settings.header.experimental.description": "调整Cider的实验性功能", +} \ No newline at end of file diff --git a/src/i18n/zh_TW.jsonc b/src/i18n/zh_TW.jsonc new file mode 100644 index 00000000..d57fccb4 --- /dev/null +++ b/src/i18n/zh_TW.jsonc @@ -0,0 +1,95 @@ +{ + // App info + "app.name": "Cider", + // Dialogs + "dialog.cancel": "取消", + "dialog.ok": "OK", + // Terms + "term.appleMusic": "Apple Music", // Follows brand term + "term.applePodcasts": "Apple Podcasts", // Follows brand term + "term.itunes": "iTunes", // Follows brand term + "term.github": "GitHub", // Follows brand term + "term.discord": "Discord", // Follows brand term + "term.learnMore": "更多内容", + "term.accountSettings": "賬戶設定", + "term.logout": "登出", + "term.login": "登入", + "term.about": "關於", + "term.privateSession": "私人時段", + "term.queue": "待播清單", + "term.search": "搜尋", + "term.library": "資料庫", + "term.recentlyAdded": "最近加入", + "term.songs": "歌曲", + "term.albums": "專輯", + "term.artists": "藝人", + "term.podcasts": "Podcasts", + "term.playlists": "播放列表", + "term.playlist": "播放列表", + "term.play": "播放", + "term.pause": "暫停", + "term.previous": "上一首", + "term.next": "下一首", + "term.shuffle": "隨機播放", + "term.repeat": "重複播放", + "term.volume": "音量", + "term.mute": "靜音", + "term.unmute": "取消靜音", + "term.share": "分享", + "term.settings": "設定", + "term.seeAll": "顯示全部", + // Home + "home.title": "主頁", + "home.recentlyPlayed": "最近播放", + "home.recentlyAdded": "最近加入", + "home.artistsFeed": "藝人追蹤", + "home.madeForYou": "為您推薦", + "home.friendsListeningTo": "朋友正在聆聽", + "home.followedArtists": "追蹤的藝人", + // Errors + "error.appleMusicSubRequired": "需要訂閱Apple Music以使用Cider", + // Actions + "action.addToLibrary": "加入資料庫", + "action.addToLibrary.success": "成功加入資料庫", + "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.follow": "追蹤", + "action.follow.success": "追蹤中", + "action.follow.error": "追蹤的過程發生錯誤", + "action.unfollow": "取消追蹤", + "action.unfollow.success": "已取消追蹤", + "action.unfollow.error": "取消追蹤的過程發生錯誤", + "action.playNext": "插播", + "action.playLater": "最後播放", + "action.startRadio": "建立電台", + "action.goToArtist": "前往藝人", + "action.goToAlbum": "前往專輯", + "action.share": "分享歌曲", + "action.love": "喜愛", + "action.unlove": "取消喜愛", + "action.dislike": "減少此類建議", + "action.undoDislike": "還原減小此類建議", + // Settings + "settings.header.audio": "音訊", + "settings.header.audio.description": "調整Cider的音訊設定", + "settings.header.audio.quality.high": "高品質", + "settings.header.audio.quality.low": "高效率", + "settings.header.audio.quality.auto": "自動", + "settings.header.visual": "外觀", + "settings.header.visual.description": "調整Cider的外觀", + "settings.header.general": "一般", + "settings.header.general.description": "調整Cider的一般設定", + "settings.header.lyrics": "歌詞", + "settings.header.lyrics.description": "調整Cider的歌詞設定", + "settings.header.connectivity": "外部連接", + "settings.header.connectivity.description": "調整Cider與外部的連接", + "settings.header.experimental": "實驗性功能", + "settings.header.experimental.description": "調整Cider的實驗性功能", +} \ No newline at end of file diff --git a/src/main/base/app.ts b/src/main/base/app.ts index 235948e3..ade28ef5 100644 --- a/src/main/base/app.ts +++ b/src/main/base/app.ts @@ -9,7 +9,7 @@ export class AppEvents { "musics", "music" ] - + private static plugin: any = null; private static store: any = null; constructor(store: any) { @@ -88,27 +88,34 @@ export class AppEvents { }) } - electron.app.on('open-url', (event, url) => { - event.preventDefault() - if (this.protocols.some((protocol: string) => url.includes(protocol))) { - AppEvents.LinkHandler(url) - } - }) + } public quit() { console.log('App stopped'); } - public ready() { + public ready(plug: any) { + AppEvents.plugin = plug console.log('App ready'); } + public bwCreated(win: Electron.BrowserWindow) { + electron.app.on('open-url', (event, url) => { + event.preventDefault() + if (AppEvents.protocols.some((protocol: string) => url.includes(protocol))) { + AppEvents.LinkHandler(url, win) + } + }) + + AppEvents.InstanceHandler(win) + } + /*********************************************************************************************************************** * Private methods **********************************************************************************************************************/ - private static LinkHandler(arg: string) { + private static LinkHandler(arg: any, win: Electron.BrowserWindow) { if (!arg) return; // LastFM Auth URL @@ -118,8 +125,8 @@ export class AppEvents { const authKey = authURI.split('lastfm?token=')[1]; AppEvents.store.set('lastfm.enabled', true); AppEvents.store.set('lastfm.auth_token', authKey); - // AppEvents.window.webContents.send('LastfmAuthenticated', authKey); - // lastfm.authenticate() + win.webContents.send('LastfmAuthenticated', authKey); + AppEvents.plugin.callPlugin('lastfm', 'authenticate', authKey); } } // Play @@ -148,4 +155,28 @@ export class AppEvents { electron.ipcRenderer.send('play', 'url', url) } } + + private static InstanceHandler(win: Electron.BrowserWindow) { + + // Detects of an existing instance is running (So if the lock has been achieved, no existing instance has been found) + const gotTheLock = electron.app.requestSingleInstanceLock() + + if (!gotTheLock) { // Runs on the new instance if another instance has been found + console.log('[Cider] Another instance has been found, quitting.') + electron.app.quit() + } else { // Runs on the first instance if no other instance has been found + electron.app.on('second-instance', (_event, startArgs) => { + if (startArgs.includes("--force-quit")) { + console.warn('[InstanceHandler][SecondInstanceHandler] Force Quit found. Quitting App.'); + electron.app.quit() + } else if (startArgs.includes("cider://")) { + AppEvents.LinkHandler(startArgs, win) + } else if (win) { + if (win.isMinimized()) win.restore() + win.focus() + } + }) + } + + } } \ No newline at end of file diff --git a/src/main/base/plugins.ts b/src/main/base/plugins.ts index be87e89f..637f6bd2 100644 --- a/src/main/base/plugins.ts +++ b/src/main/base/plugins.ts @@ -34,6 +34,7 @@ export default class PluginHandler { fs.readdirSync(this.userPluginsPath).forEach(file => { if (file.endsWith('.ts') || file.endsWith('.js')) { const plugin = require(path.join(this.userPluginsPath, file)).default; + file = file.replace('.ts', '').replace('.js', ''); if (plugins[file] || plugin in plugins) { console.log(`[${plugin.name}] Plugin already loaded / Duplicate Class Name`); } else { @@ -54,4 +55,10 @@ export default class PluginHandler { } } + public callPlugin(plugin: string, event: string, ...args: any[]) { + if (this.pluginsList[plugin][event]) { + this.pluginsList[plugin][event](...args); + } + } + } diff --git a/src/main/base/win.ts b/src/main/base/win.ts index d3e49ffc..3e402329 100644 --- a/src/main/base/win.ts +++ b/src/main/base/win.ts @@ -8,7 +8,6 @@ import * as yt from "youtube-search-without-api-key"; import * as fs from "fs"; import { Stream } from "stream"; import * as qrcode from "qrcode-terminal"; -import * as qrcode2 from "qrcode"; import * as os from "os"; import {wsapi} from "./wsapi"; @@ -62,7 +61,6 @@ export class Win { sandbox: true, allowRunningInsecureContent: true, contextIsolation: false, - webviewTag: true, plugins: true, nodeIntegrationInWorker: false, @@ -74,7 +72,7 @@ export class Win { /** * Creates the browser window */ - async createWindow(): Promise { + async createWindow(): Promise { this.clientPort = await getPort({ port: 9000 }); this.verifyFiles(); @@ -91,9 +89,6 @@ export class Win { this.startWebServer(); this.win = new electron.BrowserWindow(this.options); - this.win.on("ready-to-show", () => { - this.win.show(); - }); const ws = new wsapi(this.win) ws.InitWebSockets() // and load the renderer. diff --git a/src/main/index.ts b/src/main/index.ts index 81687a57..cad03017 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,8 +1,8 @@ require('v8-compile-cache'); // Analytics for debugging fun yeah. -const ElectronSentry = require("@sentry/electron"); -ElectronSentry.init({dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214"}); +import * as sentry from '@sentry/electron'; +sentry.init({dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214"}); import * as electron from 'electron'; import {Win} from "./base/win"; @@ -10,18 +10,19 @@ import {ConfigStore} from "./base/store"; import {AppEvents} from "./base/app"; import PluginHandler from "./base/plugins"; -// const test = new PluginHandler(); const config = new ConfigStore(); const App = new AppEvents(config.store); const Cider = new Win(electron.app, config.store) const plug = new PluginHandler(); +let win: Electron.BrowserWindow; + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * App Event Handlers * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ electron.app.on('ready', () => { - App.ready(); + App.ready(plug); console.log('[Cider] Application is Ready. Creating Window.') if (!electron.app.isPackaged) { @@ -30,13 +31,13 @@ electron.app.on('ready', () => { } electron.components.whenReady().then(async () => { - await Cider.createWindow() - plug.callPlugins('onReady', Cider); - - - }) - - + win = await Cider.createWindow() + App.bwCreated(win); + win.on("ready-to-show", () => { + win.show(); + }); + }); + plug.callPlugins('onReady', win); }); /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -51,57 +52,31 @@ electron.ipcMain.on('nowPlayingItemDidChange', (event, attributes) => { plug.callPlugins('onNowPlayingItemDidChange', attributes); }); -// electron.app.on('before-quit', () => { plug.callPlugins('onBeforeQuit'); console.warn(`${electron.app.getName()} exited.`); }); -// -// // @ts-ignore -// // Widevine Stuff -// electron.app.on('widevine-ready', (version, lastVersion) => { -// if (null !== lastVersion) { -// console.log('[Cider][Widevine] Widevine ' + version + ', upgraded from ' + lastVersion + ', is ready to be used!') -// } else { -// console.log('[Cider][Widevine] Widevine ' + version + ' is ready to be used!') -// } -// }) -// // @ts-ignore -// electron.app.on('widevine-update-pending', (currentVersion, pendingVersion) => { -// console.log('[Cider][Widevine] Widevine ' + currentVersion + ' is ready to be upgraded to ' + pendingVersion + '!') -// }) +/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +* Widevine Event Handlers +* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ -// // @ts-ignore -// electron.app.on('widevine-error', (error) => { -// console.log('[Cider][Widevine] Widevine installation encountered an error: ' + error) -// electron.app.exit() -// }) - -// -// -// app.on('open-url', (event, url) => { -// event.preventDefault() -// if (url.includes('ame://') || url.includes('itms://') || url.includes('itmss://') || url.includes('musics://') || url.includes('music://')) { -// CiderBase.LinkHandler(url) -// } -// }) -// -electron.app.on('second-instance', (_e, argv) => { - console.warn(`[InstanceHandler][SecondInstanceHandler] Second Instance Started with args: [${argv.join(', ')}]`) - - // Checks if first instance is authorized and if second instance has protocol args - if (argv.includes("--force-quit")) { - console.warn('[InstanceHandler][SecondInstanceHandler] Force Quit found. Quitting App.'); - electron.app.quit() - } else if (Cider.win) { // If a Second Instance has Been Started - console.warn('[InstanceHandler][SecondInstanceHandler] Showing window.'); - Cider.win.show() - Cider.win.focus() +// @ts-ignore +electron.app.on('widevine-ready', (version, lastVersion) => { + if (null !== lastVersion) { + console.log('[Cider][Widevine] Widevine ' + version + ', upgraded from ' + lastVersion + ', is ready to be used!') + } else { + console.log('[Cider][Widevine] Widevine ' + version + ' is ready to be used!') } }) -if (!electron.app.requestSingleInstanceLock()) { - console.warn("[InstanceHandler] Existing Instance is Blocking Second Instance."); - electron.app.quit(); -} +// @ts-ignore +electron.app.on('widevine-update-pending', (currentVersion, pendingVersion) => { + console.log('[Cider][Widevine] Widevine ' + currentVersion + ' is ready to be upgraded to ' + pendingVersion + '!') +}) + +// @ts-ignore +electron.app.on('widevine-error', (error) => { + console.log('[Cider][Widevine] Widevine installation encountered an error: ' + error) + electron.app.exit() +}) diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index 1eccf2d6..78fdfa90 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -1,4 +1,3 @@ - import * as electron from 'electron'; import * as fs from 'fs'; import {resolve} from 'path'; @@ -10,12 +9,13 @@ export default class LastFMPlugin { key: "f9986d12aab5a0fe66193c559435ede3", secret: "acba3c29bd5973efa38cc2f0b63cc625" } - /** - * Private variables for interaction in plugins - */ - private _win: any; - private _app: any; + /** + * Private variables for interaction in plugins + */ + private _win: any; + private _app: any; private _lastfm: any; + private authenticateFromFile() { let sessionData = require(this.sessionPath) console.log("[LastFM][authenticateFromFile] Logging in with Session Info.") @@ -24,64 +24,64 @@ export default class LastFMPlugin { } - private authenticate() { - try{ - if (this._win.store.store.lastfm.auth_token) { - this._win.store.store.lastfm.enabled = true; - } - - if (!this._win.store.store.lastfm.enabled || !this._win.store.store.lastfm.auth_token) { - this._win.store.store.lastfm.enabled = false; - return - } - /// dont move this require to top , app wont load - const LastfmAPI = require('lastfmapi'); - const lfmAPI = new LastfmAPI({ - 'api_key': this.apiCredentials.key, - 'secret': this.apiCredentials.secret - }); - - this._lastfm = Object.assign(lfmAPI, {cachedAttributes: false, cachedNowPlayingAttributes: false}); - - fs.stat(this.sessionPath, (err : any) => { - if (err) { - console.error("[LastFM][Session] Session file couldn't be opened or doesn't exist,", err) - console.log("[LastFM][Auth] Beginning authentication from configuration") - console.log("[LastFM][tk]", this._win.store.store.lastfm.auth_token) - this._lastfm.authenticate(this._win.store.store.lastfm.auth_token, (err: any, session: any) => { - if (err) { - throw err; - } - console.log("[LastFM] Successfully obtained LastFM session info,", session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} - console.log("[LastFM] Saving session info to disk.") - let tempData = JSON.stringify(session) - fs.writeFile(this.sessionPath, tempData, (err: any) => { - if (err) - console.log("[LastFM][fs]", err) - else { - console.log("[LastFM][fs] File was written successfully.") - this.authenticateFromFile() - new electron.Notification({ - title: electron.app.getName(), - body: "Successfully logged into LastFM using Authentication Key." - }).show() - } - }) - }); - } else { - this.authenticateFromFile() + authenticate() { + try { + if (this._win.store.store.lastfm.auth_token) { + this._win.store.store.lastfm.enabled = true; } - }) + + if (!this._win.store.store.lastfm.enabled || !this._win.store.store.lastfm.auth_token) { + this._win.store.store.lastfm.enabled = false; + return + } + /// dont move this require to top , app wont load + const LastfmAPI = require('lastfmapi'); + const lfmAPI = new LastfmAPI({ + 'api_key': this.apiCredentials.key, + 'secret': this.apiCredentials.secret + }); + + this._lastfm = Object.assign(lfmAPI, {cachedAttributes: false, cachedNowPlayingAttributes: false}); + + fs.stat(this.sessionPath, (err: any) => { + if (err) { + console.error("[LastFM][Session] Session file couldn't be opened or doesn't exist,", err) + console.log("[LastFM][Auth] Beginning authentication from configuration") + console.log("[LastFM][tk]", this._win.store.store.lastfm.auth_token) + this._lastfm.authenticate(this._win.store.store.lastfm.auth_token, (err: any, session: any) => { + if (err) { + throw err; + } + console.log("[LastFM] Successfully obtained LastFM session info,", session); // {"name": "LASTFM_USERNAME", "key": "THE_USER_SESSION_KEY"} + console.log("[LastFM] Saving session info to disk.") + let tempData = JSON.stringify(session) + fs.writeFile(this.sessionPath, tempData, (err: any) => { + if (err) + console.log("[LastFM][fs]", err) + else { + console.log("[LastFM][fs] File was written successfully.") + this.authenticateFromFile() + new electron.Notification({ + title: electron.app.getName(), + body: "Successfully logged into LastFM using Authentication Key." + }).show() + } + }) + }); + } else { + this.authenticateFromFile() + } + }) } catch (err) { console.log(err) } } - private async scrobbleSong(attributes : any) { + private async scrobbleSong(attributes: any) { await new Promise(resolve => setTimeout(resolve, Math.round(attributes.durationInMillis * (this._win.store.store.lastfm.scrobble_after / 100)))); const currentAttributes = attributes; - - if (!this._lastfm || this._lastfm.cachedAttributes === attributes ) { + + if (!this._lastfm || this._lastfm.cachedAttributes === attributes) { return } @@ -112,11 +112,11 @@ export default class LastFMPlugin { this.authenticate(); } } else { - return console.log('[LastFM] Did not add ', attributes.name , '—' , this.filterArtistName(attributes.artistName), 'because now playing a other song.'); + return console.log('[LastFM] Did not add ', attributes.name, '—', this.filterArtistName(attributes.artistName), 'because now playing a other song.'); } } - private filterArtistName(artist :any) { + private filterArtistName(artist: any) { if (!this._win.store.store.lastfm.enabledRemoveFeaturingArtists) return artist; artist = artist.split(' '); @@ -134,8 +134,8 @@ export default class LastFMPlugin { return artist.charAt(0).toUpperCase() + artist.slice(1); } - private updateNowPlayingSong(attributes : any) { - if (!this._lastfm ||this._lastfm.cachedNowPlayingAttributes === attributes || !this._win.store.store.lastfm.NowPlaying) { + private updateNowPlayingSong(attributes: any) { + if (!this._lastfm || this._lastfm.cachedNowPlayingAttributes === attributes || !this._win.store.store.lastfm.NowPlaying) { return } @@ -147,20 +147,20 @@ export default class LastFMPlugin { // update Now Playing if (attributes.status === true) { this._lastfm.track.updateNowPlaying({ - 'artist': this.filterArtistName(attributes.artistName), - 'track': attributes.name, - 'album': attributes.albumName, - 'albumArtist': this.filterArtistName(attributes.artistName) - }, function (err : any, nowPlaying :any) { + 'artist': this.filterArtistName(attributes.artistName), + 'track': attributes.name, + 'album': attributes.albumName, + 'albumArtist': this.filterArtistName(attributes.artistName) + }, function (err: any, nowPlaying: any) { if (err) { return console.error('[LastFM] An error occurred while updating nowPlayingSong', err); } - console.log('[LastFM] Successfully updated nowPlayingSong', nowPlaying); + console.log('[LastFM] Successfully updated nowPlayingSong', nowPlaying); }); this._lastfm.cachedNowPlayingAttributes = attributes } - + } else { this.authenticate() } @@ -178,10 +178,10 @@ export default class LastFMPlugin { * Runs on plugin load (Currently run on application start) */ constructor(app: any) { - this._app = app; - electron.app.on('second-instance', (_e:any, argv:any) => { + this._app = app; + electron.app.on('second-instance', (_e: any, argv: any) => { // Checks if first instance is authorized and if second instance has protocol args - argv.forEach((value: any) => { + argv.forEach((value: any) => { if (value.includes('auth')) { console.log('[LastFMPlugin ok]') let authURI = String(argv).split('/auth/')[1]; @@ -193,10 +193,10 @@ export default class LastFMPlugin { this._win.win.webContents.send('LastfmAuthenticated', authKey); this.authenticate(); } - } + } }) }) - electron.app.on('open-url', (event :any, arg:any) => { + electron.app.on('open-url', (event: any, arg: any) => { console.log('[LastFMPlugin] yes') event.preventDefault(); if (arg.includes('auth')) { @@ -211,13 +211,13 @@ export default class LastFMPlugin { } } }) - } + } /** * Runs on app ready */ onReady(win: any): void { - this._win = win; + this._win = win; this.authenticate(); } diff --git a/src/renderer/AppHeader.svg b/src/renderer/AppHeader.svg index 485110ad..d6a7b723 100644 --- a/src/renderer/AppHeader.svg +++ b/src/renderer/AppHeader.svg @@ -1,29 +1,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + diff --git a/src/renderer/index.js b/src/renderer/index.js index 60e0943c..4f78d2db 100644 --- a/src/renderer/index.js +++ b/src/renderer/index.js @@ -3306,7 +3306,7 @@ const app = new Vue({ this.tmpWidth = window.innerWidth; this.tmpHeight = window.innerHeight; ipcRenderer.send('setFullScreen', false); - ipcRenderer.send('windowresize', 250, 250, false) + ipcRenderer.send('windowresize', 364, 364, false) app.appMode = 'mini'; } else { ipcRenderer.send('windowresize', this.tmpWidth, this.tmpHeight, false) diff --git a/src/renderer/style.less b/src/renderer/style.less index 51a80f93..2511b9fe 100644 --- a/src/renderer/style.less +++ b/src/renderer/style.less @@ -2493,8 +2493,8 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { position: sticky; top: 0; left: 0; - backdrop-filter: blur(16px) saturate(180%); - box-shadow: 0px 1px 0px rgba(185, 185, 185, 0.08); + backdrop-filter: blur(32px); + //box-shadow: 0px 1px 0px rgba(185, 185, 185, 0.08); mix-blend-mode: hard-light; .nav-item { @@ -2604,7 +2604,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { background: black; padding: 0px 2em; backdrop-filter: blur(32px); - background: rgba(24, 24, 24, 0.15); + background: rgba(0, 0, 0, 0.25); top: var(--navigationBarHeight); } @@ -2806,6 +2806,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { .playlist-body { padding: 0px var(--contentInnerPadding) 0px var(--contentInnerPadding); + margin-top: -75px; } .floating-header { @@ -2816,7 +2817,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { z-index: 6; padding: 0px 1em; backdrop-filter: blur(32px); - background: rgba(24, 24, 24, 0.15); + background: rgba(0, 0, 0, 0.25); top: var(--navigationBarHeight); transition: opacity 0.1s var(--appleEase); } @@ -2833,6 +2834,8 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { bottom: 0; right: 0; margin: 0; + margin-top: calc(var(--navigationBarHeight) * -1); + margin-bottom: -10px; padding: 0; -webkit-mask-image: radial-gradient(at top left, black, transparent 70%), radial-gradient(at top right, black, transparent 70%), linear-gradient(180deg, rgb(200 200 200), transparent 98%); opacity: .7; @@ -3062,7 +3065,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { z-index: 6; padding: 0px 1em; backdrop-filter: blur(32px); - background: rgba(24, 24, 24, 0.15); + background: rgba(0, 0, 0, 0.25); top: var(--navigationBarHeight); transition: opacity 0.1s var(--appleEase); } @@ -3104,8 +3107,8 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { .more-btn-round { position: absolute; - bottom: 26px; - right: 32px; + bottom: 84px; + right: 28px; } .animated { @@ -3137,6 +3140,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { width: 200px; height: 200px; margin: 32px; + margin-top: -5px; position: relative; .overlay-play { @@ -3173,9 +3177,10 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { } .artist-play { - width: 36px; - height: 36px; - background: var(--keyColor); + width: 32px; + height: 32px; + background: rgba(100, 100, 100, 0.5); + box-shadow: var(--ciderShadow-Generic); border-radius: 100%; box-shadow: var(--mediaItemShadow); display: none; @@ -3185,14 +3190,18 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { padding: 0px; &:hover { - background: var(--keyColor-rollover); + filter: brightness(125%); } &:active { - background: var(--keyColor-pressed); + filter: brightness(75%); + transform: scale(0.98); + transition: transform 0s var(--appleEase), box-shadow 0.2s var(--appleEase); } } .artist-title { + position: relative; + top: -19px; .artist-play { transform: translateY(3px); @@ -3215,7 +3224,7 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { .artist-body { padding: 0px var(--contentInnerPadding) 0px var(--contentInnerPadding); - margin-top: -48px; + margin-top: -137px; } .showmoreless { @@ -4754,7 +4763,6 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { .mini-view { width: 100%; height: 100%; - background: black; display: flex; justify-content: center; align-items: center; @@ -5005,7 +5013,8 @@ input[type="range"].web-slider.display--small::-webkit-slider-thumb { .controls-parents { width: 100%; position: absolute; - background: black; + background: #0000009e; + backdrop-filter: blur(10px); bottom: 0px; z-index: 3; opacity: 0; diff --git a/src/renderer/views/components/miniplayer.ejs b/src/renderer/views/components/miniplayer.ejs index 0d798608..bbfbf8c2 100644 --- a/src/renderer/views/components/miniplayer.ejs +++ b/src/renderer/views/components/miniplayer.ejs @@ -3,7 +3,7 @@
-
+ style="display: inline-block; -webkit-box-orient: horizontal; white-space: nowrap; margin-top: 0.25vh; overflow: hidden; margin-bottom: 5px;">
{{ app.mk.nowPlayingItem["attributes"]["artistName"] }} @@ -39,7 +39,7 @@
-

{{ app.convertToMins(app.getSongProgress()) }}

{{ app.convertToMins(app.mk.currentPlaybackDuration) }}

diff --git a/src/web-remote/cider-icon.png b/src/web-remote/cider-icon.png new file mode 100644 index 00000000..c552a3a9 Binary files /dev/null and b/src/web-remote/cider-icon.png differ diff --git a/src/web-remote/launch.png b/src/web-remote/launch.png new file mode 100644 index 00000000..8f14135e Binary files /dev/null and b/src/web-remote/launch.png differ