diff --git a/.github/workflows/cider-chores.yml b/.github/workflows/cider-chores.yml index 2b26ea4d..7daa90e4 100644 --- a/.github/workflows/cider-chores.yml +++ b/.github/workflows/cider-chores.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: - node-version: [ 18 ] + node-version: [18] permissions: contents: write @@ -31,7 +31,7 @@ jobs: uses: actions/setup-node@v2 with: node-version: ${{ matrix.node-version }} - cache: 'pnpm' + cache: "pnpm" - name: Update lockfile run: pnpm i --lockfile-only @@ -48,7 +48,7 @@ jobs: strategy: matrix: - node-version: [ 18 ] + node-version: [18] permissions: contents: write @@ -61,7 +61,7 @@ jobs: ref: ${{ github.head_ref }} - name: Prettify code - run: npm run prettier + run: npm run format:write - name: Commit Prettier Code uses: stefanzweifel/git-auto-commit-action@v4.14.1 @@ -69,3 +69,21 @@ jobs: commit_message: "chore: Prettified Code\n [ci skip]" commit_user_name: "cider-chore[bot]" commit_user_email: "cider-chore[bot]@users.noreply.github.com" + + synchronize-with-crowdin: + runs-on: ubuntu-latest + if: ${{ false }} # disable for now + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: crowdin action + uses: crowdin/github-action@1.4.13 + with: + upload_translations: true + download_translations: true + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml index 3307a8b2..7c3309c3 100644 --- a/.github/workflows/stale-issues.yml +++ b/.github/workflows/stale-issues.yml @@ -19,4 +19,4 @@ jobs: stale-issue-label: "stale" stale-pr-label: "stale" exempt-all-assignees: true - exempt-issue-labels: 'more-info,work-in-progress,accessibility-feature,help-wanted' + exempt-issue-labels: 'more-info,work-in-progress,accessibility-feature,help-wanted,persist' diff --git a/.prettierignore b/.prettierignore index c8c940fc..ee6ef80d 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,4 @@ -src/renderer/apple-hls* +src/renderer/*hls*.js build/* src/renderer/lib/* *.min.* diff --git a/.prettierrc b/.prettierrc index 03328464..b93c35c2 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,2 +1,13 @@ -bracketSameLine: true -printWidth: 240 +{ + "printWidth": 600, + "singleAttributePerLine": true, + "bracketSameLine": true, + "overrides": [ + { + "files": "src/renderer/main/**/*.js", + "options": { + "singleAttributePerLine": false + } + } + ] +} diff --git a/package.json b/package.json index 42e31a07..208b2d5c 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,8 @@ "msft": "npm run build && electron-builder -c msft-package.json", "mstest": "npm run build && electron-builder -c msft-test.json", "postinstall": "electron-builder install-app-deps", - "prettier": "npx prettier --write '**/*.{js,json,ts,css,less}'" + "format:check": "npx prettier --check \"src/**/*.{js,json,ts,less}\"", + "format:write": "npx prettier --write \"src/**/*.{js,json,ts,less}\"" }, "dependencies": { "@sentry/electron": "^4.0.2", diff --git a/src/i18n/en_US.json b/src/i18n/en_US.json index 8d2dc287..9163dd1b 100644 --- a/src/i18n/en_US.json +++ b/src/i18n/en_US.json @@ -10,6 +10,7 @@ "notification.updatingLibrarySongs": "Updating library songs...", "notification.updatingLibraryAlbums": "Updating library albums...", "notification.updatingLibraryArtists": "Updating library artists...", + "notification.buildingPlaylistCache": "Building Playlist Cache...", "term.variables": "Variables", "term.appleInc": "Apple Inc.", "term.appleMusic": "Apple Music", @@ -260,6 +261,7 @@ "action.removeFromQueue.success": "Removed from Queue", "action.removeFromQueue.error": "Error Removing from Queue", "action.createPlaylist": "Create a New Playlist", + "action.addToPlaylist.duplicate": "Item already exists in playlist. Do you want to continue?", "action.addToPlaylist": "Add to Playlist", "action.removeFromPlaylist": "Remove from Playlist", "action.addToFavorites": "Add to Favorites", @@ -494,6 +496,7 @@ "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.updateAvailable": "[Themes] {{ theme }} has an update available", "settings.notyf.visual.theme.install.success": "Theme installed successfully", "settings.notyf.visual.theme.install.error": "Theme installation failed", "settings.header.visual.plugin": "Plugin", @@ -548,6 +551,7 @@ "settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", "settings.option.connectivity.lastfmScrobble.filterLoop.description": "Prevent looped tracks from being scrobbled or displayed in the Now Playing list on Last.fm.", "settings.option.connectivity.lastfmScrobble.filterTypes": "Filter Media Types (Last.fm)", + "settings.option.connectivity.lastfmScrobble.filterTypes.description": "Prevent tracks of the selected media types from being scrobbled or displayed in the Now Playing list on Last.fm.", "settings.option.connectivity.lastfmScrobble.manualToken": "Enter Last.fm Token Manually", "settings.option.connectivity.lastfmScrobble.manualToken.link": "Click here to get a Last.fm token", "settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm Connection Timed Out", diff --git a/src/i18n/source/en_US.json b/src/i18n/source/en_US.json index 8d2dc287..9163dd1b 100644 --- a/src/i18n/source/en_US.json +++ b/src/i18n/source/en_US.json @@ -10,6 +10,7 @@ "notification.updatingLibrarySongs": "Updating library songs...", "notification.updatingLibraryAlbums": "Updating library albums...", "notification.updatingLibraryArtists": "Updating library artists...", + "notification.buildingPlaylistCache": "Building Playlist Cache...", "term.variables": "Variables", "term.appleInc": "Apple Inc.", "term.appleMusic": "Apple Music", @@ -260,6 +261,7 @@ "action.removeFromQueue.success": "Removed from Queue", "action.removeFromQueue.error": "Error Removing from Queue", "action.createPlaylist": "Create a New Playlist", + "action.addToPlaylist.duplicate": "Item already exists in playlist. Do you want to continue?", "action.addToPlaylist": "Add to Playlist", "action.removeFromPlaylist": "Remove from Playlist", "action.addToFavorites": "Add to Favorites", @@ -494,6 +496,7 @@ "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.updateAvailable": "[Themes] {{ theme }} has an update available", "settings.notyf.visual.theme.install.success": "Theme installed successfully", "settings.notyf.visual.theme.install.error": "Theme installation failed", "settings.header.visual.plugin": "Plugin", @@ -548,6 +551,7 @@ "settings.option.connectivity.lastfmScrobble.filterLoop": "Filter looped track (Last.fm)", "settings.option.connectivity.lastfmScrobble.filterLoop.description": "Prevent looped tracks from being scrobbled or displayed in the Now Playing list on Last.fm.", "settings.option.connectivity.lastfmScrobble.filterTypes": "Filter Media Types (Last.fm)", + "settings.option.connectivity.lastfmScrobble.filterTypes.description": "Prevent tracks of the selected media types from being scrobbled or displayed in the Now Playing list on Last.fm.", "settings.option.connectivity.lastfmScrobble.manualToken": "Enter Last.fm Token Manually", "settings.option.connectivity.lastfmScrobble.manualToken.link": "Click here to get a Last.fm token", "settings.notyf.connectivity.lastfmScrobble.connectError": "Last.fm Connection Timed Out", diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index 26312caa..3e06e7d2 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -558,15 +558,11 @@ export class BrowserWindow { res.send("Stopped"); break; case "next": - BrowserWindow.win.webContents.executeJavaScript( - "if (MusicKit.getInstance().queue.nextPlayableItemIndex != -1 && MusicKit.getInstance().queue.nextPlayableItemIndex != null) {MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex);}" - ); + BrowserWindow.win.webContents.executeJavaScript("if (MusicKit.getInstance().queue.nextPlayableItemIndex != -1 && MusicKit.getInstance().queue.nextPlayableItemIndex != null) {MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.nextPlayableItemIndex);}"); res.send("Next"); break; case "previous": - BrowserWindow.win.webContents.executeJavaScript( - "if (MusicKit.getInstance().queue.previousPlayableItemIndex != -1 && MusicKit.getInstance().queue.previousPlayableItemIndex != null) {MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.previousPlayableItemIndex);}" - ); + BrowserWindow.win.webContents.executeJavaScript("if (MusicKit.getInstance().queue.previousPlayableItemIndex != -1 && MusicKit.getInstance().queue.previousPlayableItemIndex != null) {MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.previousPlayableItemIndex);}"); res.send("Previous"); break; default: { @@ -735,18 +731,11 @@ export class BrowserWindow { details.requestHeaders["user-agent"] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Cider/1.0.0 Chrome/96.0.4664.45 Electron/16.0.0 Safari/537.36"; } if (details.url.includes("https://qq.com")) { - (details.requestHeaders["Accept"] = "*/*"), - (details.requestHeaders["Accept-Encoding"] = "gzip, deflate, br"), - (details.requestHeaders["Accept-Language"] = "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"), - (details.requestHeaders["Referer"] = "https://y.qq.com/"), - (details.requestHeaders["User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 ("); + (details.requestHeaders["Accept"] = "*/*"), (details.requestHeaders["Accept-Encoding"] = "gzip, deflate, br"), (details.requestHeaders["Accept-Language"] = "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"), (details.requestHeaders["Referer"] = "https://y.qq.com/"), (details.requestHeaders["User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 ("); ("KHTML, like Gecko) Mobile/17D50 UCBrowser/12.8.2.1268 Mobile AliApp(TUnionSDK/0.1.20.3) "); } if (details.url.includes("https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg")) { - (details.requestHeaders["Accept"] = "*/*"), - (details.requestHeaders["Accept-Encoding"] = "gzip, deflate, br"), - (details.requestHeaders["Accept-Language"] = "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"), - (details.requestHeaders["User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 ("); + (details.requestHeaders["Accept"] = "*/*"), (details.requestHeaders["Accept-Encoding"] = "gzip, deflate, br"), (details.requestHeaders["Accept-Language"] = "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6"), (details.requestHeaders["User-Agent"] = "Mozilla/5.0 (iPhone; CPU iPhone OS 13_3_1 like Mac OS X; zh-CN) AppleWebKit/537.51.1 ("); ("KHTML, like Gecko) Mobile/17D50 UCBrowser/12.8.2.1268 Mobile AliApp(TUnionSDK/0.1.20.3) "); details.requestHeaders["Referer"] = "https://y.qq.com/portal/player.html"; } @@ -1361,7 +1350,7 @@ export class BrowserWindow { .then(async (buffer) => { const metadata = await mm.parseBuffer(buffer, "audio/x-m4a"); let SoundCheckTag = metadata.native.iTunes[1].value; - console.log("sc", SoundCheckTag); + console.debug("sc", SoundCheckTag); BrowserWindow.win.webContents.send("SoundCheckTag", SoundCheckTag); }) .catch((err) => { @@ -1508,11 +1497,7 @@ export class BrowserWindow { if (details.family === "IPv4" && !details.internal) { if (!/(loopback|vmware|internal|hamachi|vboxnet|virtualbox)/gi.test(dev + (alias ? ":" + alias : ""))) { if (details.address.substring(0, 8) === "192.168." || details.address.substring(0, 7) === "172.16." || details.address.substring(0, 3) === "10.") { - if ( - !ip.startsWith("192.168.") || - (String(ip2).startsWith("192.168.") && !ip.startsWith("192.168.") && String(ip2).startsWith("172.16.") && !ip.startsWith("192.168.") && !ip.startsWith("172.16.")) || - (String(ip2).startsWith("10.") && !ip.startsWith("192.168.") && !ip.startsWith("172.16.") && !ip.startsWith("10.")) - ) { + if (!ip.startsWith("192.168.") || (String(ip2).startsWith("192.168.") && !ip.startsWith("192.168.") && String(ip2).startsWith("172.16.") && !ip.startsWith("192.168.") && !ip.startsWith("172.16.")) || (String(ip2).startsWith("10.") && !ip.startsWith("192.168.") && !ip.startsWith("172.16.") && !ip.startsWith("10."))) { ip = details.address; } ++alias; diff --git a/src/main/base/store.ts b/src/main/base/store.ts index ad94b9e8..a2a98363 100644 --- a/src/main/base/store.ts +++ b/src/main/base/store.ts @@ -240,7 +240,6 @@ export class Store { }; constructor() { - this.defaults.general.language = this.checkLocale(app.getLocale().replace("-", "_")) ?? "en_US"; Store.cfg = new ElectronStore({ name: "cider-config", defaults: this.defaults, diff --git a/src/main/base/wsapi.ts b/src/main/base/wsapi.ts index 7fc25619..d161b279 100644 --- a/src/main/base/wsapi.ts +++ b/src/main/base/wsapi.ts @@ -208,9 +208,7 @@ export class wsapi { response.message = "Next"; break; case "previous": - this._win.webContents.executeJavaScript( - `if (MusicKit.getInstance().queue.previousPlayableItemIndex != -1 && MusicKit.getInstance().queue.previousPlayableItemIndex != null) {MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.previousPlayableItemIndex)}` - ); + this._win.webContents.executeJavaScript(`if (MusicKit.getInstance().queue.previousPlayableItemIndex != -1 && MusicKit.getInstance().queue.previousPlayableItemIndex != null) {MusicKit.getInstance().changeToMediaAtIndex(MusicKit.getInstance().queue.previousPlayableItemIndex)}`); response.message = "Previous"; break; case "musickit-api": diff --git a/src/main/index.ts b/src/main/index.ts index 50d3af87..abae1125 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -1,7 +1,7 @@ require("v8-compile-cache"); import { app, components, ipcMain } from "electron"; - +import { join } from "path"; import { Store } from "./base/store"; import { AppEvents } from "./base/app"; import { Plugins } from "./base/plugins"; @@ -9,6 +9,10 @@ import { BrowserWindow } from "./base/browserwindow"; import { init as Sentry } from "@sentry/electron"; import { RewriteFrames } from "@sentry/integrations"; +if (!app.isPackaged) { + app.setPath("userData", join(app.getPath("appData"), "Cider")); +} + // Analytics for debugging fun yeah. Sentry({ dsn: "https://68c422bfaaf44dea880b86aad5a820d2@o954055.ingest.sentry.io/6112214", diff --git a/src/main/plugins/chromecast.ts b/src/main/plugins/chromecast.ts index 46110e4e..84dc9321 100644 --- a/src/main/plugins/chromecast.ts +++ b/src/main/plugins/chromecast.ts @@ -200,11 +200,7 @@ export default class ChromecastPlugin { if (details.family === "IPv4" && !details.internal) { if (!/(loopback|vmware|internal|hamachi|vboxnet|virtualbox)/gi.test(dev + (alias ? ":" + alias : ""))) { if (details.address.substring(0, 8) === "192.168." || details.address.substring(0, 7) === "172.16." || details.address.substring(0, 3) === "10.") { - if ( - !ip.startsWith("192.168.") || - (ip2.startsWith("192.168.") && !ip.startsWith("192.168.") && ip2.startsWith("172.16.") && !ip.startsWith("192.168.") && !ip.startsWith("172.16.")) || - (ip2.startsWith("10.") && !ip.startsWith("192.168.") && !ip.startsWith("172.16.") && !ip.startsWith("10.")) - ) { + if (!ip.startsWith("192.168.") || (ip2.startsWith("192.168.") && !ip.startsWith("192.168.") && ip2.startsWith("172.16.") && !ip.startsWith("192.168.") && !ip.startsWith("172.16.")) || (ip2.startsWith("10.") && !ip.startsWith("192.168.") && !ip.startsWith("172.16.") && !ip.startsWith("10."))) { ip = details.address; } ++alias; diff --git a/src/main/plugins/lastfm.ts b/src/main/plugins/lastfm.ts index ba912370..bfceeea3 100644 --- a/src/main/plugins/lastfm.ts +++ b/src/main/plugins/lastfm.ts @@ -170,13 +170,7 @@ export default class lastfm { return; } - if ( - !this._authenticated || - !attributes || - this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || - (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._scrobbleCache.track === attributes.lfmTrack.name) - ) - return; + if (!this._authenticated || !attributes || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.type] || (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._scrobbleCache.track === attributes.lfmTrack.name)) return; // Scrobble const scrobble = { @@ -216,13 +210,9 @@ export default class lastfm { return; } - if ( - !this._authenticated || - !attributes || - this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || - (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._nowPlayingCache.track === attributes.lfmTrack.name) - ) - return; + if (!this._authenticated || !attributes || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.playParams.kind] || this._utils.getStoreValue("connectivity.lastfm.filter_types")[attributes.type] || (this._utils.getStoreValue("connectivity.lastfm.filter_loop") && this._nowPlayingCache.track === attributes.lfmTrack.name)) return; + + console.log(this._utils.getStoreValue("connectivity.lastfm.filter_types")); const nowPlaying = { artist: attributes.lfmTrack.artist.name, diff --git a/src/main/plugins/menubar.ts b/src/main/plugins/menubar.ts index 261605e4..dc652dec 100644 --- a/src/main/plugins/menubar.ts +++ b/src/main/plugins/menubar.ts @@ -53,20 +53,7 @@ export default class Thumbar { { label: utils.getLocale(utils.getStoreValue("general.language"), "menubar.options.view"), submenu: [ - ...(this.isMac - ? [ - { role: "reload" }, - { role: "forceReload" }, - { role: "toggleDevTools" }, - { type: "separator" }, - { role: "resetZoom" }, - { role: "zoomIn" }, - { role: "zoomOut" }, - { type: "separator" }, - { role: "togglefullscreen" }, - { type: "separator" }, - ] - : []), + ...(this.isMac ? [{ role: "reload" }, { role: "forceReload" }, { role: "toggleDevTools" }, { type: "separator" }, { role: "resetZoom" }, { role: "zoomIn" }, { role: "zoomOut" }, { type: "separator" }, { role: "togglefullscreen" }, { type: "separator" }] : []), { label: utils.getLocale(utils.getStoreValue("general.language"), "term.search"), accelerator: utils.getStoreValue("general.keybindings.search").join("+"), diff --git a/src/main/plugins/raop.ts b/src/main/plugins/raop.ts index 74eb513b..9140ce8e 100644 --- a/src/main/plugins/raop.ts +++ b/src/main/plugins/raop.ts @@ -159,7 +159,7 @@ export default class RAOP { electron.ipcMain.on("getAirplayDevice", (event, data) => { this.castDevices = []; - console.log("scan for airplay devices"); + console.debug("scan for airplay devices"); const browser = this.mdns.createBrowser(this.mdns.tcp("raop")); browser.on("ready", browser.discover); @@ -168,7 +168,7 @@ export default class RAOP { if (service.addresses && service.fullname && service.fullname.includes("_raop._tcp")) { // console.log(service.txt) this._win.webContents.executeJavaScript(`console.log( - "${service.name} ${service.host}:${service.port} ${service.addresses} ${service.fullname}" + "${service.name} ${service.host}:${service.port} ${service.addresses} ${service.fullname}" )`); let itemname = service.fullname.substring(service.fullname.indexOf("@") + 1, service.fullname.indexOf("._raop._tcp")); this.ondeviceup(itemname, service.host, service.port, service.addresses, service.txt); @@ -259,8 +259,7 @@ export default class RAOP { // this.airtunes.stopAll(() => { // console.log("end"); // }); - if (this.devices[idx]?.state != null && this.devices[idx].state != -1) - this._win.webContents.executeJavaScript(`app.airplayDisconnect(true, ${JSON.stringify([ipv4, ipport, sepassword, title, artist, album, artworkURL, txt, airplay2dv])})`).catch((err: any) => console.error(err)); + if (this.devices[idx]?.state != null && this.devices[idx].state != -1) this._win.webContents.executeJavaScript(`app.airplayDisconnect(true, ${JSON.stringify([ipv4, ipport, sepassword, title, artist, album, artworkURL, txt, airplay2dv])})`).catch((err: any) => console.error(err)); // this.airtunes = null; // this.device = null; // this.ipairplay = ""; diff --git a/src/renderer/audio/audio.js b/src/renderer/audio/audio.js index 99645e24..9a993c14 100644 --- a/src/renderer/audio/audio.js +++ b/src/renderer/audio/audio.js @@ -301,9 +301,7 @@ const CiderAudio = { filterlessGain = filterlessGain * spatialProfile.gainComp; } filterlessGain = Math.pow(10, (-1 * (20 * Math.log10(filterlessGain))) / 20).toFixed(4); - filterlessGain > 1.0 - ? CiderAudio.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(1.0, CiderAudio.context.currentTime + 0.3) - : CiderAudio.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(filterlessGain, CiderAudio.context.currentTime + 0.3); + filterlessGain > 1.0 ? CiderAudio.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(1.0, CiderAudio.context.currentTime + 0.3) : CiderAudio.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(filterlessGain, CiderAudio.context.currentTime + 0.3); console.debug(`[Cider][Audio] IntelliGainComp: ${filterlessGain > 1.0 ? 0 : (20 * Math.log10(filterlessGain)).toFixed(2)} dB (${filterlessGain > 1.0 ? 1 : filterlessGain})`); return; } @@ -358,9 +356,7 @@ const CiderAudio = { maxGain = maxGain * spatialProfile.gainComp; } maxGain = Math.pow(10, (-1 * (20 * Math.log10(maxGain))) / 20).toFixed(4); - maxGain > 1.0 - ? CiderAudio.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(1.0, CiderAudio.context.currentTime + 0.3) - : CiderAudio.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(maxGain, CiderAudio.context.currentTime + 0.3); + maxGain > 1.0 ? CiderAudio.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(1.0, CiderAudio.context.currentTime + 0.3) : CiderAudio.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(maxGain, CiderAudio.context.currentTime + 0.3); console.debug(`[Cider][Audio] IntelliGainComp: ${maxGain > 1.0 ? 0 : (20 * Math.log10(maxGain)).toFixed(2)} dB (${maxGain > 1.0 ? 1 : maxGain})`); }, sendAudio: function () { diff --git a/src/renderer/audio/renderer.js b/src/renderer/audio/renderer.js index 8ab2ea60..04d6cd8a 100644 --- a/src/renderer/audio/renderer.js +++ b/src/renderer/audio/renderer.js @@ -171,9 +171,7 @@ const CiderAudioRenderer = { maxGain = maxGain * spatialProfile.gainComp; } maxGain = Math.pow(10, (-1 * (20 * Math.log10(maxGain))) / 20).toFixed(4); - maxGain > 1.0 - ? CiderAudioRenderer.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(1.0, CiderAudioRenderer.context.currentTime + 0.3) - : CiderAudioRenderer.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(maxGain, CiderAudioRenderer.context.currentTime + 0.3); + maxGain > 1.0 ? CiderAudioRenderer.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(1.0, CiderAudioRenderer.context.currentTime + 0.3) : CiderAudioRenderer.audioNodes.intelliGainComp.gain.exponentialRampToValueAtTime(maxGain, CiderAudioRenderer.context.currentTime + 0.3); console.debug(`[Cider][Audio] IntelliGainComp: ${maxGain > 1.0 ? 0 : (20 * Math.log10(maxGain)).toFixed(2)} dB (${maxGain > 1.0 ? 1 : maxGain})`); }, atmosphereRealizer2_n6: function (status, destination) { diff --git a/src/renderer/hlscider.js b/src/renderer/hlscider.js index 9e4c34da..f7da6d23 100644 --- a/src/renderer/hlscider.js +++ b/src/renderer/hlscider.js @@ -1589,9 +1589,7 @@ typeof window !== "undefined" && } var levelDetails = levelInfo.details; - var avgDuration = - (partCurrent ? (levelDetails === null || levelDetails === void 0 ? void 0 : levelDetails.partTarget) : levelDetails === null || levelDetails === void 0 ? void 0 : levelDetails.averagetargetduration) || - currentFragDuration; + var avgDuration = (partCurrent ? (levelDetails === null || levelDetails === void 0 ? void 0 : levelDetails.partTarget) : levelDetails === null || levelDetails === void 0 ? void 0 : levelDetails.averagetargetduration) || currentFragDuration; var adjustedbw = void 0; // follow algorithm captured from stagefright : // https://android.googlesource.com/platform/frameworks/av/+/master/media/libstagefright/httplive/LiveSession.cpp // Pick the highest bandwidth stream below or equal to estimated bandwidth. @@ -1607,9 +1605,7 @@ typeof window !== "undefined" && var bitrate = levels[i].maxBitrate; var fetchDuration = (bitrate * avgDuration) / adjustedbw; - _utils_logger__WEBPACK_IMPORTED_MODULE_6__["logger"].trace( - "level/adjustedbw/bitrate/avgDuration/maxFetchDuration/fetchDuration: " + i + "/" + Math.round(adjustedbw) + "/" + bitrate + "/" + avgDuration + "/" + maxFetchDuration + "/" + fetchDuration - ); // if adjusted bw is greater than level bitrate AND + _utils_logger__WEBPACK_IMPORTED_MODULE_6__["logger"].trace("level/adjustedbw/bitrate/avgDuration/maxFetchDuration/fetchDuration: " + i + "/" + Math.round(adjustedbw) + "/" + bitrate + "/" + avgDuration + "/" + maxFetchDuration + "/" + fetchDuration); // if adjusted bw is greater than level bitrate AND if ( adjustedbw > bitrate && // fragment fetchDuration unknown OR live stream OR fragment fetchDuration less than max allowed fetch duration, then this level matches @@ -1971,11 +1967,7 @@ typeof window !== "undefined" && if (this.bufferFlushed) { this.bufferFlushed = false; - this.afterBufferFlushed( - this.mediaBuffer ? this.mediaBuffer : this.media, - _loader_fragment__WEBPACK_IMPORTED_MODULE_7__["ElementaryStreamTypes"].AUDIO, - _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].AUDIO - ); + this.afterBufferFlushed(this.mediaBuffer ? this.mediaBuffer : this.media, _loader_fragment__WEBPACK_IMPORTED_MODULE_7__["ElementaryStreamTypes"].AUDIO, _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].AUDIO); } var bufferInfo = this.getFwdBufferInfo(this.mediaBuffer ? this.mediaBuffer : this.media, _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].AUDIO); @@ -2024,10 +2016,7 @@ typeof window !== "undefined" && return; } - if ( - ((_frag$decryptdata = frag.decryptdata) === null || _frag$decryptdata === void 0 ? void 0 : _frag$decryptdata.keyFormat) === "identity" && - !((_frag$decryptdata2 = frag.decryptdata) !== null && _frag$decryptdata2 !== void 0 && _frag$decryptdata2.key) - ) { + if (((_frag$decryptdata = frag.decryptdata) === null || _frag$decryptdata === void 0 ? void 0 : _frag$decryptdata.keyFormat) === "identity" && !((_frag$decryptdata2 = frag.decryptdata) !== null && _frag$decryptdata2 !== void 0 && _frag$decryptdata2.key)) { this.loadKey(frag, trackDetails); } else { this.loadFragment(frag, trackDetails, targetBufferTime); @@ -2176,12 +2165,7 @@ typeof window !== "undefined" && var transmuxer = this.transmuxer; if (!transmuxer) { - transmuxer = this.transmuxer = new _demux_transmuxer_interface__WEBPACK_IMPORTED_MODULE_9__["default"]( - this.CiderHls, - _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].AUDIO, - this._handleTransmuxComplete.bind(this), - this._handleTransmuxerFlush.bind(this) - ); + transmuxer = this.transmuxer = new _demux_transmuxer_interface__WEBPACK_IMPORTED_MODULE_9__["default"](this.CiderHls, _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].AUDIO, this._handleTransmuxComplete.bind(this), this._handleTransmuxerFlush.bind(this)); } // Check if we have video initPTS // If not we need to wait for it @@ -2198,9 +2182,7 @@ typeof window !== "undefined" && var chunkMeta = new _types_transmuxer__WEBPACK_IMPORTED_MODULE_10__["ChunkMetadata"](frag.level, frag.sn, frag.stats.chunkCount, payload.byteLength, partIndex, partial); transmuxer.push(payload, initSegmentData, audioCodec, "", frag, part, details.totalduration, accurateTimeOffset, chunkMeta, initPTS); } else { - _utils_logger__WEBPACK_IMPORTED_MODULE_14__["logger"].log( - "Unknown video PTS for cc " + frag.cc + ", waiting for video PTS before demuxing audio frag " + frag.sn + " of [" + details.startSN + " ," + details.endSN + "],track " + trackId - ); + _utils_logger__WEBPACK_IMPORTED_MODULE_14__["logger"].log("Unknown video PTS for cc " + frag.cc + ", waiting for video PTS before demuxing audio frag " + frag.sn + " of [" + details.startSN + " ," + details.endSN + "],track " + trackId); var _this$waitingData = (this.waitingData = this.waitingData || { frag: frag, @@ -3267,9 +3249,7 @@ typeof window !== "undefined" && state = this.state; var currentTime = media ? media.currentTime : 0; var bufferInfo = _utils_buffer_helper__WEBPACK_IMPORTED_MODULE_3__["BufferHelper"].bufferInfo(mediaBuffer || media, currentTime, config.maxBufferHole); - this.log( - "media seeking to " + (Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state - ); + this.log("media seeking to " + (Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(currentTime) ? currentTime.toFixed(3) : currentTime) + ", state: " + state); if (state === State.ENDED) { this.resetLoadingState(); @@ -3619,19 +3599,7 @@ typeof window !== "undefined" && } } - this.log( - "Loading fragment " + - frag.sn + - " cc: " + - frag.cc + - " " + - (details ? "of [" + details.startSN + "-" + details.endSN + "] " : "") + - (this.logPrefix === "[stream-controller]" ? "level" : "track") + - ": " + - frag.level + - ", target: " + - parseFloat(targetBufferTime.toFixed(3)) - ); // Don't update nextLoadPosition for fragments which are not buffered + this.log("Loading fragment " + frag.sn + " cc: " + frag.cc + " " + (details ? "of [" + details.startSN + "-" + details.endSN + "] " : "") + (this.logPrefix === "[stream-controller]" ? "level" : "track") + ": " + frag.level + ", target: " + parseFloat(targetBufferTime.toFixed(3))); // Don't update nextLoadPosition for fragments which are not buffered if (Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(frag.sn) && !this.bitrateTest) { this.nextLoadPosition = frag.start + frag.duration; @@ -4099,18 +4067,7 @@ typeof window !== "undefined" && if (firstLevelLoad || (!aligned && !slidingStart)) { Object(_utils_discontinuities__WEBPACK_IMPORTED_MODULE_9__["alignStream"])(fragPrevious, lastLevel, details); var alignedSlidingStart = details.fragments[0].start; - this.log( - "Live playlist sliding: " + - alignedSlidingStart.toFixed(2) + - " start-sn: " + - (previousDetails ? previousDetails.startSN : "na") + - "->" + - details.startSN + - " prev-sn: " + - (fragPrevious ? fragPrevious.sn : "na") + - " fragments: " + - length - ); + this.log("Live playlist sliding: " + alignedSlidingStart.toFixed(2) + " start-sn: " + (previousDetails ? previousDetails.startSN : "na") + "->" + details.startSN + " prev-sn: " + (fragPrevious ? fragPrevious.sn : "na") + " fragments: " + length); return alignedSlidingStart; } @@ -5767,11 +5724,7 @@ typeof window !== "undefined" && ot: ot, }; - if ( - ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].VIDEO || - ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].AUDIO || - ot == _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].MUXED - ) { + if (ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].VIDEO || ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].AUDIO || ot == _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].MUXED) { data.br = level.bitrate / 1000; data.tb = _this.getTopBandwidth(ot); data.bl = _this.getBufferLength(ot); @@ -5871,10 +5824,7 @@ typeof window !== "undefined" && // apply baseline data _extends(data, this.createData()); - var isVideo = - data.ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].INIT || - data.ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].VIDEO || - data.ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].MUXED; + var isVideo = data.ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].INIT || data.ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].VIDEO || data.ot === _types_cmcd__WEBPACK_IMPORTED_MODULE_1__["CMCDObjectType"].MUXED; if (this.starved && isVideo) { data.bs = true; @@ -8610,10 +8560,7 @@ typeof window !== "undefined" && levels = levels.filter(function (_ref2) { var audioCodec = _ref2.audioCodec, videoCodec = _ref2.videoCodec; - return ( - (!audioCodec || Object(_utils_codecs__WEBPACK_IMPORTED_MODULE_3__["isCodecSupportedInMp4"])(audioCodec, "audio")) && - (!videoCodec || Object(_utils_codecs__WEBPACK_IMPORTED_MODULE_3__["isCodecSupportedInMp4"])(videoCodec, "video")) - ); + return (!audioCodec || Object(_utils_codecs__WEBPACK_IMPORTED_MODULE_3__["isCodecSupportedInMp4"])(audioCodec, "audio")) && (!videoCodec || Object(_utils_codecs__WEBPACK_IMPORTED_MODULE_3__["isCodecSupportedInMp4"])(videoCodec, "video")); }); if (data.audioTracks) { @@ -9319,10 +9266,7 @@ typeof window !== "undefined" && ccOffset = oldFrag.cc - newFrag.cc; } - if ( - Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(oldFrag.startPTS) && - Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(oldFrag.endPTS) - ) { + if (Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(oldFrag.startPTS) && Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(oldFrag.endPTS)) { newFrag.start = newFrag.startPTS = oldFrag.startPTS; newFrag.startDTS = oldFrag.startDTS; newFrag.appendedPTS = oldFrag.appendedPTS; @@ -9902,10 +9846,7 @@ typeof window !== "undefined" && } // We want to load the key if we're dealing with an identity key, because we will decrypt // this content using the key we fetch. Other keys will be handled by the DRM CDM via EME. - if ( - ((_frag$decryptdata = frag.decryptdata) === null || _frag$decryptdata === void 0 ? void 0 : _frag$decryptdata.keyFormat) === "identity" && - !((_frag$decryptdata2 = frag.decryptdata) !== null && _frag$decryptdata2 !== void 0 && _frag$decryptdata2.key) - ) { + if (((_frag$decryptdata = frag.decryptdata) === null || _frag$decryptdata === void 0 ? void 0 : _frag$decryptdata.keyFormat) === "identity" && !((_frag$decryptdata2 = frag.decryptdata) !== null && _frag$decryptdata2 !== void 0 && _frag$decryptdata2.key)) { this.loadKey(frag, levelDetails); } else { this.loadFragment(frag, levelDetails, targetBufferTime); @@ -10257,13 +10198,7 @@ typeof window !== "undefined" && // this.log(`Transmuxing ${frag.sn} of [${details.startSN} ,${details.endSN}],level ${frag.level}, cc ${frag.cc}`); var transmuxer = (this.transmuxer = - this.transmuxer || - new _demux_transmuxer_interface__WEBPACK_IMPORTED_MODULE_8__["default"]( - this.CiderHls, - _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].MAIN, - this._handleTransmuxComplete.bind(this), - this._handleTransmuxerFlush.bind(this) - )); + this.transmuxer || new _demux_transmuxer_interface__WEBPACK_IMPORTED_MODULE_8__["default"](this.CiderHls, _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].MAIN, this._handleTransmuxComplete.bind(this), this._handleTransmuxerFlush.bind(this))); var partIndex = part ? part.index : -1; var partial = partIndex !== -1; var chunkMeta = new _types_transmuxer__WEBPACK_IMPORTED_MODULE_9__["ChunkMetadata"](frag.level, frag.sn, frag.stats.chunkCount, payload.byteLength, partIndex, partial); @@ -14779,8 +14714,8 @@ typeof window !== "undefined" && */ var chromeVersion = null; var BitratesMap = [ - 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 32, 48, 56, 64, 80, 96, 112, - 128, 144, 160, 176, 192, 224, 256, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, + 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 8, 16, 24, 32, 40, 48, 56, + 64, 80, 96, 112, 128, 144, 160, ]; var SamplingRateMap = [44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000]; var SamplesCoefficients = [ @@ -18354,9 +18289,7 @@ typeof window !== "undefined" && var _sourceBuffer$prototy; var sourceBuffer = getSourceBuffer(); - return ( - typeof (sourceBuffer === null || sourceBuffer === void 0 ? void 0 : (_sourceBuffer$prototy = sourceBuffer.prototype) === null || _sourceBuffer$prototy === void 0 ? void 0 : _sourceBuffer$prototy.changeType) === "function" - ); + return typeof (sourceBuffer === null || sourceBuffer === void 0 ? void 0 : (_sourceBuffer$prototy = sourceBuffer.prototype) === null || _sourceBuffer$prototy === void 0 ? void 0 : _sourceBuffer$prototy.changeType) === "function"; } /***/ @@ -18743,10 +18676,7 @@ typeof window !== "undefined" && var start = segment.byteRangeStartOffset; var end = segment.byteRangeEndOffset; - if ( - Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(start) && - Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(end) - ) { + if (Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(start) && Object(_home_runner_work_CiderHls_js_CiderHls_js_src_polyfills_number__WEBPACK_IMPORTED_MODULE_0__["isFiniteNumber"])(end)) { loaderContext.rangeStart = start; loaderContext.rangeEnd = end; } @@ -18854,12 +18784,7 @@ typeof window !== "undefined" && this._url = null; this.baseurl = void 0; this.relurl = void 0; - this.elementaryStreams = - ((_this$elementaryStrea = {}), - (_this$elementaryStrea[ElementaryStreamTypes.AUDIO] = null), - (_this$elementaryStrea[ElementaryStreamTypes.VIDEO] = null), - (_this$elementaryStrea[ElementaryStreamTypes.AUDIOVIDEO] = null), - _this$elementaryStrea); + this.elementaryStreams = ((_this$elementaryStrea = {}), (_this$elementaryStrea[ElementaryStreamTypes.AUDIO] = null), (_this$elementaryStrea[ElementaryStreamTypes.VIDEO] = null), (_this$elementaryStrea[ElementaryStreamTypes.AUDIOVIDEO] = null), _this$elementaryStrea); this.baseurl = baseurl; } // setByteRange converts a EXT-X-BYTERANGE attribute into a two element array @@ -19730,11 +19655,7 @@ typeof window !== "undefined" && function isMP4Url(url) { var _URLToolkit$parseURL$, _URLToolkit$parseURL; - return MP4_REGEX_SUFFIX.test( - (_URLToolkit$parseURL$ = (_URLToolkit$parseURL = url_toolkit__WEBPACK_IMPORTED_MODULE_1__["parseURL"](url)) === null || _URLToolkit$parseURL === void 0 ? void 0 : _URLToolkit$parseURL.path) != null - ? _URLToolkit$parseURL$ - : "" - ); + return MP4_REGEX_SUFFIX.test((_URLToolkit$parseURL$ = (_URLToolkit$parseURL = url_toolkit__WEBPACK_IMPORTED_MODULE_1__["parseURL"](url)) === null || _URLToolkit$parseURL === void 0 ? void 0 : _URLToolkit$parseURL.path) != null ? _URLToolkit$parseURL$ : ""); } var M3U8Parser = /*#__PURE__*/ (function () { @@ -20819,9 +20740,7 @@ typeof window !== "undefined" && timeout = false; } - _utils_logger__WEBPACK_IMPORTED_MODULE_3__["logger"].warn( - "[playlist-loader]: A network " + (timeout ? "timeout" : "error") + " occurred while loading " + context.type + " level: " + context.level + " id: " + context.id + ' group-id: "' + context.groupId + '"' - ); + _utils_logger__WEBPACK_IMPORTED_MODULE_3__["logger"].warn("[playlist-loader]: A network " + (timeout ? "timeout" : "error") + " occurred while loading " + context.type + " level: " + context.level + " id: " + context.id + ' group-id: "' + context.groupId + '"'); var details = _errors__WEBPACK_IMPORTED_MODULE_2__["ErrorDetails"].UNKNOWN; var fatal = false; var loader = this.getInternalLoader(context); @@ -21004,20 +20923,20 @@ typeof window !== "undefined" && if (channelCount === 1) { // ffmpeg -y -f lavfi -i "aevalsrc=0:d=0.05" -c:a libfdk_aac -profile:a aac_he -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac return new Uint8Array([ - 0x1, 0x40, 0x22, 0x80, 0xa3, 0x4e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x1c, 0x6, 0xf1, 0xc1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, - 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e, + 0x1, 0x40, 0x22, 0x80, 0xa3, 0x4e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x1c, 0x6, 0xf1, 0xc1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e, ]); } else if (channelCount === 2) { // ffmpeg -y -f lavfi -i "aevalsrc=0|0:d=0.05" -c:a libfdk_aac -profile:a aac_he_v2 -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac return new Uint8Array([ - 0x1, 0x40, 0x22, 0x80, 0xa3, 0x5e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x0, 0x95, 0x0, 0x6, 0xf1, 0xa1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, - 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e, + 0x1, 0x40, 0x22, 0x80, 0xa3, 0x5e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x0, 0x95, 0x0, 0x6, 0xf1, 0xa1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e, ]); } else if (channelCount === 3) { // ffmpeg -y -f lavfi -i "aevalsrc=0|0|0:d=0.05" -c:a libfdk_aac -profile:a aac_he_v2 -b:a 4k output.aac && hexdump -v -e '16/1 "0x%x," "\n"' -v output.aac return new Uint8Array([ - 0x1, 0x40, 0x22, 0x80, 0xa3, 0x5e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x0, 0x95, 0x0, 0x6, 0xf1, 0xa1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, - 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e, + 0x1, 0x40, 0x22, 0x80, 0xa3, 0x5e, 0xe6, 0x80, 0xba, 0x8, 0x0, 0x0, 0x0, 0x0, 0x95, 0x0, 0x6, 0xf1, 0xa1, 0xa, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, + 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5a, 0x5e, ]); } @@ -22334,13 +22253,7 @@ typeof window !== "undefined" && initSegment = this.generateIS(audioTrack, videoTrack, timeOffset); } - audio = this.remuxAudio( - audioTrack, - audioTimeOffset, - this.isAudioContiguous, - accurateTimeOffset, - hasVideo || enoughVideoSamples || playlistType === _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].AUDIO ? videoTimeOffset : undefined - ); + audio = this.remuxAudio(audioTrack, audioTimeOffset, this.isAudioContiguous, accurateTimeOffset, hasVideo || enoughVideoSamples || playlistType === _types_loader__WEBPACK_IMPORTED_MODULE_6__["PlaylistLevelType"].AUDIO ? videoTimeOffset : undefined); if (enoughVideoSamples) { var audioTrackLength = audio ? audio.endPTS - audio.startPTS : 0; // if initSegment was generated without video samples, regenerate it again @@ -22531,9 +22444,7 @@ typeof window !== "undefined" && if (ptsDtsShift < averageSampleDuration * -2) { // Fix for "CNN special report, with CC" in test-streams (including Safari browser) // With large PTS < DTS errors such as this, we want to correct CTS while maintaining increasing DTS values - _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn( - "PTS < DTS detected in video samples, offsetting DTS from PTS by " + Object(_utils_timescale_conversion__WEBPACK_IMPORTED_MODULE_7__["toMsFromMpegTsClock"])(-averageSampleDuration, true) + " ms" - ); + _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn("PTS < DTS detected in video samples, offsetting DTS from PTS by " + Object(_utils_timescale_conversion__WEBPACK_IMPORTED_MODULE_7__["toMsFromMpegTsClock"])(-averageSampleDuration, true) + " ms"); var lastDts = ptsDtsShift; for (var _i = 0; _i < nbSamples; _i++) { @@ -22543,9 +22454,7 @@ typeof window !== "undefined" && } else { // Fix for "Custom IV with bad PTS DTS" in test-streams // With smaller PTS < DTS errors we can simply move all DTS back. This increases CTS without causing buffer gaps or decode errors in Safari - _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn( - "PTS < DTS detected in video samples, shifting DTS by " + Object(_utils_timescale_conversion__WEBPACK_IMPORTED_MODULE_7__["toMsFromMpegTsClock"])(ptsDtsShift, true) + " ms to overcome this issue" - ); + _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn("PTS < DTS detected in video samples, shifting DTS by " + Object(_utils_timescale_conversion__WEBPACK_IMPORTED_MODULE_7__["toMsFromMpegTsClock"])(ptsDtsShift, true) + " ms to overcome this issue"); for (var _i2 = 0; _i2 < nbSamples; _i2++) { inputSamples[_i2].dts = inputSamples[_i2].dts + ptsDtsShift; @@ -22563,13 +22472,9 @@ typeof window !== "undefined" && if (foundHole || foundOverlap) { if (foundHole) { - _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn( - "AVC: " + Object(_utils_timescale_conversion__WEBPACK_IMPORTED_MODULE_7__["toMsFromMpegTsClock"])(delta, true) + " ms (" + delta + "dts) hole between fragments detected, filling it" - ); + _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn("AVC: " + Object(_utils_timescale_conversion__WEBPACK_IMPORTED_MODULE_7__["toMsFromMpegTsClock"])(delta, true) + " ms (" + delta + "dts) hole between fragments detected, filling it"); } else { - _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn( - "AVC: " + Object(_utils_timescale_conversion__WEBPACK_IMPORTED_MODULE_7__["toMsFromMpegTsClock"])(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected" - ); + _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn("AVC: " + Object(_utils_timescale_conversion__WEBPACK_IMPORTED_MODULE_7__["toMsFromMpegTsClock"])(-delta, true) + " ms (" + delta + "dts) overlapping between fragments detected"); } firstDTS = nextAvcDts; @@ -22682,9 +22587,7 @@ typeof window !== "undefined" && mp4SampleDuration = lastFrameDuration; } - _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].log( - "[mp4-remuxer]: It is approximately " + deltaToFrameEnd / 90 + " ms to the next segment; using duration " + mp4SampleDuration / 90 + " ms for the last video frame." - ); + _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].log("[mp4-remuxer]: It is approximately " + deltaToFrameEnd / 90 + " ms to the next segment; using duration " + mp4SampleDuration / 90 + " ms for the last video frame."); } else { mp4SampleDuration = lastFrameDuration; } @@ -22759,10 +22662,7 @@ typeof window !== "undefined" && var timeOffsetMpegTS = timeOffset * inputTimeScale; this.isAudioContiguous = contiguous = - contiguous || - (inputSamples.length && - nextAudioPts > 0 && - ((accurateTimeOffset && Math.abs(timeOffsetMpegTS - nextAudioPts) < 9000) || Math.abs(normalizePts(inputSamples[0].pts - initPTS, timeOffsetMpegTS) - nextAudioPts) < 20 * inputSampleDuration)); // compute normalized PTS + contiguous || (inputSamples.length && nextAudioPts > 0 && ((accurateTimeOffset && Math.abs(timeOffsetMpegTS - nextAudioPts) < 9000) || Math.abs(normalizePts(inputSamples[0].pts - initPTS, timeOffsetMpegTS) - nextAudioPts) < 20 * inputSampleDuration)); // compute normalized PTS inputSamples.forEach(function (sample) { sample.pts = normalizePts(sample.pts - initPTS, timeOffsetMpegTS); @@ -22833,9 +22733,7 @@ typeof window !== "undefined" && this.nextAudioPts = nextAudioPts = nextPts; } - _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn( - "[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round((1000 * delta) / inputTimeScale) + " ms gap." - ); + _utils_logger__WEBPACK_IMPORTED_MODULE_5__["logger"].warn("[mp4-remuxer]: Injecting " + missing + " audio frame @ " + (nextPts / inputTimeScale).toFixed(3) + "s due to " + Math.round((1000 * delta) / inputTimeScale) + " ms gap."); for (var j = 0; j < missing; j++) { var newStamp = Math.max(nextPts, 0); diff --git a/src/renderer/less/elements.less b/src/renderer/less/elements.less index 8322c8a2..52d77735 100644 --- a/src/renderer/less/elements.less +++ b/src/renderer/less/elements.less @@ -410,6 +410,10 @@ &:hover { background: var(--selected); border-radius: 6px; + + .circular-play-button { + opacity: 1; + } } &:active { background: var(--selected-click); @@ -418,6 +422,22 @@ } } +/* Circle Play Button */ +.circular-play-button { + position: relative; + opacity: 0; + top: -34px; + z-index: 5; + left: 8px; + align-items: center; + background: rgba(100, 100, 100, 0.5); + border: none; + cursor: pointer; + border-radius: 100%; + height: 26px; + box-shadow: var(--ciderShadow-Generic); +} + /* horizontal media scroller */ .cd-hmedia-scroller { &::-webkit-scrollbar-thumb { diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index 4d8702a9..1bf457d5 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -294,6 +294,12 @@ const app = new Vue({ }, async oobeInit() { this.appMode = "oobe"; + for (const [k, v] of Object.entries(ipcRenderer.sendSync("get-i18n-listing"))) { + if (v.code === navigator.language.replace("-", "_")) { + this.cfg.general.language = v.code; + break; + } + } this.setLz(this.cfg.general.language); this.setLzManual(); clearTimeout(this.hangtimer); @@ -657,9 +663,46 @@ const app = new Vue({ this.modals.addToPlaylist = false; app.newPlaylist(app.getLz("term.newPlaylist"), pl_items); }, + async isSongInPlaylist(song_ids, playlist_id) { + let isInPlaylist = false; + const playlistTracks = ( + await app.mk.api.v3.music(`/v1/me/library/playlists/${playlist_id}/tracks`, { + platform: "web", + l: app.mklang, + }) + ).data?.data; + + playlistTracks.forEach((track) => { + if (song_ids.includes(track.id)) { + isInPlaylist = true; + } + }); + return isInPlaylist; + }, + addToPlaylist(pid, pitems) { + app.mk.api.v3 + .music( + `/v1/me/library/playlists/${pid}/tracks`, + {}, + { + fetchOptions: { + method: "POST", + body: JSON.stringify({ + data: pitems, + }), + }, + } + ) + .then(() => { + if (app.page === "playlist_" + pid) { + app.getPlaylistFromID(app.showingPlaylist.id, true); + } + }); + }, async addSelectedToPlaylist(playlist_id) { let self = this; let pl_items = []; + const song_ids = []; for (let i = 0; i < self.selectedMediaItems.length; i++) { if (self.selectedMediaItems[i].kind == "song" || self.selectedMediaItems[i].kind == "songs") { self.selectedMediaItems[i].kind = "songs"; @@ -667,6 +710,7 @@ const app = new Vue({ id: self.selectedMediaItems[i].id, type: self.selectedMediaItems[i].kind, }); + song_ids.push(self.selectedMediaItems[i].id); } else if ((self.selectedMediaItems[i].kind == "album" || self.selectedMediaItems[i].kind == "albums") && self.selectedMediaItems[i].isLibrary != true) { self.selectedMediaItems[i].kind = "albums"; let res = await self.mk.api.v3.music(`/v1/catalog/${app.mk.storefrontId}/albums/${self.selectedMediaItems[i].id}/tracks`); @@ -674,12 +718,14 @@ const app = new Vue({ return { id: i.id, type: i.type }; }); pl_items = pl_items.concat(ids); + song_ids.push(...ids.map((id) => id.id)); } else if (self.selectedMediaItems[i].kind == "library-song" || self.selectedMediaItems[i].kind == "library-songs") { self.selectedMediaItems[i].kind = "library-songs"; pl_items.push({ id: self.selectedMediaItems[i].id, type: self.selectedMediaItems[i].kind, }); + song_ids.push(self.selectedMediaItems[i].id); } else if (self.selectedMediaItems[i].kind == "library-album" || self.selectedMediaItems[i].kind == "library-albums" || (self.selectedMediaItems[i].kind == "album" && self.selectedMediaItems[i].isLibrary == true)) { self.selectedMediaItems[i].kind = "library-albums"; let res = await self.mk.api.v3.music(`/v1/me/library/albums/${self.selectedMediaItems[i].id}/tracks`); @@ -687,32 +733,26 @@ const app = new Vue({ return { id: i.id, type: i.type }; }); pl_items = pl_items.concat(ids); + song_ids.push(...ids.map((id) => id.id)); } else { pl_items.push({ id: self.selectedMediaItems[i].id, type: self.selectedMediaItems[i].kind, }); + song_ids.push(self.selectedMediaItems[i].id); } } this.modals.addToPlaylist = false; - await app.mk.api.v3 - .music( - `/v1/me/library/playlists/${playlist_id}/tracks`, - {}, - { - fetchOptions: { - method: "POST", - body: JSON.stringify({ - data: pl_items, - }), - }, - } - ) - .then(() => { - if (this.page == "playlist_" + this.showingPlaylist.id) { - this.getPlaylistFromID(this.showingPlaylist.id, true); + + if (await this.isSongInPlaylist(song_ids, playlist_id)) { + app.confirm(app.getLz("action.addToPlaylist.duplicate"), (result) => { + if (result === true) { + app.addToPlaylist(playlist_id, pl_items); } }); + } else { + app.addToPlaylist(playlist_id, pl_items); + } }, async init() { let self = this; @@ -1210,7 +1250,7 @@ const app = new Vue({ const notify = notyf.open({ className: "notyf-info", type: "info", - message: `[Themes] ${theme.name} has an update available.`, + message: app.stringTemplateParser(app.getLz("settings.notyf.visual.theme.updateAvailable"), { theme: theme.name }), }); notify.on("click", () => { app.openSettingsPage("github-themes"); @@ -1486,15 +1526,15 @@ const app = new Vue({ const cachedTrackMapping = await CiderCache.getCache("library-playlists-tracks"); if (cachedPlaylist) { - console.debug("using cached playlists"); + console.debug("[CiderCache] Using cached playlist"); this.playlists.listing = cachedPlaylist; self.sortPlaylists(); } else { - console.debug("playlist has no cache"); + console.debug("[CiderCache] Playlist has no cache"); } if (cachedTrackMapping) { - console.debug("using cached track mapping"); + console.debug("[CiderCache] Using cached track mapping"); this.playlists.trackMapping = cachedTrackMapping; } if (localOnly) { @@ -1502,7 +1542,7 @@ const app = new Vue({ } } - this.library.backgroundNotification.message = "Building playlist cache..."; + this.library.backgroundNotification.message = app.getLz("notification.buildingPlaylistCache"); this.library.backgroundNotification.show = true; async function deepScan(parent = "p.playlistsroot") { @@ -2427,12 +2467,26 @@ const app = new Vue({ self.library.songs.displayListing.sort((a, b) => { let aa = a.attributes[prefs.sort]; let bb = b.attributes[prefs.sort]; - if (prefs.sort == "genre") { + if (prefs.sort === "genre") { aa = a.attributes.genreNames[0]; bb = b.attributes.genreNames[0]; - } else if (prefs.sort == "dateAdded") { + } else if (prefs.sort === "dateAdded") { aa = a.relationships?.albums?.data[0]?.attributes?.dateAdded; bb = b.relationships?.albums?.data[0]?.attributes?.dateAdded; + } else if (prefs.sort === "artistName") { + if (a.relationships?.artists?.data[0]?.id === b.relationships?.artists?.data[0]?.id) { + aa = a.attributes.albumName; + bb = b.attributes.albumName; + } + if (a.relationships?.albums?.data[0]?.id === b.relationships?.albums?.data[0]?.id) { + aa = a.attributes.trackNumber; + bb = b.attributes.trackNumber; + } + } else if (prefs.sort === "albumName") { + if (a.relationships?.albums?.data[0]?.id === b.relationships?.albums?.data[0]?.id) { + aa = a.attributes.trackNumber; + bb = b.attributes.trackNumber; + } } if (aa == null) { aa = ""; @@ -2440,13 +2494,13 @@ const app = new Vue({ if (bb == null) { bb = ""; } - if (prefs.sortOrder == "asc") { + if (prefs.sortOrder === "asc") { if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { return aa - bb; } else { return aa.toString().toLowerCase().localeCompare(bb.toString().toLowerCase()); } - } else if (prefs.sortOrder == "desc") { + } else if (prefs.sortOrder === "desc") { if (aa.toString().match(/^\d+$/) && bb.toString().match(/^\d+$/)) { return bb - aa; } else { @@ -3104,9 +3158,7 @@ const app = new Vue({ return; } try { - let mfu = await app.mk.api.v3.music( - "/v1/me/library/playlists?platform=web&extend=editorialVideo&fields%5Bplaylists%5D=lastModifiedDate&filter%5Bfeatured%5D=made-for-you&include%5Blibrary-playlists%5D=catalog&fields%5Blibrary-playlists%5D=artwork%2Cname%2CplayParams%2CdateAdded" - ); + let mfu = await app.mk.api.v3.music("/v1/me/library/playlists?platform=web&extend=editorialVideo&fields%5Bplaylists%5D=lastModifiedDate&filter%5Bfeatured%5D=made-for-you&include%5Blibrary-playlists%5D=catalog&fields%5Blibrary-playlists%5D=artwork%2Cname%2CplayParams%2CdateAdded"); this.madeforyou = mfu.data; } catch (e) { console.log(e); @@ -3286,10 +3338,7 @@ const app = new Vue({ let id, songLang = ""; try { - if ( - jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["header"]["status_code"] == 200 && - jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["header"]["status_code"] == 200 - ) { + if (jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["header"]["status_code"] == 200 && jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["header"]["status_code"] == 200) { id = jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["body"]["track"]["track_id"] ?? ""; lrcfile = jsonResponse["message"]["body"]["macro_calls"]["track.subtitles.get"]["message"]["body"]["subtitle_list"][0]["subtitle"]["subtitle_body"]; vanity_id = jsonResponse["message"]["body"]["macro_calls"]["matcher.track.get"]["message"]["body"]["track"]["commontrack_vanity_id"]; @@ -4202,13 +4251,7 @@ const app = new Vue({ } this.currentArtUrl = ""; this.currentArtUrlRaw = ""; - if ( - app.mk.nowPlayingItem != null && - app.mk.nowPlayingItem.attributes != null && - app.mk.nowPlayingItem.attributes.artwork != null && - app.mk.nowPlayingItem.attributes.artwork.url != null && - app.mk.nowPlayingItem.attributes.artwork.url != "" - ) { + if (app.mk.nowPlayingItem != null && app.mk.nowPlayingItem.attributes != null && app.mk.nowPlayingItem.attributes.artwork != null && app.mk.nowPlayingItem.attributes.artwork.url != null && app.mk.nowPlayingItem.attributes.artwork.url != "") { this.currentArtUrlRaw = this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"] ?? ""; this.currentArtUrl = (this.mk["nowPlayingItem"]["attributes"]["artwork"]["url"] ?? "").replace("{w}", artworkSize).replace("{h}", artworkSize); if (this.mk.nowPlayingItem._assets[0].artworkURL) { @@ -4595,7 +4638,7 @@ const app = new Vue({ name: app.getLz("action.removeFromLibrary"), hidden: true, action: function () { - self.removeFromLibrary(); + self.removeFromLibrary(app.mk.nowPlayingItem.type, MusicKitInterop.getAttributes().songId); }, }, { diff --git a/src/renderer/views/components/fullscreen.ejs b/src/renderer/views/components/fullscreen.ejs index 74ccb487..728710aa 100644 --- a/src/renderer/views/components/fullscreen.ejs +++ b/src/renderer/views/components/fullscreen.ejs @@ -39,7 +39,7 @@