Merge pull request #998 from ciderapp/develop

Develop
This commit is contained in:
cryptofyre 2022-05-08 16:46:51 -05:00 committed by GitHub
commit 706e71a10d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
61 changed files with 1703 additions and 650 deletions

View file

@ -39,10 +39,10 @@
"@sentry/electron": "^3.0.7", "@sentry/electron": "^3.0.7",
"@sentry/integrations": "^6.19.6", "@sentry/integrations": "^6.19.6",
"adm-zip": "0.4.10", "adm-zip": "0.4.10",
"airtunes2": "git+https://github.com/vapormusic/node_airtunes2.git", "airtunes2": "git+https://github.com/vapormusic/node_airtunes2.git#hap",
"castv2-client": "^1.2.0", "castv2-client": "^1.2.0",
"chokidar": "^3.5.3", "chokidar": "^3.5.3",
"discord-rpc": "^4.0.1", "discord-auto-rpc": "^1.0.16",
"dns-js": "git+https://github.com/ciderapp/node-dns-js.git", "dns-js": "git+https://github.com/ciderapp/node-dns-js.git",
"ejs": "^3.1.6", "ejs": "^3.1.6",
"electron-fetch": "^1.7.4", "electron-fetch": "^1.7.4",
@ -82,7 +82,7 @@
"electron-builder-notarize-pkg": "^1.2.0", "electron-builder-notarize-pkg": "^1.2.0",
"electron-webpack": "^2.8.2", "electron-webpack": "^2.8.2",
"musickit-typescript": "^1.2.4", "musickit-typescript": "^1.2.4",
"typescript": "^4.6.3", "typescript": "^4.6.4",
"vue-devtools": "^5.1.4", "vue-devtools": "^5.1.4",
"webpack": "~5.72.0" "webpack": "~5.72.0"
}, },
@ -109,9 +109,9 @@
} }
], ],
"build": { "build": {
"electronVersion": "18.1.0", "electronVersion": "18.2.1",
"electronDownload": { "electronDownload": {
"version": "18.1.0+wvcus", "version": "18.2.1+wvcus",
"mirror": "https://github.com/castlabs/electron-releases/releases/download/v" "mirror": "https://github.com/castlabs/electron-releases/releases/download/v"
}, },
"appId": "cider", "appId": "cider",

View file

@ -297,5 +297,48 @@ Update 28/04/2022 21:45 UTC
* `settings.option.general.resumetabs.description`: Added for `en_US` * `settings.option.general.resumetabs.description`: Added for `en_US`
* `settings.option.general.resumetabs.dynamic`: Added for `en_US` * `settings.option.general.resumetabs.dynamic`: Added for `en_US`
* `settings.option.general.resumetabs.dynamic.description`: Added for `en_US` * `settings.option.general.resumetabs.dynamic.description`: Added for `en_US`
* `term.dynamic`: Added for `en_US`
Update 29/04/2022 00:00 UTC
* `menubar.options.about`: Added for `en_US`
* `menubar.options.settings`: Added for `en_US`
* `menubar.options.quit`: Added for `en_US`
* `menubar.options.view`: Added for `en_US`
* `menubar.options.reload`: Added for `en_US`
* `menubar.options.forcereload`: Added for `en_US`
* `menubar.options.toggledevtools`: Added for `en_US`
* `menubar.options.window`: Added for `en_US`
* `menubar.options.minimize`: Added for `en_US`
* `menubar.options.toggleprivate`: Added for `en_US`
* `menubar.options.webremote`: Added for `en_US`
* `menubar.options.audio`: Added for `en_US`
* `menubar.options.plugins`: Added for `en_US`
* `menubar.options.control`: Added for `en_US`
* `menubar.options.next`: "Added for `en_US`
* `menubar.options.previous`: Added for `en_US`
* `menubar.options.volumeup`: Added for `en_US`
* `menubar.options.volumedown`: Added for `en_US`
* `menubar.options.browse`: Added for `en_US`
* `menubar.options.artists`: Added for `en_US`
* `menubar.options.search`: Added for `en_US`
* `menubar.options.albums`: Added for `en_US`
* `menubar.options.cast`: Added for `en_US`
* `menubar.options.account`: Added for `en_US`
* `menubar.options.accountsettings`: Added for `en_US`
* `menubar.options.signout`: Added for `en_US`
* `menubar.options.support`: Added for `en_US`
* `menubar.options.discord`: Added for `en_US`
* `menubar.options.github`: Added for `en_US`
* `menubar.options.report`: Added for `en_US`
* `menubar.options.bug`: Added for `en_US`
* `menubar.options.feature`: Added for `en_US`
* `menubar.options.trans`: Added for `en_US`
* `menubar.options.license`: Added for `en_US`
* `menubar.options.conf`: Added for `en_US`
Update 08/05/2022 00:29 UTC
* `settings.option.visual.theme.github.available`: Added for `en_US`,
* `settings.option.visual.theme.github.applied`: Added for `en_US`,

View file

@ -10,6 +10,7 @@
"notification.updatingLibrarySongs": "Ενημέρωση βιβλιοθήκης τραγουδιών...", "notification.updatingLibrarySongs": "Ενημέρωση βιβλιοθήκης τραγουδιών...",
"notification.updatingLibraryAlbums": "Ενημέρωση βιβλιοθήκης άλμπουμ...", "notification.updatingLibraryAlbums": "Ενημέρωση βιβλιοθήκης άλμπουμ...",
"notification.updatingLibraryArtists": "Ενημέρωση βιβλιοθήκης καλλιτεχνών...", "notification.updatingLibraryArtists": "Ενημέρωση βιβλιοθήκης καλλιτεχνών...",
"term.variables": "Μεταβλητές",
"term.appleInc": "Apple Inc.", "term.appleInc": "Apple Inc.",
"term.appleMusic": "Apple Music", "term.appleMusic": "Apple Music",
"term.applePodcasts": "Apple Podcasts", "term.applePodcasts": "Apple Podcasts",
@ -20,9 +21,13 @@
"term.accountSettings": "Ρυθμίσεις λογαριασμού", "term.accountSettings": "Ρυθμίσεις λογαριασμού",
"term.logout": "Αποσύνδεση", "term.logout": "Αποσύνδεση",
"term.login": "Σύνδεση", "term.login": "Σύνδεση",
"term.cast": "Μετάδοση",
"term.about": "Σχετικά με", "term.about": "Σχετικά με",
"term.privateSession": "Ιδιωτική περίοδος λειτουργίας", "term.privateSession": "Ιδιωτική περίοδος λειτουργίας",
"term.disablePrivateSession": "Απενεργ. ιδιωτικής περ. λειτουργίας",
"term.queue": "Ουρά", "term.queue": "Ουρά",
"term.lyrics": "Στίχοι",
"term.miniplayer": "MiniPlayer",
"term.history": "Ιστορικό", "term.history": "Ιστορικό",
"term.search": "Εύρεση", "term.search": "Εύρεση",
"term.library": "Βιβλιοθήκη", "term.library": "Βιβλιοθήκη",
@ -68,6 +73,7 @@
"term.viewAs": "Προβολή ως", "term.viewAs": "Προβολή ως",
"term.viewAs.coverArt": "Εξώφυλλο", "term.viewAs.coverArt": "Εξώφυλλο",
"term.viewAs.list": "Λίστα", "term.viewAs.list": "Λίστα",
"term.dynamic": "Δυναμικό",
"term.size": "Μέγεθος", "term.size": "Μέγεθος",
"term.size.normal": "Κανονικό", "term.size.normal": "Κανονικό",
"term.size.compact": "Συμπαγή", "term.size.compact": "Συμπαγή",
@ -89,12 +95,26 @@
"term.time.added": "Προστέθηκε", "term.time.added": "Προστέθηκε",
"term.time.released": "Κυκλοφόρησε", "term.time.released": "Κυκλοφόρησε",
"term.time.updated": "Ενημερώθηκε", "term.time.updated": "Ενημερώθηκε",
"term.time.days": "μέρες",
"term.time.day": {
"one": "μέρα",
"other": "μέρες"
},
"term.time.hours": "ώρες", "term.time.hours": "ώρες",
"term.time.hour": "ώρα", "term.time.hour": {
"one": "ώρα",
"other": "ώρες"
},
"term.time.minutes": "λεπτά", "term.time.minutes": "λεπτά",
"term.time.minute": "λεπτό", "term.time.minute": {
"one": "λεπτό",
"other": "λεπτά"
},
"term.time.seconds": "δευτερόλεπτα", "term.time.seconds": "δευτερόλεπτα",
"term.time.second": "δευτερόλεπτο", "term.time.second": {
"one": "δευτερόλεπτο",
"other": "δευτερόλεπτα"
},
"term.fullscreenView": "Πλήρης οθόνη", "term.fullscreenView": "Πλήρης οθόνη",
"term.defaultView": "Κανονική οθόνη", "term.defaultView": "Κανονική οθόνη",
"term.audioSettings": "Ρυθμίσεις ήχου", "term.audioSettings": "Ρυθμίσεις ήχου",
@ -114,7 +134,8 @@
"term.contributors": "Συνεισφέροντες", "term.contributors": "Συνεισφέροντες",
"term.equalizer": "Ισοσταθμιστής", "term.equalizer": "Ισοσταθμιστής",
"term.reset": "Επαναφορά", "term.reset": "Επαναφορά",
"term.tracks": { "term.tracks": "τραγούδια",
"term.track": {
"one": "τραγούδι", "one": "τραγούδι",
"other": "τραγούδια" "other": "τραγούδια"
}, },
@ -145,6 +166,7 @@
"term.noVideos": "Δεν βρέθηκαν βίντεο", "term.noVideos": "Δεν βρέθηκαν βίντεο",
"term.plugin": "Πρόσθετα", "term.plugin": "Πρόσθετα",
"term.pluginMenu": "Μενού πρόσθετων", "term.pluginMenu": "Μενού πρόσθετων",
"term.pluginMenu.none": "Δεν υπάρχουν πρόσθετα",
"term.replay": "Replay", "term.replay": "Replay",
"term.uniqueAlbums": "Μοναδικά άλμπουμ", "term.uniqueAlbums": "Μοναδικά άλμπουμ",
"term.uniqueArtists": "Μοναδικοί καλλιτέχνες", "term.uniqueArtists": "Μοναδικοί καλλιτέχνες",
@ -156,10 +178,12 @@
"term.plays": "Αναπαραγωγές", "term.plays": "Αναπαραγωγές",
"term.topGenres": "Κορυφαία είδη", "term.topGenres": "Κορυφαία είδη",
"term.confirmLogout": "Θέλετε σίγουρα να αποσυνδεθείτε;", "term.confirmLogout": "Θέλετε σίγουρα να αποσυνδεθείτε;",
"term.creditDesignedBy": "Σχεδιάστηκε από ${authorUsername}",
"term.discNumber": "Δίσκος ${discNumber}",
"home.title": "Αρχική", "home.title": "Αρχική",
"home.recentlyPlayed": "Έπαιξαν πρόσφατα", "home.recentlyPlayed": "Έπαιξαν πρόσφατα",
"home.recentlyAdded": "Πρόσφατες προσθήκες", "home.recentlyAdded": "Πρόσφατες προσθήκες",
"home.artistsFeed": "Ροή των καλλιτεχνών σου", "home.artistsFeed": "Ροή των καλλιτεχνών σας",
"home.artistsFeed.noArtist": "Ακολούθησε μερικούς καλλιτέχνες πρώτα και οι τελευταίες κυκλοφορίες τους θα εμφανίζονται εδώ", "home.artistsFeed.noArtist": "Ακολούθησε μερικούς καλλιτέχνες πρώτα και οι τελευταίες κυκλοφορίες τους θα εμφανίζονται εδώ",
"home.madeForYou": "Δημιουργήθηκε για εσάς", "home.madeForYou": "Δημιουργήθηκε για εσάς",
"home.friendsListeningTo": "Οι φίλοι σου ακούν", "home.friendsListeningTo": "Οι φίλοι σου ακούν",
@ -176,6 +200,9 @@
"podcast.episodes": "Επεισόδια", "podcast.episodes": "Επεισόδια",
"podcast.playEpisode": "Αναπαραγωγή επεισοδίου", "podcast.playEpisode": "Αναπαραγωγή επεισοδίου",
"podcast.website": "Ιστότοπος Podcast", "podcast.website": "Ιστότοπος Podcast",
"action.edit": "Επεξεργασία",
"action.done": "Τέλος",
"action.editTracklist": "Επεξεργασία λίστας τραγουδιών",
"action.addToLibrary": "Προσθήκη στη βιβλιοθήκη", "action.addToLibrary": "Προσθήκη στη βιβλιοθήκη",
"action.addToLibrary.success": "Προστέθηκε στη βιβλιοθήκη", "action.addToLibrary.success": "Προστέθηκε στη βιβλιοθήκη",
"action.addToLibrary.error": "Σφάλμα Προσθήκης στη βιβλιοθήκης", "action.addToLibrary.error": "Σφάλμα Προσθήκης στη βιβλιοθήκης",
@ -202,6 +229,8 @@
"action.startRadio": "Έναρξη ραδιοφώνου", "action.startRadio": "Έναρξη ραδιοφώνου",
"action.goToArtist": "Μετάβαση σε καλλιτέχνη", "action.goToArtist": "Μετάβαση σε καλλιτέχνη",
"action.goToAlbum": "Μετάβαση σε άλμπουμ", "action.goToAlbum": "Μετάβαση σε άλμπουμ",
"action.showInPlaylist": "Εμφάνιση στη λίστα αναπαραγωγής",
"action.showInAppleMusic": "Εμφάνιση στο Apple Music",
"action.moveToTop": "Μετακίνηση στη κορυφή", "action.moveToTop": "Μετακίνηση στη κορυφή",
"action.share": "Κοινή χρήση", "action.share": "Κοινή χρήση",
"action.rename": "Μετονομασία", "action.rename": "Μετονομασία",
@ -209,7 +238,7 @@
"action.unlove": "Αναίρεση \"Μου αρέσει\"", "action.unlove": "Αναίρεση \"Μου αρέσει\"",
"action.dislike": "Δεν μου αρέσει", "action.dislike": "Δεν μου αρέσει",
"action.undoDislike": "Αναίρεση \"Δεν μου αρέσει\"", "action.undoDislike": "Αναίρεση \"Δεν μου αρέσει\"",
"action.showWebRemoteQR": "Εμφάνιση Web Remote QR", "action.showWebRemoteQR": "Web Remote",
"action.playTracksNext": "Αναπαραγωγή ${app.selectedMediaItems.length} τραγουδιών ως επόμενων", "action.playTracksNext": "Αναπαραγωγή ${app.selectedMediaItems.length} τραγουδιών ως επόμενων",
"action.playTracksLater": "Αναπαραγωγή ${app.selectedMediaItems.length} τραγουδιών αργότερα", "action.playTracksLater": "Αναπαραγωγή ${app.selectedMediaItems.length} τραγουδιών αργότερα",
"action.removeTracks": "Αφαίρεση ${self.selectedItems.length} τραγουδιών από την ουρά", "action.removeTracks": "Αφαίρεση ${self.selectedItems.length} τραγουδιών από την ουρά",
@ -218,13 +247,23 @@
"action.showAlbum": "Εμφάνιση ολόκληρου άλμπουμ", "action.showAlbum": "Εμφάνιση ολόκληρου άλμπουμ",
"action.tray.minimize": "Ελαχιστοποίηση στη γωνία γραμμής εργασιών", "action.tray.minimize": "Ελαχιστοποίηση στη γωνία γραμμής εργασιών",
"action.tray.quit": "Έξοδος", "action.tray.quit": "Έξοδος",
"action.tray.show": "Εμφάνιση Cider",
"action.update": "Ενημέρωση", "action.update": "Ενημέρωση",
"action.install": "Εγκατάσταση", "action.install": "Εγκατάσταση",
"action.copy": "Αντιγραφή", "action.copy": "Αντιγραφή",
"action.newpreset": "Νέα προρύθμιση...", "action.newpreset": "Νέα προρύθμιση...",
"action.deletepreset": "Διαγραφή προρύθμισης", "action.deletepreset": "Διαγραφή προρύθμισης",
"action.open": "Άνοιγμα", "action.open": "Άνοιγμα",
"action.relaunch.confirm": "Θέλετε να επανεκκινήσετε τον Cider;",
"action.cast.chromecast": "Chromecast",
"action.cast.todevices": "Μετάδοση σε συσκευές",
"action.cast.stop": "Διακοπή μετάδοσης σε όλες τις συσκευές",
"action.cast.airplay": "AirPlay",
"action.cast.airplay.underdevelopment": "Το AirPlay είναι ακόμη υπό ανάπτυξη",
"action.cast.scan": "Σάρωση",
"action.cast.scanning": "Γίνεται σάρωση...",
"action.createNew": "Δημιουργία νέας...",
"action.openArtworkInBrowser": "Άνοιγμα εξώφυλλου στον περιηγητή",
"settings.header.general": "Γενικά", "settings.header.general": "Γενικά",
"settings.header.general.description": "Προσαρμογή γενικών ρυθμίσεων για το Cider.", "settings.header.general.description": "Προσαρμογή γενικών ρυθμίσεων για το Cider.",
"settings.option.general.language": "Γλώσσα", "settings.option.general.language": "Γλώσσα",
@ -234,6 +273,10 @@
"settings.option.general.resumebehavior.locally.description": "Το Cider θα συνεχίσει την τελευταία συνεδρία σας αυτής της συσκευής.", "settings.option.general.resumebehavior.locally.description": "Το Cider θα συνεχίσει την τελευταία συνεδρία σας αυτής της συσκευής.",
"settings.option.general.resumebehavior.history": "Ιστορικό", "settings.option.general.resumebehavior.history": "Ιστορικό",
"settings.option.general.resumebehavior.history.description": "Το Cider θα βάλει στην ουρά το τελευταίο τραγούδι από το συνολικό ιστορικό Apple Music, όλων των συσκευών σας.", "settings.option.general.resumebehavior.history.description": "Το Cider θα βάλει στην ουρά το τελευταίο τραγούδι από το συνολικό ιστορικό Apple Music, όλων των συσκευών σας.",
"settings.option.general.resumetabs": "Άνοιγμα καρτέλας στην εκκίνηση",
"settings.option.general.resumetabs.description": "Μπορείτε να επιλέξετε ποια καρτέλα θα εμφανίζεται όταν ανοίγετε τον Cider.",
"settings.option.general.resumetabs.dynamic": "Δυναμικό",
"settings.option.general.resumetabs.dynamic.description": "Ο Cider θα ανοίγει την καρτέλα που χρησιμοποιήσατε τελευταία.",
"settings.option.general.language.main": "Γλώσσες", "settings.option.general.language.main": "Γλώσσες",
"settings.option.general.language.fun": "Γλώσσες για πλάκα", "settings.option.general.language.fun": "Γλώσσες για πλάκα",
"settings.option.general.language.unsorted": "Αταξινόμητες", "settings.option.general.language.unsorted": "Αταξινόμητες",
@ -242,10 +285,34 @@
"settings.option.general.updateCider.branch.description": "Επιλέξτε τον κλάδο στον οποίο θα γίνεται η ενημέρωση του Cider", "settings.option.general.updateCider.branch.description": "Επιλέξτε τον κλάδο στον οποίο θα γίνεται η ενημέρωση του Cider",
"settings.option.general.updateCider.branch.main": "Σταθερό", "settings.option.general.updateCider.branch.main": "Σταθερό",
"settings.option.general.updateCider.branch.develop": "Αναπτυξιακό", "settings.option.general.updateCider.branch.develop": "Αναπτυξιακό",
"settings.option.general.customizeSidebar": "Προσαρμογή στοιχείων πλευρικής μπάρας",
"settings.option.general.customizeSidebar.customize": "Προσαρμογή",
"settings.option.general.keybindings": "Συνδυασμοί πλήκτρων",
"settings.notyf.general.keybindings.update.success": "Ο συνδιασμός ενημερώθηκε με επιτυχία",
"settings.prompt.general.keybindings.update.success": "Ο συνδιασμός ενημερώθηκε με επιτυχία. Πατήστε ΟΚ για επανεκκίνηση του Cider",
"settings.option.general.keybindings.open": "Άνοιγμα",
"settings.description.search": "Αναζήτηση",
"settings.description.albums": "Άλμπουμ βιβλιοθήκης",
"settings.description.artists": "Καλλιτέχνες βιβλιοθήκης",
"settings.description.browse": "Περιήγηση",
"settings.description.private": "Εναλλαγή ιδιωτικής περιόδου λειτουργίας",
"settings.description.remote": "Web Remote",
"settings.description.audio": "Ρυθμίσεις ήχου",
"settings.description.plugins": "Μενού πρόσθετων",
"settings.description.cast": "Μετάδοση σε συσκευές",
"settings.description.settings": "Ρυθμίσεις",
"settings.description.developer": "Εργαλεία προγραμματιστή",
"settings.notyf.updateCider.update-not-available": "Δεν υπάρχει διαθέσιμη ενημέρωση",
"settings.notyf.updateCider.update-downloaded": "Έγινε λήψη της ενημέρωσης, επανεκκίνησε για εφαρμογή",
"settings.notyf.updateCider.update-error": "Σφάλμα ενημέρωσης του Cider",
"settings.notyf.updateCider.update-timeout": "Λήξη χρόνου ενημέρωσης",
"settings.header.audio": "Ήχος", "settings.header.audio": "Ήχος",
"settings.header.audio.description": "Προσαρμογή ρυθμίσεων ήχου για το Cider.", "settings.header.audio.description": "Προσαρμογή ρυθμίσεων ήχου για το Cider.",
"settings.option.audio.volumeStep": "Βήματα έντασης", "settings.option.audio.volumeStep": "Βήματα έντασης",
"settings.option.audio.maxVolume": "Μέγιστη ένταση", "settings.option.audio.maxVolume": "Μέγιστη ένταση",
"settings.option.audio.changePlaybackRate": "Αλλαγή ταχύτητας αναπαραγωγής",
"settings.option.audio.playbackRate": "Ταχύτητα αναπαραγωγής",
"settings.option.audio.playbackRate.change": "Αλλαγή",
"settings.option.audio.quality": "Ποιότητα ήχου", "settings.option.audio.quality": "Ποιότητα ήχου",
"settings.header.audio.quality.hireslossless": "Lossless υψηλής ανάλυσης", "settings.header.audio.quality.hireslossless": "Lossless υψηλής ανάλυσης",
"settings.header.audio.quality.hireslossless.description": "έως και 24-bit/192 kHz", "settings.header.audio.quality.hireslossless.description": "έως και 24-bit/192 kHz",
@ -258,18 +325,34 @@
"settings.option.audio.seamlessTransition": "Αδιάκοπη μετάβαση ήχου", "settings.option.audio.seamlessTransition": "Αδιάκοπη μετάβαση ήχου",
"settings.option.audio.enableAdvancedFunctionality": "Ενεργοποίηση προηγμένης λειτουργικότητας", "settings.option.audio.enableAdvancedFunctionality": "Ενεργοποίηση προηγμένης λειτουργικότητας",
"settings.option.audio.enableAdvancedFunctionality.description": "Ενεργοποιώντας τη λειτουργικότητα AudioContext θα επιτρέψει σε επεκταμένες δυνατότητες ήχου όπως Κανονικοποίηση Έντασης Ήχου, Ισοσταθμιστές και Οπτικοποιητές, ωστόσο σε κάποια συστήματα μπορεί να προκαλέσει τραύλισμα ήχου.", "settings.option.audio.enableAdvancedFunctionality.description": "Ενεργοποιώντας τη λειτουργικότητα AudioContext θα επιτρέψει σε επεκταμένες δυνατότητες ήχου όπως Κανονικοποίηση Έντασης Ήχου, Ισοσταθμιστές και Οπτικοποιητές, ωστόσο σε κάποια συστήματα μπορεί να προκαλέσει τραύλισμα ήχου.",
"settings.warn.audio.enableAdvancedFunctionality.lowcores": "Η συσκευή σου ίσως να μη μπορέσει να χειρηστεί αυτές τις δυνατότητες. Σίγουρα θέλετε να συνεχίσετε;",
"settings.option.audio.audioLab": "Cider Audio Lab", "settings.option.audio.audioLab": "Cider Audio Lab",
"settings.option.audio.audioLab.description": "Περιέχει μια ποικιλία από τροποποιήσεις ήχου που έγιναν από την ομάδα προγραμματιστών του Cider", "settings.option.audio.audioLab.description": "Μια ποικιλία τροποποιήσεων ήχου από την ομάδα προγραμματιστών του Cider.",
"settings.option.audio.audioLab.subheader": "Σχεδιάστηκε από τους προγραμματιστές του Cider",
"settings.warn.audioLab.withoutAF": "Το AudioContext (προηγμένη λειτουργικότητα) απαιτείται για την ενεργοποίηση του Cider Audio Laboratory.", "settings.warn.audioLab.withoutAF": "Το AudioContext (προηγμένη λειτουργικότητα) απαιτείται για την ενεργοποίηση του Cider Audio Laboratory.",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Ένταση Analog Warmth", "settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Αναλογική ζεστασιά",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description": "Αλλάζει την ένταση της επεξεργασίας του Analog Warmth Module.", "settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Προσομοιώνει την αναλογική ζεστασιά του Korg Nutube 6P1",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Ένταση αναλογικής ζεστασιάς",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description": "Αλλάζει την ένταση της επεξεργασίας της αναλογικής ζεστασιάς.",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.smooth": "Λείο",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.warm": "Θερμό",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer": "Ατμόσφαιρα ήχου",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description": "Εφαρμόζει μια διαφορετική ατμόσφαιρα στον ήχο.",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode": "Λειτουργία ατμόσφαιρας ήχου",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description": "Αλλάζει τη λειτουργία ατμόσφαιρας ήχου.",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural1": "Φυσική (Κανονικό)",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural2": "Φυσική (Υψηλό)",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural3": "Φυσική (Υψηλότερο)",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Επεξεργαστής ήχου Cider (CAP)",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "Βελτιώνει την αντιληπτή ποιότητα ήχου χρησιμοποιώντας αλγορίθμους.",
"settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility": "Το CAP δεν είναι συμβατό με τη Χωρικοποίηση Ήχου. Παρακαλούμε απενεργοποιήστε τη Χωρικοποίηση Ήχου για να συνεχίσετε.", "settings.warn.audio.enableAdvancedFunctionality.ciderPPE.compatibility": "Το CAP δεν είναι συμβατό με τη Χωρικοποίηση Ήχου. Παρακαλούμε απενεργοποιήστε τη Χωρικοποίηση Ήχου για να συνεχίσετε.",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "Ένταση CAP", "settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "Ένταση CAP",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "Αλλάζει την ένταση της επεξεργασίας του ήχου. (Η επιθετική επεξεργασία μπορεί να αποφέρει ανεπιθύμητα αποτελέσματα)", "settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "Αλλάζει την ένταση της επεξεργασίας του ήχου. (Η επιθετική επεξεργασία μπορεί να αποφέρει ανεπιθύμητα αποτελέσματα)",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "Κανονική", "settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "Κανονική",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "Επιθετική", "settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "Επιθετική",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "Κανονικοποίηση Έντασης Ήχου", "settings.option.audio.enableAdvancedFunctionality.audioNormalization": "Κανονικοποίηση έντασης ήχου",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "Κανονικοποιεί την ένταση για μεμονωμένα κομμάτια για μια πιο ομοιόμορφη εμπειρία ακρόασης.", "settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "Κανονικοποιεί την ένταση για μεμονωμένα κομμάτια για μια πιο ομοιόμορφη εμπειρία ακρόασης. (Δεν λειτουργεί σε κομμάτια που ανέβηκαν από χρήστες)",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.disabled": "Διαχειρίζεται από το Audio Lab",
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "Χωρικοποίηση Ήχου", "settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "Χωρικοποίηση Ήχου",
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description": "Πιο τρισδιάστατος και χωρικοποιημένος ήχος (σημείωση: Αυτό δεν είναι Dolby Atmos)", "settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description": "Πιο τρισδιάστατος και χωρικοποιημένος ήχος (σημείωση: Αυτό δεν είναι Dolby Atmos)",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization": "Χωρικοποίηση Cider", "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization": "Χωρικοποίηση Cider",
@ -281,15 +364,16 @@
"settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "Η Χωρικοποίηση δεν είναι συμβατή με το CAP. Παρακαλούμε απενεργοποιήστε το CAP για να συνεχίσετε.", "settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "Η Χωρικοποίηση δεν είναι συμβατή με το CAP. Παρακαλούμε απενεργοποιήστε το CAP για να συνεχίσετε.",
"settings.header.visual": "Οπτικά", "settings.header.visual": "Οπτικά",
"settings.header.visual.description": "Προσαρμογή οπτικών ρυθμίσεων για το Cider.", "settings.header.visual.description": "Προσαρμογή οπτικών ρυθμίσεων για το Cider.",
"settings.option.visual.windowBackgroundStyle": "Στυλ Φόντου Παραθύρου", "settings.option.visual.windowStyle": "Στυλ παραθύρου",
"settings.option.visual.windowBackgroundStyle": "Στυλ φόντου παραθύρου",
"settings.header.visual.windowBackgroundStyle.none": "Κανένα", "settings.header.visual.windowBackgroundStyle.none": "Κανένα",
"settings.header.visual.windowBackgroundStyle.artwork": "Εξώφυλλο", "settings.header.visual.windowBackgroundStyle.artwork": "Εξώφυλλο",
"settings.header.visual.windowBackgroundStyle.image": "Εικόνα", "settings.header.visual.windowBackgroundStyle.image": "Εικόνα",
"settings.option.visual.animatedArtwork": "Κινούμενο Εξώφυλλο", "settings.option.visual.animatedArtwork": "Κινούμενο εξώφυλλο",
"settings.header.visual.animatedArtwork.always": "Πάντα", "settings.header.visual.animatedArtwork.always": "Πάντα",
"settings.header.visual.animatedArtwork.limited": "Περιορισμός σε σελίδες και ειδικές καταχωρήσεις", "settings.header.visual.animatedArtwork.limited": "Περιορισμός σε σελίδες και ειδικές καταχωρήσεις",
"settings.header.visual.animatedArtwork.disable": "Απενεργοποιημένο παντού", "settings.header.visual.animatedArtwork.disable": "Απενεργοποιημένο παντού",
"settings.option.visual.animatedArtworkQuality": "Ποιότητα Κινούμενου Εξωφύλλου", "settings.option.visual.animatedArtworkQuality": "Ποιότητα κινούμενου εξωφύλλου",
"settings.header.visual.animatedArtworkQuality.low": "Χαμηλή", "settings.header.visual.animatedArtworkQuality.low": "Χαμηλή",
"settings.header.visual.animatedArtworkQuality.medium": "Μέτρια", "settings.header.visual.animatedArtworkQuality.medium": "Μέτρια",
"settings.header.visual.animatedArtworkQuality.high": "Υψηλή", "settings.header.visual.animatedArtworkQuality.high": "Υψηλή",
@ -300,30 +384,52 @@
"settings.option.visual.hardwareAcceleration.description": "Απαιτεί επανεκκίνηση", "settings.option.visual.hardwareAcceleration.description": "Απαιτεί επανεκκίνηση",
"settings.header.visual.hardwareAcceleration.default": "Προεπιλογή", "settings.header.visual.hardwareAcceleration.default": "Προεπιλογή",
"settings.header.visual.hardwareAcceleration.webGPU": "WebGPU", "settings.header.visual.hardwareAcceleration.webGPU": "WebGPU",
"settings.option.visual.uiscale": "Κλίμακα διεπαφής χρήστη",
"settings.header.visual.theme": "Θέμα", "settings.header.visual.theme": "Θέμα",
"settings.option.visual.theme.github.download": "Εγκατάσταση από σύνδεσμο GitHub", "settings.option.visual.theme.github.download": "Εγκατάσταση από σύνδεσμο GitHub",
"settings.option.visual.theme.github.openfolder": "Άνοιγμα φακέλου θεμάτων",
"settings.option.visual.theme.github.explore": "Εξερεύνηση θεμάτων GitHub", "settings.option.visual.theme.github.explore": "Εξερεύνηση θεμάτων GitHub",
"settings.header.visual.theme.github.page": "Θέματα από το GitHub", "settings.header.visual.theme.github.page": "Θέματα από το GitHub",
"settings.option.visual.theme.github.install.confirm": "Θέλετε σίγουρα να εγκαταστήσετε το θέμα {{ repo }};", "settings.option.visual.theme.github.install.confirm": "Θέλετε σίγουρα να εγκαταστήσετε το θέμα {{ repo }};",
"settings.prompt.visual.theme.github.URL": "Εισάγετε τον σύνδεσμο του θέματος που θέλετε να εγκαταστήσετε", "settings.prompt.visual.theme.github.URL": "Εισάγετε τον σύνδεσμο του θέματος που θέλετε να εγκαταστήσετε",
"settings.notyf.visual.theme.install.success": "Το θέμα εγκαταστάθηκε με επιτυχία", "settings.notyf.visual.theme.install.success": "Το θέμα εγκαταστάθηκε με επιτυχία",
"settings.notyf.visual.theme.install.error": "Αποτυχία εγκατάστασης του θέματος", "settings.notyf.visual.theme.install.error": "Αποτυχία εγκατάστασης του θέματος",
"settings.header.visual.plugin": "Πρόσθετο",
"settings.option.visual.plugin.github.download": "Εγκατάσταση από σύνδεσμο GitHub",
"settings.option.visual.plugin.github.explore": "Εξερεύνηση πρόσθετων GitHub",
"settings.header.visual.plugin.github.page": "Πρόσθετα από το GitHub",
"settings.option.visual.plugin.github.install.confirm": "Θέλετε σίγουρα να εγκαταστήσετε το πρόσθετο {{ repo }};",
"settings.prompt.visual.plugin.github.URL": "Εισάγετε τον σύνδεσμο του πρόσθετου που θέλετε να εγκαταστήσετε",
"settings.prompt.visual.plugin.github.success": "Το πρόσθετο εγκαταστάθηκε με επιτυχία, πατήστε ΟΚ για επανεκκίνηση του Cider",
"settings.notyf.visual.plugin.install.success": "Το πρόσθετο εγκαταστάθηκε με επιτυχία",
"settings.notyf.visual.plugin.install.error": "Αποτυχία εγκατάστασης του πρόσθετου",
"settings.option.visual.theme.default": "Cider", "settings.option.visual.theme.default": "Cider",
"settings.option.visual.theme.dark": "Σκοτεινό", "settings.option.visual.theme.dark": "Σκοτεινό",
"settings.option.visual.showPersonalInfo": "Εμφάνιση προσωπικών στοιχείων", "settings.option.visual.showPersonalInfo": "Εμφάνιση προσωπικών στοιχείων",
"settings.header.window": "Παράθυρο",
"settings.header.window.description": "Προσαρμογή ρυθμίσεων παραθύρου για το Cider.",
"settings.option.window.openOnStartup": "Άνοιγμα του Cider στην εκκίνηση",
"settings.option.window.openOnStartup.hidden": "Άνοιγμα κρυμμένο",
"settings.option.window.useNativeTitleBar": "Χρήση γραμμής τίτλου του συστήμστος",
"settings.option.window.windowControlStyle": "Στυλ ελέγχου παραθύρου",
"settings.option.window.windowControlStyle.right": "Δεξιά",
"settings.option.window.windowControlStyle.left": "Αριστερά",
"settings.header.lyrics": "Στίχοι", "settings.header.lyrics": "Στίχοι",
"settings.header.lyrics.description": "Προσαρμογή ρυθμίσεων στίχων για το Cider.", "settings.header.lyrics.description": "Προσαρμογή ρυθμίσεων στίχων για το Cider.",
"settings.option.lyrics.enableMusixmatch": "Ενεργοποίηση Στίχων Musixmatch", "settings.option.lyrics.enableMusixmatch": "Ενεργοποίηση στίχων Musixmatch",
"settings.option.lyrics.enableMusixmatchKaraoke": "Ενεργοποίηση Λειτουργίας Καραόκε (Musixmatch μόνο)", "settings.option.lyrics.enableMusixmatchKaraoke": "Ενεργοποίηση λειτουργίας καραόκε (Musixmatch μόνο)",
"settings.option.lyrics.musixmatchPreferredLanguage": "Προτιμώμενη Γλώσσα Μετάφρασης Musixmatch", "settings.option.lyrics.musixmatchPreferredLanguage": "Προτιμώμενη γλώσσα μετάφρασης Musixmatch",
"settings.option.lyrics.enableYoutubeLyrics": "Ενεργοποίηση Στίχων Youtube για Μουσικά Βίντεο", "settings.option.lyrics.enableYoutubeLyrics": "Ενεργοποίηση στίχων YouTube για μουσικά βίντεο",
"settings.header.connectivity": "Σύνδεση", "settings.option.lyrics.enableQQLyrics": "Ενεργοποίηση στίχων QQ",
"settings.header.connectivity.description": "Προσαρμογή ρυθμίσεων σύνδεσης για το Cider.", "settings.header.connectivity": "Συνδεσιμότητα",
"settings.header.connectivity.description": "Προσαρμογή ρυθμίσεων συνδεσιμότητας για το Cider.",
"settings.option.connectivity.playbackNotifications": "Ειδοποιήσεις αναπαραγωγής",
"settings.option.connectivity.discordRPC": "Discord Rich Presence", "settings.option.connectivity.discordRPC": "Discord Rich Presence",
"settings.option.connectivity.playbackNotifications": "Ειδοποιήσεις Αναπαραγωγής", "settings.option.connectivity.discordRPC.clientName": "Τίτλος",
"settings.header.connectivity.discordRPC.cider": "Εμφάνιση ως 'Cider'", "settings.option.connectivity.discordRPC.clearOnPause": "Εκκαθάριση του Discord Rich Presence στην παύση",
"settings.header.connectivity.discordRPC.appleMusic": "Εμφάνιση ως 'Apple Music'", "settings.option.connectivity.discordRPC.hideButtons": "Απόκρυψη κουμπιών του Discord Rich Presence",
"settings.option.connectivity.discordRPC.clearOnPause": "Εκκαθάριση του Discord Rich Presence στην Παύση", "settings.option.connectivity.discordRPC.detailsFormat": "Δομή λεπτομεριών",
"settings.option.connectivity.discordRPC.stateFormat": "Δομή κατάστασης",
"settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling", "settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling",
"settings.option.connectivity.lastfmScrobble.delay": "Καθυστέρηση LastFM Scrobble (%)", "settings.option.connectivity.lastfmScrobble.delay": "Καθυστέρηση LastFM Scrobble (%)",
"settings.option.connectivity.lastfmScrobble.nowPlaying": "Ενεργοποίηση LastFM \"Now Playing\"", "settings.option.connectivity.lastfmScrobble.nowPlaying": "Ενεργοποίηση LastFM \"Now Playing\"",
@ -334,32 +440,52 @@
"settings.option.debug.openAppData": "Άνοιγμα του φακέλου Cider", "settings.option.debug.openAppData": "Άνοιγμα του φακέλου Cider",
"settings.header.experimental": "Πειραματικές", "settings.header.experimental": "Πειραματικές",
"settings.header.experimental.description": "Προσαρμογή πειραματικών ρυθμίσεων για το Cider.", "settings.header.experimental.description": "Προσαρμογή πειραματικών ρυθμίσεων για το Cider.",
"settings.option.experimental.compactUI": "Συμπαγής Διεπαφή", "settings.option.experimental.reinstallwidevine": "Επανεγκατάσταση του WidevineCDM",
"settings.option.experimental.closeButtonBehaviour": "Συμπεριφορά Κουμπιού Εξόδου", "settings.option.experimental.reinstallwidevine.confirm": "Θέλετε σίγουρα να επανεγκαταστήσετε το Widevine;",
"settings.option.experimental.closeButtonBehaviour.quit": "Έξοδος του Cider", "settings.option.experimental.unknownPlugin": "Άγνωστες πηγές",
"settings.option.experimental.closeButtonBehaviour.minimizeTaskbar": "Ελαχιστοποίηση στη γραμμή εργασιών", "settings.option.experimental.unknownPlugin.description": "Να επιτρέπεται η εγκατάσταση πρόσθετων από repo εκτός του Cider Plugin Repository",
"settings.option.experimental.closeButtonBehaviour.minimizeTray": "Ελαχιστοποίηση στη γωνία γραμμής εργασιών", "settings.option.experimental.compactUI": "Συμπαγής διεπαφή",
"settings.option.window.close_button_hide": "Απόκρυψη εφαρμογής με το πάτημα του κουμπιού κλεισίματος",
"settings.option.experimental.inline_playlists": "Ενσωμάτωση λιστών αναπαραγωγής και άλμπουμ",
"settings.option.advanced.playlistTrackMapping": "Χαρτογράφηση κομματιών λίστών αναπαραγωγής",
"settings.option.advanced.playlistTrackMapping.description": "Ενεργοποιεί τη βαθιά σάρωση των λιστών αναπαραγωγής για να προσδιορίσει ποια κομμάτια βρίσκονται σε ποιες λίστες αναπαραγωγής. Οι χρόνοι δημιουργίας της προσωρινής μνήμης των λιστών αναπαραγωγής μπορεί να αυξηθούν σημαντικά.",
"settings.option.visual.transparent": "Διαφανές πλαίσιο",
"settings.option.visual.transparent.description": "(χρειάζεται υποστήριξη θέματος, απαιτεί επανεκκίνηση)",
"settings.header.advanced": "Για προχωρημένους",
"settings.header.connect": "Συγχρονισμός",
"settings.option.connect.link_account": "Ενεργοποίηση συγχρονισμού με Cider Connect",
"settings.option.connect.link_account.description": "Η σύνδεση του λογαριασμού σας Discord με το Cider Connect σάς επιτρέπει να αποθηκεύετε δεδομένα χρήστη, συμπεριλαμβανομένων των Ρυθμίσεων, των EQ, και άλλα. (Υπό ανάπτυξη)",
"spatial.notTurnedOn": "Η Χωρικοποίηση Ήχου είναι απενεργοποιημένη. Για χρήση, παρακαλούμε ενεργοποιήστε την πρώτα.", "spatial.notTurnedOn": "Η Χωρικοποίηση Ήχου είναι απενεργοποιημένη. Για χρήση, παρακαλούμε ενεργοποιήστε την πρώτα.",
"spatial.spatialProperties": "Χωρικές Ιδιότητες", "spatial.spatialProperties": "Χωρικές ιδιότητες",
"spatial.width": "Πλάτος", "spatial.width": "Πλάτος",
"spatial.height": "Ύψος", "spatial.height": "Ύψος",
"spatial.depth": "Βάθος", "spatial.depth": "Βάθος",
"spatial.gain": "Απολαβή", "spatial.gain": "Απολαβή",
"spatial.roomMaterials": "Υλικά Δωματίου", "spatial.roomMaterials": "Υλικά δωματίου",
"spatial.roomDimensions": "Διαστάσεις Δωματίου", "spatial.roomDimensions": "Διαστάσεις δωματίου",
"spatial.roomPositions": "Θέσεις Δωματίου", "spatial.roomPositions": "Θέσεις δωματίου",
"spatial.setDimensions": "Ορισμός Διαστάσεων", "spatial.setDimensions": "Ορισμός διαστάσεων",
"spatial.setPositions": "Ορισμός Θέσεων", "spatial.setPositions": "Ορισμός θέσεων",
"spatial.up": "Πάνω", "spatial.up": "Πάνω",
"spatial.front": "Πρόσοψη", "spatial.front": "Πρόσοψη",
"spatial.left": "Αριστερά", "spatial.left": "Αριστερά",
"spatial.right": "Δεξιά", "spatial.right": "Δεξιά",
"spatial.back": "Πίσω Όψη", "spatial.back": "Πίσω όψη",
"spatial.down": "Κάτω", "spatial.down": "Κάτω",
"spatial.listener": "Ακροατής", "spatial.listener": "Ακροατής",
"spatial.audioSource": "Πηγή Ήχου", "spatial.audioSource": "Πηγή ήχου",
"settings.header.unfinished": "Ημιτελής", "settings.header.unfinished": "Ημιτελής",
"remote.web.title": "Cider Remote", "remote.web.title": "Cider Remote",
"remote.web.description": "Σαρώστε τον κωδικό QR για σύζευξη του Cider με το κινητό σας", "remote.web.description": "Σαρώστε τον κωδικό QR για σύζευξη του Cider με το κινητό σας",
"share.platform.twitter.tweet": "Ακούστε το {{song}} στο Apple Music.\n\n{{url}}\n\n#AppleMusic #Cider",
"share.platform.twitter": "Twitter",
"share.platform.facebook": "Facebook",
"share.platform.reddit": "Reddit",
"share.platform.telegram": "Telegram",
"share.platform.whatsapp": "WhatsApp",
"share.platform.messenger": "Messenger",
"share.platform.email": "Email",
"share.platform.songLink": "Αντιγραφή με song.link",
"share.platform.clipboard": "Αντιγραφή συνδέσμου",
"about.thanks": "Μεγάλα ευχαριστώ στην Ομάδα Cider Collective και σε όλους τους συνεισφέροντές μας." "about.thanks": "Μεγάλα ευχαριστώ στην Ομάδα Cider Collective και σε όλους τους συνεισφέροντές μας."
} }

View file

@ -73,6 +73,7 @@
"term.viewAs": "View As", "term.viewAs": "View As",
"term.viewAs.coverArt": "Cuvw Awt", "term.viewAs.coverArt": "Cuvw Awt",
"term.viewAs.list": "Wist", "term.viewAs.list": "Wist",
"term.dynamic": "Dynyamic",
"term.size": "Size", "term.size": "Size",
"term.size.normal": "Nyowmaw", "term.size.normal": "Nyowmaw",
"term.size.compact": "Compact", "term.size.compact": "Compact",
@ -199,6 +200,9 @@
"podcast.episodes": "Episodes", "podcast.episodes": "Episodes",
"podcast.playEpisode": "Pway Episode", "podcast.playEpisode": "Pway Episode",
"podcast.website": "Podcast Website", "podcast.website": "Podcast Website",
"action.edit": "Edit",
"action.done": "Donye",
"action.editTracklist": "Edit Twackwist",
"action.addToLibrary": "Add to Wibwawy", "action.addToLibrary": "Add to Wibwawy",
"action.addToLibrary.success": "Added to Wibwawy", "action.addToLibrary.success": "Added to Wibwawy",
"action.addToLibrary.error": "Ewwow Adding to Wibwawy", "action.addToLibrary.error": "Ewwow Adding to Wibwawy",
@ -269,6 +273,10 @@
"settings.option.general.resumebehavior.locally.description": "Cidew wiww wesume youw wast session on this machinye.", "settings.option.general.resumebehavior.locally.description": "Cidew wiww wesume youw wast session on this machinye.",
"settings.option.general.resumebehavior.history": "Histowy", "settings.option.general.resumebehavior.history": "Histowy",
"settings.option.general.resumebehavior.history.description": "Cidew wiww queue the wast song fwom youw uvwaww Appwe Music histowy, acwoss devices.", "settings.option.general.resumebehavior.history.description": "Cidew wiww queue the wast song fwom youw uvwaww Appwe Music histowy, acwoss devices.",
"settings.option.general.resumetabs": "Open Tab on Waunch",
"settings.option.general.resumetabs.description": "You can choose what tab you want to open when you waunch Cidew.",
"settings.option.general.resumetabs.dynamic": "Dynyamic",
"settings.option.general.resumetabs.dynamic.description": "Cidew wiww open the tab that you wast used.",
"settings.option.general.language.main": "Wanguages", "settings.option.general.language.main": "Wanguages",
"settings.option.general.language.fun": "Fun Wanguages", "settings.option.general.language.fun": "Fun Wanguages",
"settings.option.general.language.unsorted": "Unsowted", "settings.option.general.language.unsorted": "Unsowted",
@ -280,6 +288,8 @@
"settings.option.general.customizeSidebar": "Customize Sidebaw Items", "settings.option.general.customizeSidebar": "Customize Sidebaw Items",
"settings.option.general.customizeSidebar.customize": "Customize", "settings.option.general.customizeSidebar.customize": "Customize",
"settings.option.general.keybindings": "Keybindings", "settings.option.general.keybindings": "Keybindings",
"settings.notyf.general.keybindings.update.success": "Keybind updated successfuwwy",
"settings.prompt.general.keybindings.update.success": "Keybind updated successfuwwy. Pwess OK to wewaunch Cidew",
"settings.option.general.keybindings.open": "Open", "settings.option.general.keybindings.open": "Open",
"settings.description.search": "Seawch", "settings.description.search": "Seawch",
"settings.description.albums": "Wibwawy Awbums", "settings.description.albums": "Wibwawy Awbums",

View file

@ -73,6 +73,7 @@
"term.viewAs": "View As", "term.viewAs": "View As",
"term.viewAs.coverArt": "Cover Art", "term.viewAs.coverArt": "Cover Art",
"term.viewAs.list": "List", "term.viewAs.list": "List",
"term.dynamic": "Dynamic",
"term.size": "Size", "term.size": "Size",
"term.size.normal": "Normal", "term.size.normal": "Normal",
"term.size.compact": "Compact", "term.size.compact": "Compact",
@ -263,6 +264,42 @@
"action.cast.scanning": "Scanning...", "action.cast.scanning": "Scanning...",
"action.createNew": "Create New...", "action.createNew": "Create New...",
"action.openArtworkInBrowser": "Open artwork in browser", "action.openArtworkInBrowser": "Open artwork in browser",
"menubar.options.about": "About",
"menubar.options.settings": "Settings",
"menubar.options.quit": "Quit Cider",
"menubar.options.view": "View ",
"menubar.options.reload": "Reload",
"menubar.options.forcereload": "Force Reload",
"menubar.options.toggledevtools": "Toggle Developer Tools",
"menubar.options.window": "Window",
"menubar.options.minimize": "Minimize",
"menubar.options.toggleprivate": "Toggle Private Session",
"menubar.options.webremote": "Web Remote",
"menubar.options.audio": "Audio Settings",
"menubar.options.plugins": "Plu-gins Menu",
"menubar.options.controls": "Controls",
"menubar.options.next": "Next",
"menubar.options.playpause": "Play/Pause",
"menubar.options.previous": "Previous",
"menubar.options.volumeup": "Volume Up",
"menubar.options.volumedown": "Volume Down",
"menubar.options.browse": "Browse",
"menubar.options.artists": "Artists",
"menubar.options.search": "Search",
"menubar.options.albums": "Albums",
"menubar.options.cast": "Cast To Devices",
"menubar.options.account": "Account",
"menubar.options.accountsettings": "Account Settings",
"menubar.options.signout": "Sign Out",
"menubar.options.support": "Support",
"menubar.options.discord": "Discord",
"menubar.options.github": "GitHub Wiki",
"menubar.options.report": "Report a...",
"menubar.options.bug": "Bug",
"menubar.options.feature": "Feature Request",
"menubar.options.trans": "Translation Report/Request",
"menubar.options.license": "View License",
"menubar.options.conf": "Open Configuration File in Editor",
"settings.header.general": "General", "settings.header.general": "General",
"settings.header.general.description": "Adjust the general settings for Cider.", "settings.header.general.description": "Adjust the general settings for Cider.",
"settings.option.general.language": "Language", "settings.option.general.language": "Language",
@ -329,6 +366,7 @@
"settings.option.audio.audioLab.description": "An assortment of in-house developed audio effects for Cider.", "settings.option.audio.audioLab.description": "An assortment of in-house developed audio effects for Cider.",
"settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California", "settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California",
"settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionality) is required to enable Cider Audio Laboratory.", "settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionality) is required to enable Cider Audio Laboratory.",
"settings.warn.enableAdvancedFunctionality": "AudioContext (Advanced Functionality) is required to enable this feature.",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Analog Warmth", "settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Analog Warmth",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simulates the analog warmth modelled after the Korg Nutube 6P1", "settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simulates the analog warmth modelled after the Korg Nutube 6P1",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Analog Warmth intensity", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Analog Warmth intensity",
@ -391,6 +429,13 @@
"settings.header.visual.theme.github.page": "Themes from GitHub", "settings.header.visual.theme.github.page": "Themes from GitHub",
"settings.option.visual.theme.github.install.confirm": "Are you sure you want to install {{ repo }}?", "settings.option.visual.theme.github.install.confirm": "Are you sure you want to install {{ repo }}?",
"settings.prompt.visual.theme.github.URL": "Enter the URL of the theme you want to install", "settings.prompt.visual.theme.github.URL": "Enter the URL of the theme you want to install",
"settings.prompt.visual.theme.uninstallTheme": "Are you sure you want to uninstall {{ theme }}?",
"settings.option.visual.theme.checkForUpdates": "Check for updates",
"settings.option.visual.theme.manageStyles": "Manage Styles",
"settings.option.visual.theme.uninstall": "Uninstall",
"settings.option.visual.theme.viewInfo": "View Info",
"settings.option.visual.theme.github.available": "Available",
"settings.option.visual.theme.github.applied": "Applied",
"settings.notyf.visual.theme.install.success": "Theme installed successfully", "settings.notyf.visual.theme.install.success": "Theme installed successfully",
"settings.notyf.visual.theme.install.error": "Theme installation failed", "settings.notyf.visual.theme.install.error": "Theme installation failed",
"settings.header.visual.plugin": "Plugin", "settings.header.visual.plugin": "Plugin",

View file

@ -73,6 +73,7 @@
"term.viewAs": "Ver como", "term.viewAs": "Ver como",
"term.viewAs.coverArt": "Portada", "term.viewAs.coverArt": "Portada",
"term.viewAs.list": "Lista", "term.viewAs.list": "Lista",
"term.dynamic": "Dinámico",
"term.size": "Tamaño", "term.size": "Tamaño",
"term.size.normal": "Normal", "term.size.normal": "Normal",
"term.size.compact": "Compacto", "term.size.compact": "Compacto",
@ -199,6 +200,9 @@
"podcast.episodes": "Episodios", "podcast.episodes": "Episodios",
"podcast.playEpisode": "Reproducir Episodio", "podcast.playEpisode": "Reproducir Episodio",
"podcast.website": "Sitio web de Podcasts", "podcast.website": "Sitio web de Podcasts",
"action.edit": "Editar",
"action.done": "Hecho",
"action.editTracklist": "Edit Tracklist",
"action.addToLibrary": "Agregar a la Biblioteca", "action.addToLibrary": "Agregar a la Biblioteca",
"action.addToLibrary.success": "Agregado a la Biblioteca", "action.addToLibrary.success": "Agregado a la Biblioteca",
"action.addToLibrary.error": "Error al agregar a la Biblioteca", "action.addToLibrary.error": "Error al agregar a la Biblioteca",
@ -260,6 +264,42 @@
"action.cast.scanning": "Escaneando...", "action.cast.scanning": "Escaneando...",
"action.createNew": "Crear Nuevo...", "action.createNew": "Crear Nuevo...",
"action.openArtworkInBrowser": "Abrir Ilustración en el navegador", "action.openArtworkInBrowser": "Abrir Ilustración en el navegador",
"menubar.options.about": "Acerca de",
"menubar.options.settings": "Ajustes",
"menubar.options.quit": "Salir",
"menubar.options.view": "Ver",
"menubar.options.reload": "Recargar",
"menubar.options.forcereload": "Forzar Recarga",
"menubar.options.toggledevtools": "Herramientas de Desarrollo",
"menubar.options.window": "Ventana",
"menubar.options.minimize": "Minimizar",
"menubar.options.toggleprivate": "Cambiar Sesión Privada",
"menubar.options.webremote": "Web Remoto",
"menubar.options.audio": "Configuraciones de Audio",
"menubar.options.plugins": "Menu de Plu-gins",
"menubar.options.controls": "Controles",
"menubar.options.next": "Siguiente",
"menubar.options.playpause": "Reproducir/Pausar",
"menubar.options.previous": "Anterior",
"menubar.options.volumeup": "Subir Volumen",
"menubar.options.volumedown": "Bajar Volumen",
"menubar.options.browse": "Explorar",
"menubar.options.artists": "Artistas",
"menubar.options.search": "Buscar",
"menubar.options.albums": "Álbumes",
"menubar.options.cast": "Transmitir a Dispositivos",
"menubar.options.account": "Cuenta",
"menubar.options.accountsettings": "Ajustes de Cuenta",
"menubar.options.signout": "Cerrar Sesión",
"menubar.options.support": "Soporte",
"menubar.options.discord": "Discord",
"menubar.options.github": "GitHub Wiki",
"menubar.options.report": "Reportar a...",
"menubar.options.bug": "Bug",
"menubar.options.feature": "Solicitud de características",
"menubar.options.trans": "Solicitud de Informe/Traducción",
"menubar.options.license": "Ver licencia",
"menubar.options.conf": "Abrir archivo de configuración en el editor",
"settings.header.general": "General", "settings.header.general": "General",
"settings.header.general.description": "Ajuste la configuración general de Cider.", "settings.header.general.description": "Ajuste la configuración general de Cider.",
"settings.option.general.language": "Idioma", "settings.option.general.language": "Idioma",
@ -269,6 +309,10 @@
"settings.option.general.resumebehavior.locally.description": "Cider reanudará su última sesión en esta PC.", "settings.option.general.resumebehavior.locally.description": "Cider reanudará su última sesión en esta PC.",
"settings.option.general.resumebehavior.history": "Histórico", "settings.option.general.resumebehavior.history": "Histórico",
"settings.option.general.resumebehavior.history.description": "Cider pondrá en cola la última canción de su historial general de Apple Music, en todos sus dispositivos.", "settings.option.general.resumebehavior.history.description": "Cider pondrá en cola la última canción de su historial general de Apple Music, en todos sus dispositivos.",
"settings.option.general.resumetabs" : "Abrir pestaña al iniciar",
"settings.option.general.resumetabs.description" : "Puede elegir qué pestaña desea abrir cuando inicie Cider.",
"settings.option.general.resumetabs.dynamic" : "Dinámico",
"settings.option.general.resumetabs.dynamic.description" : "Cider abrirá la pestaña que utilizó por última vez.",
"settings.option.general.language.main": "Idiomas", "settings.option.general.language.main": "Idiomas",
"settings.option.general.language.fun": "Idiomas Fun (Parodias)", "settings.option.general.language.fun": "Idiomas Fun (Parodias)",
"settings.option.general.language.unsorted": "Sin Clasificar", "settings.option.general.language.unsorted": "Sin Clasificar",
@ -280,6 +324,8 @@
"settings.option.general.customizeSidebar": "Personalizar elementos de la barra lateral", "settings.option.general.customizeSidebar": "Personalizar elementos de la barra lateral",
"settings.option.general.customizeSidebar.customize": "Personalizar", "settings.option.general.customizeSidebar.customize": "Personalizar",
"settings.option.general.keybindings": "Combinaciones de Teclas", "settings.option.general.keybindings": "Combinaciones de Teclas",
"settings.notyf.general.keybindings.update.success": "Combinación de teclas actualizada correctamente",
"settings.prompt.general.keybindings.update.success": "La combinación de teclas se actualizó correctamente. Pulsa OK para reiniciar Cider",
"settings.option.general.keybindings.open": "Abrir", "settings.option.general.keybindings.open": "Abrir",
"settings.description.search": "Buscar", "settings.description.search": "Buscar",
"settings.description.albums": "Álbumes de la biblioteca", "settings.description.albums": "Álbumes de la biblioteca",
@ -320,6 +366,7 @@
"settings.option.audio.audioLab.description": "Una variedad de efectos de audio desarrollados internamente para Cider.", "settings.option.audio.audioLab.description": "Una variedad de efectos de audio desarrollados internamente para Cider.",
"settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California", "settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California",
"settings.warn.audioLab.withoutAF": "Se requiere AudioContext (funcionalidad avanzada) para habilitar Laboratorio de audio de Cider.", "settings.warn.audioLab.withoutAF": "Se requiere AudioContext (funcionalidad avanzada) para habilitar Laboratorio de audio de Cider.",
"settings.warn.enableAdvancedFunctionality": "AudioContext (funcionalidad avanzada) es necesaria para habilitar esta característica.",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Calidez analógica", "settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Calidez analógica",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simula la calidez analógica inspirada en el Korg Nutube 6P1", "settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simula la calidez analógica inspirada en el Korg Nutube 6P1",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Intensidad de calidez analógica", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Intensidad de calidez analógica",
@ -382,6 +429,13 @@
"settings.header.visual.theme.github.page": "Temas de GitHub", "settings.header.visual.theme.github.page": "Temas de GitHub",
"settings.option.visual.theme.github.install.confirm": "¿Está seguro de que desea instalar {{ repo }}?", "settings.option.visual.theme.github.install.confirm": "¿Está seguro de que desea instalar {{ repo }}?",
"settings.prompt.visual.theme.github.URL": "Introduce la URL del tema que quieres instalar", "settings.prompt.visual.theme.github.URL": "Introduce la URL del tema que quieres instalar",
"settings.prompt.visual.theme.uninstallTheme": "¿Estas seguro que lo quieres desinstalar {{ theme }}?",
"settings.option.visual.theme.checkForUpdates": "Buscar actualizaciones",
"settings.option.visual.theme.manageStyles": "Gestionar Estilos",
"settings.option.visual.theme.uninstall": "Desinstalar",
"settings.option.visual.theme.viewInfo": "Ver Información",
"settings.option.visual.theme.github.available": "Disponible",
"settings.option.visual.theme.github.applied": "Aplicado",
"settings.notyf.visual.theme.install.success": "Tema Instalado Correctamente", "settings.notyf.visual.theme.install.success": "Tema Instalado Correctamente",
"settings.notyf.visual.theme.install.error": "La Instalación del Tema Falló", "settings.notyf.visual.theme.install.error": "La Instalación del Tema Falló",
"settings.header.visual.plugin": "Plugin", "settings.header.visual.plugin": "Plugin",
@ -410,6 +464,7 @@
"settings.option.lyrics.enableMusixmatchKaraoke": "Habilitar el modo Karaoke (solo Musixmatch)", "settings.option.lyrics.enableMusixmatchKaraoke": "Habilitar el modo Karaoke (solo Musixmatch)",
"settings.option.lyrics.musixmatchPreferredLanguage": "Idioma preferido de traducción de Musixmatch", "settings.option.lyrics.musixmatchPreferredLanguage": "Idioma preferido de traducción de Musixmatch",
"settings.option.lyrics.enableYoutubeLyrics": "Habilitar letras de YouTube para videos musicales", "settings.option.lyrics.enableYoutubeLyrics": "Habilitar letras de YouTube para videos musicales",
"settings.option.lyrics.enableQQLyrics": "Habilitar letras de QQ",
"settings.header.connectivity": "Conectividad", "settings.header.connectivity": "Conectividad",
"settings.header.connectivity.description": "Ajuste la configuración de conectividad para Cider.", "settings.header.connectivity.description": "Ajuste la configuración de conectividad para Cider.",
"settings.option.connectivity.playbackNotifications": "Notificaciones de Reproducción", "settings.option.connectivity.playbackNotifications": "Notificaciones de Reproducción",
@ -442,7 +497,9 @@
"settings.option.visual.transparent.description": "Marco transparente (necesita compatibilidad con temas, requiere reiniciar)", "settings.option.visual.transparent.description": "Marco transparente (necesita compatibilidad con temas, requiere reiniciar)",
"settings.header.advanced": "Avanzado", "settings.header.advanced": "Avanzado",
"settings.header.connect": "Conectar", "settings.header.connect": "Conectar",
"spatial.notTurnedOn": "La espacialización de audio está deshabilitada. Para usar, habilítelo primero.", "settings.option.connect.link_account": "Habilitar sincronización con Cider Connect",
"settings.option.connect.link_account.description": "Vincular su cuenta de Discord con Cider Connect le permite almacenar datos de usuario que incluyen configuraciones, ecualizadores y eventualmente más, una vez que haya terminado. (Trabajo en progreso)",
"spatial.notTurnedOn": "La Espacialización de audio está deshabilitada. Para usar, habilítelo primero.",
"spatial.spatialProperties": "Propiedades de Espacialización", "spatial.spatialProperties": "Propiedades de Espacialización",
"spatial.width": "Ancho", "spatial.width": "Ancho",
"spatial.height": "Alto", "spatial.height": "Alto",

View file

@ -378,6 +378,8 @@
"settings.header.visual.theme.github.page": "Témák a GitHub-ról", "settings.header.visual.theme.github.page": "Témák a GitHub-ról",
"settings.option.visual.theme.github.install.confirm": "Biztosan szeretnéd telepíteni a(z) {{ repo }} témát?", "settings.option.visual.theme.github.install.confirm": "Biztosan szeretnéd telepíteni a(z) {{ repo }} témát?",
"settings.prompt.visual.theme.github.URL": "Add meg a telepítendő téma URL-jét", "settings.prompt.visual.theme.github.URL": "Add meg a telepítendő téma URL-jét",
"settings.option.visual.theme.github.available": "Elérhető",
"settings.option.visual.theme.github.applied": "Alkalmazva",
"settings.notyf.visual.theme.install.success": "Téma sikeresen telepítve", "settings.notyf.visual.theme.install.success": "Téma sikeresen telepítve",
"settings.notyf.visual.theme.install.error": "Sikertelen volt a téma telepítése", "settings.notyf.visual.theme.install.error": "Sikertelen volt a téma telepítése",
"settings.header.visual.plugin": "Plugin", "settings.header.visual.plugin": "Plugin",
@ -406,6 +408,7 @@
"settings.option.lyrics.enableMusixmatchKaraoke": "Karaoke mód bekapcsolása (Csak MusixMatch)", "settings.option.lyrics.enableMusixmatchKaraoke": "Karaoke mód bekapcsolása (Csak MusixMatch)",
"settings.option.lyrics.musixmatchPreferredLanguage": "MusixMatch fordítás nyelve", "settings.option.lyrics.musixmatchPreferredLanguage": "MusixMatch fordítás nyelve",
"settings.option.lyrics.enableYoutubeLyrics": "YouTube dalszövegek engedélyezése a zenei videóknál", "settings.option.lyrics.enableYoutubeLyrics": "YouTube dalszövegek engedélyezése a zenei videóknál",
"settings.option.lyrics.enableQQLyrics": "QQLyrics dalszövegek engedélyezése",
"settings.header.connectivity": "Csatlakozások", "settings.header.connectivity": "Csatlakozások",
"settings.header.connectivity.description": "A Cider csatlakozás beállításainak módosítása.", "settings.header.connectivity.description": "A Cider csatlakozás beállításainak módosítása.",
"settings.option.connectivity.playbackNotifications": "Lejátszási értesítések", "settings.option.connectivity.playbackNotifications": "Lejátszási értesítések",

View file

@ -264,6 +264,42 @@
"action.cast.scanning": "Scanning...", "action.cast.scanning": "Scanning...",
"action.createNew": "Create New...", "action.createNew": "Create New...",
"action.openArtworkInBrowser": "Open artwork in browser", "action.openArtworkInBrowser": "Open artwork in browser",
"menubar.options.about": "About",
"menubar.options.settings": "Settings",
"menubar.options.quit": "Quit Cider",
"menubar.options.view": "View ",
"menubar.options.reload": "Reload",
"menubar.options.forcereload": "Force Reload",
"menubar.options.toggledevtools": "Toggle Developer Tools",
"menubar.options.window": "Window",
"menubar.options.minimize": "Minimize",
"menubar.options.toggleprivate": "Toggle Private Session",
"menubar.options.webremote": "Web Remote",
"menubar.options.audio": "Audio Settings",
"menubar.options.plugins": "Plu-gins Menu",
"menubar.options.controls": "Controls",
"menubar.options.next": "Next",
"menubar.options.playpause": "Play/Pause",
"menubar.options.previous": "Previous",
"menubar.options.volumeup": "Volume Up",
"menubar.options.volumedown": "Volume Down",
"menubar.options.browse": "Browse",
"menubar.options.artists": "Artists",
"menubar.options.search": "Search",
"menubar.options.albums": "Albums",
"menubar.options.cast": "Cast To Devices",
"menubar.options.account": "Account",
"menubar.options.accountsettings": "Account Settings",
"menubar.options.signout": "Sign Out",
"menubar.options.support": "Support",
"menubar.options.discord": "Discord",
"menubar.options.github": "GitHub Wiki",
"menubar.options.report": "Report a...",
"menubar.options.bug": "Bug",
"menubar.options.feature": "Feature Request",
"menubar.options.trans": "Translation Report/Request",
"menubar.options.license": "View License",
"menubar.options.conf": "Open Configuration File in Editor",
"settings.header.general": "General", "settings.header.general": "General",
"settings.header.general.description": "Adjust the general settings for Cider.", "settings.header.general.description": "Adjust the general settings for Cider.",
"settings.option.general.language": "Language", "settings.option.general.language": "Language",
@ -330,6 +366,7 @@
"settings.option.audio.audioLab.description": "An assortment of in-house developed audio effects for Cider.", "settings.option.audio.audioLab.description": "An assortment of in-house developed audio effects for Cider.",
"settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California", "settings.option.audio.audioLab.subheader": "Designed by Cider Acoustic Technologies in California",
"settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionality) is required to enable Cider Audio Laboratory.", "settings.warn.audioLab.withoutAF": "AudioContext (Advanced Functionality) is required to enable Cider Audio Laboratory.",
"settings.warn.enableAdvancedFunctionality": "AudioContext (Advanced Functionality) is required to enable this feature.",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Analog Warmth", "settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Analog Warmth",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simulates the analog warmth modelled after the Korg Nutube 6P1", "settings.option.audio.enableAdvancedFunctionality.analogWarmth.description": "Simulates the analog warmth modelled after the Korg Nutube 6P1",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Analog Warmth intensity", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Analog Warmth intensity",
@ -392,6 +429,13 @@
"settings.header.visual.theme.github.page": "Themes from GitHub", "settings.header.visual.theme.github.page": "Themes from GitHub",
"settings.option.visual.theme.github.install.confirm": "Are you sure you want to install {{ repo }}?", "settings.option.visual.theme.github.install.confirm": "Are you sure you want to install {{ repo }}?",
"settings.prompt.visual.theme.github.URL": "Enter the URL of the theme you want to install", "settings.prompt.visual.theme.github.URL": "Enter the URL of the theme you want to install",
"settings.prompt.visual.theme.uninstallTheme": "Are you sure you want to uninstall {{ theme }}?",
"settings.option.visual.theme.checkForUpdates": "Check for updates",
"settings.option.visual.theme.manageStyles": "Manage Styles",
"settings.option.visual.theme.uninstall": "Uninstall",
"settings.option.visual.theme.viewInfo": "View Info",
"settings.option.visual.theme.github.available": "Available",
"settings.option.visual.theme.github.applied": "Applied",
"settings.notyf.visual.theme.install.success": "Theme installed successfully", "settings.notyf.visual.theme.install.success": "Theme installed successfully",
"settings.notyf.visual.theme.install.error": "Theme installation failed", "settings.notyf.visual.theme.install.error": "Theme installation failed",
"settings.header.visual.plugin": "Plugin", "settings.header.visual.plugin": "Plugin",

View file

@ -22,6 +22,7 @@
"term.login": "登录", "term.login": "登录",
"term.about": "关于", "term.about": "关于",
"term.privateSession": "私人聆听", "term.privateSession": "私人聆听",
"term.lyrics": "歌词",
"term.queue": "待播清单", "term.queue": "待播清单",
"term.history": "历史记录", "term.history": "历史记录",
"term.miniplayer": "迷你播放器", "term.miniplayer": "迷你播放器",
@ -115,7 +116,11 @@
"term.contributors": "贡献者", "term.contributors": "贡献者",
"term.equalizer": "均衡器", "term.equalizer": "均衡器",
"term.reset": "重置", "term.reset": "重置",
"term.tracks": "首歌曲", "term.track": {
"one": "首歌曲",
"other": "首歌曲"
},
"term.tracks": "歌曲",
"term.videos": "音乐视频", "term.videos": "音乐视频",
"term.menu": "菜单", "term.menu": "菜单",
"term.check": "检查", "term.check": "检查",
@ -161,6 +166,9 @@
"podcast.episodes": "单集", "podcast.episodes": "单集",
"podcast.playEpisode": "播放单集", "podcast.playEpisode": "播放单集",
"podcast.website": "Podcast 网站", "podcast.website": "Podcast 网站",
"action.edit": "编辑",
"action.done": "完成",
"action.editTracklist": "编辑歌曲清单",
"action.addToLibrary": "加入资料库", "action.addToLibrary": "加入资料库",
"action.addToLibrary.success": "成功加入资料库", "action.addToLibrary.success": "成功加入资料库",
"action.addToLibrary.error": "加入资料库的过程发生了错误", "action.addToLibrary.error": "加入资料库的过程发生了错误",
@ -187,6 +195,7 @@
"action.startRadio": "开始电台", "action.startRadio": "开始电台",
"action.goToArtist": "前往艺人", "action.goToArtist": "前往艺人",
"action.goToAlbum": "前往专辑", "action.goToAlbum": "前往专辑",
"action.showInAppleMusic": "显示于 Apple Music",
"action.moveToTop": "移到顶部", "action.moveToTop": "移到顶部",
"action.share": "分享歌曲", "action.share": "分享歌曲",
"action.rename": "重命名", "action.rename": "重命名",
@ -203,11 +212,19 @@
"action.showAlbum": "显示专辑", "action.showAlbum": "显示专辑",
"action.tray.minimize": "最小化", "action.tray.minimize": "最小化",
"action.tray.quit": "退出", "action.tray.quit": "退出",
"action.update": "更新", "action.update": "更新",
"action.copy": "复制", "action.copy": "复制",
"action.newpreset": "新建默认...", "action.newpreset": "新建默认...",
"action.deletepreset": "删除默认", "action.deletepreset": "删除默认",
"action.open": "打开",
"action.cast.chromecast": "Chromecast",
"action.cast.todevices": "投射到设备",
"action.cast.stop": "停止投射到所有设备",
"action.cast.airplay": "AirPlay",
"action.cast.airplay.underdevelopment": "AirPlay 仍处于开发阶段中,敬请期待。",
"action.cast.scan": "搜索",
"action.cast.scanning": "搜索中...",
"action.createNew": "添加...",
"settings.header.general": "通用", "settings.header.general": "通用",
"settings.header.general.description": "调整 Cider 的通用设置", "settings.header.general.description": "调整 Cider 的通用设置",
"settings.option.audio.volumeStep": "音量改变量", "settings.option.audio.volumeStep": "音量改变量",
@ -218,6 +235,10 @@
"settings.option.general.resumebehavior.locally.description": "Cider 将还原你在这台电脑上的最后一次操作。", "settings.option.general.resumebehavior.locally.description": "Cider 将还原你在这台电脑上的最后一次操作。",
"settings.option.general.resumebehavior.history": "历史", "settings.option.general.resumebehavior.history": "历史",
"settings.option.general.resumebehavior.history.description": "Cider 将跨设备将你的整个 Apple Music 历史记录中的最后一首歌曲排队入列。", "settings.option.general.resumebehavior.history.description": "Cider 将跨设备将你的整个 Apple Music 历史记录中的最后一首歌曲排队入列。",
"settings.option.general.resumetabs": "启动时打开的选项页面",
"settings.option.general.resumetabs.description": "你可以选择启动 Cider 时要默认打开的页面。",
"settings.option.general.resumetabs.dynamic": "动态",
"settings.option.general.resumetabs.dynamic.description": "Cider 将自动打开你上次停留的页面。",
"settings.option.general.language": "语言", "settings.option.general.language": "语言",
"settings.option.general.language.main": "语言", "settings.option.general.language.main": "语言",
"settings.option.general.language.fun": "恶搞语言", "settings.option.general.language.fun": "恶搞语言",
@ -229,6 +250,8 @@
"settings.option.general.updateCider.branch.develop": "测试(Develop)", "settings.option.general.updateCider.branch.develop": "测试(Develop)",
"settings.option.general.customizeSidebar": "自定义侧边栏的功能", "settings.option.general.customizeSidebar": "自定义侧边栏的功能",
"settings.option.general.customizeSidebar.customize": "自定义", "settings.option.general.customizeSidebar.customize": "自定义",
"settings.option.general.keybindings": "快捷操作键",
"settings.option.general.keybindings.open": "打开",
"settings.notyf.updateCider.update-not-available": "没有可用的更新", "settings.notyf.updateCider.update-not-available": "没有可用的更新",
"settings.notyf.updateCider.update-downloaded": "更新已成功下载,重启后进行更新", "settings.notyf.updateCider.update-downloaded": "更新已成功下载,重启后进行更新",
"settings.notyf.updateCider.update-error": "更新时,发生错误", "settings.notyf.updateCider.update-error": "更新时,发生错误",
@ -256,6 +279,13 @@
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description": "改变模拟温暖模组处理的强度。", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description": "改变模拟温暖模组处理的强度。",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.smooth": "温和", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.smooth": "温和",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.warm": "温暖", "settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.warm": "温暖",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer": "Cider 音乐气氛实现器™️",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizer.description": "以最先进的音频置为蓝本,实现不同的音乐气氛。",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode": "Cider 音乐气氛™️模式",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.description": "更改气氛实现器模块的操作模式。",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural1": "自然(标准)",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural2": "自然(高)",
"settings.option.audio.enableAdvancedFunctionality.atmosphereRealizerMode.natural3": "自然(增强)",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider 数码增强音频处理™️", "settings.option.audio.enableAdvancedFunctionality.ciderPPE": "Cider 数码增强音频处理™️",
"settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "通过人类的听力心理学模型和 AAC 编码特色的即时算法,强化 256 kbps AAC 音频的感知音频质量。", "settings.option.audio.enableAdvancedFunctionality.ciderPPE.description": "通过人类的听力心理学模型和 AAC 编码特色的即时算法,强化 256 kbps AAC 音频的感知音频质量。",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "数码增强音频处理设置", "settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "数码增强音频处理设置",
@ -274,6 +304,7 @@
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.standard": "标准", "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.standard": "标准",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.audiophile": "发烧友", "settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.audiophile": "发烧友",
"settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "音频空间无法与 CAP 相容,请关闭 CAP 在进行操作。", "settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "音频空间无法与 CAP 相容,请关闭 CAP 在进行操作。",
"settings.option.visual.uiscale": "UI界面大小",
"settings.header.visual": "外观", "settings.header.visual": "外观",
"settings.header.visual.description": "调整 Cider 的外观", "settings.header.visual.description": "调整 Cider 的外观",
"settings.option.visual.windowBackgroundStyle": "窗口背景样式", "settings.option.visual.windowBackgroundStyle": "窗口背景样式",
@ -312,7 +343,7 @@
"settings.notyf.visual.plugin.install.error": "插件安装失败", "settings.notyf.visual.plugin.install.error": "插件安装失败",
"settings.option.visual.theme.default": "默认", "settings.option.visual.theme.default": "默认",
"settings.option.visual.theme.dark": "午夜黑", "settings.option.visual.theme.dark": "午夜黑",
"settings.option.visual.showPersonalInfo": "显示个人资料", "settings.option.visual.showPersonalInfo": "显示个人信息",
"settings.header.window": "窗口", "settings.header.window": "窗口",
"settings.header.window.description": "调整 Cider 的窗口设置", "settings.header.window.description": "调整 Cider 的窗口设置",
"settings.option.window.openOnStartup": "开机时,自动运行 Cider ", "settings.option.window.openOnStartup": "开机时,自动运行 Cider ",
@ -327,19 +358,21 @@
"settings.option.lyrics.enableMusixmatchKaraoke": "启用卡拉 OK 模式(仅 Musixmatch", "settings.option.lyrics.enableMusixmatchKaraoke": "启用卡拉 OK 模式(仅 Musixmatch",
"settings.option.lyrics.musixmatchPreferredLanguage": "Musixmatch 歌词语言偏好", "settings.option.lyrics.musixmatchPreferredLanguage": "Musixmatch 歌词语言偏好",
"settings.option.lyrics.enableYoutubeLyrics": "播放 MV 时使用 YouTube 歌词", "settings.option.lyrics.enableYoutubeLyrics": "播放 MV 时使用 YouTube 歌词",
"settings.option.lyrics.enableQQLyrics": "启用 QQ 音乐的歌词",
"settings.header.connectivity": "外部连接", "settings.header.connectivity": "外部连接",
"settings.header.connectivity.description": "调整 Cider 与外部应用的交互设置", "settings.header.connectivity.description": "调整 Cider 与外部应用的交互设置",
"settings.option.connectivity.discordRPC": "Discord 动态", "settings.option.connectivity.discordRPC": "Discord 动态",
"settings.option.connectivity.playbackNotifications": "歌曲播放通知", "settings.option.connectivity.playbackNotifications": "歌曲播放通知",
"settings.header.connectivity.discordRPC.cider": "显示正在使用 'Cider'", "settings.option.connectivity.discordRPC.clientName": "应用程序名称",
"settings.header.connectivity.discordRPC.appleMusic": "显示正在使用 'Apple Music'",
"settings.option.connectivity.discordRPC.clearOnPause": "暂停时清除 Discord 动态", "settings.option.connectivity.discordRPC.clearOnPause": "暂停时清除 Discord 动态",
"settings.option.connectivity.discordRPC.hideButtons": "隐藏 Discord 动态上的按钮", "settings.option.connectivity.discordRPC.hideButtons": "隐藏 Discord 动态上的按钮",
"settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling 记录", "settings.option.connectivity.discordRPC.detailsFormat": "详细信息格式",
"settings.option.connectivity.lastfmScrobble.delay": "LastFM Scrobble 延迟 (%)", "settings.option.connectivity.discordRPC.stateFormat": "动态格式",
"settings.option.connectivity.lastfmScrobble.nowPlaying": "打开 LastFM 正在播放", "settings.option.connectivity.lastfmScrobble": "Last.FM 音乐记录",
"settings.option.connectivity.lastfmScrobble.removeFeatured": "从歌名里去除合作者 (LastFM)", "settings.option.connectivity.lastfmScrobble.delay": "Last.FM 歌曲追踪延迟 (%)",
"settings.option.connectivity.lastfmScrobble.filterLoop": "不记录单曲循环 (LastFM)", "settings.option.connectivity.lastfmScrobble.nowPlaying": "打开 Last.FM 正在聆听",
"settings.option.connectivity.lastfmScrobble.removeFeatured": "从歌名里去除合作者 (Last.FM)",
"settings.option.connectivity.lastfmScrobble.filterLoop": "不记录单曲循环 (Last.FM)",
"settings.header.debug": "Debug", "settings.header.debug": "Debug",
"settings.option.debug.copy_log": "拷贝日志至剪贴板", "settings.option.debug.copy_log": "拷贝日志至剪贴板",
"settings.option.debug.openAppData": "打开 Cider 程序文件夹", "settings.option.debug.openAppData": "打开 Cider 程序文件夹",

View file

@ -151,6 +151,9 @@
"podcast.episodes": "單集", "podcast.episodes": "單集",
"podcast.playEpisode": "播放單集", "podcast.playEpisode": "播放單集",
"podcast.website": "Podcast 網站", "podcast.website": "Podcast 網站",
"action.edit": "編輯",
"action.done": "完成",
"action.editTracklist": "編輯歌曲清單",
"action.addToLibrary": "加入到資料庫", "action.addToLibrary": "加入到資料庫",
"action.addToLibrary.success": "成功加入資料庫", "action.addToLibrary.success": "成功加入資料庫",
"action.addToLibrary.error": "加入資料庫時,發生錯誤", "action.addToLibrary.error": "加入資料庫時,發生錯誤",
@ -215,6 +218,10 @@
"settings.option.general.resumebehavior.locally.description": "Cider 將還原你在這台電腦上的最後一次操作。", "settings.option.general.resumebehavior.locally.description": "Cider 將還原你在這台電腦上的最後一次操作。",
"settings.option.general.resumebehavior.history": "歷史", "settings.option.general.resumebehavior.history": "歷史",
"settings.option.general.resumebehavior.history.description": "Cider 將跨裝置將你的整個 Apple Music 歷史記錄中的最後一首歌曲排隊入列。", "settings.option.general.resumebehavior.history.description": "Cider 將跨裝置將你的整個 Apple Music 歷史記錄中的最後一首歌曲排隊入列。",
"settings.option.general.resumetabs": "啟動時打開的選項頁面",
"settings.option.general.resumetabs.description": "你可以選擇啟動 Cider 時要預設打開的頁面。",
"settings.option.general.resumetabs.dynamic": "自動",
"settings.option.general.resumetabs.dynamic.description": "Cider 將自動打開你上次停留的頁面。",
"settings.option.general.language.main": "語言", "settings.option.general.language.main": "語言",
"settings.option.general.language.fun": "特殊語言", "settings.option.general.language.fun": "特殊語言",
"settings.option.general.language.unsorted": "未分類", "settings.option.general.language.unsorted": "未分類",
@ -345,8 +352,8 @@
"settings.option.connectivity.discordRPC.hideButtons": "隱藏 Discord 動態上的按鈕", "settings.option.connectivity.discordRPC.hideButtons": "隱藏 Discord 動態上的按鈕",
"settings.option.connectivity.discordRPC.detailsFormat": "詳細資訊格式", "settings.option.connectivity.discordRPC.detailsFormat": "詳細資訊格式",
"settings.option.connectivity.discordRPC.stateFormat": "狀態格式", "settings.option.connectivity.discordRPC.stateFormat": "狀態格式",
"settings.option.connectivity.lastfmScrobble": "Last.FM Scrobbling 記錄", "settings.option.connectivity.lastfmScrobble": "Last.FM 音樂記錄",
"settings.option.connectivity.lastfmScrobble.delay": "Last.FM Scrobble 延遲 (%)", "settings.option.connectivity.lastfmScrobble.delay": "Last.FM 歌曲追蹤延遲 (%)",
"settings.option.connectivity.lastfmScrobble.nowPlaying": "開啟 Last.FM 正在聆聽", "settings.option.connectivity.lastfmScrobble.nowPlaying": "開啟 Last.FM 正在聆聽",
"settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除客串藝人 (Last.FM)", "settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除客串藝人 (Last.FM)",
"settings.option.connectivity.lastfmScrobble.filterLoop": "不記錄單曲循環 (Last.FM)", "settings.option.connectivity.lastfmScrobble.filterLoop": "不記錄單曲循環 (Last.FM)",

View file

@ -212,7 +212,6 @@ export class AppEvents {
* Handles the creation of a new instance of the app * Handles the creation of a new instance of the app
*/ */
private InstanceHandler() { private InstanceHandler() {
// Detects of an existing instance is running (So if the lock has been achieved, no existing instance has been found) // Detects of an existing instance is running (So if the lock has been achieved, no existing instance has been found)
const gotTheLock = app.requestSingleInstanceLock() const gotTheLock = app.requestSingleInstanceLock()

View file

@ -4,7 +4,18 @@ import * as windowStateKeeper from "electron-window-state";
import * as express from "express"; import * as express from "express";
import * as getPort from "get-port"; import * as getPort from "get-port";
import {search} from "youtube-search-without-api-key"; import {search} from "youtube-search-without-api-key";
import {existsSync, rmSync, mkdirSync, readdirSync, readFileSync, writeFileSync, statSync} from "fs"; import {
existsSync,
rmSync,
mkdirSync,
readdirSync,
readFileSync,
writeFileSync,
statSync,
unlinkSync,
rmdirSync,
lstatSync
} from "fs";
import {Stream} from "stream"; import {Stream} from "stream";
import {networkInterfaces} from "os"; import {networkInterfaces} from "os";
import * as mm from 'music-metadata'; import * as mm from 'music-metadata';
@ -37,6 +48,7 @@ export class BrowserWindow {
platform: process.platform, platform: process.platform,
dev: app.isPackaged, dev: app.isPackaged,
osRelease: os.release(), osRelease: os.release(),
updatable: !process.windowsStore || !process.mas,
components: [ components: [
"pages/podcasts", "pages/podcasts",
"pages/apple-account-settings", "pages/apple-account-settings",
@ -45,6 +57,7 @@ export class BrowserWindow {
"pages/library-artists", "pages/library-artists",
"pages/browse", "pages/browse",
"pages/settings", "pages/settings",
"pages/installed-themes",
"pages/listen_now", "pages/listen_now",
"pages/home", "pages/home",
"pages/artist-feed", "pages/artist-feed",
@ -95,6 +108,7 @@ export class BrowserWindow {
"components/fullscreen", "components/fullscreen",
"components/miniplayer", "components/miniplayer",
"components/castmenu", "components/castmenu",
"components/airplay-modal",
"components/artist-chip", "components/artist-chip",
"components/hello-world", "components/hello-world",
"components/inline-collection-list", "components/inline-collection-list",
@ -176,6 +190,10 @@ export class BrowserWindow {
page: "settings", page: "settings",
component: `<cider-settings></cider-settings>`, component: `<cider-settings></cider-settings>`,
condition: `page == 'settings'` condition: `page == 'settings'`
}, {
page: "installed-themes",
component: `<installed-themes></installed-themes>`,
condition: `page == 'installed-themes'`
}, { }, {
page: "search", page: "search",
component: `<cider-search :search="search"></cider-search>`, component: `<cider-search :search="search"></cider-search>`,
@ -254,8 +272,10 @@ export class BrowserWindow {
}, },
}; };
public static watcher: any;
StartWatcher(path: string) { StartWatcher(path: string) {
const watcher = watch(path, { BrowserWindow.watcher = watch(path, {
ignored: /[\/\\]\./, ignored: /[\/\\]\./,
persistent: true persistent: true
}); });
@ -265,7 +285,7 @@ export class BrowserWindow {
} }
// Declare the listeners of the watcher // Declare the listeners of the watcher
watcher BrowserWindow.watcher
.on('add', function (path: string) { .on('add', function (path: string) {
// console.log('File', path, 'has been added'); // console.log('File', path, 'has been added');
}) })
@ -292,6 +312,10 @@ export class BrowserWindow {
}); });
} }
async StopWatcher() {
await BrowserWindow.watcher.close();
}
/** /**
* Creates the browser window * Creates the browser window
* @generator * @generator
@ -311,6 +335,8 @@ export class BrowserWindow {
}); });
this.options.width = windowState.width; this.options.width = windowState.width;
this.options.height = windowState.height; this.options.height = windowState.height;
this.options.x = windowState.x;
this.options.y = windowState.y;
switch (process.platform) { switch (process.platform) {
default: default:
@ -696,6 +722,50 @@ export class BrowserWindow {
}; };
}) })
ipcMain.handle("uninstall-theme", async (event, path) => {
await this.StopWatcher()
const themesDir = utils.getPath("themes")
// validate the path is in the themes directory
try {
if (path.startsWith(themesDir)) {
// get last dir in path, can be either / or \ and may have a trailing slash
const themeName = path.split(/[\\\/]/).pop()
if (themeName == "Themes" || themeName == "themes") {
BrowserWindow.win.webContents.send("theme-uninstalled", {
path: path,
status: 3
});
return
}
// if path is directory, delete it
if (lstatSync(path).isDirectory()) {
await rmdirSync(path, {recursive: true});
} else {
// if path is file, delete it
await unlinkSync(path);
}
// return the path
BrowserWindow.win.webContents.send("theme-uninstalled", {
path: path,
status: 0
});
} else {
BrowserWindow.win.webContents.send("theme-uninstalled", {
path: path,
status: 1
});
}
} catch (e: any) {
BrowserWindow.win.webContents.send("theme-uninstalled", {
path: path,
message: e.message,
status: 2
});
}
this.StartWatcher(utils.getPath('themes'))
})
ipcMain.handle("reinstall-widevine-cdm", () => { ipcMain.handle("reinstall-widevine-cdm", () => {
// remove WidevineCDM from appdata folder // remove WidevineCDM from appdata folder
const widevineCdmPath = join(app.getPath("userData"), "./WidevineCdm"); const widevineCdmPath = join(app.getPath("userData"), "./WidevineCdm");
@ -811,7 +881,7 @@ export class BrowserWindow {
} else if (statSync(join(utils.getPath("themes"), file)).isDirectory()) { } else if (statSync(join(utils.getPath("themes"), file)).isDirectory()) {
let subFiles = readdirSync(join(utils.getPath("themes"), file)); let subFiles = readdirSync(join(utils.getPath("themes"), file));
for (let subFile of subFiles) { for (let subFile of subFiles) {
if (subFile.endsWith(".less")) { if (subFile.endsWith("index.less")) {
themes.push(join(file, subFile)); themes.push(join(file, subFile));
} }
} }
@ -830,6 +900,7 @@ export class BrowserWindow {
themePath = themePath.slice(0, -10); themePath = themePath.slice(0, -10);
} }
if (existsSync(join(themePath, "theme.json"))) { if (existsSync(join(themePath, "theme.json"))) {
try {
let themeJson = JSON.parse(readFileSync(join(themePath, "theme.json"), "utf8")); let themeJson = JSON.parse(readFileSync(join(themePath, "theme.json"), "utf8"));
themeObjects.push({ themeObjects.push({
name: themeJson.name || themeName, name: themeJson.name || themeName,
@ -837,8 +908,12 @@ export class BrowserWindow {
path: themePath, path: themePath,
file: theme, file: theme,
github_repo: themeJson.github_repo || "", github_repo: themeJson.github_repo || "",
commit: themeJson.commit || "" commit: themeJson.commit || "",
pack: themeJson.pack || false,
}); });
} catch (e) {
console.error(e);
}
} else { } else {
themeObjects.push({ themeObjects.push({
name: themeName, name: themeName,
@ -846,7 +921,8 @@ export class BrowserWindow {
path: themePath, path: themePath,
file: theme, file: theme,
github_repo: "", github_repo: "",
commit: "" commit: "",
pack: false
}); });
} }
} }
@ -897,6 +973,10 @@ export class BrowserWindow {
event.returnValue = process.platform; event.returnValue = process.platform;
}); });
ipcMain.on("get-port", (event) => {
event.returnValue = this.clientPort;
});
ipcMain.on("is-dev", (event) => { ipcMain.on("is-dev", (event) => {
event.returnValue = this.devMode; event.returnValue = this.devMode;
}); });
@ -965,6 +1045,11 @@ export class BrowserWindow {
BrowserWindow.win.setResizable(!lock); BrowserWindow.win.setResizable(!lock);
}); });
// Move window
ipcMain.on("windowmove", (_event, x, y) => {
BrowserWindow.win.setBounds({x, y});
});
//Fullscreen //Fullscreen
ipcMain.on('setFullScreen', (_event, flag) => { ipcMain.on('setFullScreen', (_event, flag) => {
BrowserWindow.win.setFullScreen(flag) BrowserWindow.win.setFullScreen(flag)
@ -1209,16 +1294,27 @@ export class BrowserWindow {
shell.openPath(app.getPath('userData')); shell.openPath(app.getPath('userData'));
}); });
//#region Cider Connect
ipcMain.on('cc-auth', (_event) => { ipcMain.on('cc-auth', (_event) => {
shell.openExternal(String(utils.getStoreValue('cc_authURL'))); shell.openExternal(String(utils.getStoreValue('cc_authURL')));
}); });
ipcMain.on('cc-logout', (_event) => { ipcMain.on('cc-logout', (_event) => { //Make sure to update the default store
utils.setStoreValue('connectUser', { utils.setStoreValue('connectUser', {
auth: null "auth": null,
"sync": {
themes: false,
plugins: false,
settings: false,
}
}); });
utils.getWindow().reload(); utils.getWindow().reload();
}); });
ipcMain.on('cc-push', (_event) => {
utils.pushStoreToConnect();
})
/* ********************************************************************************************* /* *********************************************************************************************
* Window Events * Window Events
* **********************************************************************************************/ * **********************************************************************************************/
@ -1262,7 +1358,7 @@ export class BrowserWindow {
BrowserWindow.win.webContents.executeJavaScript(` BrowserWindow.win.webContents.executeJavaScript(`
window.localStorage.setItem("currentTrack", JSON.stringify(app.mk.nowPlayingItem)); window.localStorage.setItem("currentTrack", JSON.stringify(app.mk.nowPlayingItem));
window.localStorage.setItem("currentTime", JSON.stringify(app.mk.currentPlaybackTime)); window.localStorage.setItem("currentTime", JSON.stringify(app.mk.currentPlaybackTime));
window.localStorage.setItem("currentQueue", JSON.stringify(app.mk.queue.items)); window.localStorage.setItem("currentQueue", JSON.stringify(app.mk.queue._unplayedQueueItems));
ipcRenderer.send('stopGCast','');`) ipcRenderer.send('stopGCast','');`)
BrowserWindow.win.destroy(); BrowserWindow.win.destroy();
} }

View file

@ -1,7 +1,7 @@
import * as ElectronStore from 'electron-store'; import * as ElectronStore from 'electron-store';
import * as electron from "electron"; import * as electron from "electron";
import {app} from "electron"; import {app} from "electron";
import fetch from "electron-fetch";
export class Store { export class Store {
static cfg: ElectronStore; static cfg: ElectronStore;
@ -12,7 +12,7 @@ export class Store {
}, },
"general": { "general": {
"close_button_hide": false, "close_button_hide": false,
"discord_rpc": { "discordrpc": {
"enabled": false, "enabled": false,
"client": "Cider", "client": "Cider",
"clear_on_pause": true, "clear_on_pause": true,
@ -52,11 +52,11 @@ export class Store {
"keybindings": { "keybindings": {
"search": [ "search": [
process.platform == "darwin" ? "Command" : "Control", process.platform == "darwin" ? "Command" : "Control",
"S" "F"
], ],
"albums": [ "albums": [
process.platform == "darwin" ? "Command" : "Control", process.platform == "darwin" ? "Command" : "Control",
"F" "S"
], ],
"artists": [ "artists": [
process.platform == "darwin" ? "Command" : "Control", process.platform == "darwin" ? "Command" : "Control",
@ -123,6 +123,8 @@ export class Store {
"quality": "HIGH", "quality": "HIGH",
"seamless_audio": true, "seamless_audio": true,
"normalization": false, "normalization": false,
"dBSPL": false,
"dBSPLcalibration": 90,
"maikiwiAudio": { "maikiwiAudio": {
"ciderPPE": false, "ciderPPE": false,
"ciderPPE_value": "MAIKIWI", "ciderPPE_value": "MAIKIWI",
@ -212,17 +214,22 @@ export class Store {
}, },
"connectUser": { "connectUser": {
"auth": null, "auth": null,
"sync": {
themes: false,
plugins: false,
settings: false,
}
}, },
} }
private migrations: any = { private migrations: any = {
'>=1.4.3': (store: ElectronStore) => { '>=1.4.3': (store: ElectronStore) => {
if (typeof store.get('general.discord_rpc') == 'number' || typeof store.get('general.discord_rpc') == 'string') { if (typeof store.get('general.discordrpc') == 'number' || typeof store.get('general.discordrpc') == 'string') {
store.delete('general.discord_rpc'); store.delete('general.discordrpc');
} }
}, },
} }
private schema: ElectronStore.Schema<any> = { private schema: ElectronStore.Schema<any> = {
"general.discord_rpc": { "general.discordrpc": {
type: 'object' type: 'object'
}, },
} }
@ -261,6 +268,7 @@ export class Store {
return target return target
} }
/** /**
* IPC Handler * IPC Handler
*/ */
@ -282,4 +290,42 @@ export class Store {
}) })
} }
static pushToCloud(): void {
if (Store.cfg.get('connectUser.auth') === null) return;
var syncData = Object();
if (Store.cfg.get('connectUser.sync.themes')) {
syncData.push({
themes: Store.cfg.store.themes
})
}
if (Store.cfg.get('connectUser.sync.plugins')) {
syncData.push({
plugins: Store.cfg.store.plugins
})
}
if (Store.cfg.get('connectUser.sync.settings')) {
syncData.push({
general: Store.cfg.get('general'),
home: Store.cfg.get('home'),
libraryPrefs: Store.cfg.get('libraryPrefs'),
advanced: Store.cfg.get('advanced'),
})
}
let postBody = {
id: Store.cfg.get('connectUser.id'),
app: electron.app.getName(),
version: electron.app.isPackaged ? electron.app.getVersion() : 'dev',
syncData: syncData
}
fetch('https://connect.cidercollective.dev/api/v1/setttings/set', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(postBody)
})
}
} }

View file

@ -80,6 +80,7 @@ export class utils {
return Store.cfg.store return Store.cfg.store
} }
/** /**
* Get the store instance * Get the store instance
* @returns {Store} * @returns {Store}
@ -97,6 +98,18 @@ export class utils {
Store.cfg.set(key, value) Store.cfg.set(key, value)
} }
/**
* Pushes Store to Connect
* @return Function
*/
static pushStoreToConnect(): Function {
return Store.pushToCloud
}
/** /**
* Gets the browser window * Gets the browser window
*/ */
@ -198,4 +211,6 @@ export class utils {
autoUpdater.logger = log autoUpdater.logger = log
await autoUpdater.checkForUpdatesAndNotify() await autoUpdater.checkForUpdatesAndNotify()
} }
} }

View file

@ -28,7 +28,7 @@ export default class ChromecastPlugin {
// private GCstream = new Stream.PassThrough(), // private GCstream = new Stream.PassThrough(),
private connectedHosts: any = {}; private connectedHosts: any = {};
private connectedPlayer: any; private connectedPlayer: any;
// private port = false; private ciderPort :any = 9000;
// private server = false; // private server = false;
// private bufcount = 0; // private bufcount = 0;
// private bufcount2 = 0; // private bufcount2 = 0;
@ -148,7 +148,7 @@ export default class ChromecastPlugin {
} }
let media = { let media = {
// Here you can plug an URL to any mp4, webm, mp3 or jpg file with the proper contentType. // Here you can plug an URL to any mp4, webm, mp3 or jpg file with the proper contentType.
contentId: 'http://' + this.getIp() + ':9000/audio.wav', contentId: 'http://' + this.getIp() + ':'+ this.ciderPort +'/audio.wav',
contentType: 'audio/wav', contentType: 'audio/wav',
streamType: 'LIVE', // or LIVE streamType: 'LIVE', // or LIVE
@ -361,4 +361,12 @@ export default class ChromecastPlugin {
} }
onRendererReady(): void {
this._win.webContents.executeJavaScript(
`ipcRenderer.sendSync('get-port')`
).then((result: any) => {
this.ciderPort = result;
});
}
} }

View file

@ -1,40 +1,29 @@
import * as RPC from 'discord-rpc' import {AutoClient} from 'discord-auto-rpc'
import {ipcMain} from "electron"; import {ipcMain} from "electron";
import fetch from 'electron-fetch' import fetch from 'electron-fetch'
export default class DiscordRPC { export default class DiscordRPC {
/**
* Private variables for interaction in plugins
*/
private _utils: any;
private _app: any;
private _attributes: any;
private _connection: boolean = false;
/** /**
* Base Plugin Details (Eventually implemented into a GUI in settings) * Base Plugin Details (Eventually implemented into a GUI in settings)
*/ */
public name: string = 'Discord Rich Presence'; public name: string = 'Discord Rich Presence';
public description: string = 'Discord RPC plugin for Cider'; public description: string = 'Discord RPC plugin for Cider';
public version: string = '1.0.0'; public version: string = '1.1.0';
public author: string = 'vapormusic/Core (Cider Collective)'; public author: string = 'vapormusic/Core (Cider Collective)';
/**
* Private variables for interaction in plugins
*/
private _utils: any;
private _attributes: any;
private ready: boolean = false;
/** /**
* Plugin Initialization * Plugin Initialization
*/ */
private _client: any = null; private _client: any = null;
private _activity: RPC.Presence = { private _activityCache: any = {
details: '',
state: '',
largeImageKey: '',
largeImageText: '',
smallImageKey: '',
smallImageText: '',
instance: false
};
private _activityCache: RPC.Presence = {
details: '', details: '',
state: '', state: '',
largeImageKey: '', largeImageKey: '',
@ -44,6 +33,73 @@ export default class DiscordRPC {
instance: false instance: false
}; };
/*******************************************************************************************
* Public Methods
* ****************************************************************************************/
/**
* Runs on plugin load (Currently run on application start)
*/
constructor(utils: any) {
this._utils = utils;
console.debug(`[Plugin][${this.name}] Loading Complete.`);
}
/**
* Runs on app ready
*/
onReady(_win: any): void {
const self = this
this.connect();
console.debug(`[Plugin][${this.name}] Ready.`);
ipcMain.on('updateRPCImage', (_event, imageurl) => {
if (!this._utils.getStoreValue("general.privateEnabled")) {
fetch('https://api.cider.sh/v1/images', {
method: 'POST',
body: JSON.stringify({url: imageurl}),
headers: {
'Content-Type': 'application/json',
'User-Agent': _win.webContents.getUserAgent()
},
})
.then(res => res.json())
.then(function (json) {
self._attributes["artwork"]["url"] = json.url
self.setActivity(self._attributes)
})
}
})
}
/**
* Runs on app stop
*/
onBeforeQuit(): void {
console.debug(`[Plugin][${this.name}] Stopped.`);
}
/**
* Runs on playback State Change
* @param attributes Music Attributes (attributes.status = current state)
*/
onPlaybackStateDidChange(attributes: object): void {
this._attributes = attributes
this.setActivity(attributes)
}
/**
* Runs on song change
* @param attributes Music Attributes
*/
onNowPlayingItemDidChange(attributes: object): void {
this._attributes = attributes
this.setActivity(attributes)
}
/******************************************************************************************* /*******************************************************************************************
* Private Methods * Private Methods
* ****************************************************************************************/ * ****************************************************************************************/
@ -53,63 +109,91 @@ export default class DiscordRPC {
* @private * @private
*/ */
private connect() { private connect() {
if (!this._utils.getStoreValue("general.discord_rpc.enabled")) { if (!this._utils.getStoreValue("general.discordrpc.enabled")) {
return; return;
} }
const clientId = this._utils.getStoreValue("general.discord_rpc.client") === "Cider" ? '911790844204437504' : '886578863147192350'; const clientId = this._utils.getStoreValue("general.discordrpc.client") === "Cider" ? '911790844204437504' : '886578863147192350';
// Apparently needed for ask to join, join, spectate etc.
RPC.register(clientId)
// Create the client // Create the client
this._client = new RPC.Client({transport: "ipc"}); this._client = new AutoClient({transport: "ipc"});
// Runs on Ready // Runs on Ready
this._client.on('ready', () => { this._client.once('ready', () => {
console.info(`[DiscordRPC][connect] Successfully Connected to Discord. Authed for user: ${this._client.user.id}.`); console.info(`[DiscordRPC][connect] Successfully Connected to Discord. Authed for user: ${this._client.user.id}.`);
if (this._activityCache && this._activityCache.details && this._activityCache.state) {
console.info(`[DiscordRPC][connect] Restoring activity cache.`);
this._client.setActivity(this._activityCache)
}
}) })
// Handles Errors
this._client.on('error', (err: any) => {
console.error(`[DiscordRPC] ${err}`);
this.disconnect()
});
// If Discord is closed, allow reconnecting
this._client.transport.once('close', () => {
console.info(`[DiscordRPC] Connection closed`);
this.disconnect()
});
// Login to Discord // Login to Discord
this._client.login({clientId}) this._client.endlessLogin({clientId: clientId})
.then(() => { .then(() => {
this._connection = true; this.ready = true
}) })
.catch((e: any) => console.error(`[DiscordRPC][connect] ${e}`)); .catch((e: any) => console.error(`[DiscordRPC][connect] ${e}`));
} }
/** /**
* Disconnects from Discord RPC * Sets the activity
* @param attributes Music Attributes
*/ */
private disconnect() { private setActivity(attributes: any) {
if (!this._client) { if (!this._client) {
return return
} }
this._client.destroy().then(() => { // Check if show buttons is (true) or (false)
this._connection = false; let activity: Object = {
console.log('[DiscordRPC][disconnect] Disconnected from discord.') details: this._utils.getStoreValue("general.discordrpc.details_format"),
}).catch((e: any) => console.error(`[DiscordRPC][disconnect] ${e}`)); state: this._utils.getStoreValue("general.discordrpc.state_format"),
largeImageKey: attributes?.artwork?.url?.replace('{w}', '1024').replace('{h}', '1024'),
largeImageText: attributes.albumName,
instance: false // Whether the activity is in a game session
}
// Clean up, allow creating a new connection // Filter the activity
this._client = null; activity = this.filterActivity(activity, attributes)
if (!this.ready) {
this._activityCache = activity
return
}
// Set the activity
if (!attributes.status && this._utils.getStoreValue("general.discordrpc.clear_on_pause")) {
this._client.clearActivity()
} else if (activity && this._activityCache !== activity) {
this._client.setActivity(activity)
}
this._activityCache = activity;
} }
/** /**
* Filter the Discord activity object * Filter the Discord activity object
*/ */
private static filterActivity(activity: any, attributes: any): Object { private filterActivity(activity: any, attributes: any): Object {
// Add the buttons if people want them
if (!this._utils.getStoreValue("general.discordrpc.hide_buttons")) {
activity.buttons = [
{label: 'Listen on Cider', url: attributes.url.cider},
{label: 'View on Apple Music', url: attributes.url.appleMusic}
] //To change attributes.url => preload/cider-preload.js
}
// Add the timestamp if its playing
if (attributes.status) {
activity.startTimestamp = Date.now() - (attributes?.durationInMillis - attributes?.remainingTime)
activity.endTimestamp = attributes.endTime
}
// If the user wants to keep the activity when paused
if (!this._utils.getStoreValue("general.discordrpc.clear_on_pause")) {
activity.smallImageKey = attributes.status ? 'play' : 'pause';
activity.smallImageText = attributes.status ? 'Playing' : 'Paused';
}
/** /**
* Works with: * Works with:
@ -173,138 +257,4 @@ export default class DiscordRPC {
} }
return activity return activity
} }
/**
* Sets the activity
* @param {activity} activity
*/
private setActivity(activity: any) {
if (!this._connection || !this._client || !activity) {
return
}
// Filter the activity
activity = DiscordRPC.filterActivity(activity, this._attributes)
// Set the activity
if (!this._attributes.status && this._utils.getStoreValue("general.discord_rpc.clear_on_pause")) {
this._client.clearActivity()
} else if (this._activity && this._activityCache !== this._activity && this._activity.details) {
this._client.setActivity(activity)
this._activityCache = this._activity;
}
}
/**
* Sets the activity of the client
* @param {object} attributes
*/
private updateActivity(attributes: any) {
if (!this._utils.getStoreValue("general.discord_rpc.enabled") || this._utils.getStoreValue("general.privateEnabled")) {
return
} else if (!this._client || !this._connection) {
this.connect()
}
// Check if show buttons is (true) or (false)
this._activity = {
details: this._utils.getStoreValue("general.discord_rpc.details_format"),
state: this._utils.getStoreValue("general.discord_rpc.state_format"),
largeImageKey: attributes?.artwork?.url?.replace('{w}', '1024').replace('{h}', '1024'),
largeImageText: attributes.albumName,
instance: false // Whether the activity is in a game session
}
// Add the buttons if people want them
if (!this._utils.getStoreValue("general.discord_rpc.hide_buttons")) {
this._activity.buttons = [
{label: 'Listen on Cider', url: attributes.url.cider},
{label: 'View on Apple Music', url: attributes.url.appleMusic}
] //To change attributes.url => preload/cider-preload.js
}
// Add the timestamp if its playing
if (attributes.status) {
this._activity.startTimestamp = Date.now() - (attributes?.durationInMillis - attributes?.remainingTime)
this._activity.endTimestamp = attributes.endTime
}
// If the user wants to keep the activity when paused
if (!this._utils.getStoreValue("general.discord_rpc.clear_on_pause")) {
this._activity.smallImageKey = attributes.status ? 'play' : 'pause';
this._activity.smallImageText = attributes.status ? 'Playing' : 'Paused';
}
this.setActivity(this._activity)
}
/*******************************************************************************************
* Public Methods
* ****************************************************************************************/
/**
* Runs on plugin load (Currently run on application start)
*/
constructor(utils: { getStore: () => any; getApp: () => any; }) {
this._utils = utils;
console.debug(`[Plugin][${this.name}] Loading Complete.`);
this._app = utils.getApp();
}
/**
* Runs on app ready
*/
onReady(_win: any): void {
let self = this
this.connect();
console.debug(`[Plugin][${this.name}] Ready.`);
ipcMain.on('updateRPCImage', (_event, imageurl) => {
if (!this._utils.getStoreValue("general.privateEnabled")) {
fetch('https://api.cider.sh/v1/images', {
method: 'POST',
body: JSON.stringify({url: imageurl}),
headers: {
'Content-Type': 'application/json',
'User-Agent': _win.webContents.getUserAgent()
},
})
.then(res => res.json())
.then(function (json) {
self._attributes["artwork"]["url"] = json.url
self.updateActivity(self._attributes)
})
}
})
}
/**
* Runs on app stop
*/
onBeforeQuit(): void {
if (this._client) {
this.disconnect()
}
console.debug(`[Plugin][${this.name}] Stopped.`);
}
/**
* Runs on playback State Change
* @param attributes Music Attributes (attributes.status = current state)
*/
onPlaybackStateDidChange(attributes: object): void {
this._attributes = attributes
this.updateActivity(attributes)
}
/**
* Runs on song change
* @param attributes Music Attributes
*/
onNowPlayingItemDidChange(attributes: object): void {
this._attributes = attributes
this.updateActivity(attributes)
}
} }

View file

@ -3,6 +3,7 @@ import {utils} from "../base/utils";
export default class Thumbar { export default class Thumbar {
/** /**
* Base Plugin Details (Eventually implemented into a GUI in settings) * Base Plugin Details (Eventually implemented into a GUI in settings)
*/ */
@ -22,30 +23,36 @@ export default class Thumbar {
label: app.getName(), label: app.getName(),
submenu: [ submenu: [
{ {
label: 'About', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.about'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('about')`) click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('about')`)
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Settings', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.settings'),
accelerator: utils.getStoreValue("general.keybindings.settings").join('+'), accelerator: utils.getStoreValue("general.keybindings.settings").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('settings')`) click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('settings')`),
}, },
...(this.isMac ? [
{type: 'separator'}, {type: 'separator'},
{role: 'services'}, {role: 'services'},
{type: 'separator'}, {type: 'separator'},
{role: 'hide'}, {role: 'hide'},
{role: 'hideOthers'}, {role: 'hideOthers'},
{role: 'unhide'}, {role: 'unhide'},
]: [
{type: 'separator'}, {type: 'separator'},
{role: 'quit'} {role: 'quit', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.quit')},
] ]),
],
}, },
{ {
label: 'View', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.view'),
submenu: [ submenu: [
{role: 'reload'}, {role: 'reload', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.reload')},
{role: 'forceReload'}, {role: 'forceReload', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.forcereload')},
...(this.isMac ? [
{role: 'toggleDevTools'}, {role: 'toggleDevTools'},
{type: 'separator'}, {type: 'separator'},
{role: 'resetZoom'}, {role: 'resetZoom'},
@ -53,24 +60,27 @@ export default class Thumbar {
{role: 'zoomOut'}, {role: 'zoomOut'},
{type: 'separator'}, {type: 'separator'},
{role: 'togglefullscreen'}, {role: 'togglefullscreen'},
]
]: []),
],
}, },
{ {
label: 'Window', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.window'),
submenu: [ submenu: [
{role: 'minimize'}, {role: 'minimize', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.minimize')},
...(this.isMac ? [
{ {
label: 'Show', label: 'Show',
click: () => utils.getWindow().show() click: () => utils.getWindow().show()
}, },
{role: 'zoom'}, {role: 'zoom'},
...(this.isMac ? [
{type: 'separator'}, {type: 'separator'},
{role: 'front'}, {role: 'front'},
{role: 'close'}, {role: 'close'},
] : [
{role: 'close'}, {role: 'close'},
]),
{ {
label: 'Edit', label: 'Edit',
@ -83,146 +93,148 @@ export default class Thumbar {
{role: 'paste'}, {role: 'paste'},
] ]
}, },
] : []
),
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Toggle Private Session', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.toggleprivate'),
accelerator: utils.getStoreValue("general.keybindings.togglePrivateSession").join('+'), accelerator: utils.getStoreValue("general.keybindings.togglePrivateSession").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.cfg.general.privateEnabled = !app.cfg.general.privateEnabled`) click: () => utils.getWindow().webContents.executeJavaScript(`app.cfg.general.privateEnabled = !app.cfg.general.privateEnabled`)
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Web Remote', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.webremote'),
accelerator: utils.getStoreValue("general.keybindings.webRemote").join('+'), accelerator: utils.getStoreValue("general.keybindings.webRemote").join('+'),
sublabel: 'Opens in external window', sublabel: 'Opens in external window',
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('remote-pair')`) click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('remote-pair')`)
}, },
{ {
label: 'Audio Settings', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.audio'),
accelerator: utils.getStoreValue("general.keybindings.audioSettings").join('+'), accelerator: utils.getStoreValue("general.keybindings.audioSettings").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.modals.audioSettings = true`) click: () => utils.getWindow().webContents.executeJavaScript(`app.modals.audioSettings = true`)
}, },
{ {
label: 'Plug-in Menu', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.plugins'),
accelerator: utils.getStoreValue("general.keybindings.pluginMenu").join('+'), accelerator: utils.getStoreValue("general.keybindings.pluginMenu").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.modals.pluginMenu = true`) click: () => utils.getWindow().webContents.executeJavaScript(`app.modals.pluginMenu = true`)
} }
] ]
}, },
{ {
label: 'Controls', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.controls'),
submenu: [ submenu: [
{ {
label: 'Pause / Play', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.playpause'),
accelerator: 'Space', accelerator: 'Space',
click: () => utils.getWindow().webContents.executeJavaScript(`app.SpacePause()`) click: () => utils.getWindow().webContents.executeJavaScript(`app.SpacePause()`)
}, },
{ {
label: 'Next', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.next'),
accelerator: 'CommandOrControl+Right', accelerator: 'CommandOrControl+Right',
click: () => utils.getWindow().webContents.executeJavaScript(`MusicKitInterop.next()`) click: () => utils.getWindow().webContents.executeJavaScript(`MusicKitInterop.next()`)
}, },
{ {
label: 'Previous', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.previous'),
accelerator: 'CommandOrControl+Left', accelerator: 'CommandOrControl+Left',
click: () => utils.getWindow().webContents.executeJavaScript(`MusicKitInterop.previous()`) click: () => utils.getWindow().webContents.executeJavaScript(`MusicKitInterop.previous()`)
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Volume Up', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.volumeup'),
accelerator: 'CommandOrControl+Up', accelerator: 'CommandOrControl+Up',
click: () => utils.getWindow().webContents.executeJavaScript(`app.volumeUp()`) click: () => utils.getWindow().webContents.executeJavaScript(`app.volumeUp()`)
}, },
{ {
label: 'Volume Down', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.volumedown'),
accelerator: 'CommandOrControl+Down', accelerator: 'CommandOrControl+Down',
click: () => utils.getWindow().webContents.executeJavaScript(`app.volumeDown()`) click: () => utils.getWindow().webContents.executeJavaScript(`app.volumeDown()`)
}, },
{ {
label: 'Browse', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.browse'),
accelerator: utils.getStoreValue("general.keybindings.browse").join('+'), accelerator: utils.getStoreValue("general.keybindings.browse").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('browse')`) click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('browse')`)
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Artists', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.artists'),
accelerator: utils.getStoreValue("general.keybindings.artists").join('+'), accelerator: utils.getStoreValue("general.keybindings.artists").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('library-artists')`) click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('library-artists')`)
}, },
{ {
label: 'Search', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.search'),
accelerator: utils.getStoreValue("general.keybindings.search").join('+'), accelerator: utils.getStoreValue("general.keybindings.search").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('search')`) click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('search')`)
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Album', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.albums'),
accelerator: utils.getStoreValue("general.keybindings.albums").join('+'), accelerator: utils.getStoreValue("general.keybindings.albums").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('library-albums')`) click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('library-albums')`)
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Cast To Devices', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.cast'),
accelerator: utils.getStoreValue("general.keybindings.castToDevices").join('+'), accelerator: utils.getStoreValue("general.keybindings.castToDevices").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.modals.castMenu = true`) click: () => utils.getWindow().webContents.executeJavaScript(`app.modals.castMenu = true`)
} }
] ]
}, },
{ {
label: 'Account', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.account'),
submenu: [ submenu: [
{ {
label: 'Account Settings', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.accountsettings'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('apple-account-settings')`) click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('apple-account-settings')`)
}, },
{ {
label: 'Sign Out', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.signout'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.unauthorize()`) click: () => utils.getWindow().webContents.executeJavaScript(`app.unauthorize()`)
} }
] ]
}, },
{ {
label: 'Support', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.support'),
role: 'help', role: 'help',
submenu: [ submenu: [
{ {
label: 'Discord', label: utils.getLocale('Discord', 'menubar.options.discord'),
click: () => shell.openExternal("https://discord.gg/AppleMusic").catch(console.error) click: () => shell.openExternal("https://discord.gg/AppleMusic").catch(console.error)
}, },
{ {
label: 'GitHub Wiki', label: utils.getLocale('GitHub Wiki', 'menubar.options.github'),
click: () => shell.openExternal("https://github.com/ciderapp/Cider/wiki/Troubleshooting").catch(console.error) click: () => shell.openExternal("https://github.com/ciderapp/Cider/wiki/Troubleshooting").catch(console.error)
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Report a...', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.report'),
submenu: [ submenu: [
{ {
label: 'Bug', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.bug'),
click: () => shell.openExternal("https://github.com/ciderapp/Cider/issues/new?assignees=&labels=bug%2Ctriage&template=bug_report.yaml&title=%5BBug%5D%3A+").catch(console.error) click: () => shell.openExternal("https://github.com/ciderapp/Cider/issues/new?assignees=&labels=bug%2Ctriage&template=bug_report.yaml&title=%5BBug%5D%3A+").catch(console.error)
}, },
{ {
label: 'Feature Request', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.feature'),
click: () => shell.openExternal("https://github.com/ciderapp/Cider/discussions/new?category=feature-request").catch(console.error) click: () => shell.openExternal("https://github.com/ciderapp/Cider/discussions/new?category=feature-request").catch(console.error)
}, },
{ {
label: 'Translation Report/Request', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.trans'),
click: () => shell.openExternal("https://github.com/ciderapp/Cider/issues/new?assignees=&labels=%F0%9F%8C%90+Translations&template=translation.yaml&title=%5BTranslation%5D%3A+").catch(console.error) click: () => shell.openExternal("https://github.com/ciderapp/Cider/issues/new?assignees=&labels=%F0%9F%8C%90+Translations&template=translation.yaml&title=%5BTranslation%5D%3A+").catch(console.error)
}, },
] ]
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'View License', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.license'),
click: () => shell.openExternal("https://github.com/ciderapp/Cider/blob/main/LICENSE").catch(console.error) click: () => shell.openExternal("https://github.com/ciderapp/Cider/blob/main/LICENSE").catch(console.error)
}, },
{type: 'separator'}, {type: 'separator'},
{ {
label: 'Toggle Developer Tools', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.toggledevtools'),
accelerator: utils.getStoreValue("general.keybindings.openDeveloperTools").join('+'), accelerator: utils.getStoreValue("general.keybindings.openDeveloperTools").join('+'),
click: () => utils.getWindow().webContents.openDevTools() click: () => utils.getWindow().webContents.openDevTools()
}, },
{ {
label: 'Open Configuration File in Editor', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.conf'),
click: () => utils.getStoreInstance().openInEditor() click: () => utils.getStoreInstance().openInEditor()
} }
] ]

View file

@ -89,9 +89,9 @@ export default class RAOP {
`; `;
private ondeviceup(name: any, host: any, port: any, addresses: any, text: any) { private ondeviceup(name: any, host: any, port: any, addresses: any, text: any) {
if (this.castDevices.findIndex((item: any) => item.name === host && item.port === port && item.addresses === addresses) === -1) { if (this.castDevices.findIndex((item: any) => item.name == host.replace(".local","") && item.port == port && item.addresses == addresses) === -1) {
this.castDevices.push({ this.castDevices.push({
name: host, name: host.replace(".local",""),
host: addresses ? addresses[0] : '', host: addresses ? addresses[0] : '',
port: port, port: port,
addresses: addresses, addresses: addresses,
@ -152,9 +152,23 @@ export default class RAOP {
this._win.webContents.executeJavaScript(`console.log( this._win.webContents.executeJavaScript(`console.log(
"${service.name} ${service.host}:${service.port} ${service.addresses}" "${service.name} ${service.host}:${service.port} ${service.addresses}"
)`); )`);
this.ondeviceup(service.name, service.host, service.port, service.addresses, service.txt);} this.ondeviceup(service.name, service.host, service.port, service.addresses, service.txt);
}
}); });
// const browser2 = this.mdns.createBrowser(this.mdns.tcp('airplay'));
// browser2.on('ready', browser2.discover);
// browser2.on('update', (service: any) => {
// if (service.addresses && service.fullname && (service.fullname.includes('_raop._tcp') || service.fullname.includes('_airplay._tcp'))) {
// // console.log(service.txt)
// this._win.webContents.executeJavaScript(`console.log(
// "${service.name} ${service.host}:${service.port} ${service.addresses}"
// )`);
// this.ondeviceup(service.name, service.host, service.port, service.addresses, service.txt);
// }
// });
}); });
@ -167,7 +181,7 @@ export default class RAOP {
this.portairplay = ipport; this.portairplay = ipport;
this.device = this.airtunes.add(ipv4, { this.device = this.airtunes.add(ipv4, {
port: ipport, port: ipport,
volume: 60, volume: 50,
password: sepassword, password: sepassword,
txt: txt txt: txt
}); });
@ -178,6 +192,15 @@ export default class RAOP {
this._win.webContents.setAudioMuted(true); this._win.webContents.setAudioMuted(true);
this._win.webContents.executeJavaScript(`CiderAudio.sendAudio()`).catch((err: any) => console.error(err)); this._win.webContents.executeJavaScript(`CiderAudio.sendAudio()`).catch((err: any) => console.error(err));
} }
if (status == "need_password"){
this._win.webContents.executeJavaScript(`app.setAirPlayCodeUI()`)
}
if (status == "pair_success"){
this._win.webContents.executeJavaScript(`app.sendAirPlaySuccess()`)
}
if (status == "pair_failed"){
this._win.webContents.executeJavaScript(`app.sendAirPlayFailed()`)
}
if (status == 'stopped') { if (status == 'stopped') {
this.airtunes.stopAll(() => { this.airtunes.stopAll(() => {
console.log('end'); console.log('end');
@ -210,6 +233,12 @@ export default class RAOP {
}); });
electron.ipcMain.on('setAirPlayPasscode', (event, passcode) => {
if (this.device){
this.device.setPasscode(passcode)
}
})
electron.ipcMain.on('writeWAV', (event, leftbuffer, rightbuffer) => { electron.ipcMain.on('writeWAV', (event, leftbuffer, rightbuffer) => {
if (this.airtunes != null) { if (this.airtunes != null) {
if (this.worker == null) { if (this.worker == null) {

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-heart"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>

After

Width:  |  Height:  |  Size: 373 B

View file

@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-heart"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg> <svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-heart"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>

Before

Width:  |  Height:  |  Size: 371 B

After

Width:  |  Height:  |  Size: 364 B

Before After
Before After

View file

@ -364,6 +364,21 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
} }
.cd-mediaitem-list-item .heart-unfilled {
background-image: url("assets/feather/heart.svg");
height: 12px;
width: 36px;
filter: contrast(0);
background-repeat: no-repeat;
}
.cd-mediaitem-list-item .heart-filled {
background-image: url("assets/feather/heart-fill.svg");
height: 12px;
width: 36px;
filter: contrast(0);
background-repeat: no-repeat;
}
.cd-mediaitem-list-item .explicit-icon { .cd-mediaitem-list-item .explicit-icon {
background-image: url("assets/explicit.svg"); background-image: url("assets/explicit.svg");
height: 12px; height: 12px;
@ -371,6 +386,9 @@
filter: contrast(0); filter: contrast(0);
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.heart-icon {
display: flex
}
@keyframes load-bar { @keyframes load-bar {
10% { 10% {
box-shadow: inset 0 -4px 0; box-shadow: inset 0 -4px 0;

View file

@ -359,7 +359,11 @@
align-items: center; align-items: center;
border-radius: var(--mediaItemRadius); border-radius: var(--mediaItemRadius);
position: relative; position: relative;
&:hover{
.heart-icon{
display: none;
}
}
.popular { .popular {
background-image: url(assets/star.svg); background-image: url(assets/star.svg);
background-repeat: no-repeat; background-repeat: no-repeat;
@ -448,6 +452,22 @@
justify-content: center; justify-content: center;
} }
.heart-unfilled {
-webkit-mask-image: url("assets/feather/heart.svg");
height: 12px;
width: 12px;
background-repeat: no-repeat;
background-color: #999;
}
.heart-filled {
-webkit-mask-image: url("assets/feather/heart-fill.svg");
height: 12px;
width: 12px;
background-repeat: no-repeat;
background-color: #999;
}
.explicit-icon { .explicit-icon {
background-image: url("./assets/explicit.svg"); background-image: url("./assets/explicit.svg");
height: 12px; height: 12px;
@ -456,6 +476,12 @@
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.heart-icon {
display: flex;
position: absolute;
left: 20px;
}
/* CSS.gg /* CSS.gg
*/ */
@keyframes load-bar { @keyframes load-bar {

View file

@ -70,10 +70,11 @@
.spatialproperties-panel { .spatialproperties-panel {
.modal-window { .modal-window {
&:not(.airplay-modal){
height : 700px; height : 700px;
max-height: 700px; max-height: 700px;
width : 800px; width : 800px;
max-width : 800px; max-width : 800px;}
overflow : hidden; overflow : hidden;
.info-header { .info-header {
@ -352,7 +353,7 @@
&:hover { &:hover {
&::before { &::before {
transition: transform .1s ease-in, opacity .1s ease-in; transition: transform 0s ease-in, opacity 0s ease-in;
opacity : 1; opacity : 1;
transform : scale(1); transform : scale(1);
} }

View file

@ -498,6 +498,18 @@
height : 100%; height : 100%;
overflow : hidden; overflow : hidden;
.cd-mediaitem-list-item {
&:hover {
.heart-icon {
display: flex;
}
}
.heart-icon {
left: -25px;
}
}
.editTracksBtn { .editTracksBtn {
position: absolute; position: absolute;
top : 20px; top : 20px;
@ -512,7 +524,8 @@
.mediaContainer { .mediaContainer {
transition: width 0.5s ease-in-out, height 0.5s ease-in-out; transition: width 0.5s ease-in-out, height 0.5s ease-in-out;
width: 260px;height:260px; width : 260px;
height : 260px;
} }
.playlist-body { .playlist-body {
@ -537,12 +550,15 @@
height : 100%; height : 100%;
overflow: hidden; overflow: hidden;
margin : 0px; margin : 0px;
.tab-pane { .tab-pane {
height : 100%; height : 100%;
overflow-y : overlay; overflow-y : overlay;
overflow-x : hidden; overflow-x : hidden;
padding : var(--contentInnerPadding); padding : var(--contentInnerPadding);
padding-inline : 40px;
-webkit-mask-image: linear-gradient(180deg, transparent, white 20px); -webkit-mask-image: linear-gradient(180deg, transparent, white 20px);
.well { .well {
margin: 0px; margin: 0px;
} }
@ -813,9 +829,7 @@
transition: min-height 0.5s ease-in-out; transition: min-height 0.5s ease-in-out;
min-height: 200px; min-height: 200px;
.playlistInfo { .playlistInfo {}
}
.mediaContainer { .mediaContainer {
transition: width 0.5s ease-in-out, height 0.5s ease-in-out; transition: width 0.5s ease-in-out, height 0.5s ease-in-out;
@ -1112,9 +1126,56 @@
/* Artist Page End */ /* Artist Page End */
// Settings page
.settings-page { .installed-themes-page {
.themeContextMenu {
background: transparent;
color : var(--keyColor);
border : 0px;
}
.list-group-item {
&.addon {
background: rgb(86 86 86 / 20%);
}
&.applied {
background: var(--keyColor-disabled);
pointer-events: none;
}
}
.repo-header {
font-size : 16px;
position : sticky;
top : 0;
left : 0;
right : 0;
width : 100%;
height : 50px;
z-index : 1;
background : rgba(36, 36, 36, 0.5);
display : flex;
justify-content: center;
align-items : center;
backdrop-filter: var(--glassFilter);
overflow : hidden;
border-bottom : 1px solid rgb(0 0 0 / 18%);
border-top : 1px solid rgb(135 135 135 / 18%);
}
.style-editor-container {
height : 100%;
flex : 1;
background: var(--color2);
padding : 0px; padding : 0px;
overflow-y: overlay;
.list-group-item {
border-radius: 0px;
}
}
.stylestack-editor { .stylestack-editor {
width: 100%; width: 100%;
@ -1129,6 +1190,23 @@
align-items: center; align-items: center;
} }
.handle {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.list-group-item {
&:hover {
cursor: grab;
}
&:active {
cursor: grabbing;
}
}
.removeItem { .removeItem {
border : 0px; border : 0px;
background : transparent; background : transparent;
@ -1145,7 +1223,11 @@
} }
} }
} }
}
// Settings page
.settings-page {
padding: 0px;
.nav { .nav {
width : 90%; width : 90%;
@ -1165,6 +1247,7 @@
height: 100%; height: 100%;
width : 100%; width : 100%;
} }
.settings-option-body { .settings-option-body {
margin: 16px; margin: 16px;
} }

View file

@ -148,6 +148,10 @@ const app = new Vue({
}, },
tmpHeight: '', tmpHeight: '',
tmpWidth: '', tmpWidth: '',
tmpX: '',
tmpY: '',
miniTmpX: '',
miniTmpY: '',
tmpVar: [], tmpVar: [],
notification: false, notification: false,
chrome: { chrome: {
@ -207,6 +211,7 @@ const app = new Vue({
showPlaylist: false, showPlaylist: false,
castMenu: false, castMenu: false,
moreInfo: false, moreInfo: false,
airplayPW: false,
}, },
socialBadges: { socialBadges: {
badgeMap: {}, badgeMap: {},
@ -230,6 +235,7 @@ const app = new Vue({
pages: [], pages: [],
}, },
moreinfodata: [], moreinfodata: [],
notyf: notyf
}, },
watch: { watch: {
cfg: { cfg: {
@ -283,6 +289,9 @@ const app = new Vue({
} }
} }
}, },
formatVolumeTooltip() {
return this.cfg.audio.dBSPL ? (Number(this.cfg.audio.dBSPLcalibration) + (Math.log10(this.mk.volume) * 20)).toFixed(2) + ' dB SPL' : (Math.log10(this.mk.volume) * 20).toFixed(2) + ' dBFS'
},
mainMenuVisibility(val) { mainMenuVisibility(val) {
if (val) { if (val) {
(this.mk.isAuthorized) ? this.chrome.menuOpened = !this.chrome.menuOpened : false; (this.mk.isAuthorized) ? this.chrome.menuOpened = !this.chrome.menuOpened : false;
@ -592,9 +601,7 @@ const app = new Vue({
}, },
async init() { async init() {
let self = this let self = this
if (this.cfg.visual.theme != "default.less" && this.cfg.visual.theme != "") {
this.setTheme(this.cfg.visual.theme)
}
if (this.cfg.visual.styles.length != 0) { if (this.cfg.visual.styles.length != 0) {
await this.reloadStyles() await this.reloadStyles()
} }
@ -702,6 +709,7 @@ const app = new Vue({
let lastItem = window.localStorage.getItem("currentTrack") let lastItem = window.localStorage.getItem("currentTrack")
let time = window.localStorage.getItem("currentTime") let time = window.localStorage.getItem("currentTime")
let queue = window.localStorage.getItem("currentQueue") let queue = window.localStorage.getItem("currentQueue")
app.mk.queue.position = 0; // Reset queue position.
if (lastItem != null) { if (lastItem != null) {
lastItem = JSON.parse(lastItem) lastItem = JSON.parse(lastItem)
let kind = lastItem.attributes.playParams.kind; let kind = lastItem.attributes.playParams.kind;
@ -721,7 +729,7 @@ const app = new Vue({
if (queue != null) { if (queue != null) {
queue = JSON.parse(queue) queue = JSON.parse(queue)
if (queue && queue.length > 0) { if (queue && queue.length > 0) {
let ids = queue.map(e => (e.playParams ? e.playParams.id : (e.attributes.playParams ? e.attributes.playParams.id : ''))) let ids = queue.map(e => (e.playParams ? e.playParams.id : (e.item.attributes.playParams ? e.item.attributes.playParams.id : '')))
let i = 0; let i = 0;
if (ids.length > 0) { if (ids.length > 0) {
for (let id of ids) { for (let id of ids) {
@ -832,6 +840,14 @@ const app = new Vue({
ipcRenderer.send('wsapi-updatePlaybackState', wsapi.getAttributes()); ipcRenderer.send('wsapi-updatePlaybackState', wsapi.getAttributes());
}) })
this.mk.addEventListener(MusicKit.Events.queueItemsDidChange, ()=>{
if (self.$refs.queue) {
setTimeout(()=>{
self.$refs.queue.updateQueue();
}, 100)
}
})
this.mk.addEventListener(MusicKit.Events.nowPlayingItemDidChange, (a) => { this.mk.addEventListener(MusicKit.Events.nowPlayingItemDidChange, (a) => {
if (self.$refs.queue) { if (self.$refs.queue) {
self.$refs.queue.updateQueue(); self.$refs.queue.updateQueue();
@ -1118,11 +1134,13 @@ const app = new Vue({
} }
}) })
}, },
async refreshPlaylists(localOnly = false) { async refreshPlaylists(localOnly = false, useCachedPlaylists = true) {
let self = this let self = this
let trackMap = this.cfg.advanced.playlistTrackMapping let trackMap = this.cfg.advanced.playlistTrackMapping
let newListing = [] let newListing = []
let trackMapping = {} let trackMapping = {}
if (useCachedPlaylists) {
const cachedPlaylist = await CiderCache.getCache("library-playlists") const cachedPlaylist = await CiderCache.getCache("library-playlists")
const cachedTrackMapping = await CiderCache.getCache("library-playlists-tracks") const cachedTrackMapping = await CiderCache.getCache("library-playlists-tracks")
@ -1141,14 +1159,17 @@ const app = new Vue({
if (localOnly) { if (localOnly) {
return return
} }
}
this.library.backgroundNotification.message = "Building playlist cache..." this.library.backgroundNotification.message = "Building playlist cache..."
this.library.backgroundNotification.show = true this.library.backgroundNotification.show = true
async function deepScan(parent = "p.playlistsroot") { async function deepScan(parent = "p.playlistsroot") {
console.debug(`scanning ${parent}`) console.debug(`scanning ${parent}`)
const playlistData = await app.mk.api.v3.music(`/v1/me/library/playlist-folders/${parent}/children/`) // const playlistData = await app.mk.api.v3.music(`/v1/me/library/playlist-folders/${parent}/children/`)
await asyncForEach(playlistData.data.data, async (playlist) => { const playlistData = await MusicKitTools.v3Continuous({href: `/v1/me/library/playlist-folders/${parent}/children/`})
console.log(playlistData)
await asyncForEach(playlistData, async (playlist) => {
playlist.parent = parent playlist.parent = parent
if ( if (
playlist.type != "library-playlist-folders" && playlist.type != "library-playlist-folders" &&
@ -1242,7 +1263,7 @@ const app = new Vue({
} }
} }
).then(res => { ).then(res => {
self.refreshPlaylists() self.refreshPlaylists(false, false)
}) })
}, },
async editPlaylist(id, name = app.getLz('term.newPlaylist')) { async editPlaylist(id, name = app.getLz('term.newPlaylist')) {
@ -1257,7 +1278,7 @@ const app = new Vue({
} }
} }
).then(res => { ).then(res => {
self.refreshPlaylists() self.refreshPlaylists(false, false)
}) })
}, },
copyToClipboard(str) { copyToClipboard(str) {
@ -1301,7 +1322,7 @@ const app = new Vue({
}) })
self.sortPlaylists() self.sortPlaylists()
setTimeout(() => { setTimeout(() => {
app.refreshPlaylists() app.refreshPlaylists(false, false)
}, 8000) }, 8000)
}) })
}, },
@ -1318,6 +1339,9 @@ const app = new Vue({
if (found) { if (found) {
self.playlists.listing.splice(self.playlists.listing.indexOf(found), 1) self.playlists.listing.splice(self.playlists.listing.indexOf(found), 1)
} }
setTimeout(() => {
app.refreshPlaylists(false, false);
}, 8000);
}) })
} }
}, },
@ -2563,7 +2587,7 @@ const app = new Vue({
}) })
self.sortPlaylists() self.sortPlaylists()
setTimeout(() => { setTimeout(() => {
app.refreshPlaylists() app.refreshPlaylists(false, false)
}, 13000) }, 13000)
}) })
}, },
@ -3830,6 +3854,15 @@ const app = new Vue({
// tracks are found in relationship.data // tracks are found in relationship.data
}, },
setAirPlayCodeUI() {
this.modals.airplayPW = true
},
sendAirPlaySuccess(){
notyf.success('Device paired successfully!');
},
sendAirPlayFailed(){
notyf.error('Device paring failed!');
},
windowFocus(val) { windowFocus(val) {
if (val) { if (val) {
document.querySelectorAll(".animated-artwork-video").forEach(el => { document.querySelectorAll(".animated-artwork-video").forEach(el => {
@ -4009,7 +4042,8 @@ const app = new Vue({
} }
} }
if (app.mk.nowPlayingItem._container["attributes"] && app.mk.nowPlayingItem._container.name != "station") { const nowPlayingContainer = app.mk.nowPlayingItem._container;
if (nowPlayingContainer && nowPlayingContainer["attributes"] && nowPlayingContainer.name != "station") {
menus.normal.items.find(x => x.id == "showInMusic").hidden = false menus.normal.items.find(x => x.id == "showInMusic").hidden = false
} }
@ -4096,13 +4130,19 @@ const app = new Vue({
if (flag) { if (flag) {
this.tmpWidth = window.innerWidth; this.tmpWidth = window.innerWidth;
this.tmpHeight = window.innerHeight; this.tmpHeight = window.innerHeight;
this.tmpX = window.screenX;
this.tmpY = window.screenY;
ipcRenderer.send('unmaximize'); ipcRenderer.send('unmaximize');
ipcRenderer.send('windowmin', 250, 250) ipcRenderer.send('windowmin', 250, 250)
if (this.miniTmpX !== '' && this.miniTmpY !== '') ipcRenderer.send('windowmove', this.miniTmpX, this.miniTmpY)
ipcRenderer.send('windowresize', 300, 300, false) ipcRenderer.send('windowresize', 300, 300, false)
app.appMode = 'mini'; app.appMode = 'mini';
} else { } else {
this.miniTmpX = window.screenX;
this.miniTmpY = window.screenY;
ipcRenderer.send('windowmin', 844, 410) ipcRenderer.send('windowmin', 844, 410)
ipcRenderer.send('windowresize', this.tmpWidth, this.tmpHeight, false) ipcRenderer.send('windowresize', this.tmpWidth, this.tmpHeight, false)
ipcRenderer.send('windowmove', this.tmpX, this.tmpY)
ipcRenderer.send('windowontop', false) ipcRenderer.send('windowontop', false)
//this.cfg.visual.miniplayer_top_toggle = true; //this.cfg.visual.miniplayer_top_toggle = true;
app.appMode = 'player'; app.appMode = 'player';

View file

@ -7936,6 +7936,15 @@ fieldset:disabled .btn {
filter: contrast(0); filter: contrast(0);
background-repeat: no-repeat; background-repeat: no-repeat;
} }
.cd-mediaitem-list-item .playIcon{
width: 44px;
margin-left: 11px;
}
.cd-mediaitem-list-item .heart-icon {
position: absolute;
filter: contrast(0);
background-repeat: no-repeat;
}
@keyframes load-bar { @keyframes load-bar {
10% { 10% {
box-shadow: inset 0 -4px 0; box-shadow: inset 0 -4px 0;
@ -12935,6 +12944,7 @@ body[platform='darwin'] #window-controls-container {
} }
body[platform='darwin'] .app-chrome .app-chrome-item > .app-mainmenu { body[platform='darwin'] .app-chrome .app-chrome-item > .app-mainmenu {
opacity: 0; opacity: 0;
width: 52px;
pointer-events: none; pointer-events: none;
-webkit-app-region: drag; -webkit-app-region: drag;
} }

View file

@ -1207,6 +1207,14 @@ body[platform="darwin"] .app-chrome .app-chrome-item > .window-controls > div.cl
background-repeat: no-repeat; background-repeat: no-repeat;
margin-left: 3px; margin-left: 3px;
} }
.heart-icon {
height: 9px;
width: 13px;
filter: contrast(0);
background-repeat: no-repeat;
margin-left: 3px;
}
} }
.lossless-icon { .lossless-icon {
@ -3281,6 +3289,7 @@ body[platform='darwin'] {
.app-chrome .app-chrome-item > .app-mainmenu { .app-chrome .app-chrome-item > .app-mainmenu {
opacity: 0; opacity: 0;
width: 52px;
pointer-events: none; pointer-events: none;
-webkit-app-region: drag; -webkit-app-region: drag;
} }

View file

@ -101,7 +101,7 @@
:class="{'active': this.cfg.audio.volume == 0}"></button> :class="{'active': this.cfg.audio.volume == 0}"></button>
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume" <input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume"
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()" v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()"
v-b-tooltip.hover :title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`"> v-b-tooltip.hover :title="formatVolumeTooltip()">
</div> </div>
<div class="app-chrome-item generic"> <div class="app-chrome-item generic">
<button class="playback-button--small miniplayer" <button class="playback-button--small miniplayer"

View file

@ -134,7 +134,7 @@
:class="{'active': this.cfg.audio.volume == 0}"></button> :class="{'active': this.cfg.audio.volume == 0}"></button>
<input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume" <input type="range" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" :max="cfg.audio.maxVolume"
v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()" v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" @change="checkMuteChange()"
v-b-tooltip.hover :title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`"> v-b-tooltip.hover :title="formatVolumeTooltip()">
</div> </div>
<div class="app-chrome-item generic"> <div class="app-chrome-item generic">
<button class="playback-button--small miniplayer" <button class="playback-button--small miniplayer"

View file

@ -28,6 +28,9 @@
<transition name="modal"> <transition name="modal">
<castmenu v-if="modals.castMenu"></castmenu> <castmenu v-if="modals.castMenu"></castmenu>
</transition> </transition>
<transition name="modal">
<airplay-modal v-if="modals.airplayPW"></airplay-modal>
</transition>
<transition name="modal"> <transition name="modal">
<plugin-menu v-if="modals.pluginMenu"></plugin-menu> <plugin-menu v-if="modals.pluginMenu"></plugin-menu>
</transition> </transition>

View file

@ -142,13 +142,13 @@
</span> </span>
<span class="usermenu-item-name">{{$root.getLz('action.showWebRemoteQR')}}</span> <span class="usermenu-item-name">{{$root.getLz('action.showWebRemoteQR')}}</span>
</button> </button>
<button class="usermenu-item" v-if="cfg.advanced.AudioContext" @click="modals.castMenu = true"> <button class="usermenu-item" @click="cfg.advanced.AudioContext ? modals.castMenu = true : $root.notyf.error($root.getLz('settings.warn.enableAdvancedFunctionality'))">
<span class="usermenu-item-icon"> <span class="usermenu-item-icon">
<%- include("../svg/cast.svg") %> <%- include("../svg/cast.svg") %>
</span> </span>
<span class="usermenu-item-name">{{$root.getLz('term.cast')}}</span> <span class="usermenu-item-name">{{$root.getLz('term.cast')}}</span>
</button> </button>
<button class="usermenu-item" v-if="cfg.advanced.AudioContext" @click="modals.audioSettings = true"> <button class="usermenu-item" @click="cfg.advanced.AudioContext ? modals.audioSettings = true : $root.notyf.error($root.getLz('settings.warn.enableAdvancedFunctionality'))">
<span class="usermenu-item-icon"> <span class="usermenu-item-icon">
<%- include("../svg/headphones.svg") %> <%- include("../svg/headphones.svg") %>
</span> </span>
@ -216,7 +216,7 @@
<input type="range" class="" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0" <input type="range" class="" @wheel="volumeWheel" :step="cfg.audio.volumeStep" min="0"
:max="cfg.audio.maxVolume" v-model="mk.volume" v-if="typeof mk.volume != 'undefined'" :max="cfg.audio.maxVolume" v-model="mk.volume" v-if="typeof mk.volume != 'undefined'"
@change="checkMuteChange()" v-b-tooltip.hover @change="checkMuteChange()" v-b-tooltip.hover
:title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`"> :title="formatVolumeTooltip()">
</div> </div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,42 @@
<script type="text/x-template" id="airplay-modal">
<div class="spatialproperties-panel castmenu modal-fullscreen airplay-modal" @click.self="close()" @contextmenu.self="close()">
<div class="modal-window airplay-modal">
<div class="modal-header">
<div class="modal-title">{{'Enter password'}}</div>
<button class="close-btn" @click="close()"></button>
</div>
<div class="modal-content" style="overflow-y: overlay; padding: 3%">
<input type="text" v-model="passcode"/>
</div>
<div class="md-footer">
<div class="row">
<div class="col" >
<button style="width:100%" @click="enterPassword()" class="md-btn md-btn-block md-btn-primary">{{'OK'}}</button>
</div>
</div>
</div>
</div>
</div>
</script>
<script>
Vue.component('airplay-modal', {
template: '#airplay-modal',
data: function () {
return {
passcode: '',
}
},
mounted() {
},
methods: {
close() {
this.$root.modals.airplayPW = false
},
enterPassword() {
console.log('Entered passCode: ', this.passcode)
ipcRenderer.send("setAirPlayPasscode",this.passcode)
this.close()
}
}
});
</script>

View file

@ -14,7 +14,7 @@
<div class="md-option-segment md-option-segment_auto percent"> <div class="md-option-segment md-option-segment_auto percent">
<input type="number" <input type="number"
style="width: 100%; text-align: center; margin-right: 5px;" min="0" style="width: 100%; text-align: center; margin-right: 5px;" min="0"
step="5" v-model="volume"/> step="2" v-model="volume"/>
</div> </div>
</div> </div>
<div class="md-option-line"> <div class="md-option-line">

View file

@ -37,7 +37,7 @@
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;"> <div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;">
<div class="md-option-line"> <div class="md-option-line">
<div class="md-option-segment"> <div class="md-option-segment">
{{true ? 'Homepods only for now! (NO PASSWORD PLEASE!)' : 'Please add FFmpeg location in Settings -> Advanced'}} {{'EXPERIMENTAL!!! Supports Homepods / Apple TVs / Shairport for now, AirPlay on Samsung/LG/Sony devices will be added later'}}
<!-- {{$root.getLz('action.cast.airplay.underdevelopment')}} --> <!-- {{$root.getLz('action.cast.airplay.underdevelopment')}} -->
<template v-if="true" v-for="(device) in devices.airplay"> <template v-if="true" v-for="(device) in devices.airplay">
<div class="md-option-line" style="cursor: pointer" @click="setAirPlayCast(device)"> <div class="md-option-line" style="cursor: pointer" @click="setAirPlayCast(device)">

View file

@ -82,7 +82,7 @@
<button class="volume-button--small volume" @click="app.muteButtonPressed()" :class="{'active': app.cfg.audio.volume == 0}"></button> <button class="volume-button--small volume" @click="app.muteButtonPressed()" :class="{'active': app.cfg.audio.volume == 0}"></button>
<input type="range" class="slider" @wheel="app.volumeWheel" :step="app.cfg.audio.volumeStep" min="0" :max="app.cfg.audio.maxVolume" v-model="app.mk.volume" <input type="range" class="slider" @wheel="app.volumeWheel" :step="app.cfg.audio.volumeStep" min="0" :max="app.cfg.audio.maxVolume" v-model="app.mk.volume"
v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()" v-if="typeof app.mk.volume != 'undefined'" @change="app.checkMuteChange()"
v-b-tooltip.hover :title="`${(Math.log10(app.mk.volume) * 20).toFixed(2)} dB`"> v-b-tooltip.hover :title="$root.formatVolumeTooltip()">
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,6 +1,6 @@
<script type="text/x-template" id="lyrics-view"> <script type="text/x-template" id="lyrics-view">
<div ref="lyricsview" class="md-body lyric-body"> <div ref="lyricsview" class="md-body lyric-body">
<template v-if="lyrics && lyrics != [] && lyrics.length > 0"> <template v-if="lyrics && lyrics != [] && lyrics.length > 0 && !qqInstrumental(lyrics)">
<template v-for="(lyric, index) in lyrics" v-if="lyric && lyric.line && lyric.line != 'lrcInstrumental'"> <template v-for="(lyric, index) in lyrics" v-if="lyric && lyric.line && lyric.line != 'lrcInstrumental'">
<h3 class="lyric-line" @click="seekTo(lyric.startTime)" :class="{unsynced : lyric.startTime == 9999999}" <h3 class="lyric-line" @click="seekTo(lyric.startTime)" :class="{unsynced : lyric.startTime == 9999999}"
v-bind:line-index="index.toString()"> v-bind:line-index="index.toString()">
@ -183,6 +183,14 @@
} }
else return [] else return []
}, },
qqInstrumental(lyrics) {
for(lyric of lyrics){
if (lyric.line.includes("纯音乐") && lyric.line.includes("欣赏")){
return true
}
}
return false
},
checkIfScrollIsStatic : setInterval(() => { checkIfScrollIsStatic : setInterval(() => {
try { try {
if (position === this.$refs.lyricsview.scrollTop) { if (position === this.$refs.lyricsview.scrollTop) {

View file

@ -23,7 +23,7 @@
<button @click="addToLibrary()" v-if="!addedToLibrary && (showIndex == false ||(showIndex == true && showIndexPlaylist != false))"> <button @click="addToLibrary()" v-if="!addedToLibrary && (showIndex == false ||(showIndex == true && showIndexPlaylist != false))">
<div class="svg-icon addIcon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/plus.svg)'}"></div> <div class="svg-icon addIcon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/plus.svg)'}"></div>
</button> </button>
<button v-else-if='!(showArtwork == true && (showIndex == false ||(showIndex == true && showIndexPlaylist != false)))' @click="playTrack()" style="width: 44px;margin-left: -5px;"> <button v-else-if='!(showArtwork == true && (showIndex == false ||(showIndex == true && showIndexPlaylist != false)))' @click="playTrack()">
<div class="svg-icon playIcon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/play.svg)'}"></div> <div class="svg-icon playIcon" :style="{'--color': 'var(--keyColor)', '--url': 'url(./assets/feather/play.svg)'}"></div>
</button> </button>
</div> </div>
@ -65,6 +65,10 @@
</template> </template>
</div> </div>
</div> </div>
<div class="heart-icon" v-if="!(app.mk.isPlaying && (((app.mk.nowPlayingItem._songId ?? (app.mk.nowPlayingItem.songId ?? app.mk.nowPlayingItem.id )) == itemId) || (app.mk.nowPlayingItem.id == item.id)))">
<!-- <div class="heart-unfilled" v-if="isLoved == false" :style="{'--url': 'url(./assets/feather/heart.svg)'}" /> -->
<div class="heart-filled" v-if="isLoved == true" :style="{'--url': 'url(./assets/feather/heart-fill.svg)'}" />
</div>
<div class="explicit-icon" v-if="item.attributes && item.attributes.contentRating == 'explicit'"></div> <div class="explicit-icon" v-if="item.attributes && item.attributes.contentRating == 'explicit'"></div>
<template v-if="showMetaData == true" @dblclick="route()"> <template v-if="showMetaData == true" @dblclick="route()">
<div class="metainfo"> <div class="metainfo">
@ -98,7 +102,8 @@
displayDuration: true, displayDuration: true,
addClasses: {}, addClasses: {},
itemId: 0, itemId: 0,
isLibrary: false isLibrary: false,
isLoved: null
} }
}, },
props: { props: {
@ -121,6 +126,9 @@
} else { } else {
this.itemId = this.item.id; this.itemId = this.item.id;
} }
if (this.item.attributes.playParams) {
this.getHeartStatus();
}
let duration = this.item.attributes.durationInMillis ?? 0 let duration = this.item.attributes.durationInMillis ?? 0
if (duration == 0 || !this.showDuration) { if (duration == 0 || !this.showDuration) {
this.displayDuration = false this.displayDuration = false
@ -323,6 +331,7 @@
"hidden": false, "hidden": false,
"disabled": true, "disabled": true,
"action": function () { "action": function () {
self.isLoved = true
app.love(self.item) app.love(self.item)
} }
}, },
@ -333,6 +342,7 @@
"name": this.app.getLz('action.unlove'), "name": this.app.getLz('action.unlove'),
"hidden": true, "hidden": true,
"action": function () { "action": function () {
self.isLoved = false
app.unlove(self.item) app.unlove(self.item)
} }
}, },
@ -499,6 +509,19 @@
visibilityChanged: function (isVisible, entry) { visibilityChanged: function (isVisible, entry) {
this.isVisible = isVisible this.isVisible = isVisible
}, },
async getHeartStatus() {
try {
await app.getRating(this.item).then(res => {
if (res == 1) {
this.isLoved = true
} else {
this.isLoved = false
}
})
} catch (err) {
console.log(err)
}
},
addToLibrary() { addToLibrary() {
let item = this.item let item = this.item
if (item.attributes.playParams.id) { if (item.attributes.playParams.id) {

View file

@ -13,12 +13,11 @@
</div> </div>
<div class="queue-body" v-if="page == 'queue'"> <div class="queue-body" v-if="page == 'queue'">
<draggable v-model="queueItems" @start="drag=true" @end="drag=false;move()"> <draggable v-model="queueItems" @start="drag=true" @end="drag=false;move()">
<template v-for="(queueItem, position) in queueItems"> <template v-for="(queueItem, position) in displayQueueItems">
<div v-if="position <= queuePosition" style="display: none;">{{ position }}</div>
<div class="cd-queue-item" <div class="cd-queue-item"
:class="{selected: selectedItems.includes(position)}" :class="{selected: selectedItems.includes(position)}"
@click="select($event, position)" @click="select($event, position)"
@dblclick="playQueueItem(position)" v-else :key="position" @dblclick="playQueueItem(position)" :key="position"
@contextmenu="selected = position;queueContext($event, queueItem.item, position)"> @contextmenu="selected = position;queueContext($event, queueItem.item, position)">
<div class="row"> <div class="row">
<div class="col-auto flex-center"> <div class="col-auto flex-center">
@ -61,6 +60,13 @@
app: this.$root app: this.$root
} }
}, },
computed: {
displayQueueItems() {
const displayLimit = 50;
const lastDisplayPosition = Math.min(displayLimit + this.queuePosition, this.queueItems.length);
return this.queueItems.slice(this.queuePosition, lastDisplayPosition);
}
},
mounted() { mounted() {
this.updateQueue() this.updateQueue()
}, },

View file

@ -0,0 +1,368 @@
<script type="text/x-template" id="installed-themes">
<div class="content-inner github-themes-page installed-themes-page">
<div class="gh-header">
<div class="row">
<div class="col nopadding">
<h1 class="header-text">
{{ $root.getLz("settings.option.visual.theme.manageStyles") }}
</h1>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="$root.appRoute('themes-github')">
{{$root.getLz('settings.option.visual.theme.github.explore')}}
</button>
</div>
<div class="col-auto flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="$root.checkForThemeUpdates()">
{{ $root.getLz('settings.option.visual.theme.checkForUpdates') }}
</button>
</div>
<div class="col-auto nopadding flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="openThemesFolder()">
{{$root.getLz('settings.option.visual.theme.github.openfolder')}}
</button>
</div>
</div>
</div>
<div class="gh-content">
<div class="repos-list">
<div class="repo-header">
<h4>{{$root.getLz('settings.option.visual.theme.github.available')}}</h4>
</div>
<ul class="list-group list-group-flush">
<template v-for="theme in themes">
<li @click="addStyle(theme.file)"
@contextmenu="contextMenu($event, theme)"
class="list-group-item list-group-item-dark"
:class="{'applied': $root.cfg.visual.styles.includes(theme.file)}">
<b-row>
<b-col class="themeLabel">{{theme.name}}</b-col>
<template v-if="$root.cfg.visual.styles.includes(theme.file)">
<b-col sm="auto" v-if="theme.pack">
<button class="themeContextMenu codicon codicon-package"></button>
</b-col>
<b-col sm="auto">
<button class="themeContextMenu codicon codicon-check"></button>
</b-col>
</template>
<template v-else>
<b-col sm="auto" v-if="theme.pack">
<button class="themeContextMenu codicon codicon-package"></button>
</b-col>
<b-col sm="auto">
<button @click.stop="contextMenu($event, theme)" class="themeContextMenu codicon codicon-list-unordered"></button>
</b-col>
</template>
</b-row>
</li>
<li @click="addStyle(packEntry.file)"
@contextmenu="contextMenu($event, theme)"
class="list-group-item list-group-item-dark addon"
v-for="packEntry in theme.pack"
:class="{'applied': $root.cfg.visual.styles.includes(packEntry.file)}"
v-if="theme.pack">
<b-row>
<b-col class="themeLabel">{{packEntry.name}}</b-col>
<template v-if="$root.cfg.visual.styles.includes(packEntry.file)">
<b-col sm="auto">
<button class="themeContextMenu codicon codicon-check"></button>
</b-col>
</template>
<template v-else>
<b-col sm="auto">
<button class="themeContextMenu codicon codicon-diff-added"></button>
</b-col>
</template>
</b-row>
</li>
</template>
</ul>
</div>
<div class="style-editor-container">
<div class="repo-header">
<h4>{{ $root.getLz("settings.option.visual.theme.github.applied") }} </h4>
</div>
<stylestack-editor ref="stackEditor" v-if="themes.length != 0" :themes="themes"/>
</div>
</div>
</div>
</script>
<script>
// do not translate
Vue.component('stylestack-editor', {
/*html*/
template: `
<div class="stylestack-editor" >
<draggable class="list-group" v-model="$root.cfg.visual.styles" @end="$root.reloadStyles()">
<b-list-group-item variant="dark" v-for="theme in $root.cfg.visual.styles" :key="theme">
<b-row>
<b-col sm="auto">
<div class="handle codicon codicon-grabber"></div>
</b-col>
<b-col class="themeLabel">{{getThemeName(theme)}}</b-col>
<b-col sm="auto">
<button class="removeItem codicon codicon-close" @click="remove(theme)"></button>
</b-col>
</b-row>
</b-list-group-item>
</draggable>
</div>
`,
props: {
themes: {
type: Array,
default: [],
required: true
}
},
data: function () {
return {
selected: null,
newTheme: null,
themeList: []
}
},
mounted() {
console.log(this.themes)
this.themeList = [...this.themes]
this.themeList.forEach(theme => {
if (theme.pack) {
theme.pack.forEach(packEntry => {
packEntry.file = theme.file.replace('index.less', '') + packEntry.file
this.themeList.push(packEntry)
})
}
})
},
methods: {
gitHubExplore() {
this.$root.appRoute("themes-github")
},
getThemeName(filename) {
try {
return this.themeList.find(theme => theme.file === filename).name;
} catch (e) {
return filename;
}
},
moveUp() {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(this.selected)
if (index > 0) {
styles.splice(index, 1)
styles.splice(index - 1, 0, this.selected)
}
this.$root.reloadStyles()
},
moveDown() {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(this.selected)
if (index < styles.length - 1) {
styles.splice(index, 1)
styles.splice(index + 1, 0, this.selected)
}
this.$root.reloadStyles()
},
remove(style) {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(style)
styles.splice(index, 1)
this.$root.reloadStyles()
},
addStyle(style) {
const styles = this.$root.cfg.visual.styles
styles.push(style)
this.$root.reloadStyles()
}
}
})
</script>
<script>
Vue.component('installed-themes', {
template: "#installed-themes",
props: [],
data: function () {
return {
repos: [],
openRepo: {
id: -1,
name: '',
description: '',
html_url: '',
stargazers_count: 0,
owner: {
avatar_url: ''
},
readme: ""
},
themesInstalled: [],
themes: []
}
},
mounted() {
this.getThemesList();
},
methods: {
getThemesList() {
let self = this
let themes = ipcRenderer.sendSync("get-themes")
themes.unshift({
name: "Acrylic Grain",
file: "grain.less"
})
themes.unshift({
name: "Sweetener",
file: "sweetener.less"
})
themes.unshift({
name: "Reduce Visuals",
file: "reduce_visuals.less"
})
themes.unshift({
name: "Inline Drawer",
file: "inline_drawer.less"
})
themes.unshift({
name: "Dark",
file: "dark.less"
})
this.themes = themes
},
contextMenu(event, theme) {
let self = this
let menu = {
items: {
"uninstall": {
name: app.getLz("settings.option.visual.theme.uninstall"),
disabled: true,
action: () => {
bootbox.confirm(app.stringTemplateParser(app.getLz("settings.prompt.visual.theme.uninstallTheme"), {
theme: theme.name ?? theme.file
}), (res) => {
if (res) {
console.debug(theme)
ipcRenderer.once("theme-uninstalled", (event, args) => {
console.debug(event, args)
self.getThemesList()
})
ipcRenderer.invoke("uninstall-theme", theme.path)
}
})
}
},
"viewInfo": {
name: app.getLz("settings.option.visual.theme.viewInfo"),
disabled: true,
action: () => {
}
}
}
}
if (theme.path) {
menu.items.uninstall.disabled = false
}
this.$root.showMenuPanel(menu, event)
},
openThemesFolder() {
ipcRenderer.invoke("open-path", "themes")
},
getInstalledThemes() {
let self = this
const themes = ipcRenderer.sendSync("get-themes")
// for each theme, get the github_repo property and push it to the themesInstalled array, if not blank
themes.forEach(theme => {
if (theme.github_repo !== "" && typeof theme.commit != "") {
self.themesInstalled.push(theme.github_repo.toLowerCase())
}
})
},
addStyle(filename) {
this.$refs.stackEditor.addStyle(filename)
},
showRepo(repo) {
const self = this
const readmeUrl = `https://raw.githubusercontent.com/${repo.full_name}/main/README.md`;
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch(readmeUrl, requestOptions)
.then(response => response.text())
.then(result => {
self.openRepo = repo
self.openRepo.readme = self.convertReadMe(result);
})
.catch(error => {
self.openRepo = repo
self.openRepo.readme = `This repository doesn't have a README.md file.`;
console.log('error', error)
});
},
convertReadMe(text) {
return marked.parse(text)
},
installThemeRepo(repo) {
let self = this
let msg = app.stringTemplateParser(app.getLz('settings.option.visual.theme.github.install.confirm'), {
repo: repo.full_name
});
bootbox.confirm(msg, (res) => {
if (res) {
ipcRenderer.once("theme-installed", (event, arg) => {
if (arg.success) {
self.themes = ipcRenderer.sendSync("get-themes")
self.getInstalledThemes()
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
} else {
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
}
});
ipcRenderer.invoke("get-github-theme", repo.html_url)
}
})
},
installThemeURL() {
let self = this
bootbox.prompt(app.getLz('settings.prompt.visual.theme.github.URL'), (result) => {
if (result) {
ipcRenderer.once("theme-installed", (event, arg) => {
if (arg.success) {
self.themes = ipcRenderer.sendSync("get-themes")
notyf.success(app.getLz('settings.notyf.visual.theme.install.success'));
} else {
notyf.error(app.getLz('settings.notyf.visual.theme.install.error'));
}
});
ipcRenderer.invoke("get-github-theme", result)
}
});
},
getRepos() {
let self = this
var requestOptions = {
method: 'GET',
redirect: 'follow'
};
fetch("https://api.github.com/search/repositories?q=topic:cidermusictheme fork:true", requestOptions)
.then(response => response.text())
.then(result => {
let items = JSON.parse(result).items
self.repos = items
})
.catch(error => console.log('error', error));
}
}
})
</script>

View file

@ -22,7 +22,7 @@
<hr> <hr>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<h4>{{ loaded.attributes.listenTimeInMinutes }} {{$root.getLz('term.time.minutes')}}</h4> <h4>{{ convertToHours(loaded.attributes.listenTimeInMinutes) }} {{$root.getLz('term.time.hours')}}</h4>
<h4>{{ loaded.attributes.uniqueAlbumCount }} {{$root.getLz('term.uniqueAlbums')}}</h4> <h4>{{ loaded.attributes.uniqueAlbumCount }} {{$root.getLz('term.uniqueAlbums')}}</h4>
<h4>{{ loaded.attributes.uniqueArtistCount }} {{$root.getLz('term.uniqueArtists')}}</h4> <h4>{{ loaded.attributes.uniqueArtistCount }} {{$root.getLz('term.uniqueArtists')}}</h4>
<h4>{{ loaded.attributes.uniqueSongCount }} {{$root.getLz('term.uniqueSongs')}}</h4> <h4>{{ loaded.attributes.uniqueSongCount }} {{$root.getLz('term.uniqueSongs')}}</h4>
@ -40,7 +40,7 @@
<mediaitem-square :item="artistData.relationships.artist.data[0]"></mediaitem-square> <mediaitem-square :item="artistData.relationships.artist.data[0]"></mediaitem-square>
</div> </div>
<div class="card-footer"> <div class="card-footer">
{{ artistData.attributes.listenTimeInMinutes }} {{$root.getLz('term.time.minutes', {'count': artistData.attributes.listenTimeInMinutes})}}<br> {{ convertToHours(artistData.attributes.listenTimeInMinutes) }} {{$root.getLz('term.time.hours', {'count': convertToHours(artistData.attributes.listenTimeInMinutes) })}}<br>
{{$root.getLz('term.listenedTo')}} {{ artistData.attributes.playCount }} {{$root.getLz('term.times')}} {{$root.getLz('term.listenedTo')}} {{ artistData.attributes.playCount }} {{$root.getLz('term.times')}}
</div> </div>
</div> </div>
@ -55,7 +55,7 @@
<mediaitem-square :item="albumData.relationships.album.data[0]"></mediaitem-square> <mediaitem-square :item="albumData.relationships.album.data[0]"></mediaitem-square>
</div> </div>
<div class="card-footer"> <div class="card-footer">
{{ albumData.attributes.listenTimeInMinutes }} {{$root.getLz('term.time.minutes', {'count': albumData.attributes.listenTimeInMinutes})}}<br> {{ convertToHours(albumData.attributes.listenTimeInMinutes) }} {{$root.getLz('term.time.hours', {'count': convertToHours(albumData.attributes.listenTimeInMinutes)})}}<br>
{{ albumData.attributes.playCount }} {{$root.getLz('term.plays')}} {{ albumData.attributes.playCount }} {{$root.getLz('term.plays')}}
</div> </div>
</div> </div>
@ -151,6 +151,9 @@
let playlist = await app.mk.api.v3.music(replayData.relationships.playlist.data[0].href, {extend: "editorialArtwork,editorialVideo"}) let playlist = await app.mk.api.v3.music(replayData.relationships.playlist.data[0].href, {extend: "editorialArtwork,editorialVideo"})
replayData.playlist = playlist.data.data[0] replayData.playlist = playlist.data.data[0]
this.loaded = replayData this.loaded = replayData
},
convertToHours(minutes) {
return Math.floor(minutes / 60)
} }
} }
}); });

View file

@ -441,6 +441,30 @@
</label> </label>
</div> </div>
</div> </div>
<div class="md-option-line" v-show="app.cfg.advanced.AudioContext && app.cfg.audio.normalization">
<div class="md-option-segment">
dB SPL Display
<br>
<small>(Advanced users only) Display dB SPL instead of dBFS on the volume slider.</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="checkbox" v-model="app.cfg.audio.dBSPL" switch/>
</label>
</div>
</div>
<div class="md-option-line" v-show="app.cfg.audio.dBSPL">
<div class="md-option-segment">
0 dBFS Calibration
<br>
<small>Enter the peak Z-weighted dB SPL when Cider is at 0 dBFS.</small>
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<input type="number" v-model="app.cfg.audio.dBSPLcalibration"/>
</label>
</div>
</div>
</div> </div>
</div> </div>
</b-tab> </b-tab>
@ -456,20 +480,8 @@
{{$root.getLz('settings.header.visual.theme')}} {{$root.getLz('settings.header.visual.theme')}}
</div> </div>
<div class="md-option-segment md-option-segment_auto"> <div class="md-option-segment md-option-segment_auto">
<label> <button class="md-btn md-btn-block" @click="$root.appRoute('installed-themes')">
<select class="md-select" @change="$root.setTheme($root.cfg.visual.theme)" {{$root.getLz('settings.option.visual.theme.manageStyles')}}
v-model="$root.cfg.visual.theme">
<option value="default.less">
{{$root.getLz('settings.option.visual.theme.default')}}
</option>
<option value="dark.less">{{$root.getLz('settings.option.visual.theme.dark')}}
</option>
<option v-for="theme in themes" :value="theme.file">{{ theme.name }}</option>
</select>
</label>
<button class="md-btn md-btn-small md-btn-block" @click="gitHubExplore()"
style="margin-top: 8px">
{{$root.getLz('settings.option.visual.theme.github.explore')}}
</button> </button>
</div> </div>
</div> </div>
@ -1013,18 +1025,18 @@
</div> </div>
<div class="md-option-segment md-option-segment_auto"> <div class="md-option-segment md-option-segment_auto">
<label> <label>
<input type="checkbox" v-model="app.cfg.general.discord_rpc.enabled" switch/> <input type="checkbox" v-model="app.cfg.general.discordrpc.enabled" switch/>
</label> </label>
</div> </div>
</div> </div>
<div class="md-option-line" v-show="app.cfg.general.discord_rpc.enabled != false"> <div class="md-option-line" v-show="app.cfg.general.discordrpc.enabled != false">
<div class="md-option-segment"> <div class="md-option-segment">
{{$root.getLz('settings.option.connectivity.discordRPC.clientName')}} {{$root.getLz('settings.option.connectivity.discordRPC.clientName')}}
</div> </div>
<div class="md-option-segment md-option-segment_auto"> <div class="md-option-segment md-option-segment_auto">
<label> <label>
<select class="md-select" v-model="app.cfg.general.discord_rpc.client"> <select class="md-select" v-model="app.cfg.general.discordrpc.client">
<option value="Cider">{{$root.getLz('app.name')}}</option> <option value="Cider">{{$root.getLz('app.name')}}</option>
<option value="AppleMusic">{{$root.getLz('term.appleMusic')}} <option value="AppleMusic">{{$root.getLz('term.appleMusic')}}
</option> </option>
@ -1033,29 +1045,29 @@
</div> </div>
</div> </div>
<div class="md-option-line" v-show="app.cfg.general.discord_rpc.enabled != false"> <div class="md-option-line" v-show="app.cfg.general.discordrpc.enabled != false">
<div class="md-option-segment"> <div class="md-option-segment">
{{$root.getLz('settings.option.connectivity.discordRPC.clearOnPause')}} {{$root.getLz('settings.option.connectivity.discordRPC.clearOnPause')}}
</div> </div>
<div class="md-option-segment md-option-segment_auto"> <div class="md-option-segment md-option-segment_auto">
<label> <label>
<input type="checkbox" v-model="app.cfg.general.discord_rpc.clear_on_pause" switch/> <input type="checkbox" v-model="app.cfg.general.discordrpc.clear_on_pause" switch/>
</label> </label>
</div> </div>
</div> </div>
<div class="md-option-line" v-show="app.cfg.general.discord_rpc.enabled != false"> <div class="md-option-line" v-show="app.cfg.general.discordrpc.enabled != false">
<div class="md-option-segment"> <div class="md-option-segment">
{{$root.getLz('settings.option.connectivity.discordRPC.hideButtons')}} {{$root.getLz('settings.option.connectivity.discordRPC.hideButtons')}}
</div> </div>
<div class="md-option-segment md-option-segment_auto"> <div class="md-option-segment md-option-segment_auto">
<label> <label>
<input type="checkbox" v-model="app.cfg.general.discord_rpc.hide_buttons" switch/> <input type="checkbox" v-model="app.cfg.general.discordrpc.hide_buttons" switch/>
</label> </label>
</div> </div>
</div> </div>
<div class="md-option-line" v-show="app.cfg.general.discord_rpc.enabled != false"> <div class="md-option-line" v-show="app.cfg.general.discordrpc.enabled != false">
<div class="md-option-segment"> <div class="md-option-segment">
{{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}<br/> {{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}<br/>
<small>{{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album}, <small>{{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album},
@ -1063,12 +1075,12 @@
</div> </div>
<div class="md-option-segment md-option-segment_auto"> <div class="md-option-segment md-option-segment_auto">
<label> <label>
<input type="text" v-model="app.cfg.general.discord_rpc.details_format"/> <input type="text" v-model="app.cfg.general.discordrpc.details_format"/>
</label> </label>
</div> </div>
</div> </div>
<div class="md-option-line" v-show="app.cfg.general.discord_rpc.enabled != false"> <div class="md-option-line" v-show="app.cfg.general.discordrpc.enabled != false">
<div class="md-option-segment"> <div class="md-option-segment">
{{$root.getLz('settings.option.connectivity.discordRPC.stateFormat')}} {{$root.getLz('settings.option.connectivity.discordRPC.stateFormat')}}
<small>{{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album}, <small>{{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album},
@ -1076,7 +1088,7 @@
</div> </div>
<div class="md-option-segment md-option-segment_auto"> <div class="md-option-segment md-option-segment_auto">
<label> <label>
<input type="text" v-model="app.cfg.general.discord_rpc.state_format"/> <input type="text" v-model="app.cfg.general.discordrpc.state_format"/>
</label> </label>
</div> </div>
</div> </div>
@ -1192,19 +1204,6 @@
</button> </button>
</div> </div>
</div> </div>
<div class="md-option-line">
<!-- Do not translate -->
<div class="md-option-segment">
Style Editor<br>
<small>Mix and match various theme components to get Cider looking exactly how you
want.</small>
</div>
<div class="md-option-segment">
<stylestack-editor :themes="themes"/>
</div>
</div>
<div class="md-option-line"> <div class="md-option-line">
<div class="md-option-segment"> <div class="md-option-segment">
{{$root.getLz('settings.option.experimental.unknownPlugin')}} {{$root.getLz('settings.option.experimental.unknownPlugin')}}
@ -1412,112 +1411,6 @@
</div> </div>
</script> </script>
<script>
// do not translate
Vue.component('stylestack-editor', {
/*html*/
template: `
<div class="stylestack-editor">
<draggable class="list-group" v-model="$root.cfg.visual.styles" @end="$root.reloadStyles()">
<b-list-group-item variant="dark" v-for="theme in $root.cfg.visual.styles" :key="theme">
<b-row>
<b-col class="themeLabel">{{getThemeName(theme)}}</b-col>
<b-col sm="auto">
<button class="removeItem codicon codicon-close" @click="remove(theme)"></button>
</b-col>
</b-row>
</b-list-group-item>
<b-list-group-item slot="footer" style="-webkit-user-drag: none" variant="dark">
<b-row>
<b-col>
<b-dropdown class="stylesDropdown" variant="primary" text="Add Style...">
<b-dropdown-item v-for="theme in themeList" @click="addStyle(theme.file)">{{theme.name}}</b-dropdown-item>
</b-dropdown>
</b-col>
<b-col>
<b-btn @click="gitHubExplore()">{{$root.getLz('settings.option.visual.theme.github.explore')}}</b-btn>
</b-col>
</b-row>
</b-list-group-item>
</draggable>
</div>
`,
props: {
themes: {
type: Array,
default: []
}
},
data: function () {
return {
selected: null,
newTheme: null,
themeList: []
}
},
mounted() {
this.themeList = [...this.themes]
this.themeList.unshift({
name: "Acrylic Grain",
file: "grain.less"
})
this.themeList.unshift({
name: "Sweetener",
file: "sweetener.less"
})
this.themeList.unshift({
name: "Reduce Visuals",
file: "reduce_visuals.less"
})
this.themeList.unshift({
name: "Inline Drawer",
file: "inline_drawer.less"
})
},
methods: {
gitHubExplore() {
this.$root.appRoute("themes-github")
},
getThemeName(filename) {
try {
return this.themeList.find(theme => theme.file === filename).name;
} catch (e) {
return filename;
}
},
moveUp() {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(this.selected)
if (index > 0) {
styles.splice(index, 1)
styles.splice(index - 1, 0, this.selected)
}
this.$root.reloadStyles()
},
moveDown() {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(this.selected)
if (index < styles.length - 1) {
styles.splice(index, 1)
styles.splice(index + 1, 0, this.selected)
}
this.$root.reloadStyles()
},
remove(style) {
const styles = this.$root.cfg.visual.styles
const index = styles.indexOf(style)
styles.splice(index, 1)
this.$root.reloadStyles()
},
addStyle(style) {
const styles = this.$root.cfg.visual.styles
styles.push(style)
this.$root.reloadStyles()
}
}
})
</script>
<script> <script>
Vue.component('cider-settings', { Vue.component('cider-settings', {
template: "#cider-settings", template: "#cider-settings",
@ -1629,10 +1522,10 @@
app.cfg.general.keybindings.browse = [app.platform == "darwin" ? "Command" : "Control", "B"]; app.cfg.general.keybindings.browse = [app.platform == "darwin" ? "Command" : "Control", "B"];
app.cfg.general.keybindings.togglePrivateSession = [app.platform == "darwin" ? "Command" : "Control", "P"]; app.cfg.general.keybindings.togglePrivateSession = [app.platform == "darwin" ? "Command" : "Control", "P"];
app.cfg.general.keybindings.webRemote = [app.platform == "darwin" ? "Command" : "Control", "W"]; app.cfg.general.keybindings.webRemote = [app.platform == "darwin" ? "Command" : "Control", "W"];
app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Option" : "Shift", "A"]; app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Option" : "Alt", "A"];
app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Option" : "Shift", "P"]; app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Option" : "Alt", "P"];
app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Option" : "Shift", "C"]; app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Option" : "Alt", "C"];
app.cfg.general.keybindings.settings = [app.platform == "darwin" ? "Option" : "Shift", "S"]; app.cfg.general.keybindings.settings = [app.platform == "darwin" ? "Option" : "Alt", "S"];
app.cfg.general.keybindings.openDeveloperTools = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : "Shift", "I"]; app.cfg.general.keybindings.openDeveloperTools = [app.platform == "darwin" ? "Command" : "Control", app.platform == "darwin" ? "Option" : "Shift", "I"];
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success')); notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
bootbox.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => { bootbox.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {

View file

@ -5,17 +5,14 @@
<div class="col nopadding"> <div class="col nopadding">
<h1 class="header-text">{{$root.getLz('settings.header.visual.theme.github.page')}}</h1> <h1 class="header-text">{{$root.getLz('settings.header.visual.theme.github.page')}}</h1>
</div> </div>
<div class="col-auto flex-center"> <div class="col-auto nopadding flex-center">
<select class="md-select" @change="$root.setTheme($root.cfg.visual.theme)" <button class="md-btn md-btn-small md-btn-block" @click="$root.appRoute('installed-themes')">
v-model="$root.cfg.visual.theme"> {{$root.getLz('settings.option.visual.theme.manageStyles')}}
<option value="default.less">{{$root.getLz('settings.option.visual.theme.default')}}</option> </button>
<option value="dark.less">{{$root.getLz('settings.option.visual.theme.dark')}}</option>
<option v-for="theme in themes" :value="theme.file">{{ theme.name }}</option>
</select>
</div> </div>
<div class="col-auto flex-center"> <div class="col-auto flex-center">
<button class="md-btn md-btn-small md-btn-block" @click="openThemesFolder()"> <button class="md-btn md-btn-small md-btn-block" @click="$root.checkForThemeUpdates()">
{{$root.getLz('settings.option.visual.theme.github.openfolder')}} {{ $root.getLz('settings.option.visual.theme.checkForUpdates') }}
</button> </button>
</div> </div>
<div class="col-auto nopadding flex-center"> <div class="col-auto nopadding flex-center">
@ -106,7 +103,6 @@
this.themes = ipcRenderer.sendSync("get-themes") this.themes = ipcRenderer.sendSync("get-themes")
this.getRepos(); this.getRepos();
this.getInstalledThemes(); this.getInstalledThemes();
app.checkForThemeUpdates()
}, },
methods: { methods: {
openThemesFolder() { openThemesFolder() {

View file

@ -1,7 +1,7 @@
{ {
"electronVersion": "18.0.4", "electronVersion": "18.2.0",
"electronDownload": { "electronDownload": {
"version": "18.0.4+wvcus", "version": "18.2.0+wvcus",
"mirror": "https://github.com/castlabs/electron-releases/releases/download/v" "mirror": "https://github.com/castlabs/electron-releases/releases/download/v"
}, },
"appId": "cider", "appId": "cider",