diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3ba13e0ce..26cd65aa8 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,17 @@ blank_issues_enabled: false +contact_links: + - name: Discussions + url: https://github.com/FreeTubeApp/FreeTube/discussions/categories/general + about: View discussions or start one yourself + - name: Questions + url: https://github.com/FreeTubeApp/FreeTube/discussions/categories/q-a + about: Ask and answer questions + - name: Matrix Community + url: https://matrix.to/#/+freetube:matrix.org + about: Join our Matrix chatroom - "Note: Bugs and Feature requests should be made on GitHub and not in the Matrix room" + - name: Translate FreeTube + url: https://hosted.weblate.org/engage/free-tube/ + about: Help translate FreeTube on Weblate + - name: FreeTube Documentation + url: https://docs.freetubeapp.io/ + about: View the Documentation to find all relevant information about FreeTube diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 63a54a471..569ded447 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -108,91 +108,91 @@ jobs: run: yarn run build:arm64 - name: Upload Linux .zip x64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_linux_portable_x64 path: build/freetube-${{ steps.versionNumber.outputs.result }}.zip - name: Upload Linux .7z x64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_linux_portable_x64.7z path: build/freetube-${{ steps.versionNumber.outputs.result }}.7z - name: Upload Linux .zip ARMv7l Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') with: name: freetube_${{ steps.versionNumber.outputs.result }}_linux_portable_armv7l path: build/freetube-${{ steps.versionNumber.outputs.result }}-armv7l.zip - name: Upload Linux .7z ARMv7l Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') with: name: freetube_${{ steps.versionNumber.outputs.result }}_linux_portable_armv7l.7z path: build/freetube-${{ steps.versionNumber.outputs.result }}-armv7l.7z - name: Upload Linux .zip ARM64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_linux_portable_arm64 path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64.zip - name: Upload Linux .7z ARM64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_linux_portable_arm64.7z path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64.7z - name: Upload .deb x64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_amd64.deb path: build/freetube_${{ steps.versionNumber.outputs.result }}_amd64.deb - name: Upload .deb ARMv7l Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') with: name: freetube_${{ steps.versionNumber.outputs.result }}_armv7l.deb path: build/freetube_${{ steps.versionNumber.outputs.result }}_armv7l.deb - name: Upload .deb ARM64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_arm64.deb path: build/freetube_${{ steps.versionNumber.outputs.result }}_arm64.deb - name: Upload AppImage x64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_amd64.AppImage path: build/FreeTube-${{ steps.versionNumber.outputs.result }}.AppImage - name: Upload AppImage ARMv7l Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') with: name: freetube_${{ steps.versionNumber.outputs.result }}_armv7l.AppImage path: build/FreeTube-${{ steps.versionNumber.outputs.result }}-armv7l.AppImage - name: Upload AppImage ARM64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_arm64.AppImage path: build/FreeTube-${{ steps.versionNumber.outputs.result }}-arm64.AppImage - name: Upload .rpm x64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_amd64.rpm @@ -201,133 +201,133 @@ jobs: # rpm are not built for armv7l - name: Upload .rpm ARM64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_arm64.rpm path: build/freetube-${{ steps.versionNumber.outputs.result }}.aarch64.rpm - name: Upload Alpine .apk x64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_alpine_amd64.apk path: build/freetube-${{ steps.versionNumber.outputs.result }}.apk - name: Upload Alpine .apk ARMv7l Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') with: name: freetube_${{ steps.versionNumber.outputs.result }}_alpine_armv7l.apk path: build/freetube-${{ steps.versionNumber.outputs.result }}-armv7l.apk - name: Upload Alpine .apk ARM64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_alpine_arm64.apk path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64.apk - name: Upload Pacman .pacman x64 Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_amd64.pacman path: build/freetube-${{ steps.versionNumber.outputs.result }}.pacman # - name: Upload Web Build - # uses: actions/upload-artifact@v3 + # uses: actions/upload-artifact@v4 # if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') # with: # name: freetube_${{ steps.versionNumber.outputs.result }}_static_web # path: dist/web - name: Upload Windows x64 .exe Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-setup-x64.exe path: build/freetube Setup ${{ steps.versionNumber.outputs.result }}.exe - name: Upload Windows arm64 .exe Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-setup-arm64.exe path: build/freetube Setup ${{ steps.versionNumber.outputs.result }}.exe - name: Upload Windows x64 .zip Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-win-x64-portable path: build/freetube-${{ steps.versionNumber.outputs.result }}-win.zip - name: Upload Windows x64 .7z Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-win-x64-portable.7z path: build/freetube-${{ steps.versionNumber.outputs.result }}-win.7z - name: Upload Windows arm64 .zip Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-win-arm64-portable path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64-win.zip - name: Upload Windows arm64 .7z Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-win-arm64-portable.7z path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64-win.7z - name: Upload Windows x64 Portable Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-portable-x64.exe path: build/freetube ${{ steps.versionNumber.outputs.result }}.exe - name: Upload Windows arm64 Portable Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-portable-arm64.exe path: build/freetube ${{ steps.versionNumber.outputs.result }}.exe - name: Upload Mac x64 .dmg Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-mac-x64.dmg path: build/freetube-${{ steps.versionNumber.outputs.result }}.dmg # - name: Upload Mac arm64 .dmg Artifact -# uses: actions/upload-artifact@v3 +# uses: actions/upload-artifact@v4 # if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64') # with: # name: freetube-${{ steps.versionNumber.outputs.result }}-mac-arm64.dmg # path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64.dmg - name: Upload Mac x64 .zip Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-mac-x64.zip path: build/freetube-${{ steps.versionNumber.outputs.result }}-mac.zip - name: Upload Mac x64 .7z Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64') with: name: freetube-${{ steps.versionNumber.outputs.result }}-mac-x64.7z path: build/freetube-${{ steps.versionNumber.outputs.result }}-mac.7z # - name: Upload Mac arm64 .zip Artifact -# uses: actions/upload-artifact@v3 +# uses: actions/upload-artifact@v4 # if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64') # with: # name: freetube-${{ steps.versionNumber.outputs.result }}-mac-arm64.zip diff --git a/.github/workflows/calibreapp-image-actions.yml b/.github/workflows/calibreapp-image-actions.yml index f94e1ac32..d336cad23 100644 --- a/.github/workflows/calibreapp-image-actions.yml +++ b/.github/workflows/calibreapp-image-actions.yml @@ -20,7 +20,7 @@ jobs: compressOnly: true - name: Create New Pull Request If Needed if: steps.calibre.outputs.markdown != '' - uses: peter-evans/create-pull-request@v5 + uses: peter-evans/create-pull-request@v6 with: title: Compressed Images Nightly branch-suffix: timestamp diff --git a/.github/workflows/label-issue.yml b/.github/workflows/label-issue.yml index 46eed6d43..24e42dc04 100644 --- a/.github/workflows/label-issue.yml +++ b/.github/workflows/label-issue.yml @@ -11,7 +11,7 @@ jobs: triage: runs-on: ubuntu-latest steps: - - uses: github/issue-labeler@v3.3 + - uses: github/issue-labeler@v3.4 with: configuration-path: .github/issue-labeler.yml enable-versioned-regex: 0 diff --git a/_icons/iconNordicLightSmall.png b/_icons/iconNordicLightSmall.png new file mode 100644 index 000000000..b5b83494c Binary files /dev/null and b/_icons/iconNordicLightSmall.png differ diff --git a/_icons/textNordicLightSmall.png b/_icons/textNordicLightSmall.png new file mode 100644 index 000000000..b23422a08 Binary files /dev/null and b/_icons/textNordicLightSmall.png differ diff --git a/_scripts/dev-runner.js b/_scripts/dev-runner.js index d030c8b81..0a4678040 100644 --- a/_scripts/dev-runner.js +++ b/_scripts/dev-runner.js @@ -1,6 +1,5 @@ process.env.NODE_ENV = 'development' -const open = require('open') const electron = require('electron') const webpack = require('webpack') const WebpackDevServer = require('webpack-dev-server') @@ -161,7 +160,8 @@ function startWeb (callback) { if (!web) { startRenderer(startMain) } else { - startWeb(({ port }) => { + startWeb(async ({ port }) => { + const open = (await import('open')).default open(`http://localhost:${port}`) }) } diff --git a/_scripts/webpack.renderer.config.js b/_scripts/webpack.renderer.config.js index 057be25f4..5cb371e8a 100644 --- a/_scripts/webpack.renderer.config.js +++ b/_scripts/webpack.renderer.config.js @@ -1,5 +1,5 @@ const path = require('path') -const { readFileSync } = require('fs') +const { readFileSync, readdirSync } = require('fs') const webpack = require('webpack') const HtmlWebpackPlugin = require('html-webpack-plugin') const VueLoaderPlugin = require('vue-loader/lib/plugin') @@ -11,6 +11,8 @@ const CopyWebpackPlugin = require('copy-webpack-plugin') const isDevMode = process.env.NODE_ENV === 'development' +const { version: swiperVersion } = JSON.parse(readFileSync(path.join(__dirname, '../node_modules/swiper/package.json'))) + const processLocalesPlugin = new ProcessLocalesPlugin({ compress: !isDevMode, inputDir: path.join(__dirname, '../static/locales'), @@ -117,7 +119,9 @@ const config = { new webpack.DefinePlugin({ 'process.env.IS_ELECTRON': true, 'process.env.IS_ELECTRON_MAIN': false, - 'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames) + 'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames), + 'process.env.GEOLOCATION_NAMES': JSON.stringify(readdirSync(path.join(__dirname, '..', 'static', 'geolocations')).map(filename => filename.replace('.json', ''))), + 'process.env.SWIPER_VERSION': `'${swiperVersion}'` }), new HtmlWebpackPlugin({ excludeChunks: ['processTaskWorker'], @@ -136,7 +140,7 @@ const config = { patterns: [ { from: path.join(__dirname, '../node_modules/swiper/modules/{a11y,navigation,pagination}-element.css').replaceAll('\\', '/'), - to: 'swiper.css', + to: `swiper-${swiperVersion}.css`, context: path.join(__dirname, '../node_modules/swiper/modules'), transformAll: (assets) => { return Buffer.concat(assets.map(asset => asset.data)) diff --git a/_scripts/webpack.web.config.js b/_scripts/webpack.web.config.js index 9dd0e20f1..5113f06a7 100644 --- a/_scripts/webpack.web.config.js +++ b/_scripts/webpack.web.config.js @@ -11,6 +11,8 @@ const ProcessLocalesPlugin = require('./ProcessLocalesPlugin') const isDevMode = process.env.NODE_ENV === 'development' +const { version: swiperVersion } = JSON.parse(fs.readFileSync(path.join(__dirname, '../node_modules/swiper/package.json'))) + const config = { name: 'web', mode: process.env.NODE_ENV, @@ -114,6 +116,7 @@ const config = { new webpack.DefinePlugin({ 'process.env.IS_ELECTRON': false, 'process.env.IS_ELECTRON_MAIN': false, + 'process.env.SWIPER_VERSION': `'${swiperVersion}'`, // video.js' vhs-utils supports both atob() in web browsers and Buffer in node // As the FreeTube web build only runs in web browsers, we can override their check for atob() here: https://github.com/videojs/vhs-utils/blob/main/src/decode-b64-to-uint8-array.js#L3 @@ -145,7 +148,7 @@ const config = { patterns: [ { from: path.join(__dirname, '../node_modules/swiper/modules/{a11y,navigation,pagination}-element.css').replaceAll('\\', '/'), - to: 'swiper.css', + to: `swiper-${swiperVersion}.css`, context: path.join(__dirname, '../node_modules/swiper/modules'), transformAll: (assets) => { return Buffer.concat(assets.map(asset => asset.data)) diff --git a/jsconfig.json b/jsconfig.json index 8f5ea8a22..6efa53c23 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -1,5 +1,8 @@ { "vueCompilerOptions": { "target": 2.7 + }, + "compilerOptions": { + "strictNullChecks": true } } diff --git a/package.json b/package.json index e0fe5fb09..52472b28b 100644 --- a/package.json +++ b/package.json @@ -62,10 +62,10 @@ "autolinker": "^4.0.0", "electron-context-menu": "^3.6.1", "lodash.debounce": "^4.0.8", - "marked": "^11.2.0", + "marked": "^12.0.0", "path-browserify": "^1.0.1", "process": "^0.11.10", - "swiper": "^11.0.5", + "swiper": "^11.0.7", "video.js": "7.21.5", "videojs-contrib-quality-levels": "^3.0.0", "videojs-http-source-selector": "^1.1.6", @@ -77,21 +77,21 @@ "vue-observe-visibility": "^1.0.0", "vue-router": "^3.6.5", "vuex": "^3.6.2", - "youtubei.js": "^8.2.0" + "youtubei.js": "^9.1.0" }, "devDependencies": { - "@babel/core": "^7.23.9", - "@babel/eslint-parser": "^7.23.9", + "@babel/core": "^7.24.0", + "@babel/eslint-parser": "^7.23.10", "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/preset-env": "^7.23.9", - "@double-great/stylelint-a11y": "^3.0.0", + "@babel/preset-env": "^7.24.0", + "@double-great/stylelint-a11y": "^3.0.2", "babel-loader": "^9.1.3", "copy-webpack-plugin": "^12.0.2", - "css-loader": "^6.9.1", + "css-loader": "^6.10.0", "css-minimizer-webpack-plugin": "^6.0.0", - "electron": "^28.2.0", - "electron-builder": "^24.9.1", - "eslint": "^8.56.0", + "electron": "^29.1.0", + "electron-builder": "^24.13.3", + "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-config-standard": "^17.1.0", "eslint-plugin-import": "^2.29.1", @@ -99,23 +99,23 @@ "eslint-plugin-n": "^16.6.2", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-unicorn": "^50.0.1", - "eslint-plugin-vue": "^9.20.1", + "eslint-plugin-unicorn": "^51.0.1", + "eslint-plugin-vue": "^9.22.0", "eslint-plugin-vuejs-accessibility": "^2.2.1", "eslint-plugin-yml": "^1.12.2", "html-webpack-plugin": "^5.6.0", "js-yaml": "^4.1.0", "json-minimizer-webpack-plugin": "^5.0.0", - "lefthook": "^1.6.1", - "mini-css-extract-plugin": "^2.7.7", + "lefthook": "^1.6.4", + "mini-css-extract-plugin": "^2.8.1", "npm-run-all": "^4.1.5", - "postcss": "^8.4.33", + "postcss": "^8.4.35", "postcss-scss": "^4.0.9", "prettier": "^2.8.8", "rimraf": "^5.0.5", - "sass": "^1.70.0", - "sass-loader": "^14.0.0", - "stylelint": "^16.2.0", + "sass": "^1.71.1", + "sass-loader": "^14.1.1", + "stylelint": "^16.2.1", "stylelint-config-sass-guidelines": "^11.0.0", "stylelint-config-standard": "^36.0.0", "stylelint-high-performance-animation": "^1.10.0", @@ -124,9 +124,9 @@ "vue-devtools": "^5.1.4", "vue-eslint-parser": "^9.4.2", "vue-loader": "^15.10.0", - "webpack": "^5.90.0", + "webpack": "^5.90.3", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^4.15.1", + "webpack-dev-server": "^5.0.2", "webpack-watch-external-files-plugin": "^3.0.0", "yaml-eslint-parser": "^1.2.2" } diff --git a/src/main/index.js b/src/main/index.js index 23b561cee..f9c8fd7a9 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -64,7 +64,9 @@ function runApp() { const path = urlParts[1] if (path) { - visible = ['/playlist', '/channel', '/watch'].some(p => path.startsWith(p)) + visible = ['/channel', '/watch'].some(p => path.startsWith(p)) || + // Only show copy link entry for non user playlists + (path.startsWith('/playlist') && !/playlistType=user/.test(path)) } } else { visible = true @@ -103,17 +105,17 @@ function runApp() { let url if (toYouTube) { - url = `https://youtu.be/${id}` + url = new URL(`https://youtu.be/${id}`) } else { - url = `https://redirect.invidious.io/watch?v=${id}` + url = new URL(`https://redirect.invidious.io/watch?v=${id}`) } if (query) { const params = new URLSearchParams(query) - const newParams = new URLSearchParams() + const newParams = new URLSearchParams(url.search) let hasParams = false - if (params.has('playlistId')) { + if (params.has('playlistId') && params.get('playlistType') !== 'user') { newParams.set('list', params.get('playlistId')) hasParams = true } @@ -124,11 +126,11 @@ function runApp() { } if (hasParams) { - url += '?' + newParams.toString() + url.search = newParams.toString() } } - return url + return url.toString() } } } @@ -493,6 +495,8 @@ function runApp() { return '#ffd1dc' case 'hot-pink': return '#de1c85' + case 'nordic': + return '#2b2f3a' case 'system': default: return nativeTheme.shouldUseDarkColors ? '#212121' : '#f1f1f1' diff --git a/src/renderer/components/data-settings/data-settings.js b/src/renderer/components/data-settings/data-settings.js index 4f036a9f8..fac608c4b 100644 --- a/src/renderer/components/data-settings/data-settings.js +++ b/src/renderer/components/data-settings/data-settings.js @@ -882,7 +882,23 @@ export default defineComponent({ showToast(`${message}: ${err}`) return } - const playlists = JSON.parse(data) + let playlists = null + + // for the sake of backwards compatibility, + // check if this is the old JSON array export (used until version 0.19.1), + // that didn't match the actual database format + const trimmedData = data.trim() + + if (trimmedData[0] === '[' && trimmedData[trimmedData.length - 1] === ']') { + playlists = JSON.parse(trimmedData) + } else { + // otherwise assume this is the correct database format, + // which is also what we export now (used in 0.20.0 and later versions) + data = data.split('\n') + data.pop() + + playlists = data.map(playlistJson => JSON.parse(playlistJson)) + } const requiredKeys = [ 'playlistName', @@ -1015,7 +1031,11 @@ export default defineComponent({ ] } - await this.promptAndWriteToFile(options, JSON.stringify(this.allPlaylists), 'All playlists has been successfully exported') + const playlistsDb = this.allPlaylists.map(playlist => { + return JSON.stringify(playlist) + }).join('\n') + '\n'// a trailing line is expected + + await this.promptAndWriteToFile(options, playlistsDb, 'All playlists has been successfully exported') }, exportPlaylistsForOlderVersionsSometimes: function () { @@ -1133,7 +1153,7 @@ export default defineComponent({ }) if (process.env.IS_ELECTRON && this.backendFallback && this.backendPreference === 'invidious') { - showToast(this.$t('Falling back to the local API')) + showToast(this.$t('Falling back to Local API')) resolve(this.getChannelInfoLocal(channelId)) } else { resolve([]) diff --git a/src/renderer/components/ft-age-restricted/ft-age-restricted.js b/src/renderer/components/ft-age-restricted/ft-age-restricted.js index 7e925441b..c9cd917bc 100644 --- a/src/renderer/components/ft-age-restricted/ft-age-restricted.js +++ b/src/renderer/components/ft-age-restricted/ft-age-restricted.js @@ -3,10 +3,14 @@ import { defineComponent } from 'vue' export default defineComponent({ name: 'FtAgeRestricted', props: { - contentTypeString: { - type: String, - required: true - } + isChannel: { + type: Boolean, + default: false, + }, + isVideo: { + type: Boolean, + default: false, + }, }, computed: { emoji: function () { @@ -15,8 +19,11 @@ export default defineComponent({ }, restrictedMessage: function () { - const contentType = this.$t('Age Restricted.Type.' + this.contentTypeString) - return this.$t('Age Restricted.This {videoOrPlaylist} is age restricted', { videoOrPlaylist: contentType }) + if (this.isChannel) { + return this.$t('Age Restricted.This channel is age restricted') + } + + return this.$t('Age Restricted.This video is age restricted:') } } }) diff --git a/src/renderer/components/ft-community-post/ft-community-post.js b/src/renderer/components/ft-community-post/ft-community-post.js index 350eccc10..6be036209 100644 --- a/src/renderer/components/ft-community-post/ft-community-post.js +++ b/src/renderer/components/ft-community-post/ft-community-post.js @@ -40,7 +40,6 @@ export default defineComponent({ voteCount: '', postContent: '', commentCount: '', - isLoading: true, author: '', authorId: '', } @@ -73,7 +72,7 @@ export default defineComponent({ injectStylesUrls: [ // This file is created with the copy webpack plugin in the web and renderer webpack configs. // If you add more modules, please remember to add their CSS files to the list in webpack config files. - createWebURL('/swiper.css') + createWebURL(`/swiper-${process.env.SWIPER_VERSION}.css`) ], a11y: true, @@ -132,7 +131,6 @@ export default defineComponent({ this.type = (this.data.postContent !== null && this.data.postContent !== undefined) ? this.data.postContent.type : 'text' this.author = this.data.author this.authorId = this.data.authorId - this.isLoading = false }, getBestQualityImage(imageArray) { diff --git a/src/renderer/components/ft-community-post/ft-community-post.vue b/src/renderer/components/ft-community-post/ft-community-post.vue index 053bd4c61..f65e379e4 100644 --- a/src/renderer/components/ft-community-post/ft-community-post.vue +++ b/src/renderer/components/ft-community-post/ft-community-post.vue @@ -1,6 +1,5 @@