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/integrations": "^6.19.6",
"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",
"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",
"ejs": "^3.1.6",
"electron-fetch": "^1.7.4",
@ -82,7 +82,7 @@
"electron-builder-notarize-pkg": "^1.2.0",
"electron-webpack": "^2.8.2",
"musickit-typescript": "^1.2.4",
"typescript": "^4.6.3",
"typescript": "^4.6.4",
"vue-devtools": "^5.1.4",
"webpack": "~5.72.0"
},
@ -109,9 +109,9 @@
}
],
"build": {
"electronVersion": "18.1.0",
"electronVersion": "18.2.1",
"electronDownload": {
"version": "18.1.0+wvcus",
"version": "18.2.1+wvcus",
"mirror": "https://github.com/castlabs/electron-releases/releases/download/v"
},
"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.dynamic`: 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.updatingLibraryAlbums": "Ενημέρωση βιβλιοθήκης άλμπουμ...",
"notification.updatingLibraryArtists": "Ενημέρωση βιβλιοθήκης καλλιτεχνών...",
"term.variables": "Μεταβλητές",
"term.appleInc": "Apple Inc.",
"term.appleMusic": "Apple Music",
"term.applePodcasts": "Apple Podcasts",
@ -20,9 +21,13 @@
"term.accountSettings": "Ρυθμίσεις λογαριασμού",
"term.logout": "Αποσύνδεση",
"term.login": "Σύνδεση",
"term.cast": "Μετάδοση",
"term.about": "Σχετικά με",
"term.privateSession": "Ιδιωτική περίοδος λειτουργίας",
"term.disablePrivateSession": "Απενεργ. ιδιωτικής περ. λειτουργίας",
"term.queue": "Ουρά",
"term.lyrics": "Στίχοι",
"term.miniplayer": "MiniPlayer",
"term.history": "Ιστορικό",
"term.search": "Εύρεση",
"term.library": "Βιβλιοθήκη",
@ -68,6 +73,7 @@
"term.viewAs": "Προβολή ως",
"term.viewAs.coverArt": "Εξώφυλλο",
"term.viewAs.list": "Λίστα",
"term.dynamic": "Δυναμικό",
"term.size": "Μέγεθος",
"term.size.normal": "Κανονικό",
"term.size.compact": "Συμπαγή",
@ -89,12 +95,26 @@
"term.time.added": "Προστέθηκε",
"term.time.released": "Κυκλοφόρησε",
"term.time.updated": "Ενημερώθηκε",
"term.time.days": "μέρες",
"term.time.day": {
"one": "μέρα",
"other": "μέρες"
},
"term.time.hours": "ώρες",
"term.time.hour": "ώρα",
"term.time.hour": {
"one": "ώρα",
"other": "ώρες"
},
"term.time.minutes": "λεπτά",
"term.time.minute": "λεπτό",
"term.time.minute": {
"one": "λεπτό",
"other": "λεπτά"
},
"term.time.seconds": "δευτερόλεπτα",
"term.time.second": "δευτερόλεπτο",
"term.time.second": {
"one": "δευτερόλεπτο",
"other": "δευτερόλεπτα"
},
"term.fullscreenView": "Πλήρης οθόνη",
"term.defaultView": "Κανονική οθόνη",
"term.audioSettings": "Ρυθμίσεις ήχου",
@ -114,7 +134,8 @@
"term.contributors": "Συνεισφέροντες",
"term.equalizer": "Ισοσταθμιστής",
"term.reset": "Επαναφορά",
"term.tracks": {
"term.tracks": "τραγούδια",
"term.track": {
"one": "τραγούδι",
"other": "τραγούδια"
},
@ -145,6 +166,7 @@
"term.noVideos": "Δεν βρέθηκαν βίντεο",
"term.plugin": "Πρόσθετα",
"term.pluginMenu": "Μενού πρόσθετων",
"term.pluginMenu.none": "Δεν υπάρχουν πρόσθετα",
"term.replay": "Replay",
"term.uniqueAlbums": "Μοναδικά άλμπουμ",
"term.uniqueArtists": "Μοναδικοί καλλιτέχνες",
@ -156,10 +178,12 @@
"term.plays": "Αναπαραγωγές",
"term.topGenres": "Κορυφαία είδη",
"term.confirmLogout": "Θέλετε σίγουρα να αποσυνδεθείτε;",
"term.creditDesignedBy": "Σχεδιάστηκε από ${authorUsername}",
"term.discNumber": "Δίσκος ${discNumber}",
"home.title": "Αρχική",
"home.recentlyPlayed": "Έπαιξαν πρόσφατα",
"home.recentlyAdded": "Πρόσφατες προσθήκες",
"home.artistsFeed": "Ροή των καλλιτεχνών σου",
"home.artistsFeed": "Ροή των καλλιτεχνών σας",
"home.artistsFeed.noArtist": "Ακολούθησε μερικούς καλλιτέχνες πρώτα και οι τελευταίες κυκλοφορίες τους θα εμφανίζονται εδώ",
"home.madeForYou": "Δημιουργήθηκε για εσάς",
"home.friendsListeningTo": "Οι φίλοι σου ακούν",
@ -176,6 +200,9 @@
"podcast.episodes": "Επεισόδια",
"podcast.playEpisode": "Αναπαραγωγή επεισοδίου",
"podcast.website": "Ιστότοπος Podcast",
"action.edit": "Επεξεργασία",
"action.done": "Τέλος",
"action.editTracklist": "Επεξεργασία λίστας τραγουδιών",
"action.addToLibrary": "Προσθήκη στη βιβλιοθήκη",
"action.addToLibrary.success": "Προστέθηκε στη βιβλιοθήκη",
"action.addToLibrary.error": "Σφάλμα Προσθήκης στη βιβλιοθήκης",
@ -202,6 +229,8 @@
"action.startRadio": "Έναρξη ραδιοφώνου",
"action.goToArtist": "Μετάβαση σε καλλιτέχνη",
"action.goToAlbum": "Μετάβαση σε άλμπουμ",
"action.showInPlaylist": "Εμφάνιση στη λίστα αναπαραγωγής",
"action.showInAppleMusic": "Εμφάνιση στο Apple Music",
"action.moveToTop": "Μετακίνηση στη κορυφή",
"action.share": "Κοινή χρήση",
"action.rename": "Μετονομασία",
@ -209,7 +238,7 @@
"action.unlove": "Αναίρεση \"Μου αρέσει\"",
"action.dislike": "Δεν μου αρέσει",
"action.undoDislike": "Αναίρεση \"Δεν μου αρέσει\"",
"action.showWebRemoteQR": "Εμφάνιση Web Remote QR",
"action.showWebRemoteQR": "Web Remote",
"action.playTracksNext": "Αναπαραγωγή ${app.selectedMediaItems.length} τραγουδιών ως επόμενων",
"action.playTracksLater": "Αναπαραγωγή ${app.selectedMediaItems.length} τραγουδιών αργότερα",
"action.removeTracks": "Αφαίρεση ${self.selectedItems.length} τραγουδιών από την ουρά",
@ -218,13 +247,23 @@
"action.showAlbum": "Εμφάνιση ολόκληρου άλμπουμ",
"action.tray.minimize": "Ελαχιστοποίηση στη γωνία γραμμής εργασιών",
"action.tray.quit": "Έξοδος",
"action.tray.show": "Εμφάνιση Cider",
"action.update": "Ενημέρωση",
"action.install": "Εγκατάσταση",
"action.copy": "Αντιγραφή",
"action.newpreset": "Νέα προρύθμιση...",
"action.deletepreset": "Διαγραφή προρύθμισης",
"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.description": "Προσαρμογή γενικών ρυθμίσεων για το Cider.",
"settings.option.general.language": "Γλώσσα",
@ -234,6 +273,10 @@
"settings.option.general.resumebehavior.locally.description": "Το Cider θα συνεχίσει την τελευταία συνεδρία σας αυτής της συσκευής.",
"settings.option.general.resumebehavior.history": "Ιστορικό",
"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.fun": "Γλώσσες για πλάκα",
"settings.option.general.language.unsorted": "Αταξινόμητες",
@ -242,10 +285,34 @@
"settings.option.general.updateCider.branch.description": "Επιλέξτε τον κλάδο στον οποίο θα γίνεται η ενημέρωση του Cider",
"settings.option.general.updateCider.branch.main": "Σταθερό",
"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.description": "Προσαρμογή ρυθμίσεων ήχου για το Cider.",
"settings.option.audio.volumeStep": "Βήματα έντασης",
"settings.option.audio.maxVolume": "Μέγιστη ένταση",
"settings.option.audio.changePlaybackRate": "Αλλαγή ταχύτητας αναπαραγωγής",
"settings.option.audio.playbackRate": "Ταχύτητα αναπαραγωγής",
"settings.option.audio.playbackRate.change": "Αλλαγή",
"settings.option.audio.quality": "Ποιότητα ήχου",
"settings.header.audio.quality.hireslossless": "Lossless υψηλής ανάλυσης",
"settings.header.audio.quality.hireslossless.description": "έως και 24-bit/192 kHz",
@ -258,18 +325,34 @@
"settings.option.audio.seamlessTransition": "Αδιάκοπη μετάβαση ήχου",
"settings.option.audio.enableAdvancedFunctionality": "Ενεργοποίηση προηγμένης λειτουργικότητας",
"settings.option.audio.enableAdvancedFunctionality.description": "Ενεργοποιώντας τη λειτουργικότητα AudioContext θα επιτρέψει σε επεκταμένες δυνατότητες ήχου όπως Κανονικοποίηση Έντασης Ήχου, Ισοσταθμιστές και Οπτικοποιητές, ωστόσο σε κάποια συστήματα μπορεί να προκαλέσει τραύλισμα ήχου.",
"settings.warn.audio.enableAdvancedFunctionality.lowcores": "Η συσκευή σου ίσως να μη μπορέσει να χειρηστεί αυτές τις δυνατότητες. Σίγουρα θέλετε να συνεχίσετε;",
"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.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Ένταση Analog Warmth",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity.description": "Αλλάζει την ένταση της επεξεργασίας του Analog Warmth Module.",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth": "Αναλογική ζεστασιά",
"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.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "Ένταση CAP",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "Αλλάζει την ένταση της επεξεργασίας του ήχου. (Η επιθετική επεξεργασία μπορεί να αποφέρει ανεπιθύμητα αποτελέσματα)",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "Κανονική",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "Επιθετική",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "Κανονικοποίηση Έντασης Ήχου",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "Κανονικοποιεί την ένταση για μεμονωμένα κομμάτια για μια πιο ομοιόμορφη εμπειρία ακρόασης.",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "Κανονικοποίηση έντασης ήχου",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "Κανονικοποιεί την ένταση για μεμονωμένα κομμάτια για μια πιο ομοιόμορφη εμπειρία ακρόασης. (Δεν λειτουργεί σε κομμάτια που ανέβηκαν από χρήστες)",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.disabled": "Διαχειρίζεται από το Audio Lab",
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "Χωρικοποίηση Ήχου",
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description": "Πιο τρισδιάστατος και χωρικοποιημένος ήχος (σημείωση: Αυτό δεν είναι Dolby Atmos)",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization": "Χωρικοποίηση Cider",
@ -281,15 +364,16 @@
"settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "Η Χωρικοποίηση δεν είναι συμβατή με το CAP. Παρακαλούμε απενεργοποιήστε το CAP για να συνεχίσετε.",
"settings.header.visual": "Οπτικά",
"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.artwork": "Εξώφυλλο",
"settings.header.visual.windowBackgroundStyle.image": "Εικόνα",
"settings.option.visual.animatedArtwork": "Κινούμενο Εξώφυλλο",
"settings.option.visual.animatedArtwork": "Κινούμενο εξώφυλλο",
"settings.header.visual.animatedArtwork.always": "Πάντα",
"settings.header.visual.animatedArtwork.limited": "Περιορισμός σε σελίδες και ειδικές καταχωρήσεις",
"settings.header.visual.animatedArtwork.disable": "Απενεργοποιημένο παντού",
"settings.option.visual.animatedArtworkQuality": "Ποιότητα Κινούμενου Εξωφύλλου",
"settings.option.visual.animatedArtworkQuality": "Ποιότητα κινούμενου εξωφύλλου",
"settings.header.visual.animatedArtworkQuality.low": "Χαμηλή",
"settings.header.visual.animatedArtworkQuality.medium": "Μέτρια",
"settings.header.visual.animatedArtworkQuality.high": "Υψηλή",
@ -300,30 +384,52 @@
"settings.option.visual.hardwareAcceleration.description": "Απαιτεί επανεκκίνηση",
"settings.header.visual.hardwareAcceleration.default": "Προεπιλογή",
"settings.header.visual.hardwareAcceleration.webGPU": "WebGPU",
"settings.option.visual.uiscale": "Κλίμακα διεπαφής χρήστη",
"settings.header.visual.theme": "Θέμα",
"settings.option.visual.theme.github.download": "Εγκατάσταση από σύνδεσμο GitHub",
"settings.option.visual.theme.github.openfolder": "Άνοιγμα φακέλου θεμάτων",
"settings.option.visual.theme.github.explore": "Εξερεύνηση θεμάτων GitHub",
"settings.header.visual.theme.github.page": "Θέματα από το GitHub",
"settings.option.visual.theme.github.install.confirm": "Θέλετε σίγουρα να εγκαταστήσετε το θέμα {{ repo }};",
"settings.prompt.visual.theme.github.URL": "Εισάγετε τον σύνδεσμο του θέματος που θέλετε να εγκαταστήσετε",
"settings.notyf.visual.theme.install.success": "Το θέμα εγκαταστάθηκε με επιτυχία",
"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.dark": "Σκοτεινό",
"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.description": "Προσαρμογή ρυθμίσεων στίχων για το Cider.",
"settings.option.lyrics.enableMusixmatch": "Ενεργοποίηση Στίχων Musixmatch",
"settings.option.lyrics.enableMusixmatchKaraoke": "Ενεργοποίηση Λειτουργίας Καραόκε (Musixmatch μόνο)",
"settings.option.lyrics.musixmatchPreferredLanguage": "Προτιμώμενη Γλώσσα Μετάφρασης Musixmatch",
"settings.option.lyrics.enableYoutubeLyrics": "Ενεργοποίηση Στίχων Youtube για Μουσικά Βίντεο",
"settings.header.connectivity": "Σύνδεση",
"settings.header.connectivity.description": "Προσαρμογή ρυθμίσεων σύνδεσης για το Cider.",
"settings.option.lyrics.enableMusixmatch": "Ενεργοποίηση στίχων Musixmatch",
"settings.option.lyrics.enableMusixmatchKaraoke": "Ενεργοποίηση λειτουργίας καραόκε (Musixmatch μόνο)",
"settings.option.lyrics.musixmatchPreferredLanguage": "Προτιμώμενη γλώσσα μετάφρασης Musixmatch",
"settings.option.lyrics.enableYoutubeLyrics": "Ενεργοποίηση στίχων YouTube για μουσικά βίντεο",
"settings.option.lyrics.enableQQLyrics": "Ενεργοποίηση στίχων QQ",
"settings.header.connectivity": "Συνδεσιμότητα",
"settings.header.connectivity.description": "Προσαρμογή ρυθμίσεων συνδεσιμότητας για το Cider.",
"settings.option.connectivity.playbackNotifications": "Ειδοποιήσεις αναπαραγωγής",
"settings.option.connectivity.discordRPC": "Discord Rich Presence",
"settings.option.connectivity.playbackNotifications": "Ειδοποιήσεις Αναπαραγωγής",
"settings.header.connectivity.discordRPC.cider": "Εμφάνιση ως 'Cider'",
"settings.header.connectivity.discordRPC.appleMusic": "Εμφάνιση ως 'Apple Music'",
"settings.option.connectivity.discordRPC.clearOnPause": "Εκκαθάριση του Discord Rich Presence στην Παύση",
"settings.option.connectivity.discordRPC.clientName": "Τίτλος",
"settings.option.connectivity.discordRPC.clearOnPause": "Εκκαθάριση του Discord Rich Presence στην παύση",
"settings.option.connectivity.discordRPC.hideButtons": "Απόκρυψη κουμπιών του Discord Rich Presence",
"settings.option.connectivity.discordRPC.detailsFormat": "Δομή λεπτομεριών",
"settings.option.connectivity.discordRPC.stateFormat": "Δομή κατάστασης",
"settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling",
"settings.option.connectivity.lastfmScrobble.delay": "Καθυστέρηση LastFM Scrobble (%)",
"settings.option.connectivity.lastfmScrobble.nowPlaying": "Ενεργοποίηση LastFM \"Now Playing\"",
@ -334,32 +440,52 @@
"settings.option.debug.openAppData": "Άνοιγμα του φακέλου Cider",
"settings.header.experimental": "Πειραματικές",
"settings.header.experimental.description": "Προσαρμογή πειραματικών ρυθμίσεων για το Cider.",
"settings.option.experimental.compactUI": "Συμπαγής Διεπαφή",
"settings.option.experimental.closeButtonBehaviour": "Συμπεριφορά Κουμπιού Εξόδου",
"settings.option.experimental.closeButtonBehaviour.quit": "Έξοδος του Cider",
"settings.option.experimental.closeButtonBehaviour.minimizeTaskbar": "Ελαχιστοποίηση στη γραμμή εργασιών",
"settings.option.experimental.closeButtonBehaviour.minimizeTray": "Ελαχιστοποίηση στη γωνία γραμμής εργασιών",
"settings.option.experimental.reinstallwidevine": "Επανεγκατάσταση του WidevineCDM",
"settings.option.experimental.reinstallwidevine.confirm": "Θέλετε σίγουρα να επανεγκαταστήσετε το Widevine;",
"settings.option.experimental.unknownPlugin": "Άγνωστες πηγές",
"settings.option.experimental.unknownPlugin.description": "Να επιτρέπεται η εγκατάσταση πρόσθετων από repo εκτός του Cider Plugin Repository",
"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.spatialProperties": "Χωρικές Ιδιότητες",
"spatial.spatialProperties": "Χωρικές ιδιότητες",
"spatial.width": "Πλάτος",
"spatial.height": "Ύψος",
"spatial.depth": "Βάθος",
"spatial.gain": "Απολαβή",
"spatial.roomMaterials": "Υλικά Δωματίου",
"spatial.roomDimensions": "Διαστάσεις Δωματίου",
"spatial.roomPositions": "Θέσεις Δωματίου",
"spatial.setDimensions": "Ορισμός Διαστάσεων",
"spatial.setPositions": "Ορισμός Θέσεων",
"spatial.roomMaterials": "Υλικά δωματίου",
"spatial.roomDimensions": "Διαστάσεις δωματίου",
"spatial.roomPositions": "Θέσεις δωματίου",
"spatial.setDimensions": "Ορισμός διαστάσεων",
"spatial.setPositions": "Ορισμός θέσεων",
"spatial.up": "Πάνω",
"spatial.front": "Πρόσοψη",
"spatial.left": "Αριστερά",
"spatial.right": "Δεξιά",
"spatial.back": "Πίσω Όψη",
"spatial.back": "Πίσω όψη",
"spatial.down": "Κάτω",
"spatial.listener": "Ακροατής",
"spatial.audioSource": "Πηγή Ήχου",
"spatial.audioSource": "Πηγή ήχου",
"settings.header.unfinished": "Ημιτελής",
"remote.web.title": "Cider Remote",
"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 και σε όλους τους συνεισφέροντές μας."
}
}

View file

@ -73,6 +73,7 @@
"term.viewAs": "View As",
"term.viewAs.coverArt": "Cuvw Awt",
"term.viewAs.list": "Wist",
"term.dynamic": "Dynyamic",
"term.size": "Size",
"term.size.normal": "Nyowmaw",
"term.size.compact": "Compact",
@ -199,6 +200,9 @@
"podcast.episodes": "Episodes",
"podcast.playEpisode": "Pway Episode",
"podcast.website": "Podcast Website",
"action.edit": "Edit",
"action.done": "Donye",
"action.editTracklist": "Edit Twackwist",
"action.addToLibrary": "Add to Wibwawy",
"action.addToLibrary.success": "Added 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.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.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.fun": "Fun Wanguages",
"settings.option.general.language.unsorted": "Unsowted",
@ -280,6 +288,8 @@
"settings.option.general.customizeSidebar": "Customize Sidebaw Items",
"settings.option.general.customizeSidebar.customize": "Customize",
"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.description.search": "Seawch",
"settings.description.albums": "Wibwawy Awbums",

View file

@ -73,6 +73,7 @@
"term.viewAs": "View As",
"term.viewAs.coverArt": "Cover Art",
"term.viewAs.list": "List",
"term.dynamic": "Dynamic",
"term.size": "Size",
"term.size.normal": "Normal",
"term.size.compact": "Compact",
@ -263,6 +264,42 @@
"action.cast.scanning": "Scanning...",
"action.createNew": "Create New...",
"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.description": "Adjust the general settings for Cider.",
"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.subheader": "Designed by Cider Acoustic Technologies in California",
"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.description": "Simulates the analog warmth modelled after the Korg Nutube 6P1",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Analog Warmth intensity",
@ -391,6 +429,13 @@
"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.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.error": "Theme installation failed",
"settings.header.visual.plugin": "Plugin",

View file

@ -73,6 +73,7 @@
"term.viewAs": "Ver como",
"term.viewAs.coverArt": "Portada",
"term.viewAs.list": "Lista",
"term.dynamic": "Dinámico",
"term.size": "Tamaño",
"term.size.normal": "Normal",
"term.size.compact": "Compacto",
@ -199,6 +200,9 @@
"podcast.episodes": "Episodios",
"podcast.playEpisode": "Reproducir Episodio",
"podcast.website": "Sitio web de Podcasts",
"action.edit": "Editar",
"action.done": "Hecho",
"action.editTracklist": "Edit Tracklist",
"action.addToLibrary": "Agregar a la Biblioteca",
"action.addToLibrary.success": "Agregado a la Biblioteca",
"action.addToLibrary.error": "Error al agregar a la Biblioteca",
@ -260,6 +264,42 @@
"action.cast.scanning": "Escaneando...",
"action.createNew": "Crear Nuevo...",
"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.description": "Ajuste la configuración general de Cider.",
"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.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.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.fun": "Idiomas Fun (Parodias)",
"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.customize": "Personalizar",
"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.description.search": "Buscar",
"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.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.enableAdvancedFunctionality": "AudioContext (funcionalidad avanzada) es necesaria para habilitar esta característica.",
"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.analogWarmthIntensity": "Intensidad de calidez analógica",
@ -382,6 +429,13 @@
"settings.header.visual.theme.github.page": "Temas de GitHub",
"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.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.error": "La Instalación del Tema Falló",
"settings.header.visual.plugin": "Plugin",
@ -410,6 +464,7 @@
"settings.option.lyrics.enableMusixmatchKaraoke": "Habilitar el modo Karaoke (solo 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.enableQQLyrics": "Habilitar letras de QQ",
"settings.header.connectivity": "Conectividad",
"settings.header.connectivity.description": "Ajuste la configuración de conectividad para Cider.",
"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.header.advanced": "Avanzado",
"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.width": "Ancho",
"spatial.height": "Alto",

View file

@ -378,6 +378,8 @@
"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.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.error": "Sikertelen volt a téma telepítése",
"settings.header.visual.plugin": "Plugin",
@ -406,6 +408,7 @@
"settings.option.lyrics.enableMusixmatchKaraoke": "Karaoke mód bekapcsolása (Csak MusixMatch)",
"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.enableQQLyrics": "QQLyrics dalszövegek engedélyezése",
"settings.header.connectivity": "Csatlakozások",
"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",

View file

@ -264,6 +264,42 @@
"action.cast.scanning": "Scanning...",
"action.createNew": "Create New...",
"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.description": "Adjust the general settings for Cider.",
"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.subheader": "Designed by Cider Acoustic Technologies in California",
"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.description": "Simulates the analog warmth modelled after the Korg Nutube 6P1",
"settings.option.audio.enableAdvancedFunctionality.analogWarmthIntensity": "Analog Warmth intensity",
@ -392,6 +429,13 @@
"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.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.error": "Theme installation failed",
"settings.header.visual.plugin": "Plugin",

View file

@ -22,6 +22,7 @@
"term.login": "登录",
"term.about": "关于",
"term.privateSession": "私人聆听",
"term.lyrics": "歌词",
"term.queue": "待播清单",
"term.history": "历史记录",
"term.miniplayer": "迷你播放器",
@ -115,7 +116,11 @@
"term.contributors": "贡献者",
"term.equalizer": "均衡器",
"term.reset": "重置",
"term.tracks": "首歌曲",
"term.track": {
"one": "首歌曲",
"other": "首歌曲"
},
"term.tracks": "歌曲",
"term.videos": "音乐视频",
"term.menu": "菜单",
"term.check": "检查",
@ -161,6 +166,9 @@
"podcast.episodes": "单集",
"podcast.playEpisode": "播放单集",
"podcast.website": "Podcast 网站",
"action.edit": "编辑",
"action.done": "完成",
"action.editTracklist": "编辑歌曲清单",
"action.addToLibrary": "加入资料库",
"action.addToLibrary.success": "成功加入资料库",
"action.addToLibrary.error": "加入资料库的过程发生了错误",
@ -187,6 +195,7 @@
"action.startRadio": "开始电台",
"action.goToArtist": "前往艺人",
"action.goToAlbum": "前往专辑",
"action.showInAppleMusic": "显示于 Apple Music",
"action.moveToTop": "移到顶部",
"action.share": "分享歌曲",
"action.rename": "重命名",
@ -203,11 +212,19 @@
"action.showAlbum": "显示专辑",
"action.tray.minimize": "最小化",
"action.tray.quit": "退出",
"action.update": "更新",
"action.copy": "复制",
"action.newpreset": "新建默认...",
"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.description": "调整 Cider 的通用设置",
"settings.option.audio.volumeStep": "音量改变量",
@ -218,6 +235,10 @@
"settings.option.general.resumebehavior.locally.description": "Cider 将还原你在这台电脑上的最后一次操作。",
"settings.option.general.resumebehavior.history": "历史",
"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.main": "语言",
"settings.option.general.language.fun": "恶搞语言",
@ -229,6 +250,8 @@
"settings.option.general.updateCider.branch.develop": "测试(Develop)",
"settings.option.general.customizeSidebar": "自定义侧边栏的功能",
"settings.option.general.customizeSidebar.customize": "自定义",
"settings.option.general.keybindings": "快捷操作键",
"settings.option.general.keybindings.open": "打开",
"settings.notyf.updateCider.update-not-available": "没有可用的更新",
"settings.notyf.updateCider.update-downloaded": "更新已成功下载,重启后进行更新",
"settings.notyf.updateCider.update-error": "更新时,发生错误",
@ -250,20 +273,27 @@
"settings.option.audio.audioLab": "Cider 音频实验室",
"settings.option.audio.audioLab.description": "包含由 Cider 开发团队进行的各种音频优化功能。",
"settings.warn.audioLab.withoutAF": "使用 Cider 音频实验室需要打开进阶音频功能才可使用。" ,
"settings.option.audio.enableAdvancedFunctionality.analogWarmth": "模拟温暖",
"settings.option.audio.enableAdvancedFunctionality.analogWarmth": "模拟温暖",
"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.ciderPPE": "Cider 数码增强音频处理™️",
"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.description": "通过人类的听力心理学模型和 AAC 编码特色的即时算法,强化 256 kbps AAC 音频的感知音频质量。",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength": "数码增强音频处理设置",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.description": "将更改音频处理的激进/振奋程度(增强选项有可能会引起杂讯)。",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.standard": "标准",
"settings.option.audio.enableAdvancedFunctionality.ciderPPEStrength.aggressive": "增强",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization": "音量平衡",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "自动将歌曲播放音量调整到相同水平,享受更舒适的聆听体验。",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.description": "自动将歌曲播放音量调整到相同水平,享受更舒适的聆听体验。",
"settings.option.audio.enableAdvancedFunctionality.audioNormalization.disabled": "此功能由音频实验室管理",
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization": "空间音频",
"settings.option.audio.enableAdvancedFunctionality.audioSpatialization.description": "将音频进行空间化处理来制造一个更立体的聆听体验(注:此功能不是官方的杜比全景声)。",
@ -274,6 +304,7 @@
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.standard": "标准",
"settings.option.audio.enableAdvancedFunctionality.tunedAudioSpatialization.profile.audiophile": "发烧友",
"settings.warn.audio.enableAdvancedFunctionality.audioSpatialization.compatibility": "音频空间无法与 CAP 相容,请关闭 CAP 在进行操作。",
"settings.option.visual.uiscale": "UI界面大小",
"settings.header.visual": "外观",
"settings.header.visual.description": "调整 Cider 的外观",
"settings.option.visual.windowBackgroundStyle": "窗口背景样式",
@ -312,7 +343,7 @@
"settings.notyf.visual.plugin.install.error": "插件安装失败",
"settings.option.visual.theme.default": "默认",
"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 ",
@ -327,19 +358,21 @@
"settings.option.lyrics.enableMusixmatchKaraoke": "启用卡拉 OK 模式(仅 Musixmatch",
"settings.option.lyrics.musixmatchPreferredLanguage": "Musixmatch 歌词语言偏好",
"settings.option.lyrics.enableYoutubeLyrics": "播放 MV 时使用 YouTube 歌词",
"settings.option.lyrics.enableQQLyrics": "启用 QQ 音乐的歌词",
"settings.header.connectivity": "外部连接",
"settings.header.connectivity.description": "调整 Cider 与外部应用的交互设置",
"settings.option.connectivity.discordRPC": "Discord 动态",
"settings.option.connectivity.playbackNotifications": "歌曲播放通知",
"settings.header.connectivity.discordRPC.cider": "显示正在使用 'Cider'",
"settings.header.connectivity.discordRPC.appleMusic": "显示正在使用 'Apple Music'",
"settings.option.connectivity.discordRPC.clientName": "应用程序名称",
"settings.option.connectivity.discordRPC.clearOnPause": "暂停时清除 Discord 动态",
"settings.option.connectivity.discordRPC.hideButtons": "隐藏 Discord 动态上的按钮",
"settings.option.connectivity.lastfmScrobble": "LastFM Scrobbling 记录",
"settings.option.connectivity.lastfmScrobble.delay": "LastFM Scrobble 延迟 (%)",
"settings.option.connectivity.lastfmScrobble.nowPlaying": "打开 LastFM 正在播放",
"settings.option.connectivity.lastfmScrobble.removeFeatured": "从歌名里去除合作者 (LastFM)",
"settings.option.connectivity.lastfmScrobble.filterLoop": "不记录单曲循环 (LastFM)",
"settings.option.connectivity.discordRPC.detailsFormat": "详细信息格式",
"settings.option.connectivity.discordRPC.stateFormat": "动态格式",
"settings.option.connectivity.lastfmScrobble": "Last.FM 音乐记录",
"settings.option.connectivity.lastfmScrobble.delay": "Last.FM 歌曲追踪延迟 (%)",
"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.option.debug.copy_log": "拷贝日志至剪贴板",
"settings.option.debug.openAppData": "打开 Cider 程序文件夹",

View file

@ -151,6 +151,9 @@
"podcast.episodes": "單集",
"podcast.playEpisode": "播放單集",
"podcast.website": "Podcast 網站",
"action.edit": "編輯",
"action.done": "完成",
"action.editTracklist": "編輯歌曲清單",
"action.addToLibrary": "加入到資料庫",
"action.addToLibrary.success": "成功加入資料庫",
"action.addToLibrary.error": "加入資料庫時,發生錯誤",
@ -215,6 +218,10 @@
"settings.option.general.resumebehavior.locally.description": "Cider 將還原你在這台電腦上的最後一次操作。",
"settings.option.general.resumebehavior.history": "歷史",
"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.fun": "特殊語言",
"settings.option.general.language.unsorted": "未分類",
@ -345,8 +352,8 @@
"settings.option.connectivity.discordRPC.hideButtons": "隱藏 Discord 動態上的按鈕",
"settings.option.connectivity.discordRPC.detailsFormat": "詳細資訊格式",
"settings.option.connectivity.discordRPC.stateFormat": "狀態格式",
"settings.option.connectivity.lastfmScrobble": "Last.FM Scrobbling 記錄",
"settings.option.connectivity.lastfmScrobble.delay": "Last.FM Scrobble 延遲 (%)",
"settings.option.connectivity.lastfmScrobble": "Last.FM 音樂記錄",
"settings.option.connectivity.lastfmScrobble.delay": "Last.FM 歌曲追蹤延遲 (%)",
"settings.option.connectivity.lastfmScrobble.nowPlaying": "開啟 Last.FM 正在聆聽",
"settings.option.connectivity.lastfmScrobble.removeFeatured": "從歌名中移除客串藝人 (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
*/
private InstanceHandler() {
// Detects of an existing instance is running (So if the lock has been achieved, no existing instance has been found)
const gotTheLock = app.requestSingleInstanceLock()

View file

@ -4,7 +4,18 @@ import * as windowStateKeeper from "electron-window-state";
import * as express from "express";
import * as getPort from "get-port";
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 {networkInterfaces} from "os";
import * as mm from 'music-metadata';
@ -37,6 +48,7 @@ export class BrowserWindow {
platform: process.platform,
dev: app.isPackaged,
osRelease: os.release(),
updatable: !process.windowsStore || !process.mas,
components: [
"pages/podcasts",
"pages/apple-account-settings",
@ -45,6 +57,7 @@ export class BrowserWindow {
"pages/library-artists",
"pages/browse",
"pages/settings",
"pages/installed-themes",
"pages/listen_now",
"pages/home",
"pages/artist-feed",
@ -95,6 +108,7 @@ export class BrowserWindow {
"components/fullscreen",
"components/miniplayer",
"components/castmenu",
"components/airplay-modal",
"components/artist-chip",
"components/hello-world",
"components/inline-collection-list",
@ -176,6 +190,10 @@ export class BrowserWindow {
page: "settings",
component: `<cider-settings></cider-settings>`,
condition: `page == 'settings'`
}, {
page: "installed-themes",
component: `<installed-themes></installed-themes>`,
condition: `page == 'installed-themes'`
}, {
page: "search",
component: `<cider-search :search="search"></cider-search>`,
@ -254,8 +272,10 @@ export class BrowserWindow {
},
};
public static watcher: any;
StartWatcher(path: string) {
const watcher = watch(path, {
BrowserWindow.watcher = watch(path, {
ignored: /[\/\\]\./,
persistent: true
});
@ -265,7 +285,7 @@ export class BrowserWindow {
}
// Declare the listeners of the watcher
watcher
BrowserWindow.watcher
.on('add', function (path: string) {
// console.log('File', path, 'has been added');
})
@ -292,6 +312,10 @@ export class BrowserWindow {
});
}
async StopWatcher() {
await BrowserWindow.watcher.close();
}
/**
* Creates the browser window
* @generator
@ -311,6 +335,8 @@ export class BrowserWindow {
});
this.options.width = windowState.width;
this.options.height = windowState.height;
this.options.x = windowState.x;
this.options.y = windowState.y;
switch (process.platform) {
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", () => {
// remove WidevineCDM from appdata folder
const widevineCdmPath = join(app.getPath("userData"), "./WidevineCdm");
@ -811,7 +881,7 @@ export class BrowserWindow {
} else if (statSync(join(utils.getPath("themes"), file)).isDirectory()) {
let subFiles = readdirSync(join(utils.getPath("themes"), file));
for (let subFile of subFiles) {
if (subFile.endsWith(".less")) {
if (subFile.endsWith("index.less")) {
themes.push(join(file, subFile));
}
}
@ -830,15 +900,20 @@ export class BrowserWindow {
themePath = themePath.slice(0, -10);
}
if (existsSync(join(themePath, "theme.json"))) {
let themeJson = JSON.parse(readFileSync(join(themePath, "theme.json"), "utf8"));
themeObjects.push({
name: themeJson.name || themeName,
description: themeJson.description || themeDescription,
path: themePath,
file: theme,
github_repo: themeJson.github_repo || "",
commit: themeJson.commit || ""
});
try {
let themeJson = JSON.parse(readFileSync(join(themePath, "theme.json"), "utf8"));
themeObjects.push({
name: themeJson.name || themeName,
description: themeJson.description || themeDescription,
path: themePath,
file: theme,
github_repo: themeJson.github_repo || "",
commit: themeJson.commit || "",
pack: themeJson.pack || false,
});
} catch (e) {
console.error(e);
}
} else {
themeObjects.push({
name: themeName,
@ -846,7 +921,8 @@ export class BrowserWindow {
path: themePath,
file: theme,
github_repo: "",
commit: ""
commit: "",
pack: false
});
}
}
@ -897,6 +973,10 @@ export class BrowserWindow {
event.returnValue = process.platform;
});
ipcMain.on("get-port", (event) => {
event.returnValue = this.clientPort;
});
ipcMain.on("is-dev", (event) => {
event.returnValue = this.devMode;
});
@ -965,6 +1045,11 @@ export class BrowserWindow {
BrowserWindow.win.setResizable(!lock);
});
// Move window
ipcMain.on("windowmove", (_event, x, y) => {
BrowserWindow.win.setBounds({x, y});
});
//Fullscreen
ipcMain.on('setFullScreen', (_event, flag) => {
BrowserWindow.win.setFullScreen(flag)
@ -1209,16 +1294,27 @@ export class BrowserWindow {
shell.openPath(app.getPath('userData'));
});
//#region Cider Connect
ipcMain.on('cc-auth', (_event) => {
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', {
auth: null
"auth": null,
"sync": {
themes: false,
plugins: false,
settings: false,
}
});
utils.getWindow().reload();
});
ipcMain.on('cc-push', (_event) => {
utils.pushStoreToConnect();
})
/* *********************************************************************************************
* Window Events
* **********************************************************************************************/
@ -1262,7 +1358,7 @@ export class BrowserWindow {
BrowserWindow.win.webContents.executeJavaScript(`
window.localStorage.setItem("currentTrack", JSON.stringify(app.mk.nowPlayingItem));
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','');`)
BrowserWindow.win.destroy();
}

View file

@ -26,9 +26,9 @@ export class Plugins {
}
public static getPluginFromMap(plugin: string): any {
if(Plugins.PluginMap[plugin]) {
if (Plugins.PluginMap[plugin]) {
return Plugins.PluginMap[plugin];
}else{
} else {
return plugin;
}
}

View file

@ -1,7 +1,7 @@
import * as ElectronStore from 'electron-store';
import * as electron from "electron";
import {app} from "electron";
import fetch from "electron-fetch";
export class Store {
static cfg: ElectronStore;
@ -12,7 +12,7 @@ export class Store {
},
"general": {
"close_button_hide": false,
"discord_rpc": {
"discordrpc": {
"enabled": false,
"client": "Cider",
"clear_on_pause": true,
@ -52,11 +52,11 @@ export class Store {
"keybindings": {
"search": [
process.platform == "darwin" ? "Command" : "Control",
"S"
"F"
],
"albums": [
process.platform == "darwin" ? "Command" : "Control",
"F"
"S"
],
"artists": [
process.platform == "darwin" ? "Command" : "Control",
@ -123,6 +123,8 @@ export class Store {
"quality": "HIGH",
"seamless_audio": true,
"normalization": false,
"dBSPL": false,
"dBSPLcalibration": 90,
"maikiwiAudio": {
"ciderPPE": false,
"ciderPPE_value": "MAIKIWI",
@ -212,17 +214,22 @@ export class Store {
},
"connectUser": {
"auth": null,
"sync": {
themes: false,
plugins: false,
settings: false,
}
},
}
private migrations: any = {
'>=1.4.3': (store: ElectronStore) => {
if (typeof store.get('general.discord_rpc') == 'number' || typeof store.get('general.discord_rpc') == 'string') {
store.delete('general.discord_rpc');
if (typeof store.get('general.discordrpc') == 'number' || typeof store.get('general.discordrpc') == 'string') {
store.delete('general.discordrpc');
}
},
}
private schema: ElectronStore.Schema<any> = {
"general.discord_rpc": {
"general.discordrpc": {
type: 'object'
},
}
@ -261,6 +268,7 @@ export class Store {
return target
}
/**
* IPC Handler
*/
@ -281,5 +289,43 @@ export class Store {
Store.cfg.store = 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
}
/**
* Get the store instance
* @returns {Store}
@ -97,6 +98,18 @@ export class utils {
Store.cfg.set(key, value)
}
/**
* Pushes Store to Connect
* @return Function
*/
static pushStoreToConnect(): Function {
return Store.pushToCloud
}
/**
* Gets the browser window
*/
@ -198,4 +211,6 @@ export class utils {
autoUpdater.logger = log
await autoUpdater.checkForUpdatesAndNotify()
}
}

View file

@ -28,7 +28,7 @@ export default class ChromecastPlugin {
// private GCstream = new Stream.PassThrough(),
private connectedHosts: any = {};
private connectedPlayer: any;
// private port = false;
private ciderPort :any = 9000;
// private server = false;
// private bufcount = 0;
// private bufcount2 = 0;
@ -148,7 +148,7 @@ export default class ChromecastPlugin {
}
let media = {
// 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',
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 fetch from 'electron-fetch'
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)
*/
public name: string = 'Discord Rich Presence';
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)';
/**
* Private variables for interaction in plugins
*/
private _utils: any;
private _attributes: any;
private ready: boolean = false;
/**
* Plugin Initialization
*/
private _client: any = null;
private _activity: RPC.Presence = {
details: '',
state: '',
largeImageKey: '',
largeImageText: '',
smallImageKey: '',
smallImageText: '',
instance: false
};
private _activityCache: RPC.Presence = {
private _activityCache: any = {
details: '',
state: '',
largeImageKey: '',
@ -44,6 +33,73 @@ export default class DiscordRPC {
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
* ****************************************************************************************/
@ -53,63 +109,91 @@ export default class DiscordRPC {
* @private
*/
private connect() {
if (!this._utils.getStoreValue("general.discord_rpc.enabled")) {
if (!this._utils.getStoreValue("general.discordrpc.enabled")) {
return;
}
const clientId = this._utils.getStoreValue("general.discord_rpc.client") === "Cider" ? '911790844204437504' : '886578863147192350';
// Apparently needed for ask to join, join, spectate etc.
RPC.register(clientId)
const clientId = this._utils.getStoreValue("general.discordrpc.client") === "Cider" ? '911790844204437504' : '886578863147192350';
// Create the client
this._client = new RPC.Client({transport: "ipc"});
this._client = new AutoClient({transport: "ipc"});
// 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}.`);
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
this._client.login({clientId})
this._client.endlessLogin({clientId: clientId})
.then(() => {
this._connection = true;
this.ready = true
})
.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) {
return
}
this._client.destroy().then(() => {
this._connection = false;
console.log('[DiscordRPC][disconnect] Disconnected from discord.')
}).catch((e: any) => console.error(`[DiscordRPC][disconnect] ${e}`));
// Check if show buttons is (true) or (false)
let activity: Object = {
details: this._utils.getStoreValue("general.discordrpc.details_format"),
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
this._client = null;
// Filter the activity
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
*/
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:
@ -173,138 +257,4 @@ export default class DiscordRPC {
}
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 {
/**
* Base Plugin Details (Eventually implemented into a GUI in settings)
*/
@ -16,36 +17,42 @@ export default class Thumbar {
* Menubar Assets
* @private
*/
private isMac: boolean = process.platform === 'darwin';
private isMac: boolean = process.platform === 'darwin';
private _menuTemplate: any = [
{
label: app.getName(),
submenu: [
{
label: 'About',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.about'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('about')`)
},
{type: 'separator'},
{
label: 'Settings',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.settings'),
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'},
{role: 'services'},
{type: 'separator'},
{role: 'hide'},
{role: 'hideOthers'},
{role: 'unhide'},
]: [
{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: [
{role: 'reload'},
{role: 'forceReload'},
{role: 'reload', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.reload')},
{role: 'forceReload', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.forcereload')},
...(this.isMac ? [
{role: 'toggleDevTools'},
{type: 'separator'},
{role: 'resetZoom'},
@ -53,25 +60,28 @@ export default class Thumbar {
{role: 'zoomOut'},
{type: 'separator'},
{role: 'togglefullscreen'},
]
]: []),
],
},
{
label: 'Window',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.window'),
submenu: [
{role: 'minimize'},
{role: 'minimize', label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.minimize')},
...(this.isMac ? [
{
label: 'Show',
click: () => utils.getWindow().show()
},
{role: 'zoom'},
...(this.isMac ? [
{type: 'separator'},
{role: 'front'},
{role: 'close'},
] : [
{role: 'close'},
]),
{
label: 'Edit',
submenu: [
@ -83,146 +93,148 @@ export default class Thumbar {
{role: 'paste'},
]
},
] : []
),
{type: 'separator'},
{
label: 'Toggle Private Session',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.toggleprivate'),
accelerator: utils.getStoreValue("general.keybindings.togglePrivateSession").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.cfg.general.privateEnabled = !app.cfg.general.privateEnabled`)
},
{type: 'separator'},
{
label: 'Web Remote',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.webremote'),
accelerator: utils.getStoreValue("general.keybindings.webRemote").join('+'),
sublabel: 'Opens in external window',
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('+'),
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('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.modals.pluginMenu = true`)
}
]
},
{
label: 'Controls',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.controls'),
submenu: [
{
label: 'Pause / Play',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.playpause'),
accelerator: 'Space',
click: () => utils.getWindow().webContents.executeJavaScript(`app.SpacePause()`)
},
{
label: 'Next',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.next'),
accelerator: 'CommandOrControl+Right',
click: () => utils.getWindow().webContents.executeJavaScript(`MusicKitInterop.next()`)
},
{
label: 'Previous',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.previous'),
accelerator: 'CommandOrControl+Left',
click: () => utils.getWindow().webContents.executeJavaScript(`MusicKitInterop.previous()`)
},
{type: 'separator'},
{
label: 'Volume Up',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.volumeup'),
accelerator: 'CommandOrControl+Up',
click: () => utils.getWindow().webContents.executeJavaScript(`app.volumeUp()`)
},
{
label: 'Volume Down',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.volumedown'),
accelerator: 'CommandOrControl+Down',
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('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('browse')`)
},
{type: 'separator'},
{
label: 'Artists',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.artists'),
accelerator: utils.getStoreValue("general.keybindings.artists").join('+'),
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('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('search')`)
},
{type: 'separator'},
{
label: 'Album',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.albums'),
accelerator: utils.getStoreValue("general.keybindings.albums").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.appRoute('library-albums')`)
},
{type: 'separator'},
{
label: 'Cast To Devices',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.cast'),
accelerator: utils.getStoreValue("general.keybindings.castToDevices").join('+'),
click: () => utils.getWindow().webContents.executeJavaScript(`app.modals.castMenu = true`)
}
]
},
{
label: 'Account',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.account'),
submenu: [
{
label: 'Account Settings',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.accountsettings'),
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()`)
}
]
},
{
label: 'Support',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.support'),
role: 'help',
submenu: [
{
label: 'Discord',
label: utils.getLocale('Discord', 'menubar.options.discord'),
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)
},
{type: 'separator'},
{
label: 'Report a...',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.report'),
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)
},
{
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)
},
{
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)
},
]
},
{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)
},
{type: 'separator'},
{
label: 'Toggle Developer Tools',
label: utils.getLocale(utils.getStoreValue('general.language'), 'menubar.options.toggledevtools'),
accelerator: utils.getStoreValue("general.keybindings.openDeveloperTools").join('+'),
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()
}
]

View file

@ -89,9 +89,9 @@ export default class RAOP {
`;
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({
name: host,
name: host.replace(".local",""),
host: addresses ? addresses[0] : '',
port: port,
addresses: addresses,
@ -147,14 +147,28 @@ export default class RAOP {
browser.on('ready', browser.discover);
browser.on('update', (service: any) => {
if (service.addresses && service.fullname && (service.fullname.includes('_raop._tcp') || service.fullname.includes('_airplay._tcp'))) {
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);}
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.device = this.airtunes.add(ipv4, {
port: ipport,
volume: 60,
volume: 50,
password: sepassword,
txt: txt
});
@ -178,6 +192,15 @@ export default class RAOP {
this._win.webContents.setAudioMuted(true);
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') {
this.airtunes.stopAll(() => {
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) => {
if (this.airtunes != 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

@ -105,7 +105,7 @@ function fallbackinitMusicKit() {
})
setTimeout(() => {
app.init()
if(app.cfg.visual.window_background_style == "mica" && !app.isDev) {
if (app.cfg.visual.window_background_style == "mica" && !app.isDev) {
app.spawnMica()
}
}, 1000)
@ -134,7 +134,7 @@ document.addEventListener('musickitloaded', function () {
function waitForApp() {
if (typeof app.init !== "undefined") {
app.init()
if(app.cfg.visual.window_background_style == "mica" && !app.isDev) {
if (app.cfg.visual.window_background_style == "mica" && !app.isDev) {
app.spawnMica()
}
}

View file

@ -364,6 +364,21 @@
align-items: 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 {
background-image: url("assets/explicit.svg");
height: 12px;
@ -371,6 +386,9 @@
filter: contrast(0);
background-repeat: no-repeat;
}
.heart-icon {
display: flex
}
@keyframes load-bar {
10% {
box-shadow: inset 0 -4px 0;

View file

@ -359,7 +359,11 @@
align-items: center;
border-radius: var(--mediaItemRadius);
position: relative;
&:hover{
.heart-icon{
display: none;
}
}
.popular {
background-image: url(assets/star.svg);
background-repeat: no-repeat;
@ -448,6 +452,22 @@
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 {
background-image: url("./assets/explicit.svg");
height: 12px;
@ -456,6 +476,12 @@
background-repeat: no-repeat;
}
.heart-icon {
display: flex;
position: absolute;
left: 20px;
}
/* CSS.gg
*/
@keyframes load-bar {

View file

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

View file

@ -488,63 +488,79 @@
/* Album / Playlist Page */
.playlist-page {
--bgColor : transparent;
padding : 0px;
--bgColor : transparent;
padding : 0px;
//background: linear-gradient(180deg, var(--bgColor) 32px, var(--bgColor) 18px, transparent 60px, transparent 100%);
top : 0;
padding-top : var(--navigationBarHeight);
display:flex;
top : 0;
padding-top : var(--navigationBarHeight);
display : flex;
flex-direction: column;
height: 100%;
overflow: hidden;
height : 100%;
overflow : hidden;
.cd-mediaitem-list-item {
&:hover {
.heart-icon {
display: flex;
}
}
.heart-icon {
left: -25px;
}
}
.editTracksBtn {
position: absolute;
top: 20px;
right: 20px;
z-index: 1;
top : 20px;
right : 20px;
z-index : 1;
>span {
display: flex;
gap: 8px;
gap : 8px;
}
}
.mediaContainer {
transition: width 0.5s ease-in-out, height 0.5s ease-in-out;
width: 260px;height:260px;
width : 260px;
height : 260px;
}
.playlist-body {
padding : 32px;
padding : 32px;
// margin-top: -75px;
overflow-y:overlay;
height:100%;
padding:0px;
overflow-y : overlay;
height : 100%;
padding : 0px;
background-color: var(--color1);
&.scrollbody {
.tabs {
display: flex;
display : flex;
flex-flow: column;
height: 100%;
height : 100%;
.nav-link {
text-transform:capitalize;
text-transform: capitalize;
}
.tab-content {
height: 100%;
height : 100%;
overflow: hidden;
margin:0px;
margin : 0px;
.tab-pane {
height: 100%;
overflow-y: overlay;
overflow-x:hidden;
padding: var(--contentInnerPadding);
height : 100%;
overflow-y : overlay;
overflow-x : hidden;
padding : var(--contentInnerPadding);
padding-inline : 40px;
-webkit-mask-image: linear-gradient(180deg, transparent, white 20px);
.well {
margin:0px;
margin: 0px;
}
}
}
@ -563,7 +579,7 @@
background : rgba(0, 0, 0, 0.25);
top : var(--navigationBarHeight);
transition : opacity 0.1s var(--appleEase);
display: none;
display : none;
}
.playlist-display {
@ -649,14 +665,14 @@
}
.playlist-desc {
transition: height .2s ease-in-out, opacity .2s ease-in-out;
transition : height .2s ease-in-out, opacity .2s ease-in-out;
box-sizing : border-box;
font-size : 14px;
flex-shrink : unset;
margin-right: 5px;
max-height : 100px;
position : relative;
height : 4vh;
height : 4vh;
.content {
height : 4vh;
@ -750,11 +766,11 @@
}
.playlist-time {
font-size: 0.9em;
margin : 6px;
opacity : 0.7;
font-size : 0.9em;
margin : 6px;
opacity : 0.7;
transition: height .2s ease-in-out, opacity .2s ease-in-out;
height: 0.9em;
height : 0.9em;
}
&.inline-playlist {
@ -802,8 +818,8 @@
.pilldim {
.nav-pills {
width: max-content;
margin: 0 auto;
width : max-content;
margin : 0 auto;
margin-top: 16px;
}
}
@ -813,26 +829,24 @@
transition: min-height 0.5s ease-in-out;
min-height: 200px;
.playlistInfo {
}
.playlistInfo {}
.mediaContainer {
transition: width 0.5s ease-in-out, height 0.5s ease-in-out;
width: 128px!important;
height: 128px!important;
width : 128px !important;
height : 128px !important;
}
.playlist-time {
transition: height .2s ease-in-out, opacity .2s ease-in-out;
height: 0px;
opacity: 0;
height : 0px;
opacity : 0;
}
.playlist-desc {
transition: height .2s ease-in-out, opacity .2s ease-in-out;
height: 0px!important;
opacity: 0;
height : 0px !important;
opacity : 0;
}
}
}
@ -920,7 +934,7 @@
pointer-events : none;
.header-content {
z-index : 1;
z-index : 1;
// margin-top: -16px;
}
@ -1112,9 +1126,56 @@
/* Artist Page End */
// Settings page
.settings-page {
padding: 0px;
.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;
overflow-y: overlay;
.list-group-item {
border-radius: 0px;
}
}
.stylestack-editor {
width: 100%;
@ -1125,17 +1186,34 @@
}
.themeLabel {
display:flex;
display : flex;
align-items: center;
}
.handle {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.list-group-item {
&:hover {
cursor: grab;
}
&:active {
cursor: grabbing;
}
}
.removeItem {
border: 0px;
background: transparent;
height: 32px;
border : 0px;
background : transparent;
height : 32px;
font-weight: bold;
color: var(--textColor);
cursor: pointer;
color : var(--textColor);
cursor : pointer;
}
.stylesDropdown {
@ -1145,7 +1223,11 @@
}
}
}
}
// Settings page
.settings-page {
padding: 0px;
.nav {
width : 90%;
@ -1163,8 +1245,9 @@
.settings-option-body-webview {
height: 100%;
width: 100%;
width : 100%;
}
.settings-option-body {
margin: 16px;
}

View file

@ -22,7 +22,7 @@ const Events = {
if (event.keyCode === 82 && event.ctrlKey) {
event.preventDefault()
bootbox.confirm("Reload Cider?", (res)=>{
if(res) {
if (res) {
window.location.reload()
}
})

View file

@ -251,9 +251,9 @@ function simulateGamepad () {
cursorPos[1] -= cursorSpeed
// sounds.Hover.play()
// if(intTabIndex <= 0) {
// if (intTabIndex <= 0) {
// intTabIndex = 0
// }else{
// } else {
// intTabIndex--
// }
// $(tabbable[intTabIndex]).focus()
@ -263,9 +263,9 @@ function simulateGamepad () {
e.preventDefault()
cursorPos[1] += cursorSpeed
// if(intTabIndex < tabbable.length) {
// if (intTabIndex < tabbable.length) {
// intTabIndex++
// }else{
// } else {
// intTabIndex = tabbable.length
// }
// $(tabbable[intTabIndex]).focus()

View file

@ -148,6 +148,10 @@ const app = new Vue({
},
tmpHeight: '',
tmpWidth: '',
tmpX: '',
tmpY: '',
miniTmpX: '',
miniTmpY: '',
tmpVar: [],
notification: false,
chrome: {
@ -207,6 +211,7 @@ const app = new Vue({
showPlaylist: false,
castMenu: false,
moreInfo: false,
airplayPW: false,
},
socialBadges: {
badgeMap: {},
@ -230,6 +235,7 @@ const app = new Vue({
pages: [],
},
moreinfodata: [],
notyf: notyf
},
watch: {
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) {
if (val) {
(this.mk.isAuthorized) ? this.chrome.menuOpened = !this.chrome.menuOpened : false;
@ -592,9 +601,7 @@ const app = new Vue({
},
async init() {
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) {
await this.reloadStyles()
}
@ -702,6 +709,7 @@ const app = new Vue({
let lastItem = window.localStorage.getItem("currentTrack")
let time = window.localStorage.getItem("currentTime")
let queue = window.localStorage.getItem("currentQueue")
app.mk.queue.position = 0; // Reset queue position.
if (lastItem != null) {
lastItem = JSON.parse(lastItem)
let kind = lastItem.attributes.playParams.kind;
@ -721,7 +729,7 @@ const app = new Vue({
if (queue != null) {
queue = JSON.parse(queue)
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;
if (ids.length > 0) {
for (let id of ids) {
@ -832,6 +840,14 @@ const app = new Vue({
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) => {
if (self.$refs.queue) {
self.$refs.queue.updateQueue();
@ -1118,28 +1134,31 @@ const app = new Vue({
}
})
},
async refreshPlaylists(localOnly = false) {
async refreshPlaylists(localOnly = false, useCachedPlaylists = true) {
let self = this
let trackMap = this.cfg.advanced.playlistTrackMapping
let newListing = []
let trackMapping = {}
const cachedPlaylist = await CiderCache.getCache("library-playlists")
const cachedTrackMapping = await CiderCache.getCache("library-playlists-tracks")
if (useCachedPlaylists) {
const cachedPlaylist = await CiderCache.getCache("library-playlists")
const cachedTrackMapping = await CiderCache.getCache("library-playlists-tracks")
if (cachedPlaylist) {
console.debug("using cached playlists")
this.playlists.listing = cachedPlaylist
self.sortPlaylists()
} else {
console.debug("playlist has no cache")
}
if (cachedPlaylist) {
console.debug("using cached playlists")
this.playlists.listing = cachedPlaylist
self.sortPlaylists()
} else {
console.debug("playlist has no cache")
}
if (cachedTrackMapping) {
console.debug("using cached track mapping")
this.playlists.trackMapping = cachedTrackMapping
}
if (localOnly) {
return
if (cachedTrackMapping) {
console.debug("using cached track mapping")
this.playlists.trackMapping = cachedTrackMapping
}
if (localOnly) {
return
}
}
this.library.backgroundNotification.message = "Building playlist cache..."
@ -1147,8 +1166,10 @@ const app = new Vue({
async function deepScan(parent = "p.playlistsroot") {
console.debug(`scanning ${parent}`)
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 app.mk.api.v3.music(`/v1/me/library/playlist-folders/${parent}/children/`)
const playlistData = await MusicKitTools.v3Continuous({href: `/v1/me/library/playlist-folders/${parent}/children/`})
console.log(playlistData)
await asyncForEach(playlistData, async (playlist) => {
playlist.parent = parent
if (
playlist.type != "library-playlist-folders" &&
@ -1242,7 +1263,7 @@ const app = new Vue({
}
}
).then(res => {
self.refreshPlaylists()
self.refreshPlaylists(false, false)
})
},
async editPlaylist(id, name = app.getLz('term.newPlaylist')) {
@ -1257,7 +1278,7 @@ const app = new Vue({
}
}
).then(res => {
self.refreshPlaylists()
self.refreshPlaylists(false, false)
})
},
copyToClipboard(str) {
@ -1301,7 +1322,7 @@ const app = new Vue({
})
self.sortPlaylists()
setTimeout(() => {
app.refreshPlaylists()
app.refreshPlaylists(false, false)
}, 8000)
})
},
@ -1318,6 +1339,9 @@ const app = new Vue({
if (found) {
self.playlists.listing.splice(self.playlists.listing.indexOf(found), 1)
}
setTimeout(() => {
app.refreshPlaylists(false, false);
}, 8000);
})
}
},
@ -1671,11 +1695,11 @@ const app = new Vue({
params["meta[albums:tracks]"] = 'popularity'
params["fields[albums]"] = "artistName,artistUrl,artwork,contentRating,editorialArtwork,editorialNotes,editorialVideo,name,playParams,releaseDate,url,copyright"
}
if(kind.includes("playlist") || kind.includes("album")){
if (kind.includes("playlist") || kind.includes("album")){
app.page = (kind) + "_" + (id);
window.location.hash = `${kind}/${id}${isLibrary ? "/" + isLibrary : ''}`
app.getTypeFromID((kind), (id), (isLibrary), params);
}else{
} else {
app.page = (kind)
window.location.hash = `${kind}/${id}${isLibrary ? "/" + isLibrary : ''}`
}
@ -2563,7 +2587,7 @@ const app = new Vue({
})
self.sortPlaylists()
setTimeout(() => {
app.refreshPlaylists()
app.refreshPlaylists(false, false)
}, 13000)
})
},
@ -3830,6 +3854,15 @@ const app = new Vue({
// 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) {
if (val) {
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
}
@ -4096,13 +4130,19 @@ const app = new Vue({
if (flag) {
this.tmpWidth = window.innerWidth;
this.tmpHeight = window.innerHeight;
this.tmpX = window.screenX;
this.tmpY = window.screenY;
ipcRenderer.send('unmaximize');
ipcRenderer.send('windowmin', 250, 250)
if (this.miniTmpX !== '' && this.miniTmpY !== '') ipcRenderer.send('windowmove', this.miniTmpX, this.miniTmpY)
ipcRenderer.send('windowresize', 300, 300, false)
app.appMode = 'mini';
} else {
this.miniTmpX = window.screenX;
this.miniTmpY = window.screenY;
ipcRenderer.send('windowmin', 844, 410)
ipcRenderer.send('windowresize', this.tmpWidth, this.tmpHeight, false)
ipcRenderer.send('windowmove', this.tmpX, this.tmpY)
ipcRenderer.send('windowontop', false)
//this.cfg.visual.miniplayer_top_toggle = true;
app.appMode = 'player';

View file

@ -108,11 +108,11 @@ const wsapi = {
app.mk.isPlaying ? app.mk.pause() : app.mk.play()
},
toggleRepeat() {
if(MusicKit.getInstance().repeatMode == 0) {
if (MusicKit.getInstance().repeatMode == 0) {
MusicKit.getInstance().repeatMode = 1
}else if(MusicKit.getInstance().repeatMode == 1){
} else if (MusicKit.getInstance().repeatMode == 1){
MusicKit.getInstance().repeatMode = 2
}else{
} else {
MusicKit.getInstance().repeatMode = 0
}
},

View file

@ -7936,6 +7936,15 @@ fieldset:disabled .btn {
filter: contrast(0);
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 {
10% {
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 {
opacity: 0;
width: 52px;
pointer-events: none;
-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;
margin-left: 3px;
}
.heart-icon {
height: 9px;
width: 13px;
filter: contrast(0);
background-repeat: no-repeat;
margin-left: 3px;
}
}
.lossless-icon {
@ -3281,6 +3289,7 @@ body[platform='darwin'] {
.app-chrome .app-chrome-item > .app-mainmenu {
opacity: 0;
width: 52px;
pointer-events: none;
-webkit-app-region: drag;
}

View file

@ -133,11 +133,11 @@ app.mkapi("artists", false, "412778295", {
var library = []
var downloaded = null;
function downloadChunk () {
if(downloaded == null) {
if (downloaded == null) {
app.mk.api.library.songs("", {limit: 100}, {includeResponseMeta: !0}).then((response)=>{
processChunk(response)
})
}else{
} else {
downloaded.next("", {limit: 100}, {includeResponseMeta: !0}).then((response)=>{
processChunk(response)
})

View file

@ -101,7 +101,7 @@
:class="{'active': this.cfg.audio.volume == 0}"></button>
<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-b-tooltip.hover :title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`">
v-b-tooltip.hover :title="formatVolumeTooltip()">
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small miniplayer"

View file

@ -134,7 +134,7 @@
:class="{'active': this.cfg.audio.volume == 0}"></button>
<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-b-tooltip.hover :title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`">
v-b-tooltip.hover :title="formatVolumeTooltip()">
</div>
<div class="app-chrome-item generic">
<button class="playback-button--small miniplayer"

View file

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

View file

@ -142,13 +142,13 @@
</span>
<span class="usermenu-item-name">{{$root.getLz('action.showWebRemoteQR')}}</span>
</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">
<%- include("../svg/cast.svg") %>
</span>
<span class="usermenu-item-name">{{$root.getLz('term.cast')}}</span>
</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">
<%- include("../svg/headphones.svg") %>
</span>
@ -216,7 +216,7 @@
<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'"
@change="checkMuteChange()" v-b-tooltip.hover
:title="`${(Math.log10(mk.volume) * 20).toFixed(2)} dB`">
:title="formatVolumeTooltip()">
</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

@ -29,7 +29,7 @@
template: '#artist-chip',
async mounted() {
let artistId = this.item.id
if(typeof this.item.relationships == "object") {
if (typeof this.item.relationships == "object") {
artistId = this.item.relationships.catalog.data[0].id
}
app.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/artists/${artistId}`).then(response => {

View file

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

View file

@ -54,7 +54,7 @@
app.modals.audioSettings = false
},
openSpatialAudio() {
if(app.cfg.audio.spatial === true && app.cfg.audio.maikiwiAudio.spatial === false) {
if (app.cfg.audio.spatial === true && app.cfg.audio.maikiwiAudio.spatial === false) {
app.modals.spatialProperties = true
app.modals.audioSettings = false
} else {

View file

@ -37,7 +37,7 @@
<div class="md-option-container" style="margin-top: 12px;margin-bottom: 12px;">
<div class="md-option-line">
<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')}} -->
<template v-if="true" v-for="(device) in devices.airplay">
<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>
<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-b-tooltip.hover :title="`${(Math.log10(app.mk.volume) * 20).toFixed(2)} dB`">
v-b-tooltip.hover :title="$root.formatVolumeTooltip()">
</div>
</div>
</div>

View file

@ -1,6 +1,6 @@
<script type="text/x-template" id="lyrics-view">
<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'">
<h3 class="lyric-line" @click="seekTo(lyric.startTime)" :class="{unsynced : lyric.startTime == 9999999}"
v-bind:line-index="index.toString()">
@ -115,7 +115,7 @@
},
methods: {
seekTo(startTime) {
if(startTime != 9999999) this.app.seekTo(startTime, false);
if (startTime != 9999999) this.app.seekTo(startTime, false);
},
getActiveLyric() {
const delayfix = 0.1
@ -125,7 +125,7 @@
if (app.currentLyricsLine != i) {
app.currentLyricsLine = i;
if (((app.lyricon && app.drawer.open) || app.appMode == 'fullscreen') && this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)) {
if(this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`)) {this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).classList.remove("active");}
if (this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`)) {this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${prevLine}"]`).classList.remove("active");}
this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`).classList.add("active")
if (this.checkIfScrollIsStatic) {
let lyricElement = this.$refs.lyricsview.querySelector(`.lyric-line[line-index="${i}"]`)
@ -183,6 +183,14 @@
}
else return []
},
qqInstrumental(lyrics) {
for(lyric of lyrics){
if (lyric.line.includes("纯音乐") && lyric.line.includes("欣赏")){
return true
}
}
return false
},
checkIfScrollIsStatic : setInterval(() => {
try {
if (position === this.$refs.lyricsview.scrollTop) {

View file

@ -76,9 +76,9 @@
}, event)
},
getVideoPriority() {
if(app.cfg.visual.animated_artwork == "always") {
if (app.cfg.visual.animated_artwork == "always") {
return true;
}else if (this.videoPriority && app.cfg.visual.animated_artwork == "limited") {
} else if (this.videoPriority && app.cfg.visual.animated_artwork == "limited") {
return true
} else if (app.cfg.visual.animated_artwork == "disabled") {
return false

View file

@ -23,7 +23,7 @@
<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>
</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>
</button>
</div>
@ -65,6 +65,10 @@
</template>
</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>
<template v-if="showMetaData == true" @dblclick="route()">
<div class="metainfo">
@ -98,7 +102,8 @@
displayDuration: true,
addClasses: {},
itemId: 0,
isLibrary: false
isLibrary: false,
isLoved: null
}
},
props: {
@ -121,6 +126,9 @@
} else {
this.itemId = this.item.id;
}
if (this.item.attributes.playParams) {
this.getHeartStatus();
}
let duration = this.item.attributes.durationInMillis ?? 0
if (duration == 0 || !this.showDuration) {
this.displayDuration = false
@ -145,7 +153,7 @@
},
getClasses() {
this.addClasses = {}
if(typeof this.item.attributes.playParams == "undefined") {
if (typeof this.item.attributes.playParams == "undefined") {
this.addClasses["disabled"] = true
}
if (this.classList) {
@ -178,7 +186,7 @@
} else {
return this.item.attributes.playParams.kind
}
}else{
} else {
return this.item.type
}
},
@ -323,6 +331,7 @@
"hidden": false,
"disabled": true,
"action": function () {
self.isLoved = true
app.love(self.item)
}
},
@ -333,6 +342,7 @@
"name": this.app.getLz('action.unlove'),
"hidden": true,
"action": function () {
self.isLoved = false
app.unlove(self.item)
}
},
@ -499,6 +509,19 @@
visibilityChanged: function (isVisible, entry) {
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() {
let item = this.item
if (item.attributes.playParams.id) {

View file

@ -27,7 +27,7 @@
<div class="title text-overflow-elipsis" @click='app.routeView(item)'>
{{ item.attributes.name ?? '' }}
</div>
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName" :style = "{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}" @click="if(item.attributes.artistName)app.searchAndNavigate(item,'artist')">
<div class="subtitle text-overflow-elipsis item-navigate" v-if="item.attributes.artistName" :style = "{'z-index': ((item.attributes.editorialNotes == null) && item.attributes.artistName) ? '4' : ''}" @click="if (item.attributes.artistName)app.searchAndNavigate(item,'artist')">
{{ item.attributes.artistName ?? '' }}
</div>

View file

@ -93,12 +93,12 @@
},
async mounted() {
await this.getBadges()
if(typeof this.item.attributes.playParams == "object") {
if(this.item.attributes.playParams.kind.includes("radioStation") && (this.item.attributes.playParams.streamingKind == 1 || this.item.attributes.playParams.streamingKind == 2)) {
if (typeof this.item.attributes.playParams == "object") {
if (this.item.attributes.playParams.kind.includes("radioStation") && (this.item.attributes.playParams.streamingKind == 1 || this.item.attributes.playParams.streamingKind == 2)) {
this.unavailable = true
}
}else{
if(this.item.type == "music-movies" || this.item.type == "tv-episodes") {
} else {
if (this.item.type == "music-movies" || this.item.type == "tv-episodes") {
this.unavailable = true
}
}
@ -116,7 +116,7 @@
}
},
getSubtitle() {
if(this.kind == 'card') {
if (this.kind == 'card') {
try {
if (typeof this.item.attributes.artistNames != "undefined") {
return this.item.attributes.artistNames
@ -130,7 +130,7 @@
}catch(e) {
return ''
}
}else {
} else {
if (typeof this.item.attributes.artistName != "undefined") {
return this.item.attributes.artistName
} else {
@ -139,7 +139,7 @@
}
},
getSubtitleNavigation() {
if(this.kind == 'card') {
if (this.kind == 'card') {
try {
if (typeof this.item.attributes.artistNames != "undefined") {
return app.routeView(this.item)
@ -153,7 +153,7 @@
}catch(e) {
return app.routeView(this.item)
}
}else {
} else {
if (typeof this.item.attributes.artistName != "undefined") {
return app.searchAndNavigate(this.item,'artist')
} else {
@ -224,7 +224,7 @@
},
getArtworkUrl(size = -1, includeUrl = false) {
let artwork = this.item.attributes.artwork ? this.item.attributes.artwork.url : ''
if(size != -1) {
if (size != -1) {
artwork = artwork.replace('{w}', size).replace('{h}', size).replace('{f}', "webp").replace('{c}', ((size === 900) ? "sr" : "cc"))
}
switch (this.kind) {
@ -232,9 +232,9 @@
artwork = this.item.attributes.editorialArtwork?.subscriptionHero?.url ?? (this.item.attributes.artwork?.url ?? (this.item.relationships?.contents?.data[0]?.attributes?.editorialArtwork?.subscriptionHero?.url ?? ''))
break;
}
if(!includeUrl) {
if (!includeUrl) {
return artwork
}else{
} else {
return `url("${artwork}")`
}
},
@ -442,7 +442,7 @@
if (self.item.relationships.catalog){
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {self.app.copyToClipboard((u.data.data.length && u.data.data.length > 0)? u.data.data[0].attributes.url : u.data.data.attributes.url)})
}
}else {
} else {
self.app.copyToClipboard(self.item.attributes.url)}
}
},
@ -454,7 +454,7 @@
if (self.item.relationships.catalog){
app.mkapi(self.item.attributes.playParams.kind, false, self.item.relationships.catalog.data[0].id).then(u => {self.app.songLinkShare((u.data.data.length && u.data.data.length > 0)? u.data.data[0].attributes.url : u.data.data.attributes.url)})
}
}else {
} else {
self.app.songLinkShare(self.item.attributes.url)}
}
}
@ -471,10 +471,10 @@
try {
await this.isInLibrary().then((_) => {
if(self.addedToLibrary) {
if (self.addedToLibrary) {
menus.normal.items.find(x => x.id == 'addToLibrary').hidden = true
menus.normal.items.find(x => x.id == 'removeFromLibrary').hidden = false
}else{
} else {
menus.normal.items.find(x => x.id == 'addToLibrary').disabled = false
}
})
@ -530,7 +530,7 @@
}
}
}
if(self.app.cfg.home.followedArtists.includes(this.item.id)) {
if (self.app.cfg.home.followedArtists.includes(this.item.id)) {
followAction = "unfollow"
}
app.showMenuPanel({

View file

@ -13,12 +13,11 @@
</div>
<div class="queue-body" v-if="page == 'queue'">
<draggable v-model="queueItems" @start="drag=true" @end="drag=false;move()">
<template v-for="(queueItem, position) in queueItems">
<div v-if="position <= queuePosition" style="display: none;">{{ position }}</div>
<template v-for="(queueItem, position) in displayQueueItems">
<div class="cd-queue-item"
:class="{selected: selectedItems.includes(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)">
<div class="row">
<div class="col-auto flex-center">
@ -61,6 +60,13 @@
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() {
this.updateQueue()
},
@ -70,8 +76,8 @@
this.history = history.data.data
},
select(e, position) {
if(e.ctrlKey || e.shiftKey) {
if(this.selectedItems.indexOf(position) == -1) {
if (e.ctrlKey || e.shiftKey) {
if (this.selectedItems.indexOf(position) == -1) {
this.selectedItems.push(position)
} else {
this.selectedItems.splice(this.selectedItems.indexOf(position), 1)
@ -83,7 +89,7 @@
queueContext(event, item, position) {
let self = this
let useMenu = "single"
if(this.selectedItems.length > 1) {
if (this.selectedItems.length > 1) {
useMenu = "multiple"
}
let menus = {

View file

@ -63,7 +63,7 @@
},
methods: {
playlistSelect(playlist) {
if(playlist.type != "library-playlist-folders") {
if (playlist.type != "library-playlist-folders") {
this.addToPlaylist(playlist.id)
}
},

View file

@ -294,7 +294,7 @@
this.room_materials = JSON.parse(JSON.stringify(this.$root.cfg.audio.spatial_properties.room_materials))
this.audio_position = JSON.parse(JSON.stringify(this.$root.cfg.audio.spatial_properties.audio_position))
this.listener_position = JSON.parse(JSON.stringify(this.$root.cfg.audio.spatial_properties.listener_position))
if(typeof this.app.mk.nowPlayingItem != "undefined") {
if (typeof this.app.mk.nowPlayingItem != "undefined") {
this.setRoom()
}
this.ready = true
@ -320,7 +320,7 @@
},
objectContainerStyle() {
let scale = 1
if(this.room_dimensions.width * this.visualMultiplier > 300) {
if (this.room_dimensions.width * this.visualMultiplier > 300) {
scale = 300 / (this.room_dimensions.width * this.visualMultiplier)
}
let style = {
@ -346,7 +346,7 @@
window.CiderAudio.audioNodes.spatialNode.setRoomProperties(this.room_dimensions, this.room_materials);
CiderAudio.audioNodes.spatialInput.setPosition(...this.audio_position)
CiderAudio.audioNodes.spatialNode.setListenerPosition(...this.listener_position)
if(!this.app.cfg.audio.normalization) {
if (!this.app.cfg.audio.normalization) {
window.CiderAudio.audioNodes.gainNode.gain.value = app.cfg.audio.spatial_properties.gain
}
}

View file

@ -172,7 +172,7 @@
}
}
}
if(this.app.cfg.home.followedArtists.includes(self.data.id)) {
if (this.app.cfg.home.followedArtists.includes(self.data.id)) {
followAction = "unfollow"
}
app.showMenuPanel({

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

@ -132,9 +132,9 @@
self.themes = []
notyf.success(app.getLz('settings.notyf.visual.plugin.install.success'));
bootbox.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok)=>{
if(ok) {
if (ok) {
ipcRenderer.invoke("relaunchApp")
}else{
} else {
return
}
})
@ -154,9 +154,9 @@
if (arg.success) {
self.themes = ipcRenderer.sendSync("get-themes")
bootbox.confirm(app.getLz("settings.prompt.visual.plugin.github.success"), (ok)=>{
if(ok) {
if (ok) {
ipcRenderer.invoke("relaunchApp")
}else{
} else {
return
}
})

View file

@ -187,7 +187,7 @@
},
searchPodcasts() {
let self = this
if(this.search.term == "") {
if (this.search.term == "") {
return
}
app.mk.api.v3.podcasts("/v1/catalog/us/search", {term: this.search.term, types: ["podcasts"], limit: 25}).then(response => {
@ -227,7 +227,7 @@
async getNextEpisodes(next, podcastId) {
let podcastShow = await app.mk.api.v3.podcasts(next)
if(podcastId != this.podcastSelected.id) {
if (podcastId != this.podcastSelected.id) {
return
}
podcastShow.data.data.forEach(ep => {

View file

@ -22,7 +22,7 @@
<hr>
<div class="row">
<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.uniqueArtistCount }} {{$root.getLz('term.uniqueArtists')}}</h4>
<h4>{{ loaded.attributes.uniqueSongCount }} {{$root.getLz('term.uniqueSongs')}}</h4>
@ -40,7 +40,7 @@
<mediaitem-square :item="artistData.relationships.artist.data[0]"></mediaitem-square>
</div>
<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')}}
</div>
</div>
@ -55,7 +55,7 @@
<mediaitem-square :item="albumData.relationships.album.data[0]"></mediaitem-square>
</div>
<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')}}
</div>
</div>
@ -151,6 +151,9 @@
let playlist = await app.mk.api.v3.music(replayData.relationships.playlist.data[0].href, {extend: "editorialArtwork,editorialVideo"})
replayData.playlist = playlist.data.data[0]
this.loaded = replayData
},
convertToHours(minutes) {
return Math.floor(minutes / 60)
}
}
});

View file

@ -441,6 +441,30 @@
</label>
</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>
</b-tab>
@ -456,20 +480,8 @@
{{$root.getLz('settings.header.visual.theme')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<label>
<select class="md-select" @change="$root.setTheme($root.cfg.visual.theme)"
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 class="md-btn md-btn-block" @click="$root.appRoute('installed-themes')">
{{$root.getLz('settings.option.visual.theme.manageStyles')}}
</button>
</div>
</div>
@ -1013,18 +1025,18 @@
</div>
<div class="md-option-segment md-option-segment_auto">
<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>
</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">
{{$root.getLz('settings.option.connectivity.discordRPC.clientName')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<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="AppleMusic">{{$root.getLz('term.appleMusic')}}
</option>
@ -1033,29 +1045,29 @@
</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">
{{$root.getLz('settings.option.connectivity.discordRPC.clearOnPause')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<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>
</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">
{{$root.getLz('settings.option.connectivity.discordRPC.hideButtons')}}
</div>
<div class="md-option-segment md-option-segment_auto">
<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>
</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">
{{$root.getLz('settings.option.connectivity.discordRPC.detailsFormat')}}<br/>
<small>{{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album},
@ -1063,12 +1075,12 @@
</div>
<div class="md-option-segment md-option-segment_auto">
<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>
</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">
{{$root.getLz('settings.option.connectivity.discordRPC.stateFormat')}}
<small>{{$root.getLz('term.variables')}}: {artist}, {composer}, {title}, {album},
@ -1076,7 +1088,7 @@
</div>
<div class="md-option-segment md-option-segment_auto">
<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>
</div>
</div>
@ -1192,19 +1204,6 @@
</button>
</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-segment">
{{$root.getLz('settings.option.experimental.unknownPlugin')}}
@ -1412,112 +1411,6 @@
</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 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>
Vue.component('cider-settings', {
template: "#cider-settings",
@ -1542,7 +1435,7 @@
this.tabIndex = parseInt(window.location.hash.split("/")[1])
console.debug("tabIndex", this.tabIndex)
this.canChangeHash = true
}else{
} else {
this.canChangeHash = true
}
})
@ -1629,10 +1522,10 @@
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.webRemote = [app.platform == "darwin" ? "Command" : "Control", "W"];
app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Option" : "Shift", "A"];
app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Option" : "Shift", "P"];
app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Option" : "Shift", "C"];
app.cfg.general.keybindings.settings = [app.platform == "darwin" ? "Option" : "Shift", "S"];
app.cfg.general.keybindings.audioSettings = [app.platform == "darwin" ? "Option" : "Alt", "A"];
app.cfg.general.keybindings.pluginMenu = [app.platform == "darwin" ? "Option" : "Alt", "P"];
app.cfg.general.keybindings.castToDevices = [app.platform == "darwin" ? "Option" : "Alt", "C"];
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"];
notyf.success(app.getLz('settings.notyf.general.keybindings.update.success'));
bootbox.confirm(app.getLz("settings.prompt.general.keybindings.update.success"), (ok) => {

View file

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

View file

@ -90,7 +90,7 @@
return "https://beta.music.apple.com/assets/product/MissingArtworkMusic.svg"
}
height = parseInt(height * window.devicePixelRatio)
if(width) {
if (width) {
width = parseInt(width * window.devicePixelRatio)
}
let newurl = `${url.replace('{w}', width ?? height).replace('{h}', height).replace('{f}', "webp").replace('{c}', ((width === 900) ? "sr" : "cc"))}`;

View file

@ -86,14 +86,14 @@
if (luma > 140) {
return "#aaaaaa"
}else{
} else {
return color
}
},
getSubtitle() {
if(this.kind == 'card') {
if (this.kind == 'card') {
try {
if (typeof this.item.attributes.artistNames != "undefined") {
return this.item.attributes.artistNames
@ -107,7 +107,7 @@
}catch(e) {
return ''
}
}else {
} else {
if (typeof this.item.attributes.artistName != "undefined") {
return this.item.attributes.artistName
} else {
@ -116,7 +116,7 @@
}
},
getSubtitleNavigation() {
if(this.kind == 'card') {
if (this.kind == 'card') {
try {
if (typeof this.item.attributes.artistNames != "undefined") {
return app.routeView(this.item)
@ -130,7 +130,7 @@
}catch(e) {
return app.routeView(this.item)
}
}else {
} else {
if (typeof this.item.attributes.artistName != "undefined") {
return app.searchAndNavigate(this.item,'artist')
} else {
@ -200,7 +200,7 @@
},
getArtworkUrl(size = -1, includeUrl = false) {
let artwork = this.item.attributes.artwork ? this.item.attributes.artwork.url : ''
if(size != -1) {
if (size != -1) {
artwork = artwork.replace('{w}', size).replace('{h}', size).replace('{f}', "webp").replace('{c}', ((size === 900) ? "sr" : "cc"))
}
switch (this.kind) {
@ -208,9 +208,9 @@
artwork = this.item.attributes.editorialArtwork.subscriptionHero.url
break;
}
if(!includeUrl) {
if (!includeUrl) {
return artwork
}else{
} else {
return `url("${artwork}")`
}
},
@ -423,10 +423,10 @@
try {
await this.isInLibrary().then((_) => {
if(self.addedToLibrary) {
if (self.addedToLibrary) {
menus.normal.items.find(x => x.id == 'addToLibrary').hidden = true
menus.normal.items.find(x => x.id == 'removeFromLibrary').hidden = false
}else{
} else {
menus.normal.items.find(x => x.id == 'addToLibrary').disabled = false
}
})

View file

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