diff --git a/.babelrc b/.babelrc index f60bd75e8..abf4798b2 100644 --- a/.babelrc +++ b/.babelrc @@ -4,8 +4,8 @@ "@babel/env", { "targets": { - "chrome": "96", - "node": 16 + "chrome": "106", + "node": "16.16.0" } } ] diff --git a/.eslintrc.js b/.eslintrc.js index 14c73fcdc..d1af5515a 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,12 +32,14 @@ module.exports = { plugins: ['vue'], rules: { - 'space-before-function-paren': 0, + 'space-before-function-paren': 'off', 'comma-dangle': ['error', 'never'], 'vue/no-v-html': 'off', - 'no-console': 0, - 'no-unused-vars': 1, - 'no-undef': 1, - 'vue/no-template-key': 1 + 'no-console': ['error', { allow: ['warn', 'error'] }], + 'no-unused-vars': 'warn', + 'no-undef': 'warn', + 'vue/no-template-key': 'warn', + 'vue/no-useless-template-attributes': 'off', + 'vue/multi-word-component-names': 'off' } } diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 464ec55de..6daae4e51 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -15,7 +15,7 @@ body: options: - label: I have encountered this bug in the [latest release of FreeTube](https://github.com/FreeTubeApp/FreeTube/releases). required: true - - label: I have searched the [issue tracker](https://github.com/FreeTubeApp/FreeTube/issues) for a bug report that matches the one I want to file, without success. + - label: I have searched the [issue tracker](https://github.com/FreeTubeApp/FreeTube/issues) for open and closed issues that are similar to the bug report I want to file, without success. required: true - label: I have searched the [documentation](https://docs.freetubeapp.io/) for information that matches the description of the bug I want to file, without success. required: true @@ -85,10 +85,12 @@ body: - .dmg - .exe - Flathub + - MPR - .pacman - Portable - PortableApps - .rpm + - Scoop - winget - .zip - other diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index c010ec761..868b9ef1d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -13,7 +13,7 @@ body: label: Guidelines description: Please ensure you've completed all of the following. options: - - label: I have searched the [issue tracker](https://github.com/FreeTubeApp/FreeTube/issues) for a feature request that matches the one I want to file, without success. + - label: I have searched the [issue tracker](https://github.com/FreeTubeApp/FreeTube/issues) for open and closed issues that are similar to the feature request I want to file, without success. required: true - label: I have searched the [documentation](https://docs.freetubeapp.io/) for information that matches the description of the feature request I want to file, without success. required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4b21f07a9..2b3779e6f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,34 +1,36 @@ ---- -Title ---- +# Title -**Important note** -We may remove your pull request if you do not use this provided PR template correctly. + + -**Pull Request Type** -Please select what type of pull request this is: +## Pull Request Type + - [ ] Bugfix - [ ] Feature Implementation - [ ] Documentation - [ ] Other -**Related issue** -Please link the issue your pull request is referring to. If this pull request fully resolves the relevant issue, put "closes" before the issue number. Example: "closes #123456". +## Related issue + + + -**Description** -Please write a clear and concise description of what the pull request does. +## Description + -**Screenshots (if appropriate)** -Please add before and after screenshots if there is a visible change. +## Screenshots + -**Testing (for code that is not small enough to be easily understandable)** -Has this pull request been tested? -Please describe shortly how you tested it and whether there are any ramifications remaining. +## Testing + + + -**Desktop (please complete the following information):** - - OS: [e.g. iOS] - - OS Version: [e.g. 22] - - FreeTube version: [e.g. 0.8] +## Desktop + +- **OS:** +- **OS Version:** +- **FreeTube version:** -**Additional context** -Add any other context about the problem here. +## Additional context + diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..396fc42b3 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,16 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "weekly" + labels: + - "PR: waiting for review" + - "PR: dependencies" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "PR: waiting for review" + - "PR: dependencies" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..dff087046 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,19 @@ +'PR: waiting for review': + - '*' + - '.babelrc' + - '.editorconfig' + - '.eslintignore' + - '.eslintrc.js' + - '.gitignore' + - '.prettierrc' + - '.whitesource' + - '.github/**/*' + - '.vscode/**/*' + - '_icons/**/*' + - '_scripts/**/*' + - 'src/**/*' + - 'static/**/*' + +'PR: dependencies': + - 'yarn.lock' + - 'package.json' diff --git a/.github/workflows/autoLabelIssue.yaml b/.github/workflows/autoLabelIssue.yaml index adf9a90c2..f5f14d54b 100644 --- a/.github/workflows/autoLabelIssue.yaml +++ b/.github/workflows/autoLabelIssue.yaml @@ -10,5 +10,95 @@ jobs: - uses: Naturalclar/issue-action@v2.0.2 with: body: "both" - parameters: '[ {"keywords": ["visual bug"], "labels": ["B: visual"]}, {"keywords": ["AUR", "Chocolatey", "PortableApps", "winget"], "labels": ["B: Unofficial Download"]}, {"keywords": ["keyboard control not working"], "labels": ["B: keyboard control"]}, {"keywords": ["text/string issue"], "labels": ["B: text/string"]}, {"keywords": ["content not loading"], "labels": ["B: content not loading"]}, {"keywords": ["accessibility issue"], "labels": ["B: accessibility"]}, {"keywords": ["usability issue"], "labels": ["B: usability"]}, {"keywords": ["causes crash"], "labels": ["B: crash"]}, {"keywords": ["feature stopped working"], "labels": ["B: feature stopped working"]}, {"keywords": ["inconsistent behavior"], "labels": ["B: inconsistent behavior"]}, {"keywords": ["data loss"], "labels": ["B: data loss"]}, {"keywords": ["race condition"], "labels": ["B: race condition"]}, {"keywords": ["API issue"], "labels": ["B: API issue"]}, {"keywords": ["only happens in developer mode"], "labels": ["B: developer mode"]}, {"keywords": ["improvement to existing feature"], "labels": ["E: improvement existing feature"]}, {"keywords": ["new optional setting"], "labels": ["E: new optional setting"]}, {"keywords": ["visual improvement"], "labels": ["E: visual improvement"]}, {"keywords": ["display more information to user"], "labels": ["E: display more information"]}, {"keywords": ["ease of use improvement"], "labels": ["E: ease of use improvement"]}, {"keywords": ["support for external software"], "labels": ["E: support external software"]}, {"keywords": ["new feature"], "labels": ["E: new feature"]}, {"keywords": ["new keyboard shortcut"], "labels": ["E: keyboard shortcut"]}]' + parameters: >- + [ + { + "keywords": ["visual bug"], + "labels": ["B: visual"] + }, + { + "keywords": ["AUR", "Chocolatey", "PortableApps", "winget", "Scoop", "MPR"], + "labels": ["B: Unofficial Download"] + }, + { + "keywords": ["keyboard control not working"], + "labels": ["B: keyboard control"] + }, + { + "keywords": ["text/string issue"], + "labels": ["B: text/string"] + }, + { + "keywords": ["content not loading"], + "labels": ["B: content not loading"] + }, + { + "keywords": ["accessibility issue"], + "labels": ["B: accessibility"] + }, + { + "keywords": ["usability issue"], + "labels": ["B: usability"] + }, + { + "keywords": ["causes crash"], + "labels": ["B: crash"] + }, + { + "keywords": ["feature stopped working"], + "labels": ["B: feature stopped working"] + }, + { + "keywords": ["inconsistent behavior"], + "labels": ["B: inconsistent behavior"] + }, + { + "keywords": ["data loss"], + "labels": ["B: data loss"] + }, + { + "keywords": ["race condition"], + "labels": ["B: race condition"] + }, + { + "keywords": ["API issue"], + "labels": ["B: API issue"] + }, + { + "keywords": ["only happens in developer mode"], + "labels": ["B: developer mode"] + }, + { + "keywords": ["improvement to existing feature"], + "labels": ["E: improvement existing feature"] + }, + { + "keywords": ["new optional setting"], + "labels": ["E: new optional setting"] + }, + { + "keywords": ["visual improvement"], + "labels": ["E: visual improvement"] + }, + { + "keywords": ["display more information to user"], + "labels": ["E: display more information"] + }, + { + "keywords": ["ease of use improvement"], + "labels": ["E: ease of use improvement"] + }, + { + "keywords": ["support for external software"], + "labels": ["E: support external software"] + }, + { + "keywords": ["new feature"], + "labels": ["E: new feature"] + }, + { + "keywords": ["new keyboard shortcut"], + "labels": ["E: keyboard shortcut"] + } + ] github-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 77b99a85f..f184051d8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -6,37 +6,56 @@ name: Build on: push: branches: [ master, development, '**-RC' ] + workflow_dispatch: jobs: build: strategy: matrix: node-version: [16.x] - runtime: [ linux-x64, linux-arm64, win-x64, osx-x64 ] + runtime: + - linux-x64 + - linux-armv7l + - linux-arm64 + - win-x64 + - win-arm64 + - osx-x64 + # `osx-arm64` disabled due to "macOS gatekeeper" + # See details in https://github.com/FreeTubeApp/FreeTube/pull/2113 + # - osx-arm64 include: - runtime: linux-x64 os: ubuntu-latest + - runtime: linux-armv7l + os: ubuntu-latest + - runtime: linux-arm64 os: ubuntu-latest - runtime: osx-x64 os: macOS-latest +# - runtime: osx-arm64 +# os: macOS-latest + - runtime: win-x64 os: windows-latest + - runtime: win-arm64 + os: windows-latest + runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} cache: "yarn" - - run: npm run ci - - run: npm run lint + - run: yarn run ci + - run: yarn run lint - name: Get Version Number uses: nyaayaya/package-version@v1 with: @@ -45,7 +64,7 @@ jobs: - name: Set Version Number Variable id: versionNumber - uses: actions/github-script@v3 + uses: actions/github-script@v6 env: IS_DEV: ${{ contains(github.ref, 'development') }} IS_RC: ${{ contains(github.ref, 'RC') }} @@ -65,7 +84,7 @@ jobs: # script: if ${{ env.IS_DEV }} then echo "::set-output name=VERSION_NUMBER::${{ env.VERSION_NUMBER_NIGHTLY }}" else echo "::set-output name=VERSION_NUMBER::${{ env.VERSION_NUMBER }}" fi - name: Update package.json version - uses: jossef/action-set-json-field@v1 + uses: jossef/action-set-json-field@v2 with: file: package.json field: version @@ -73,125 +92,243 @@ jobs: - name: Install libarchive-tools - if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') + if: startsWith(matrix.os, 'ubuntu') run: sudo apt -y install libarchive-tools; echo "Version Number ${{ toJson(job) }} ${{ toJson(needs) }}" - name: Build x64 with Node.js ${{ matrix.node-version}} if: contains(matrix.runtime, 'x64') - run: npm run build --if-present + run: yarn run build + + - name: Build ARMv7l with Node.js ${{ matrix.node-version}} + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') + run: yarn run build:arm32 - name: Build ARM64 with Node.js ${{ matrix.node-version}} - if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') - run: npm run build:arm64 --if-present + if: contains(matrix.runtime, 'arm64') + run: yarn run build:arm64 - name: Upload Linux .zip x64 Artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 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 .zip ARM Artifact - uses: actions/upload-artifact@v2 + - name: Upload Linux .7z x64 Artifact + uses: actions/upload-artifact@v3 + 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 + 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 + 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 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 + 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@v2 + uses: actions/upload-artifact@v3 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 ARM Artifact - uses: actions/upload-artifact@v2 + - name: Upload .deb ARMv7l Artifact + uses: actions/upload-artifact@v3 + 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 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@v2 + uses: actions/upload-artifact@v3 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 ARM Artifact - uses: actions/upload-artifact@v2 + - name: Upload AppImage ARMv7l Artifact + uses: actions/upload-artifact@v3 + 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 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@v2 + uses: actions/upload-artifact@v3 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') with: name: freetube_${{ steps.versionNumber.outputs.result }}_amd64.rpm path: build/freetube-${{ steps.versionNumber.outputs.result }}.x86_64.rpm - - name: Upload .rpm ARM Artifact - uses: actions/upload-artifact@v2 + # rpm are not built for armv7l + + - name: Upload .rpm ARM64 Artifact + uses: actions/upload-artifact@v3 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@v2 + uses: actions/upload-artifact@v3 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 ARM Artifact - uses: actions/upload-artifact@v2 + - name: Upload Alpine .apk ARMv7l Artifact + uses: actions/upload-artifact@v3 + 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 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@v2 + uses: actions/upload-artifact@v3 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@v2 + # uses: actions/upload-artifact@v3 # 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 .exe Artifact - uses: actions/upload-artifact@v2 - if: startsWith(matrix.os, 'windows') - with: - name: freetube-${{ steps.versionNumber.outputs.result }}-win-x64-portable - path: build/freetube-${{ steps.versionNumber.outputs.result }}-win.zip - - - name: Upload Windows .zip Artifact - uses: actions/upload-artifact@v2 - if: startsWith(matrix.os, 'windows') + - name: Upload Windows x64 .exe Artifact + uses: actions/upload-artifact@v3 + 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 Portable Artifact - uses: actions/upload-artifact@v2 - if: startsWith(matrix.os, 'windows') + - name: Upload Windows arm64 .exe Artifact + uses: actions/upload-artifact@v3 + 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 + 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 + 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 + 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 + 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 + 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 Mac .dmg Artifact - uses: actions/upload-artifact@v2 - if: startsWith(matrix.os, 'macos') + - name: Upload Windows arm64 Portable Artifact + uses: actions/upload-artifact@v3 + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') with: - name: freetube-${{ steps.versionNumber.outputs.result }}-mac.dmg + 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 + 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 +# 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 + 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 + 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 +# if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64') +# with: +# name: freetube-${{ steps.versionNumber.outputs.result }}-mac-arm64.zip +# path: build/freetube-${{ steps.versionNumber.outputs.result }}-arm64-mac.zip diff --git a/.github/workflows/calibreapp-image-actions.yml b/.github/workflows/calibreapp-image-actions.yml new file mode 100644 index 000000000..c3953aa32 --- /dev/null +++ b/.github/workflows/calibreapp-image-actions.yml @@ -0,0 +1,28 @@ +# Compress images on demand (workflow_dispatch), and at 12am every Sunday (schedule). +# Open a Pull Request if any images can be compressed. +name: Compress Images +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * 0' +jobs: + build: + name: calibreapp/image-actions + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + - name: Compress Images + id: calibre + uses: calibreapp/image-actions@main + with: + githubToken: ${{ secrets.GITHUB_TOKEN }} + compressOnly: true + - name: Create New Pull Request If Needed + if: steps.calibre.outputs.markdown != '' + uses: peter-evans/create-pull-request@v4 + with: + title: Compressed Images Nightly + branch-suffix: timestamp + commit-message: Compressed Images + body: ${{ steps.calibre.outputs.markdown }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 000000000..f7c01e4fa --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,63 @@ +name: "CodeQL" + +on: + push: + branches: [ "development" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "development" ] + schedule: + - cron: '36 3 * * 5' + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: [ 'javascript' ] + # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] + # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v2 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v2 + + # ℹī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + + # If the Autobuild fails above, remove it and uncomment the following three lines. + # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + + # - run: | + # echo "Run, Build Application using script" + # ./location_of_script_within_repo/buildscript.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v2 + with: + category: "/language:${{matrix.language}}" diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml new file mode 100644 index 000000000..c0f221025 --- /dev/null +++ b/.github/workflows/conflicts.yml @@ -0,0 +1,25 @@ +name: "Conflicts" +on: + # So that PRs touching the same files as the push are updated + push: + # So that the `dirtyLabel` is removed if conflicts are resolve + # We recommend `pull_request_target` so that github secrets are available. + # In `pull_request` we wouldn't be able to change labels of fork PRs + pull_request_target: + types: [synchronize] + workflow_run: + workflows: ['Dummy workflow for conflicts'] + types: [requested] + +jobs: + main: + runs-on: ubuntu-latest + steps: + - name: check if prs are dirty + uses: eps1lon/actions-label-merge-conflict@releases/2.x + with: + dirtyLabel: "PR: merge conflicts / rebase needed" + removeOnDirtyLabel: "PR: waiting for review" + repoToken: "${{ secrets.GITHUB_TOKEN }}" + commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request." + commentOnClean: "Conflicts have been resolved. A maintainer will review the pull request shortly." diff --git a/.github/workflows/dummy-conflicts.yml b/.github/workflows/dummy-conflicts.yml new file mode 100644 index 000000000..cc4ba4250 --- /dev/null +++ b/.github/workflows/dummy-conflicts.yml @@ -0,0 +1,9 @@ +name: Dummy workflow for conflicts +on: + pull_request_review: + types: [submitted] +jobs: + dummy: + runs-on: ubuntu-latest + steps: + - run: echo "this is a dummy workflow that triggers a workflow_run; it's necessary because otherwise the repo secrets will not be in scope for externally forked pull requests" diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml index ad6c44646..bc1b7ed4f 100644 --- a/.github/workflows/flatpak.yml +++ b/.github/workflows/flatpak.yml @@ -15,10 +15,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: repository: flathub/io.freetubeapp.FreeTube - token: ${{ secrets.PUSH_TOKEN }} + token: ${{ secrets.FLATHUB_TOKEN }} - name: GitHub API exec action uses: moustacheful/github-api-exec-action@v0 id: api_results @@ -36,7 +36,7 @@ jobs: - name: Install xmlstarlet run: sudo apt -y install xmlstarlet - name: Create Version Variable - uses: bluwy/substitute-string-action@v1 + uses: bluwy/substitute-string-action@v2 id: sub with: _input-text: ${{ fromJson(steps.api_results.outputs.result).tag_name }} @@ -77,25 +77,13 @@ jobs: date +"%Y-%m-%d" >> $GITHUB_ENV echo 'EOF' >> $GITHUB_ENV - name: Update x64 File Location in yml File - uses: mikefarah/yq@4.0.0-beta1 - with: - # The Command which should be run - cmd: yq w -i io.freetubeapp.FreeTube.yml modules[0].sources[0].url 'https://github.com/FreeTubeApp/FreeTube/releases/download/v${{ steps.sub.outputs.result }}-beta/freetube-${{ steps.sub.outputs.result }}-linux-portable-x64.zip' + run: yq w -i io.freetubeapp.FreeTube.yml modules[0].sources[0].url 'https://github.com/FreeTubeApp/FreeTube/releases/download/v${{ steps.sub.outputs.result }}-beta/freetube-${{ steps.sub.outputs.result }}-linux-portable-x64.zip' - name: Update x64 Hash in yml File - uses: mikefarah/yq@4.0.0-beta1 - with: - # The Command which should be run - cmd: yq w -i io.freetubeapp.FreeTube.yml modules[0].sources[0].sha256 ${{ env.HASH_X64 }} + run: yq w -i io.freetubeapp.FreeTube.yml modules[0].sources[0].sha256 ${{ env.HASH_X64 }} - name: Update ARM File Location in yml File - uses: mikefarah/yq@4.0.0-beta1 - with: - # The Command which should be run - cmd: yq w -i io.freetubeapp.FreeTube.yml modules[0].sources[1].url 'https://github.com/FreeTubeApp/FreeTube/releases/download/v${{ steps.sub.outputs.result }}-beta/freetube-${{ steps.sub.outputs.result }}-linux-portable-arm64.zip' + run: yq w -i io.freetubeapp.FreeTube.yml modules[0].sources[1].url 'https://github.com/FreeTubeApp/FreeTube/releases/download/v${{ steps.sub.outputs.result }}-beta/freetube-${{ steps.sub.outputs.result }}-linux-portable-arm64.zip' - name: Update ARM Hash in yml File - uses: mikefarah/yq@4.0.0-beta1 - with: - # The Command which should be run - cmd: yq w -i io.freetubeapp.FreeTube.yml modules[0].sources[1].sha256 ${{ env.HASH_ARM64 }} + run: yq w -i io.freetubeapp.FreeTube.yml modules[0].sources[1].sha256 ${{ env.HASH_ARM64 }} - name: Add Patch Notes to XML File run: xmlstarlet ed -L -i /application/releases/release[1] -t elem -n releaseTMP -v "" -i //releaseTMP -t attr -n version -v "${{ steps.sub.outputs.result }} Beta" -i //releaseTMP -t attr -n date -v "${{ env.CURRENT_DATE }}" -s //releaseTMP -t elem -n url -v "" -s //releaseTMP/url -t text -n "" -v "https://github.com/FreeTubeApp/FreeTube/releases/tag/v${{ steps.sub.outputs.result }}-beta" -r //releaseTMP -v "release" io.freetubeapp.FreeTube.metainfo.xml - name: Remove Release Files @@ -108,7 +96,7 @@ jobs: # Optional but recommended # Defaults to "Apply automatic changes" commit_message: Update files for v${{ steps.sub.outputs.result }} - token: ${{ secrets.PUSH_TOKEN }} + token: ${{ secrets.FLATHUB_TOKEN }} # Optional options appended to `git-commit` # See https://git-scm.com/docs/git-commit for a list of available options @@ -118,7 +106,7 @@ jobs: skip_dirty_check: true - name: Create PR run: | - echo ${{ secrets.PUSH_TOKEN }} >> auth.txt + echo ${{ secrets.FLATHUB_TOKEN }} >> auth.txt gh auth login --with-token < auth.txt rm auth.txt gh pr create --title "Release v${{ steps.sub.outputs.result }}" --body "This is an automated PR for the v${{ steps.sub.outputs.result }} release. This PR will be updated and merged once testing is complete." diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml new file mode 100644 index 000000000..492a3ab71 --- /dev/null +++ b/.github/workflows/label-pr.yml @@ -0,0 +1,15 @@ +name: "Pull Request Labeler" +on: + pull_request_target: + types: [opened, reopened] + +jobs: + triage: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@v4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 3b9015b9c..ce0a1101d 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -17,11 +17,11 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js 16.x - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: 16.x cache: "yarn" - - run: npm run ci - - run: npm run lint + - run: yarn run ci + - run: yarn run lint diff --git a/.github/workflows/no-response.yml b/.github/workflows/no-response.yml index f4a51d270..a0a8bf8fc 100644 --- a/.github/workflows/no-response.yml +++ b/.github/workflows/no-response.yml @@ -20,5 +20,5 @@ jobs: This issue has been automatically closed because there has been no response to our request for more information from the original author. With only the information that is currently in the issue, we don't have enough information to take action. Please reach out if you have or find the answers we need so that we can investigate further. - daysUntilClose: 21 + daysUntilClose: 14 responseRequiredLabel: "U: Waiting for Response from Author" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 962124ffd..7cc9d89ed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,31 +13,49 @@ jobs: strategy: matrix: node-version: [16.x] - runtime: [ linux-x64, linux-arm64, win-x64, osx-x64 ] + runtime: + - linux-x64 + - linux-armv7l + - linux-arm64 + - win-x64 + - win-arm64 + - osx-x64 + # `osx-arm64` disabled due to "macOS gatekeeper" + # See details in https://github.com/FreeTubeApp/FreeTube/pull/2113 + # - osx-arm64 include: - runtime: linux-x64 os: ubuntu-latest + - runtime: linux-armv7l + os: ubuntu-latest + - runtime: linux-arm64 os: ubuntu-latest - runtime: osx-x64 os: macOS-latest +# - runtime: osx-arm64 +# os: macOS-latest + - runtime: win-x64 os: windows-latest + - runtime: win-arm64 + os: windows-latest + runs-on: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} cache: "yarn" - - run: npm run ci - - run: npm run lint + - run: yarn run ci + - run: yarn run lint - name: Get Version Number uses: nyaayaya/package-version@v1 @@ -47,11 +65,15 @@ jobs: - name: Build x64 with Node.js ${{ matrix.node-version}} if: contains(matrix.runtime, 'x64') - run: npm run build --if-present + run: yarn run build + + - name: Build ARMv7l with Node.js ${{ matrix.node-version}} + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') + run: yarn run build:arm32 - name: Build ARM64 with Node.js ${{ matrix.node-version}} - if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') - run: npm run build:arm64 --if-present + if: contains(matrix.runtime, 'arm64') + run: yarn run build:arm64 - name: Upload AppImage x64 Release uses: actions/upload-release-asset@v1 @@ -75,7 +97,40 @@ jobs: asset_path: build/freetube-${{ env.PACKAGE_VERSION }}.zip asset_content_type: application/zip - - name: Upload Linux .zip ARM Release + - name: Upload Linux .7z x64 Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-linux-portable-x64.7z + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}.7z + asset_content_type: application/x-7z-compressed + + - name: Upload Linux .zip ARMv7l Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-linux-portable-armv7l.zip + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-armv7l.zip + asset_content_type: application/zip + + - name: Upload Linux .7z ARMv7l Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-linux-portable-armv7l.7z + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-armv7l.7z + asset_content_type: application/x-7z-compressed + + - name: Upload Linux .zip ARM64 Release uses: actions/upload-release-asset@v1 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') env: @@ -86,6 +141,17 @@ jobs: asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-arm64.zip asset_content_type: application/zip + - name: Upload Linux .7z ARM64 Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-linux-portable-arm64.7z + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-arm64.7z + asset_content_type: application/x-7z-compressed + - name: Upload Linux .deb x64 Release uses: actions/upload-release-asset@v1 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-x64') @@ -97,7 +163,18 @@ jobs: asset_path: build/freetube_${{ env.PACKAGE_VERSION }}_amd64.deb asset_content_type: application/vnd.debian.binary-package - - name: Upload Linux .deb ARM Release + - name: Upload Linux .deb ARMv7l Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-armv7l') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube_${{ env.PACKAGE_VERSION }}_armv7l.deb + asset_path: build/freetube_${{ env.PACKAGE_VERSION }}_armv7l.deb + asset_content_type: application/vnd.debian.binary-package + + - name: Upload Linux .deb ARM64 Release uses: actions/upload-release-asset@v1 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') env: @@ -119,7 +196,9 @@ jobs: asset_path: build/freetube-${{ env.PACKAGE_VERSION }}.x86_64.rpm asset_content_type: application/x-rpm - - name: Upload Linux .rpm ARM Release + # rpm are not built for armv7l + + - name: Upload Linux .rpm ARM64 Release uses: actions/upload-release-asset@v1 if: startsWith(matrix.os, 'ubuntu') && startsWith(matrix.runtime, 'linux-arm64') env: @@ -130,9 +209,9 @@ jobs: asset_path: build/freetube-${{ env.PACKAGE_VERSION }}.aarch64.rpm asset_content_type: application/x-rpm - - name: Upload Windows .exe Release + - name: Upload Windows x64 .exe Release uses: actions/upload-release-asset@v1 - if: startsWith(matrix.os, 'windows') + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64') env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -141,9 +220,20 @@ jobs: asset_path: build/freetube Setup ${{ env.PACKAGE_VERSION }}.exe asset_content_type: application/x-ms-dos-executable - - name: Upload Windows .zip Release + - name: Upload Windows arm64 .exe Release uses: actions/upload-release-asset@v1 - if: startsWith(matrix.os, 'windows') + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-setup-arm64.exe + asset_path: build/freetube Setup ${{ env.PACKAGE_VERSION }}.exe + asset_content_type: application/x-ms-dos-executable + + - name: Upload Windows x64 .zip Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64') env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -152,13 +242,113 @@ jobs: asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-win.zip asset_content_type: application/zip - - name: Upload Mac .dmg Release + - name: Upload Windows x64 .7z Release uses: actions/upload-release-asset@v1 - if: startsWith(matrix.os, 'macos') + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64') env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} - asset_name: freetube-${{ env.PACKAGE_VERSION }}-mac.dmg + asset_name: freetube-${{ env.PACKAGE_VERSION }}-win-x64-portable.7z + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-win.7z + asset_content_type: application/x-7z-compressed + + - name: Upload Windows arm64 .zip Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-win-arm64-portable.zip + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-arm64-win.zip + asset_content_type: application/zip + + - name: Upload Windows arm64 .7z Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-win-arm64-portable.7z + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-arm64-win.7z + asset_content_type: application/x-7z-compressed + + - name: Upload Windows x64 portable Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-x64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-win-x64-portable.exe + asset_path: build/FreeTube ${{ env.PACKAGE_VERSION }}.exe + asset_content_type: application/x-ms-dos-executable + + - name: Upload Windows arm64 portable Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'windows') && startsWith(matrix.runtime, 'win-arm64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-win-arm64-portable.exe + asset_path: build/FreeTube ${{ env.PACKAGE_VERSION }}.exe + asset_content_type: application/x-ms-dos-executable + + - name: Upload Mac x64 .dmg Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-mac-x64.dmg asset_path: build/freetube-${{ env.PACKAGE_VERSION }}.dmg asset_content_type: application/x-apple-diskimage + +# - name: Upload Mac arm64 .dmg Release +# uses: actions/upload-release-asset@v1 +# if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64') +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# with: +# upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} +# asset_name: freetube-${{ env.PACKAGE_VERSION }}-mac-arm64.dmg +# asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-arm64.dmg +# asset_content_type: application/x-apple-diskimage + + - name: Upload Mac x64 .zip Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-mac-x64.zip + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-mac.zip + asset_content_type: application/zip + + - name: Upload Mac x64 .7z Release + uses: actions/upload-release-asset@v1 + if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-x64') + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} + asset_name: freetube-${{ env.PACKAGE_VERSION }}-mac-x64.7z + asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-mac.7z + asset_content_type: application/x-7z-compressed + +# - name: Upload Mac arm64 .zip Release +# uses: actions/upload-release-asset@v1 +# if: startsWith(matrix.os, 'macos') && startsWith(matrix.runtime, 'osx-arm64') +# env: +# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# with: +# upload_url: https://uploads.github.com/repos/FreeTubeApp/FreeTube/releases/${{ secrets.UPLOAD_ID }}/assets{?name,label} +# asset_name: freetube-${{ env.PACKAGE_VERSION }}-mac-arm64.zip +# asset_path: build/freetube-${{ env.PACKAGE_VERSION }}-arm64-mac.zip +# asset_content_type: application/x-apple-diskimage + diff --git a/.github/workflows/report.yml b/.github/workflows/report.yml index e24f0b48e..fddf6630d 100644 --- a/.github/workflows/report.yml +++ b/.github/workflows/report.yml @@ -4,7 +4,7 @@ name: Project Board Automation on: issues: - types: [labeled, unlabeled, closed, deleted] + types: [closed, deleted, reopened, opened] jobs: assign-issues-to-projects: @@ -13,38 +13,58 @@ jobs: # For bug reports - name: New bug issue - uses: alex-page/github-project-automation-plus@v0.5.1 - if: github.event.action == 'labeled' && contains(github.event.issue.labels.*.name, 'bug') + uses: alex-page/github-project-automation-plus@v0.8.2 + if: contains(github.event.issue.labels.*.name, 'bug') && github.event.action == 'opened' with: project: Bug Reports column: To assign repo-token: ${{ secrets.PUSH_TOKEN }} action: update - - - name: Bug label removed - uses: alex-page/github-project-automation-plus@v0.5.1 - if: github.event.action == 'unlabeled' || github.event.action == 'closed' || github.event.action == 'deleted' + + - name: Bug issue closed + uses: alex-page/github-project-automation-plus@v0.8.2 + if: github.event.action == 'closed' || github.event.action == 'deleted' with: action: delete project: Bug Reports column: To assign repo-token: ${{ secrets.PUSH_TOKEN }} + + - name: Bug issue reopened + uses: alex-page/github-project-automation-plus@v0.8.2 + if: contains(github.event.issue.labels.*.name, 'bug') && github.event.action == 'reopened' + with: + project: Bug Reports + column: To assign + repo-token: ${{ secrets.PUSH_TOKEN }} + action: update # For feature requests - name: New feature issue - uses: alex-page/github-project-automation-plus@v0.5.1 - if: github.event.action == 'labeled' && contains(github.event.issue.labels.*.name, 'enhancement') + uses: alex-page/github-project-automation-plus@v0.8.2 + if: contains(github.event.issue.labels.*.name, 'enhancement') && github.event.action == 'opened' with: project: Feature Requests column: To assign repo-token: ${{ secrets.PUSH_TOKEN }} action: update - - name: Feature request label removed - uses: alex-page/github-project-automation-plus@v0.5.1 - if: github.event.action == 'unlabeled' || github.event.action == 'closed' || github.event.action == 'deleted' + - name: Feature request issue closed + uses: alex-page/github-project-automation-plus@v0.8.2 + if: github.event.action == 'closed' || github.event.action == 'deleted' with: action: delete project: Feature Requests column: To assign repo-token: ${{ secrets.PUSH_TOKEN }} + + - name: Feature request issue reopened + uses: alex-page/github-project-automation-plus@v0.8.2 + if: contains(github.event.issue.labels.*.name, 'enhancement') && github.event.action == 'reopened' + with: + project: Feature Requests + column: To assign + repo-token: ${{ secrets.PUSH_TOKEN }} + action: update + + diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000..02a937fe3 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,21 @@ +name: 'Close stale issues and PRs' +on: + schedule: + - cron: '30 1 * * *' + +jobs: + stale: + runs-on: ubuntu-latest + steps: + - uses: actions/stale@v6 + with: + stale-issue-message: 'This issue is stale because it has been open 28 days with no activity. Remove stale label or comment or this will be closed in 7 days.' + stale-pr-message: 'This PR is stale because it has been open 28 days with no activity. Remove stale label or comment or this will be closed in 14 days.' + close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.' + close-pr-message: 'This PR was closed because it has been stalled for 14 days with no activity.' + days-before-issue-stale: 28 + days-before-pr-stale: 28 + days-before-issue-close: 7 + days-before-pr-close: 14 + stale-issue-label: 'U: stale' + stale-pr-label: 'PR: stale' diff --git a/README.md b/README.md index a7acefd3e..9b03d688e 100644 --- a/README.md +++ b/README.md @@ -6,79 +6,86 @@ FreeTube is an open source desktop YouTube player built with privacy in mind. Use YouTube without advertisements and prevent Google from tracking you with their cookies and JavaScript. Available for Windows, Mac & Linux thanks to Electron. -Please note that FreeTube is currently in Beta. While it should work well for -most users, there are still bugs and missing features that need to be -addressed. +

Download FreeTube

-[Download FreeTube](https://github.com/FreeTubeApp/FreeTube/releases) +
+

ScreenshotsHow does it work?FeaturesDownload LinksContributingLocalizationContactDonateLicense

+

WebsiteBlogDocumentationFAQDiscussions

+
-### Browser Extension +Please note that FreeTube is currently in Beta. While it should work well for most users, there are still bugs and missing features that need to be addressed. If you have an idea or if you found a bug, please submit a [GitHub issue](https://github.com/FreeTubeApp/FreeTube/issues/new/choose) so that +we can track it. Please search [the existing issues](https://github.com/FreeTubeApp/FreeTube/issues) before submitting to +prevent duplicates! -FreeTube is supported by the [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect) and [LibRedirect](https://github.com/libredirect/libredirect) extension, which will allow you to open YouTube links into FreeTube. You must enable the option within the advanced settings for it to work. - -Download Privacy Redirect for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/privacy-redirect/) or [Google Chrome](https://chrome.google.com/webstore/detail/privacy-redirect/pmcmeagblkinmogikoikkdjiligflglb). - -Download LibRedirect for [Firefox](https://addons.mozilla.org/firefox/addon/libredirect/) or [Google Chrome](https://github.com/libredirect/libredirect/blob/master/chromium.md). - -Disclaimer: Learn more about why a browser extension is bad for your [privacy](https://www.privacyguides.org/browsers/#extensions). - -If you have issues with the extension working with FreeTube, please create an issue in this repository instead of the extension repository. +## Screenshots + ## How does it work? FreeTube uses a built in extractor to grab and serve data / videos. The [Invidious API](https://github.com/iv-org/invidious) can also optionally be used. FreeTube does not use any official APIs to obtain data. While YouTube can still see your video requests, it can no longer track you using cookies or JavaScript. Your subscriptions and history are stored locally on your computer and never sent out. Using a VPN or Tor is highly recommended to hide your IP while using FreeTube. -Go to [FreeTube's Documentation](https://docs.freetubeapp.io/) if you'd like to know more about how to operate FreeTube and its features. - -## Screenshots - - ## Features * Watch videos without ads * Use YouTube without Google tracking you using cookies and JavaScript * Two extractor APIs to choose from (Built in or Invidious) * Subscribe to channels without an account -* Local subscriptions, history, and saved videos +* Connect to an externally setup proxy such as Tor +* View and search your local subscriptions, history, and saved videos * Organize your subscriptions into "Profiles" to create a more focused feed * Export & import subscriptions +* Youtube Trending +* Youtube Chapters +* Most popular videos page based on the set Invidious instance +* SponsorBlock * Open videos from your browser directly into FreeTube (with extension) -* Mini Player +* Watch videos using an external player * Full Theme support +* Make a screenshot of a video +* Multiple windows +* Mini Player (Picture-in-Picture) +* Keyboard shortcuts +* Option to show only family friendly content +* Show/hide functionality or elements within the app using the distraction free settings + +### Browser Extension +FreeTube is supported by the [Privacy Redirect](https://github.com/SimonBrazell/privacy-redirect) and [LibRedirect](https://github.com/libredirect/libredirect) extensions, which will allow you to open YouTube links into FreeTube. You must enable the option within the advanced settings of the extension for it to work. + +* Download Privacy Redirect for [Firefox](https://addons.mozilla.org/en-US/firefox/addon/privacy-redirect/) or [Google Chrome](https://chrome.google.com/webstore/detail/privacy-redirect/pmcmeagblkinmogikoikkdjiligflglb). + +* Download LibRedirect for [Firefox](https://addons.mozilla.org/firefox/addon/libredirect/) or [Google Chrome](https://github.com/libredirect/libredirect/blob/master/chromium.md). + +If you have issues with the extension working with FreeTube, please create an issue in this repository instead of the extension repository. This extension does not work on Linux portable builds! ## Download Links - ### Official Downloads +* [GitHub Releases](https://github.com/FreeTubeApp/FreeTube/releases) -[GitHub Releases](https://github.com/FreeTubeApp/FreeTube/releases) +* [FreeTube Website](https://freetubeapp.io/#download) -[FreeTube Website](https://freetubeapp.io/#download) - -Flatpak on Flathub: [Download](https://flathub.org/apps/details/io.freetubeapp.FreeTube) [Source](https://github.com/flathub/io.freetubeapp.FreeTube) - -### Unofficial Downloads - -These builds are maintained by the community. While they should be safe, download at your own risk. There may be issues with using these versus the official builds. Any issues specific with these builds should be sent to their respective maintainer. - -Arch User Repository (AUR): [Download](https://aur.archlinux.org/packages/freetube-bin/) - -Chocolatey: [Download](https://chocolatey.org/packages/freetube/) - -PortableApps (Windows Only): [Download](https://github.com/rddim/FreeTubePortable/releases) [Source](https://github.com/rddim/FreeTubePortable) - -Windows Package Manager (winget): [Usage](https://docs.microsoft.com/en-us/windows/package-manager/winget/) - -### Automated Builds (Nightly / Weekly) +* Flatpak on Flathub: [Download](https://flathub.org/apps/details/io.freetubeapp.FreeTube) [Source](https://github.com/flathub/io.freetubeapp.FreeTube) +#### Automated Builds (Nightly / Weekly) Builds are automatically created from changes to our development branch via [GitHub Actions](https://github.com/FreeTubeApp/FreeTube/actions?query=workflow%3ABuild). The first build with a green check mark is the latest build. You will need to have a GitHub account to download these builds. -## Contributing -If you have an idea or if you found a bug, please submit a GitHub issue so that -we can track it. Please search the existing issues before submitting to -prevent duplicates. +### Unofficial Downloads +These builds are maintained by the community. While they should be safe, download at your own risk. There may be issues with using these versus the official builds. Any issues specific with these builds should be sent to their respective maintainer. +* Arch User Repository (AUR): [Download](https://aur.archlinux.org/packages/freetube-bin/) + +* Chocolatey: [Download](https://chocolatey.org/packages/freetube/) + +* makedeb Package Repository (MPR): [Download](https://mpr.makedeb.org/packages/freetube-bin) + +* PortableApps (Windows Only): [Download](https://github.com/rddim/FreeTubePortable/releases) [Source](https://github.com/rddim/FreeTubePortable) + +* Scoop (Windows Only): [Usage](https://github.com/ScoopInstaller/Scoop) + +* Windows Package Manager (winget): [Usage](https://docs.microsoft.com/en-us/windows/package-manager/winget/) + +## Contributing If you like to get your hands dirty and want to contribute, we would love to have your help. Send a pull request and someone will review your code. Please follow the [Contribution @@ -89,7 +96,7 @@ Thank you very much to the [People and Projects](https://docs.freetubeapp.io/cre ## Localization -Translation status +Translation status We are actively looking for translations! We use [Weblate](https://hosted.weblate.org/engage/free-tube/) to make it easy for translators to get involved. Click on the badge above to learn how to get involved. @@ -97,20 +104,18 @@ We are actively looking for translations! We use [Weblate](https://hosted.webla For the Linux Flatpak, the desktop entry comment string can be translated at our [Flatpak repository](https://github.com/flathub/io.freetubeapp.FreeTube/blob/master/io.freetubeapp.FreeTube.desktop). ## Contact - -If you ever have any questions, feel free to make an issue here on GitHub. Alternatively, you can email me at FreeTubeApp@protonmail.com or you can join our [Matrix Community](https://matrix.to/#/+freetube:matrix.org). Don't forget to check out the [rules](https://docs.freetubeapp.io/community/matrix/) before joining. - -You can also stay up to date by reading the [FreeTube Blog](https://write.as/freetube/). [View the welcome blog](https://write.as/freetube/welcome-to-freetube-blogs). +If you ever have any questions, feel free to ask it on our [Discussions](https://github.com/FreeTubeApp/FreeTube/discussions) page. Alternatively, you can email us at FreeTubeApp@protonmail.com or you can join our [Matrix Community](https://matrix.to/#/+freetube:matrix.org). Don't forget to check out the [rules](https://docs.freetubeapp.io/community/matrix/) before joining. ## Donate +If you enjoy using FreeTube, you're welcome to leave a donation using the following methods. -[FreeTube on Liberapay](https://liberapay.com/FreeTube) +* [FreeTube on Liberapay](https://liberapay.com/FreeTube) -Bitcoin Address: 1Lih7Ho5gnxb1CwPD4o59ss78pwo2T91eS +* Bitcoin Address: `1Lih7Ho5gnxb1CwPD4o59ss78pwo2T91eS` -Monero Address: 48WyAPdjwc6VokeXACxSZCFeKEXBiYPV6GjfvBsfg4CrUJ95LLCQSfpM9pvNKy5GE5H4hNaw99P8RZyzmaU9kb1pD7kzhCB +* Monero Address: `48WyAPdjwc6VokeXACxSZCFeKEXBiYPV6GjfvBsfg4CrUJ95LLCQSfpM9pvNKy5GE5H4hNaw99P8RZyzmaU9kb1pD7kzhCB` -If you enjoy using FreeTube, you're welcome to leave a donation using the following methods. While your donations are much appreciated, only donate if you really want to. Donations are used for keeping the website up and running and eventual code signing costs. +While your donations are much appreciated, only donate if you really want to. Donations are used for keeping the website up and running and eventual code signing costs. ## License [![GNU AGPLv3 Image](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.html) diff --git a/_icons/.icon-set/iconColor_256.png b/_icons/.icon-set/iconColor_256.png index 1ea2028e6..7818894de 100644 Binary files a/_icons/.icon-set/iconColor_256.png and b/_icons/.icon-set/iconColor_256.png differ diff --git a/_icons/.icon-set/icon_128x128.png b/_icons/.icon-set/icon_128x128.png index 324ca1520..ac8f23332 100644 Binary files a/_icons/.icon-set/icon_128x128.png and b/_icons/.icon-set/icon_128x128.png differ diff --git a/_icons/.icon-set/icon_16x16.png b/_icons/.icon-set/icon_16x16.png index 2faf48e60..9c6ea12d0 100644 Binary files a/_icons/.icon-set/icon_16x16.png and b/_icons/.icon-set/icon_16x16.png differ diff --git a/_icons/.icon-set/icon_32x32.png b/_icons/.icon-set/icon_32x32.png index 4240b9750..0cc282795 100644 Binary files a/_icons/.icon-set/icon_32x32.png and b/_icons/.icon-set/icon_32x32.png differ diff --git a/_icons/.icon-set/icon_48x48.png b/_icons/.icon-set/icon_48x48.png index 402e87156..08a7db092 100644 Binary files a/_icons/.icon-set/icon_48x48.png and b/_icons/.icon-set/icon_48x48.png differ diff --git a/_icons/.icon-set/icon_64x64.png b/_icons/.icon-set/icon_64x64.png index 80b3724d2..43b0e7699 100644 Binary files a/_icons/.icon-set/icon_64x64.png and b/_icons/.icon-set/icon_64x64.png differ diff --git a/_icons/256x256.png b/_icons/256x256.png index 5b40c707e..191266143 100644 Binary files a/_icons/256x256.png and b/_icons/256x256.png differ diff --git a/_icons/iconBlackSmall.png b/_icons/iconBlackSmall.png index ef5c46018..04528fd49 100644 Binary files a/_icons/iconBlackSmall.png and b/_icons/iconBlackSmall.png differ diff --git a/_icons/iconCatppuccinMochaDarkSmall.png b/_icons/iconCatppuccinMochaDarkSmall.png index bfc93ad56..c963e8a0e 100644 Binary files a/_icons/iconCatppuccinMochaDarkSmall.png and b/_icons/iconCatppuccinMochaDarkSmall.png differ diff --git a/_icons/iconCatppuccinMochaLightSmall.png b/_icons/iconCatppuccinMochaLightSmall.png index 021f62670..618b08e29 100644 Binary files a/_icons/iconCatppuccinMochaLightSmall.png and b/_icons/iconCatppuccinMochaLightSmall.png differ diff --git a/_icons/iconColor.png b/_icons/iconColor.png index 5b40c707e..191266143 100644 Binary files a/_icons/iconColor.png and b/_icons/iconColor.png differ diff --git a/_icons/iconColorSmall.png b/_icons/iconColorSmall.png index c9fb08621..fd0060151 100644 Binary files a/_icons/iconColorSmall.png and b/_icons/iconColorSmall.png differ diff --git a/_icons/iconDraculaDarkSmall.png b/_icons/iconDraculaDarkSmall.png index 3f2a93583..5b515c649 100644 Binary files a/_icons/iconDraculaDarkSmall.png and b/_icons/iconDraculaDarkSmall.png differ diff --git a/_icons/iconDraculaLightSmall.png b/_icons/iconDraculaLightSmall.png index 3f34041d5..e497925fb 100644 Binary files a/_icons/iconDraculaLightSmall.png and b/_icons/iconDraculaLightSmall.png differ diff --git a/_icons/logoColor.png b/_icons/logoColor.png index 4766f8cfa..9851c8f93 100644 Binary files a/_icons/logoColor.png and b/_icons/logoColor.png differ diff --git a/_icons/textCatppuccinMochaDarkSmall.png b/_icons/textCatppuccinMochaDarkSmall.png index e2fba035e..c5b70b215 100644 Binary files a/_icons/textCatppuccinMochaDarkSmall.png and b/_icons/textCatppuccinMochaDarkSmall.png differ diff --git a/_icons/textCatppuccinMochaLightSmall.png b/_icons/textCatppuccinMochaLightSmall.png index 70e969010..8a7bd5bc5 100644 Binary files a/_icons/textCatppuccinMochaLightSmall.png and b/_icons/textCatppuccinMochaLightSmall.png differ diff --git a/_icons/textColor.png b/_icons/textColor.png index 8552c1988..bdc83759e 100644 Binary files a/_icons/textColor.png and b/_icons/textColor.png differ diff --git a/_icons/textColorSmall.png b/_icons/textColorSmall.png index 705ab0e3e..7a2196aff 100644 Binary files a/_icons/textColorSmall.png and b/_icons/textColorSmall.png differ diff --git a/_icons/textDraculaDarkSmall.png b/_icons/textDraculaDarkSmall.png index 3ca93c5b7..ae2329595 100644 Binary files a/_icons/textDraculaDarkSmall.png and b/_icons/textDraculaDarkSmall.png differ diff --git a/_icons/textDraculaLightSmall.png b/_icons/textDraculaLightSmall.png index 0ba1a3d8d..219397d61 100644 Binary files a/_icons/textDraculaLightSmall.png and b/_icons/textDraculaLightSmall.png differ diff --git a/_icons/textWhite.png b/_icons/textWhite.png index 0ba1a3d8d..219397d61 100644 Binary files a/_icons/textWhite.png and b/_icons/textWhite.png differ diff --git a/_scripts/ProcessLocalesPlugin.js b/_scripts/ProcessLocalesPlugin.js new file mode 100644 index 000000000..4d471cd21 --- /dev/null +++ b/_scripts/ProcessLocalesPlugin.js @@ -0,0 +1,94 @@ +const { existsSync, readFileSync } = require('fs') +const { brotliCompressSync, constants } = require('zlib') +const { load: loadYaml } = require('js-yaml') + +class ProcessLocalesPlugin { + constructor(options = {}) { + this.compress = !!options.compress + + if (typeof options.inputDir !== 'string') { + throw new Error('ProcessLocalesPlugin: no input directory `inputDir` specified.') + } else if (!existsSync(options.inputDir)) { + throw new Error('ProcessLocalesPlugin: the specified input directory does not exist.') + } + this.inputDir = options.inputDir + + if (typeof options.outputDir !== 'string') { + throw new Error('ProcessLocalesPlugin: no output directory `outputDir` specified.') + } + this.outputDir = options.outputDir + + this.localeNames = [] + + this.loadLocales() + } + + apply(compiler) { + compiler.hooks.thisCompilation.tap('ProcessLocalesPlugin', (compilation) => { + + const { RawSource } = compiler.webpack.sources; + + compilation.hooks.processAssets.tapPromise({ + name: 'process-locales-plugin', + stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL + }, + async (_assets) => { + const promises = [] + + for (const { locale, data } of this.locales) { + promises.push(new Promise((resolve) => { + if (Object.prototype.hasOwnProperty.call(data, 'Locale Name')) { + delete data['Locale Name'] + } + + let filename = `${this.outputDir}/${locale}.json` + let output = JSON.stringify(data) + + if (this.compress) { + filename += '.br' + output = this.compressLocale(output) + } + + compilation.emitAsset( + filename, + new RawSource(output), + { minimized: true } + ) + + resolve() + })) + } + + await Promise.all(promises) + }) + }) + } + + loadLocales() { + this.locales = [] + + const activeLocales = JSON.parse(readFileSync(`${this.inputDir}/activeLocales.json`)) + + for (const locale of activeLocales) { + const contents = readFileSync(`${this.inputDir}/${locale}.yaml`, 'utf-8') + const data = loadYaml(contents) + + this.localeNames.push(data['Locale Name'] ?? locale) + this.locales.push({ locale, data }) + } + } + + compressLocale(data) { + const buffer = Buffer.from(data, 'utf-8') + + return brotliCompressSync(buffer, { + params: { + [constants.BROTLI_PARAM_MODE]: constants.BROTLI_MODE_TEXT, + [constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY, + [constants.BROTLI_PARAM_SIZE_HINT]: buffer.byteLength + } + }) + } +} + +module.exports = ProcessLocalesPlugin diff --git a/_scripts/build.js b/_scripts/build.js index 6b762cc76..fea20bf8c 100644 --- a/_scripts/build.js +++ b/_scripts/build.js @@ -8,20 +8,23 @@ const args = process.argv let targets const platform = os.platform() -const cpus = os.cpus() if (platform === 'darwin') { let arch = Arch.x64 -// Macbook Air 2020 with M1 = 'Apple M1' - // Macbook Pro 2021 with M1 Pro = 'Apple M1 Pro' - if (cpus[0].model.startsWith('Apple')) { + if (args[2] === 'arm64') { arch = Arch.arm64 } - targets = Platform.MAC.createTarget(['dmg'], arch) + targets = Platform.MAC.createTarget(['DMG','zip', '7z'], arch) } else if (platform === 'win32') { - targets = Platform.WINDOWS.createTarget() + let arch = Arch.x64 + + if (args[2] === 'arm64') { + arch = Arch.arm64 + } + + targets = Platform.WINDOWS.createTarget(['nsis', 'zip', '7z', 'portable'], arch) } else if (platform === 'linux') { let arch = Arch.x64 @@ -33,7 +36,7 @@ if (platform === 'darwin') { arch = Arch.armv7l } - targets = Platform.LINUX.createTarget(['deb', 'zip', 'apk', 'rpm', 'AppImage', 'pacman'], arch) + targets = Platform.LINUX.createTarget(['deb', 'zip', '7z', 'apk', 'rpm', 'AppImage', 'pacman'], arch) } const config = { @@ -58,22 +61,14 @@ const config = { 'icon.svg', './dist/**/*', '!dist/web/*', - '!**/node_modules/**/.*', - '!**/node_modules/**/index.html', - '!**/{.github,Jenkinsfile}', - '!**/{CHANGES.md,CODE_OF_CONDUCT.md,CONTRIBUTING.md,CONTRIBUTION.md,DEVELOPMENT.md,docs,docs.md,docs.mli,examples,History.md,HISTORY.md,README.md,TODO.md,UPGRADE_GUIDE.md,UPGRADING.md}', - '!**/{commitlint.config.js,.editorconfig,.eslintignore,.eslintrc.{js,yml},.gitmodules,.huskyrc,.lintstagedrc,.nvmrc,.nycrc{,.json},.prettierrc{,.yaml},tslint.json}', - '!**/{.babelrc,bower.json,Gruntfile.js,Makefile,.npmrc.proregistry,rollup.config.js,.tm_properties,.tool-versions,tsconfig.json,webpack.config.js}', - '!**/*.{{,c,m}js,min,ts}.map', - '!**/*.d.ts', + '!node_modules/**/*', - // only exclude the src directory for specific packages - // as some of them have their dist code in there and we don't want to exclude those - '!**/node_modules/{@fortawesome/vue-fontawesome,agent-base,jquery,localforage,m3u8-parser,marked,mpd-parser,performance-now,video.js,vue,vue-i18n,vue-router}/src/*', - '!**/node_modules/**/{bin,man,scripts}/*', - '!**/node_modules/jquery/dist/jquery.slim*.js', - '!**/node_modules/video.js/dist/{alt/*,video.js}', - '!**/node_modules/@videojs/*/src' + // renderer + 'node_modules/{miniget,ytpl,ytsr}/**/*', + + '!**/README.md', + '!**/*.js.map', + '!**/*.d.ts', ], dmg: { contents: [ @@ -97,7 +92,7 @@ const config = { linux: { category: 'Network', icon: '_icons/icon.svg', - target: ['deb', 'zip', 'apk', 'rpm', 'AppImage', 'pacman'], + target: ['deb', 'zip', '7z', 'apk', 'rpm', 'AppImage', 'pacman'], }, // See the following issues for more information // https://github.com/jordansissel/fpm/issues/1503 @@ -121,7 +116,7 @@ const config = { mac: { category: 'public.app-category.utilities', icon: '_icons/iconMac.icns', - target: ['dmg', 'zip'], + target: ['dmg', 'zip', '7z'], type: 'distribution', extendInfo: { CFBundleURLTypes: [ @@ -134,7 +129,7 @@ const config = { }, win: { icon: '_icons/icon.ico', - target: ['nsis', 'zip', 'portable', 'squirrel'], + target: ['nsis', 'zip', '7z', 'portable'], }, nsis: { allowToChangeInstallationDirectory: true, diff --git a/_scripts/dev-runner.js b/_scripts/dev-runner.js index c48daa56b..24857459b 100644 --- a/_scripts/dev-runner.js +++ b/_scripts/dev-runner.js @@ -1,5 +1,6 @@ process.env.NODE_ENV = 'development' +const open = require('open') const electron = require('electron') const webpack = require('webpack') const WebpackDevServer = require('webpack-dev-server') @@ -10,13 +11,14 @@ const { spawn } = require('child_process') const mainConfig = require('./webpack.main.config') const rendererConfig = require('./webpack.renderer.config') +const webConfig = require('./webpack.web.config') const workersConfig = require('./webpack.workers.config') let electronProcess = null let manualRestart = null -const remoteDebugging = !!( - process.argv[2] && process.argv[2] === '--remote-debug' -) + +const remoteDebugging = process.argv.indexOf('--remote-debug') !== -1 +const web = process.argv.indexOf('--web') !== -1 if (remoteDebugging) { // disable dvtools open in electron @@ -51,10 +53,12 @@ async function restartElectron() { electronProcess = spawn(electron, [ path.join(__dirname, '../dist/main.js'), - // '--enable-logging', Enable to show logs from all electron processes + // '--enable-logging', // Enable to show logs from all electron processes remoteDebugging ? '--inspect=9222' : '', - remoteDebugging ? '--remote-debugging-port=9223' : '', - ]) + remoteDebugging ? '--remote-debugging-port=9223' : '' + ], + // { stdio: 'inherit' } // required for logs to actually appear in the stdout + ) electronProcess.on('exit', (code, _) => { if (code === relaunchExitCode) { @@ -87,7 +91,6 @@ function startMain() { manualRestart = true await restartElectron() - setTimeout(() => { manualRestart = false }, 2500) @@ -135,4 +138,38 @@ function startRenderer(callback) { }) } -startRenderer(startMain) +function startWeb (callback) { + const compiler = webpack(webConfig) + const { name } = compiler + + compiler.hooks.afterEmit.tap('afterEmit', () => { + console.log(`\nCompiled ${name} script!`) + console.log(`\nWatching file changes for ${name} script...`) + }) + + const server = new WebpackDevServer({ + static: { + directory: path.join(process.cwd(), 'dist/web/static'), + watch: { + ignored: [ + /(dashFiles|storyboards)\/*/, + '/**/.DS_Store', + ] + } + }, + port + }, compiler) + + server.startCallback(err => { + if (err) console.error(err) + + callback({ port: server.options.port }) + }) +} +if (!web) { + startRenderer(startMain) +} else { + startWeb(({ port }) => { + open(`http://localhost:${port}`) + }) +} diff --git a/_scripts/webpack.main.config.js b/_scripts/webpack.main.config.js index d7316fd74..c5561dcb1 100644 --- a/_scripts/webpack.main.config.js +++ b/_scripts/webpack.main.config.js @@ -1,16 +1,11 @@ const path = require('path') const webpack = require('webpack') const CopyWebpackPlugin = require('copy-webpack-plugin') +const JsonMinimizerPlugin = require('json-minimizer-webpack-plugin') -const { - dependencies, - devDependencies, - productName, -} = require('../package.json') +const { productName } = require('../package.json') -const externals = Object.keys(dependencies).concat(Object.keys(devDependencies)) const isDevMode = process.env.NODE_ENV === 'development' -const whiteListedModules = [] const config = { name: 'main', @@ -19,7 +14,6 @@ const config = { entry: { main: path.join(__dirname, '../src/main/index.js'), }, - externals: externals.filter(d => !whiteListedModules.includes(d)), module: { rules: [ { @@ -27,12 +21,17 @@ const config = { use: 'babel-loader', exclude: /node_modules/, }, - { - test: /\.node$/, - loader: 'node-loader', - }, ], }, + // webpack defaults to only optimising the production builds, so having this here is fine + optimization: { + minimizer: [ + '...', // extend webpack's list instead of overwriting it + new JsonMinimizerPlugin({ + exclude: /\/locales\/.*\.json/ + }) + ] + }, node: { __dirname: isDevMode, __filename: isDevMode, @@ -58,49 +57,19 @@ const config = { target: 'electron-main', } -if (isDevMode) { - config.plugins.push( - new webpack.DefinePlugin({ - __static: `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`, - }) - ) -} else { +if (!isDevMode) { config.plugins.push( new CopyWebpackPlugin({ patterns: [ - { - from: path.join(__dirname, '../static/pwabuilder-sw.js'), - to: path.join(__dirname, '../dist/web/pwabuilder-sw.js'), - }, { from: path.join(__dirname, '../static'), - to: path.join(__dirname, '../dist/web/static'), + to: path.join(__dirname, '../dist/static'), globOptions: { dot: true, - ignore: ['**/.*', '**/pwabuilder-sw.js', '**/dashFiles/**', '**/storyboards/**'], + ignore: ['**/.*', '**/locales/**', '**/pwabuilder-sw.js', '**/dashFiles/**', '**/storyboards/**'], }, }, - { - from: path.join(__dirname, '../_icons'), - to: path.join(__dirname, '../dist/_icons'), - globOptions: { - dot: true, - ignore: ['**/.*'], - }, - }, - { - from: path.join(__dirname, '../src/renderer/assets/img'), - to: path.join(__dirname, '../dist/images'), - globOptions: { - dot: true, - ignore: ['**/.*'], - }, - }, - ] - } - ), - new webpack.LoaderOptionsPlugin({ - minimize: true, + ] }) ) } diff --git a/_scripts/webpack.renderer.config.js b/_scripts/webpack.renderer.config.js index 4f73ce068..f2a07d731 100644 --- a/_scripts/webpack.renderer.config.js +++ b/_scripts/webpack.renderer.config.js @@ -2,18 +2,13 @@ const path = require('path') const webpack = require('webpack') const HtmlWebpackPlugin = require('html-webpack-plugin') const VueLoaderPlugin = require('vue-loader/lib/plugin') -const CopyWebpackPlugin = require('copy-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') +const ProcessLocalesPlugin = require('./ProcessLocalesPlugin') -const { - dependencies, - devDependencies, - productName, -} = require('../package.json') +const { productName } = require('../package.json') -const externals = Object.keys(dependencies).concat(Object.keys(devDependencies)) const isDevMode = process.env.NODE_ENV === 'development' -const whiteListedModules = ['vue'] const config = { name: 'renderer', @@ -33,7 +28,10 @@ const config = { path: path.join(__dirname, '../dist'), filename: '[name].js', }, - externals: externals.filter(d => !whiteListedModules.includes(d)), + // webpack spits out errors while inlining ytpl and ytsr as + // they dynamically import their package.json file to extract the bug report URL + // the error: "Critical dependency: the request of a dependency is an expression" + externals: ['ytpl', 'ytsr'], module: { rules: [ { @@ -41,10 +39,6 @@ const config = { use: 'babel-loader', exclude: /node_modules/, }, - { - test: /\.node$/, - loader: 'node-loader', - }, { test: /\.vue$/, loader: 'vue-loader', @@ -54,10 +48,12 @@ const config = { use: [ { loader: MiniCssExtractPlugin.loader, - options: {}, }, { loader: 'css-loader', + options: { + esModule: false + } }, { loader: 'sass-loader', @@ -75,43 +71,49 @@ const config = { test: /\.css$/, use: [ { - loader: MiniCssExtractPlugin.loader, - options: {}, + loader: MiniCssExtractPlugin.loader }, - 'css-loader', + { + loader: 'css-loader', + options: { + esModule: false + } + } ], }, { test: /\.(png|jpe?g|gif|tif?f|bmp|webp|svg)(\?.*)?$/, - use: { - loader: 'url-loader', - options: { - esModule: false, - limit: 10000, - name: 'imgs/[name]--[folder].[ext]', - }, - }, + type: 'asset/resource', + generator: { + filename: 'imgs/[name][ext]' + } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, - use: { - loader: 'url-loader', - options: { - esModule: false, - limit: 10000, - name: 'fonts/[name]--[folder].[ext]', - }, - }, + type: 'asset/resource', + generator: { + filename: 'fonts/[name][ext]' + } }, ], }, + // webpack defaults to only optimising the production builds, so having this here is fine + optimization: { + minimizer: [ + '...', // extend webpack's list instead of overwriting it + new CssMinimizerPlugin() + ] + }, node: { __dirname: isDevMode, __filename: isDevMode, global: isDevMode, }, plugins: [ - // new WriteFilePlugin(), + new webpack.DefinePlugin({ + 'process.env.PRODUCT_NAME': JSON.stringify(productName), + 'process.env.IS_ELECTRON': true + }), new HtmlWebpackPlugin({ excludeChunks: ['processTaskWorker'], filename: 'index.html', @@ -121,9 +123,6 @@ const config = { : false, }), new VueLoaderPlugin(), - new webpack.DefinePlugin({ - 'process.env.PRODUCT_NAME': JSON.stringify(productName), - }), new MiniCssExtractPlugin({ filename: isDevMode ? '[name].css' : '[name].[contenthash].css', chunkFilename: isDevMode ? '[id].css' : '[id].[contenthash].css', @@ -146,58 +145,23 @@ const config = { /** * Adjust rendererConfig for production settings */ -if (isDevMode) { - // any dev only config +if (!isDevMode) { + const processLocalesPlugin = new ProcessLocalesPlugin({ + compress: true, + inputDir: path.join(__dirname, '../static/locales'), + outputDir: 'static/locales', + }) + config.plugins.push( + processLocalesPlugin, new webpack.DefinePlugin({ - __static: `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`, - }) - ) -} else { - config.plugins.push( - new CopyWebpackPlugin({ - patterns: [ - { - from: path.join(__dirname, '../static/pwabuilder-sw.js'), - to: path.join(__dirname, '../dist/web/pwabuilder-sw.js'), - }, - { - from: path.join(__dirname, '../static'), - to: path.join(__dirname, '../dist/web/static'), - globOptions: { - dot: true, - ignore: ['**/.*', '**/pwabuilder-sw.js', '**/dashFiles/**', '**/storyboards/**'], - }, - }, - { - from: path.join(__dirname, '../static'), - to: path.join(__dirname, '../dist/static'), - globOptions: { - dot: true, - ignore: ['**/.*', '**/pwabuilder-sw.js', '**/dashFiles/**', '**/storyboards/**'], - }, - }, - { - from: path.join(__dirname, '../_icons'), - to: path.join(__dirname, '../dist/web/_icons'), - globOptions: { - dot: true, - ignore: ['**/.*'], - }, - }, - { - from: path.join(__dirname, '../src/renderer/assets/img'), - to: path.join(__dirname, '../dist/web/images'), - globOptions: { - dot: true, - ignore: ['**/.*'], - }, - }, - ] - } - ), - new webpack.LoaderOptionsPlugin({ - minimize: true, + 'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames) + }), + // webpack doesn't get rid of js-yaml even though it isn't used in the production builds + // so we need to manually tell it to ignore any imports for `js-yaml` + new webpack.IgnorePlugin({ + resourceRegExp: /^js-yaml$/, + contextRegExp: /i18n$/ }) ) } diff --git a/_scripts/webpack.web.config.js b/_scripts/webpack.web.config.js index 1b15f319f..845832fa9 100644 --- a/_scripts/webpack.web.config.js +++ b/_scripts/webpack.web.config.js @@ -1,9 +1,13 @@ const path = require('path') +const fs = require('fs') const webpack = require('webpack') const HtmlWebpackPlugin = require('html-webpack-plugin') const VueLoaderPlugin = require('vue-loader/lib/plugin') const CopyWebpackPlugin = require('copy-webpack-plugin') const MiniCssExtractPlugin = require('mini-css-extract-plugin') +const JsonMinimizerPlugin = require('json-minimizer-webpack-plugin') +const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') +const ProcessLocalesPlugin = require('./ProcessLocalesPlugin') const { productName } = require('../package.json') @@ -12,7 +16,7 @@ const isDevMode = process.env.NODE_ENV === 'development' const config = { name: 'web', mode: process.env.NODE_ENV, - devtool: isDevMode ? '#cheap-module-eval-source-map' : false, + devtool: isDevMode ? 'eval-cheap-module-source-map' : false, entry: { web: path.join(__dirname, '../src/renderer/main.js'), }, @@ -20,6 +24,11 @@ const config = { path: path.join(__dirname, '../dist/web'), filename: '[name].js', }, + externals: { + electron: '{}', + ytpl: '{}', + ytsr: '{}' + }, module: { rules: [ { @@ -29,27 +38,19 @@ const config = { }, { test: /\.vue$/, - use: { - loader: 'vue-loader', - options: { - extractCSS: true, - loaders: { - sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1', - scss: 'vue-style-loader!css-loader!sass-loader', - less: 'vue-style-loader!css-loader!less-loader', - }, - }, - }, + loader: 'vue-loader' }, { test: /\.s(c|a)ss$/, use: [ { loader: MiniCssExtractPlugin.loader, - options: {}, }, { loader: 'css-loader', + options: { + esModule: false + } }, { loader: 'sass-loader', @@ -67,10 +68,14 @@ const config = { test: /\.css$/, use: [ { - loader: MiniCssExtractPlugin.loader, - options: {}, + loader: MiniCssExtractPlugin.loader }, - 'css-loader', + { + loader: 'css-loader', + options: { + esModule: false + } + } ], }, { @@ -79,39 +84,43 @@ const config = { }, { test: /\.(png|jpe?g|gif|tif?f|bmp|webp|svg)(\?.*)?$/, - use: { - loader: 'url-loader', - options: { - esModule: false, - limit: 10000, - name: 'imgs/[name]--[folder].[ext]', - }, - }, + type: 'asset/resource', + generator: { + filename: 'imgs/[name][ext]' + } }, { test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, - use: { - loader: 'url-loader', - options: { - esModule: false, - limit: 10000, - name: 'fonts/[name]--[folder].[ext]', - }, - }, + type: 'asset/resource', + generator: { + filename: 'fonts/[name][ext]' + } }, ], }, + // webpack defaults to only optimising the production builds, so having this here is fine + optimization: { + minimizer: [ + '...', // extend webpack's list instead of overwriting it + new JsonMinimizerPlugin({ + exclude: /\/locales\/.*\.json/ + }), + new CssMinimizerPlugin() + ] + }, node: { - __dirname: isDevMode, + __dirname: true, __filename: isDevMode, - fs: 'empty', - net: 'empty', - tls: 'empty', - child_process: 'empty', - dns: 'empty' }, plugins: [ - // new WriteFilePlugin(), + new webpack.DefinePlugin({ + 'process.env.PRODUCT_NAME': JSON.stringify(productName), + 'process.env.IS_ELECTRON': false + }), + new webpack.ProvidePlugin({ + process: 'process/browser', + Buffer: ['buffer', 'Buffer'], + }), new HtmlWebpackPlugin({ excludeChunks: ['processTaskWorker'], filename: 'index.html', @@ -119,9 +128,6 @@ const config = { nodeModules: false, }), new VueLoaderPlugin(), - new webpack.DefinePlugin({ - 'process.env.PRODUCT_NAME': JSON.stringify(productName), - }), new MiniCssExtractPlugin({ filename: isDevMode ? '[name].css' : '[name].[contenthash].css', chunkFilename: isDevMode ? '[id].css' : '[id].[contenthash].css', @@ -136,60 +142,61 @@ const config = { images: path.join(__dirname, '../src/renderer/assets/img/'), static: path.join(__dirname, '../static/'), }, + fallback: { + buffer: require.resolve('buffer/'), + dns: require.resolve('browserify/lib/_empty.js'), + fs: require.resolve('browserify/lib/_empty.js'), + http: require.resolve('stream-http'), + https: require.resolve('https-browserify'), + net: require.resolve('browserify/lib/_empty.js'), + os: require.resolve('os-browserify/browser.js'), + path: require.resolve('path-browserify'), + stream: require.resolve('stream-browserify'), + timers: require.resolve('timers-browserify'), + tls: require.resolve('browserify/lib/_empty.js'), + vm: require.resolve('vm-browserify'), + zlib: require.resolve('browserify-zlib') + }, extensions: ['.js', '.vue', '.json', '.css'], }, target: 'web', } -/** - * Adjust web for production settings - */ -if (isDevMode) { - // any dev only config - config.plugins.push( - new webpack.DefinePlugin({ - __static: `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`, - }) - ) -} else { - config.plugins.push( - new CopyWebpackPlugin({ - patterns: [ - { - from: path.join(__dirname, '../static/pwabuilder-sw.js'), - to: path.join(__dirname, '../dist/web/pwabuilder-sw.js'), +const processLocalesPlugin = new ProcessLocalesPlugin({ + compress: false, + inputDir: path.join(__dirname, '../static/locales'), + outputDir: 'static/locales', +}) + +config.plugins.push( + processLocalesPlugin, + new webpack.DefinePlugin({ + 'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames), + 'process.env.GEOLOCATION_NAMES': JSON.stringify(fs.readdirSync(path.join(__dirname, '..', 'static', 'geolocations'))) + }), + new CopyWebpackPlugin({ + patterns: [ + { + from: path.join(__dirname, '../static/pwabuilder-sw.js'), + to: path.join(__dirname, '../dist/web/pwabuilder-sw.js'), + }, + { + from: path.join(__dirname, '../static'), + to: path.join(__dirname, '../dist/web/static'), + globOptions: { + dot: true, + ignore: ['**/.*', '**/locales/**', '**/pwabuilder-sw.js', '**/dashFiles/**', '**/storyboards/**'], }, - { - from: path.join(__dirname, '../static'), - to: path.join(__dirname, '../dist/web/static'), - globOptions: { - dot: true, - ignore: ['**/.*', '**/pwabuilder-sw.js', '**/dashFiles/**', '**/storyboards/**'], - }, - }, - { - from: path.join(__dirname, '../_icons'), - to: path.join(__dirname, '../dist/web/_icons'), - globOptions: { - dot: true, - ignore: ['**/.*'], - }, - }, - { - from: path.join(__dirname, '../src/renderer/assets/img'), - to: path.join(__dirname, '../dist/web/images'), - globOptions: { - dot: true, - ignore: ['**/.*'], - }, - }, - ] - } - ), - new webpack.LoaderOptionsPlugin({ - minimize: true, - }) - ) -} + }, + ] + }), + // webpack doesn't get rid of js-yaml even though it isn't used in the production builds + // so we need to manually tell it to ignore any imports for `js-yaml` + new webpack.IgnorePlugin({ + resourceRegExp: /^js-yaml$/, + contextRegExp: /i18n$/ + }) +) + module.exports = config diff --git a/_scripts/webpack.workers.config.js b/_scripts/webpack.workers.config.js index 7ca42754f..1ac26a191 100644 --- a/_scripts/webpack.workers.config.js +++ b/_scripts/webpack.workers.config.js @@ -30,10 +30,6 @@ const config = { use: 'babel-loader', exclude: /node_modules/, }, - { - test: /\.node$/, - loader: 'node-loader', - }, ], }, node: { @@ -63,11 +59,7 @@ const config = { if (isDevMode) { // any dev only config } else { - config.plugins.push( - new webpack.LoaderOptionsPlugin({ - minimize: true, - }) - ) + // any producation only config } module.exports = config diff --git a/lefthook.yml b/lefthook.yml new file mode 100644 index 000000000..7f6f4e3d6 --- /dev/null +++ b/lefthook.yml @@ -0,0 +1,48 @@ + +# Refer for explanation to following link: +# https://github.com/evilmartians/lefthook/blob/master/docs/full_guide.md +pre-commit: + parallel: true + commands: + lint: + # Only runs when any file with filename + # matching the glob is being committed + glob: "*.{js,vue}" + run: yarn run eslint --no-color {staged_files} + skip: + - rebase + + + +# EXAMPLE USAGE +# +# pre-push: +# commands: +# packages-audit: +# tags: frontend security +# run: yarn audit +# gems-audit: +# tags: backend security +# run: bundle audit +# +# pre-commit: +# parallel: true +# commands: +# eslint: +# glob: "*.{js,ts}" +# run: yarn eslint {staged_files} +# rubocop: +# tags: backend style +# glob: "*.rb" +# exclude: "application.rb|routes.rb" +# run: bundle exec rubocop --force-exclusion {all_files} +# govet: +# tags: backend style +# files: git ls-files -m +# glob: "*.go" +# run: go vet {files} +# scripts: +# "hello.js": +# runner: node +# "any.go": +# runner: go run diff --git a/package.json b/package.json index e8861bcbe..7a6c940fd 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "freetube", "productName": "FreeTube", "description": "A private YouTube client", - "version": "0.17.1", + "version": "0.18.0", "license": "AGPL-3.0-or-later", "main": "./dist/main.js", "private": true, @@ -29,6 +29,7 @@ "debug": "run-s rebuild:electron debug-runner", "debug-runner": "node _scripts/dev-runner.js --remote-debug", "dev": "run-s rebuild:electron dev-runner", + "dev:web": "node _scripts/dev-runner.js --web", "dev-runner": "node _scripts/dev-runner.js", "lint-fix": "eslint --fix --ext .js,.vue ./", "lint": "eslint --ext .js,.vue ./", @@ -37,92 +38,88 @@ "pack:renderer": "webpack --mode=production --node-env=production --config _scripts/webpack.renderer.config.js", "pack:web": "webpack --mode=production --node-env=production --config _scripts/webpack.web.config.js", "pack:workers": "webpack --mode=production --node-env=production --config _scripts/webpack.workers.config.js", - "postinstall": "npm run rebuild:electron", + "postinstall": "yarn run --silent rebuild:electron", "prettier": "prettier --write \"{src,_scripts}/**/*.{js,vue}\"", "rebuild:electron": "electron-builder install-app-deps", - "rebuild:node": "npm rebuild", "release": "run-s test build", - "ci": "yarn install --frozen-lockfile" + "ci": "yarn install --silent --frozen-lockfile" }, "dependencies": { - "@fortawesome/fontawesome-svg-core": "^1.2.36", - "@fortawesome/free-brands-svg-icons": "^5.15.4", - "@fortawesome/free-solid-svg-icons": "^5.15.4", - "@fortawesome/vue-fontawesome": "^2.0.2", + "@fortawesome/fontawesome-svg-core": "^6.2.0", + "@fortawesome/free-brands-svg-icons": "^6.2.0", + "@fortawesome/free-solid-svg-icons": "^6.2.0", + "@fortawesome/vue-fontawesome": "^2.0.8", "@freetube/youtube-chat": "^1.1.2", - "@freetube/yt-comment-scraper": "^6.1.0", + "@freetube/yt-comment-scraper": "^6.2.0", + "@freetube/yt-trending-scraper": "^3.1.1", "@silvermine/videojs-quality-selector": "^1.2.5", - "autolinker": "^3.15.0", - "electron-context-menu": "^3.1.2", - "http-proxy-agent": "^4.0.1", + "autolinker": "^4.0.0", + "browserify": "^17.0.0", + "browserify-zlib": "^0.2.0", + "electron-context-menu": "^3.5.0", + "http-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0", - "jquery": "^3.6.0", - "js-yaml": "^4.1.0", "lodash.debounce": "^4.0.8", "lodash.isequal": "^4.5.0", - "marked": "^4.0.17", - "nedb-promises": "^5.0.1", + "marked": "^4.1.1", + "nedb-promises": "^6.2.1", "opml-to-json": "^1.0.1", - "rss-parser": "^3.12.0", + "process": "^0.11.10", "socks-proxy-agent": "^6.0.0", "video.js": "7.18.1", "videojs-contrib-quality-levels": "^2.1.0", "videojs-http-source-selector": "^1.1.6", + "videojs-mobile-ui": "^0.8.0", "videojs-overlay": "^2.1.4", "videojs-vtt-thumbnails-freetube": "0.0.15", - "vue": "^2.6.14", - "vue-i18n": "^8.25.0", + "vue": "^2.7.13", + "vue-i18n": "^8.28.1", "vue-observe-visibility": "^1.0.0", - "vue-router": "^3.5.2", + "vue-router": "^3.6.5", "vuex": "^3.6.2", - "youtube-suggest": "^1.1.2", - "yt-channel-info": "^3.0.4", + "youtube-suggest": "^1.2.0", + "yt-channel-info": "^3.2.1", "yt-dash-manifest-generator": "1.1.0", - "yt-trending-scraper": "^2.0.1", - "ytdl-core": "git+https://github.com/absidue/node-ytdl-core#temp-fix-11-08-2022", + "ytdl-core": "^4.11.2", "ytpl": "^2.3.0", "ytsr": "^3.8.0" }, "devDependencies": { - "@babel/core": "^7.17.10", - "@babel/plugin-proposal-class-properties": "^7.16.7", - "@babel/preset-env": "^7.17.10", + "@babel/core": "^7.18.13", + "@babel/plugin-proposal-class-properties": "^7.18.6", + "@babel/preset-env": "^7.18.10", "babel-eslint": "^10.1.0", "babel-loader": "^8.2.5", - "copy-webpack-plugin": "^9.0.1", - "css-loader": "5.2.6", - "electron": "^16.2.7", - "electron-builder": "^23.0.3", - "electron-builder-squirrel-windows": "^22.13.1", - "electron-debug": "^3.2.0", + "copy-webpack-plugin": "^11.0.0", + "css-loader": "^6.7.1", + "css-minimizer-webpack-plugin": "^4.2.2", + "electron": "^21.2.0", + "electron-builder": "^23.6.0", "eslint": "^7.32.0", "eslint-config-prettier": "^8.3.0", "eslint-config-standard": "^16.0.3", "eslint-plugin-import": "^2.24.2", "eslint-plugin-node": "^11.1.0", - "eslint-plugin-prettier": "^4.0.0", + "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-promise": "^5.1.0", "eslint-plugin-standard": "^5.0.0", - "eslint-plugin-vue": "^7.17.0", - "file-loader": "^6.2.0", + "eslint-plugin-vue": "^9.6.0", "html-webpack-plugin": "^5.3.2", - "mini-css-extract-plugin": "^2.2.2", - "node-loader": "^2.0.0", + "js-yaml": "^4.1.0", + "json-minimizer-webpack-plugin": "^4.0.0", + "lefthook": "^1.1.3", + "mini-css-extract-plugin": "^2.6.1", "npm-run-all": "^4.1.5", - "prettier": "^2.3.2", + "prettier": "^2.7.1", "rimraf": "^3.0.2", - "sass": "^1.38.2", - "sass-loader": "^12.1.0", - "style-loader": "^3.2.1", + "sass": "^1.54.9", + "sass-loader": "^13.0.2", "tree-kill": "1.2.2", - "url-loader": "^4.1.1", "vue-devtools": "^5.1.4", - "vue-eslint-parser": "^7.10.0", - "vue-loader": "^15.9.8", - "vue-style-loader": "^4.1.3", - "vue-template-compiler": "^2.6.14", - "webpack": "^5.51.1", - "webpack-cli": "^4.8.0", - "webpack-dev-server": "^4.1.0" + "vue-eslint-parser": "^9.1.0", + "vue-loader": "^15.10.0", + "webpack": "^5.74.0", + "webpack-cli": "^4.10.0", + "webpack-dev-server": "^4.11.1" } } diff --git a/src/datastores/handlers/index.js b/src/datastores/handlers/index.js index 0b1dc938b..e96565d1f 100644 --- a/src/datastores/handlers/index.js +++ b/src/datastores/handlers/index.js @@ -1,6 +1,5 @@ let handlers -const usingElectron = window?.process?.type === 'renderer' -if (usingElectron) { +if (process.env.IS_ELECTRON) { handlers = require('./electron').default } else { handlers = require('./web').default diff --git a/src/index.ejs b/src/index.ejs index f0dad7e03..9fd3136e3 100644 --- a/src/index.ejs +++ b/src/index.ejs @@ -18,23 +18,13 @@
- - -