diff --git a/.env.example b/.env.example index 22abd24bd..566656632 100644 --- a/.env.example +++ b/.env.example @@ -9,3 +9,6 @@ ENABLE_UPDATE_CHECK= LASTFM_API_KEY= LASTFM_API_SECRET= + +# Release channel. Can be: nightly, stable +RELEASE_CHANNEL= diff --git a/.github/Dockerfile b/.github/Dockerfile index 007d1a6e7..2e3934499 100644 --- a/.github/Dockerfile +++ b/.github/Dockerfile @@ -10,14 +10,10 @@ COPY . . RUN chown -R $(whoami) /app -RUN flutter pub get &&\ - flutter config --enable-linux-desktop &&\ - flutter pub get &&\ - dart run build_runner build --delete-conflicting-outputs +RUN flutter pub get RUN alias dpkg-deb="dpkg-deb --Zxz" &&\ - flutter_distributor package --platform=linux --targets=deb - + flutter_distributor package --platform=linux --targets=deb --skip-clean RUN make tar VERSION=${BUILD_VERSION} ARCH=arm64 PKG_ARCH=aarch64 diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index cabe2dbf6..0fe1f1bac 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -2,296 +2,65 @@ name: Spotube Release Binary on: workflow_dispatch: inputs: - version: - description: Version to release (x.x.x) - default: 3.6.0 - required: true channel: type: choice - description: Release Channel - required: true options: - stable - nightly default: nightly + description: The release channel debug: - description: Debug on failed when channel is nightly - required: true type: boolean default: false + description: Debug with SSH toggle + required: false dry_run: - description: Dry run - required: true type: boolean - default: true + default: false + description: Dry run without uploading to release env: - FLUTTER_VERSION: '3.19.5' - -jobs: - windows: - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.12.0 - with: - cache: true - flutter-version: ${{ env.FLUTTER_VERSION }} - - - name: Replace pubspec version and BUILD_VERSION Env (nightly) - if: ${{ inputs.channel == 'nightly' }} - run: | - choco install sed make yq -y - yq -i '.version |= sub("\+\d+", "-${{ inputs.channel }}+")' pubspec.yaml - yq -i '.version += strenv(GITHUB_RUN_NUMBER)' pubspec.yaml - echo "BUILD_VERSION=${{ inputs.version }}+${{ inputs.channel }}.${{ github.run_number }}" >> $GITHUB_ENV - shell: bash - - - name: BUILD_VERSION Env (stable) - if: ${{ inputs.channel == 'stable' }} - run: | - "BUILD_VERSION=${{ inputs.version }}" >> $env:GITHUB_ENV - - - name: Replace version in files - run: | - choco install sed make -y - sed -i "s/%{{SPOTUBE_VERSION}}%/${{ env.BUILD_VERSION }}/" windows/runner/Runner.rc - sed -i "s/%{{SPOTUBE_VERSION}}%/${{ env.BUILD_VERSION }}/" choco-struct/tools/VERIFICATION.txt - sed -i "s/%{{SPOTUBE_VERSION}}%/${{ env.BUILD_VERSION }}/" choco-struct/spotube.nuspec - - - name: Create Stable .env - if: ${{ inputs.channel == 'stable' }} - run: echo '${{ secrets.DOTENV_RELEASE }}' > .env - - - name: Create Nightly .env - if: ${{ inputs.channel == 'nightly' }} - run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env - - - name: Generating Secrets - run: | - flutter config --enable-windows-desktop - flutter pub get - dart run build_runner build --delete-conflicting-outputs - - - name: Build Windows Executable - run: | - dart pub global activate flutter_distributor - make innoinstall - flutter_distributor package --platform=windows --targets=exe --skip-clean - mv dist/**/spotube-*-windows-setup.exe dist/Spotube-windows-x86_64-setup.exe - - - name: Create Chocolatey Package and set hash - if: ${{ inputs.channel == 'stable' }} - run: | - Set-Variable -Name HASH -Value (Get-FileHash dist\Spotube-windows-x86_64-setup.exe).Hash - sed -i "s/%{{WIN_SHA256}}%/$HASH/" choco-struct/tools/VERIFICATION.txt - make choco - mv dist/spotube.*.nupkg dist/Spotube-windows-x86_64.nupkg - - - - name: Upload Artifact - uses: actions/upload-artifact@v3 - with: - if-no-files-found: error - name: Spotube-Release-Binaries - path: | - dist/Spotube-windows-x86_64.nupkg - dist/Spotube-windows-x86_64-setup.exe - - - name: Debug With SSH When fails - if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - - linux: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.12.0 - with: - cache: true - flutter-version: ${{ env.FLUTTER_VERSION }} - - - name: Get current date - id: date - run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - - name: Install Dependencies - run: | - sudo apt-get update -y - sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev libsecret-1-0 libjsoncpp25 libsecret-1-dev libjsoncpp-dev libnotify-bin libnotify-dev mpv libmpv-dev - - - name: Install AppImage Tool - run: | - wget -O appimagetool "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" - chmod +x appimagetool - mv appimagetool /usr/local/bin/ - - - name: Replace pubspec version and BUILD_VERSION Env (nightly) - if: ${{ inputs.channel == 'nightly' }} - run: | - curl -sS https://webi.sh/yq | sh - yq -i '.version |= sub("\+\d+", "+${{ inputs.channel }}.")' pubspec.yaml - yq -i '.version += strenv(GITHUB_RUN_NUMBER)' pubspec.yaml - echo "BUILD_VERSION=${{ inputs.version }}+${{ inputs.channel }}.${{ github.run_number }}" >> $GITHUB_ENV - - - name: BUILD_VERSION Env (stable) - if: ${{ inputs.channel == 'stable' }} - run: | - echo "BUILD_VERSION=${{ inputs.version }}" >> $GITHUB_ENV - - - name: Create Stable .env - if: ${{ inputs.channel == 'stable' }} - run: echo '${{ secrets.DOTENV_RELEASE }}' > .env - - - name: Create Nightly .env - if: ${{ inputs.channel == 'nightly' }} - run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env - - - name: Replace Version in files - run: | - sed -i 's|%{{APPDATA_RELEASE}}%||' linux/com.github.KRTirtho.Spotube.appdata.xml - - - name: Generate Secrets - run: | - flutter config --enable-linux-desktop - flutter pub get - dart run build_runner build --delete-conflicting-outputs - - - name: Build Linux Packages - run: | - dart pub global activate flutter_distributor - alias dpkg-deb="dpkg-deb --Zxz" - flutter_distributor package --platform=linux --targets=deb - flutter_distributor package --platform=linux --targets=rpm - - - name: Create tar.xz (stable) - if: ${{ inputs.channel == 'stable' }} - run: make tar VERSION=${{ env.BUILD_VERSION }} ARCH=x64 PKG_ARCH=x86_64 - - - name: Create tar.xz (nightly) - if: ${{ inputs.channel == 'nightly' }} - run: make tar VERSION=nightly ARCH=x64 PKG_ARCH=x86_64 - - - name: Move Files to dist - run: | - mv build/spotube-linux-*-x86_64.tar.xz dist/ - mv dist/**/spotube-*-linux.deb dist/Spotube-linux-x86_64.deb - mv dist/**/spotube-*-linux.rpm dist/Spotube-linux-x86_64.rpm - - - - uses: actions/upload-artifact@v3 - if: ${{ inputs.channel == 'stable' }} - with: - if-no-files-found: error - name: Spotube-Release-Binaries - path: | - dist/Spotube-linux-x86_64.deb - dist/Spotube-linux-x86_64.rpm - dist/spotube-linux-${{ env.BUILD_VERSION }}-x86_64.tar.xz - - - uses: actions/upload-artifact@v3 - if: ${{ inputs.channel == 'nightly' }} - with: - if-no-files-found: error - name: Spotube-Release-Binaries - path: | - dist/Spotube-linux-x86_64.deb - dist/Spotube-linux-x86_64.rpm - dist/spotube-linux-nightly-x86_64.tar.xz - - - name: Debug With SSH When fails - if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - - linux_arm: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Get current date - id: date - run: echo "::set-output name=date::$(date +'%Y-%m-%d')" - - - name: Install Dependencies - run: | - sudo apt-get update -y - sudo apt-get install -y pkg-config make python3-pip python3-setuptools - - - name: Replace pubspec version and BUILD_VERSION Env (nightly) - if: ${{ inputs.channel == 'nightly' }} - run: | - curl -sS https://webi.sh/yq | sh - yq -i '.version |= sub("\+\d+", "+${{ inputs.channel }}.")' pubspec.yaml - yq -i '.version += strenv(GITHUB_RUN_NUMBER)' pubspec.yaml - echo "BUILD_VERSION=${{ inputs.version }}+${{ inputs.channel }}.${{ github.run_number }}" >> $GITHUB_ENV - - - name: BUILD_VERSION Env (stable) - if: ${{ inputs.channel == 'stable' }} - run: | - echo "BUILD_VERSION=${{ inputs.version }}" >> $GITHUB_ENV - - - name: Create Stable .env - if: ${{ inputs.channel == 'stable' }} - run: echo '${{ secrets.DOTENV_RELEASE }}' > .env - - - name: Create Nightly .env - if: ${{ inputs.channel == 'nightly' }} - run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env - - - name: Replace Version in files - run: | - sed -i 's|%{{APPDATA_RELEASE}}%||' linux/com.github.KRTirtho.Spotube.appdata.xml - - - name: Build Binaries (stable) - if: ${{ inputs.channel == 'stable' }} - run: | - docker buildx build --platform=linux/arm64 -f .github/Dockerfile . --build-arg FLUTTER_VERSION=${{env.FLUTTER_VERSION}} --build-arg BUILD_VERSION=${{env.BUILD_VERSION}} -t krtirtho/spotube_linux_arm:latest --load - - - name: Build Binaries (nightly) - if: ${{ inputs.channel == 'nightly' }} - run: | - docker buildx build --platform=linux/arm64 -f .github/Dockerfile . --build-arg FLUTTER_VERSION=${{env.FLUTTER_VERSION}} --build-arg BUILD_VERSION=nightly -t krtirtho/spotube_linux_arm:latest --load - - - name: Copy the built packages - run: | - docker images ls - docker create --name spotube_linux_arm krtirtho/spotube_linux_arm:latest - docker cp spotube_linux_arm:/app/dist/ dist/ + FLUTTER_VERSION: 3.19.5 - - uses: actions/upload-artifact@v3 - if: ${{ inputs.channel == 'stable' }} - with: - if-no-files-found: error - name: Spotube-Release-Binaries - path: | - dist/Spotube-linux-aarch64.deb - dist/spotube-linux-${{ env.BUILD_VERSION }}-aarch64.tar.xz - - - uses: actions/upload-artifact@v3 - if: ${{ inputs.channel == 'nightly' }} - with: - if-no-files-found: error - name: Spotube-Release-Binaries - path: | - dist/Spotube-linux-aarch64.deb - dist/spotube-linux-nightly-aarch64.tar.xz +permissions: + contents: write - - name: Debug With SSH When fails - if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - - android: - runs-on: ubuntu-latest +jobs: + build_platform: + strategy: + matrix: + include: + - os: ubuntu-latest + platform: linux + files: | + dist/Spotube-linux-x86_64.deb + dist/Spotube-linux-x86_64.rpm + dist/spotube-linux-*-x86_64.tar.xz + - os: ubuntu-latest + platform: linux_arm + files: | + dist/Spotube-linux-aarch64.deb + dist/spotube-linux-*-aarch64.tar.xz + - os: ubuntu-latest + platform: android + files: | + build/Spotube-android-all-arch.apk + build/Spotube-playstore-all-arch.aab + - os: windows-latest + platform: windows + files: | + dist/Spotube-windows-x86_64.nupkg + dist/Spotube-windows-x86_64-setup.exe + - os: macos-latest + platform: ios + files: | + Spotube-iOS.ipa + - os: macos-14 + platform: macos + files: | + build/Spotube-macos-universal.dmg + build/Spotube-macos-universal.pkg + runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2.12.0 @@ -299,137 +68,42 @@ jobs: cache: true flutter-version: ${{ env.FLUTTER_VERSION }} - name: Setup Java + if: ${{matrix.platform == 'android'}} uses: actions/setup-java@v4 with: distribution: 'zulu' java-version: '17' cache: 'gradle' check-latest: true + - name: Set up QEMU + if: ${{matrix.platform == 'linux_arm'}} + uses: docker/setup-qemu-action@v3 + - name: Set up Docker Buildx + if: ${{matrix.platform == 'linux_arm'}} + uses: docker/setup-buildx-action@v3 - - name: Install Dependencies - run: | - sudo apt-get update -y - sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse xmlstarlet - - - name: Replace pubspec version and BUILD_VERSION Env (nightly) - if: ${{ inputs.channel == 'nightly' }} - run: | - curl -sS https://webi.sh/yq | sh - yq -i '.version |= sub("\+\d+", "+${{ inputs.channel }}.")' pubspec.yaml - yq -i '.version += strenv(GITHUB_RUN_NUMBER)' pubspec.yaml - echo "BUILD_VERSION=${{ inputs.version }}+${{ inputs.channel }}.${{ github.run_number }}" >> $GITHUB_ENV - - - name: BUILD_VERSION Env (stable) - if: ${{ inputs.channel == 'stable' }} - run: | - echo "BUILD_VERSION=${{ inputs.version }}" >> $GITHUB_ENV - - - name: Create Stable .env - if: ${{ inputs.channel == 'stable' }} - run: echo '${{ secrets.DOTENV_RELEASE }}' > .env - - - name: Create Nightly .env - if: ${{ inputs.channel == 'nightly' }} - run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env - - - name: Generate Secrets + - name: Install ${{matrix.platform}} dependencies run: | flutter pub get - dart run build_runner build --delete-conflicting-outputs + dart cli/cli.dart install-dependencies --platform=${{matrix.platform}} - name: Sign Apk + if: ${{matrix.platform == 'android'}} run: | echo '${{ secrets.KEYSTORE }}' | base64 --decode > android/app/upload-keystore.jks echo '${{ secrets.KEY_PROPERTIES }}' > android/key.properties - - - name: Build Apk - run: | - flutter build apk --flavor ${{ inputs.channel }} - mv build/app/outputs/flutter-apk/app-${{ inputs.channel }}-release.apk build/Spotube-android-all-arch.apk - - - name: Build Playstore AppBundle - run: | - echo 'ENABLE_UPDATE_CHECK=0' >> .env - dart run build_runner build --delete-conflicting-outputs - export MANIFEST=android/app/src/main/AndroidManifest.xml - xmlstarlet ed -d '//meta-data[@android:name="com.google.android.gms.car.application"]' $MANIFEST > $MANIFEST.tmp - mv $MANIFEST.tmp $MANIFEST - flutter build appbundle --flavor ${{ inputs.channel }} - mv build/app/outputs/bundle/${{ inputs.channel }}Release/app-${{ inputs.channel }}-release.aab build/Spotube-playstore-all-arch.aab - - - - uses: actions/upload-artifact@v3 - with: - if-no-files-found: error - name: Spotube-Release-Binaries - path: | - build/Spotube-android-all-arch.apk - build/Spotube-playstore-all-arch.aab - - - name: Debug With SSH When fails - if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - - macos: - runs-on: macos-14 - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.12.0 - with: - cache: true - flutter-version: ${{ env.FLUTTER_VERSION }} - - - name: Replace pubspec version and BUILD_VERSION Env (nightly) - if: ${{ inputs.channel == 'nightly' }} - run: | - brew install yq - yq -i '.version |= sub("\+\d+", "+${{ inputs.channel }}.")' pubspec.yaml - yq -i '.version += strenv(GITHUB_RUN_NUMBER)' pubspec.yaml - echo "BUILD_VERSION=${{ inputs.version }}+${{ inputs.channel }}.${{ github.run_number }}" >> $GITHUB_ENV - - - name: BUILD_VERSION Env (stable) - if: ${{ inputs.channel == 'stable' }} - run: | - echo "BUILD_VERSION=${{ inputs.version }}" >> $GITHUB_ENV - - - name: Create Stable .env - if: ${{ inputs.channel == 'stable' }} - run: echo '${{ secrets.DOTENV_RELEASE }}' > .env - - - name: Create Nightly .env - if: ${{ inputs.channel == 'nightly' }} - run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env - - - name: Generate Secrets - run: | - dart pub global activate flutter_distributor - flutter pub get - dart run build_runner build --delete-conflicting-outputs - - - name: Build Macos App - run: | - flutter config --enable-macos-desktop - flutter build macos - du -sh build/macos/Build/Products/Release/spotube.app - - - name: Package Macos App - run: | - brew install python-setuptools - npm install -g appdmg - mkdir -p build/${{ env.BUILD_VERSION }} - appdmg appdmg.json build/Spotube-macos-universal.dmg - flutter_distributor package --platform=macos --targets pkg --skip-clean - mv dist/**/spotube-*-macos.pkg build/Spotube-macos-universal.pkg - + + - name: Build ${{matrix.platform}} binaries + run: dart cli/cli.dart build ${{matrix.platform}} + env: + CHANNEL: ${{inputs.channel}} + DOTENV: ${{secrets.DOTENV_RELEASE}} + - uses: actions/upload-artifact@v3 with: if-no-files-found: error name: Spotube-Release-Binaries - path: | - build/Spotube-macos-universal.dmg - build/Spotube-macos-universal.pkg + path: ${{matrix.files}} - name: Debug With SSH When fails if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} @@ -437,70 +111,10 @@ jobs: with: limit-access-to-actor: true - iOS: - runs-on: macos-14 - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.10.0 - with: - cache: true - flutter-version: ${{ env.FLUTTER_VERSION }} - - - name: Replace pubspec version and BUILD_VERSION Env (nightly) - if: ${{ inputs.channel == 'nightly' }} - run: | - brew install yq - yq -i '.version |= sub("\+\d+", "+${{ inputs.channel }}.")' pubspec.yaml - yq -i '.version += strenv(GITHUB_RUN_NUMBER)' pubspec.yaml - echo "BUILD_VERSION=${{ inputs.version }}+${{ inputs.channel }}.${{ github.run_number }}" >> $GITHUB_ENV - - - name: BUILD_VERSION Env (stable) - if: ${{ inputs.channel == 'stable' }} - run: | - echo "BUILD_VERSION=${{ inputs.version }}" >> $GITHUB_ENV - - - name: Create Stable .env - if: ${{ inputs.channel == 'stable' }} - run: echo '${{ secrets.DOTENV_RELEASE }}' > .env - - - name: Create Nightly .env - if: ${{ inputs.channel == 'nightly' }} - run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env - - - name: Generate Secrets - run: | - flutter pub get - dart run build_runner build --delete-conflicting-outputs - - - name: Build iOS iPA - run: | - flutter build ios --release --no-codesign --flavor ${{ inputs.channel }} - ln -sf ./build/ios/iphoneos Payload - zip -r9 Spotube-iOS.ipa Payload/${{ inputs.channel }}.app - - - uses: actions/upload-artifact@v3 - with: - if-no-files-found: error - name: Spotube-Release-Binaries - path: | - Spotube-iOS.ipa - - - name: Debug With SSH When fails - if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - upload: runs-on: ubuntu-latest - needs: - - windows - - linux - - linux_arm - - android - - macos - - iOS + - build_platform steps: - uses: actions/download-artifact@v3 with: @@ -516,6 +130,10 @@ jobs: md5sum Spotube-Release-Binaries/* >> RELEASE.md5sum sha256sum Spotube-Release-Binaries/* >> RELEASE.sha256sum sed -i 's|Spotube-Release-Binaries/||' RELEASE.sha256sum RELEASE.md5sum + + - name: Extract pubspec version + run: | + echo "PUBSPEC_VERSION=$(grep -oP 'version:\s*\K[^+]+(?=\+)' pubspec.yaml)" >> $GITHUB_ENV - uses: actions/upload-artifact@v3 with: @@ -530,7 +148,7 @@ jobs: uses: ncipollo/release-action@v1 with: token: ${{ secrets.GITHUB_TOKEN }} - tag: v${{ inputs.version }} # mind the "v" prefix + tag: v${{ env.PUBSPEC_VERSION }} # mind the "v" prefix omitBodyDuringUpdate: true omitNameDuringUpdate: true omitPrereleaseDuringUpdate: true @@ -548,3 +166,8 @@ jobs: omitPrereleaseDuringUpdate: true allowUpdates: true artifacts: Spotube-Release-Binaries/*,RELEASE.sha256sum,RELEASE.md5sum + body: | + Build Number: ${{github.run_number}} + + Nightly release includes newest features but may contain bugs + It is preferred to use the stable version unless you know what you're doing diff --git a/.metadata b/.metadata index 082985ad4..828f2c0ad 100644 --- a/.metadata +++ b/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: eb6d86ee27deecba4a83536aa20f366a6044895c - channel: stable + revision: "300451adae589accbece3490f4396f10bdf15e6e" + channel: "stable" project_type: app @@ -13,11 +13,11 @@ project_type: app migration: platforms: - platform: root - create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c - base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c - - platform: macos - create_revision: eb6d86ee27deecba4a83536aa20f366a6044895c - base_revision: eb6d86ee27deecba4a83536aa20f366a6044895c + create_revision: 300451adae589accbece3490f4396f10bdf15e6e + base_revision: 300451adae589accbece3490f4396f10bdf15e6e + - platform: windows + create_revision: 300451adae589accbece3490f4396f10bdf15e6e + base_revision: 300451adae589accbece3490f4396f10bdf15e6e # User provided section diff --git a/cli/README.md b/cli/README.md new file mode 100644 index 000000000..b2ba8ebda --- /dev/null +++ b/cli/README.md @@ -0,0 +1,4 @@ +## Spotube Configuration CLI + +This is used for building the project for multiple platforms and having utilities specific for the project. +Written in Dart diff --git a/cli/cli.dart b/cli/cli.dart new file mode 100644 index 000000000..3210f5574 --- /dev/null +++ b/cli/cli.dart @@ -0,0 +1,16 @@ +import 'package:args/command_runner.dart'; + +import 'commands/build.dart'; +import 'commands/install-dependencies.dart'; + +void main(List args) { + final commandRunner = CommandRunner( + "cli", + "Configuration CLI for Spotube", + ); + + commandRunner.addCommand(InstallDependenciesCommand()); + commandRunner.addCommand(BuildCommand()); + + commandRunner.run(args); +} diff --git a/cli/commands/build.dart b/cli/commands/build.dart new file mode 100644 index 000000000..fdf35a952 --- /dev/null +++ b/cli/commands/build.dart @@ -0,0 +1,25 @@ +import 'package:args/command_runner.dart'; + +import 'build/android.dart'; +import 'build/ios.dart'; +import 'build/linux.dart'; +import 'build/linux_arm.dart'; +import 'build/macos.dart'; +import 'build/windows.dart'; + +class BuildCommand extends Command { + @override + String get description => "Build for different platforms"; + + @override + String get name => "build"; + + BuildCommand() { + addSubcommand(AndroidBuildCommand()); + addSubcommand(IosBuildCommand()); + addSubcommand(LinuxBuildCommand()); + addSubcommand(LinuxArmBuildCommand()); + addSubcommand(MacosBuildCommand()); + addSubcommand(WindowsBuildCommand()); + } +} diff --git a/cli/commands/build/android.dart b/cli/commands/build/android.dart new file mode 100644 index 000000000..800522b8a --- /dev/null +++ b/cli/commands/build/android.dart @@ -0,0 +1,90 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:collection/collection.dart'; +import 'package:path/path.dart'; +import 'package:xml/xml.dart'; + +import '../../core/env.dart'; +import 'common.dart'; + +class AndroidBuildCommand extends Command with BuildCommandCommonSteps { + @override + String get description => "Build for android"; + + @override + String get name => "android"; + + @override + FutureOr? run() async { + await bootstrap(); + + await shell.run( + "flutter build apk --flavor ${CliEnv.channel.name}", + ); + + await dotEnvFile.writeAsString( + "\nENABLE_UPDATE_CHECK=0", + mode: FileMode.append, + ); + + final androidManifestFile = File( + join(cwd.path, "android", "app", "src", "main", "AndroidManifest.xml")); + + final androidManifestXml = + XmlDocument.parse(await androidManifestFile.readAsString()); + + final deletingElement = + androidManifestXml.findAllElements("meta-data").firstWhereOrNull( + (el) => + el.getAttribute("android:name") == + "com.google.android.gms.car.application", + ); + + deletingElement?.parent?.children.remove(deletingElement); + + await androidManifestFile.writeAsString( + androidManifestXml.toXmlString(pretty: true), + ); + + await shell.run( + """ + dart run build_runner build --delete-conflicting-outputs + flutter build appbundle --flavor ${CliEnv.channel.name} + """, + ); + + final ogApkFile = File( + join( + "build", + "app", + "outputs", + "flutter-apk", + "app-${CliEnv.channel.name}-release.apk", + ), + ); + + await ogApkFile.copy( + join(cwd.path, "build", "Spotube-android-all-arch.apk"), + ); + + final ogAppbundleFile = File( + join( + cwd.path, + "build", + "app", + "outputs", + "bundle", + "${CliEnv.channel.name}Release", + "app-${CliEnv.channel.name}-release.aab", + ), + ); + + await ogAppbundleFile.copy( + join(cwd.path, "build", "Spotube-playstore-all-arch.aab"), + ); + + stdout.writeln("✅ Built Android Apk and Appbundle"); + } +} diff --git a/cli/commands/build/common.dart b/cli/commands/build/common.dart new file mode 100644 index 000000000..4c7e3e510 --- /dev/null +++ b/cli/commands/build/common.dart @@ -0,0 +1,66 @@ +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:path/path.dart'; +import 'package:process_run/shell_run.dart'; +import 'package:pubspec_parse/pubspec_parse.dart'; + +import '../../core/env.dart'; + +mixin BuildCommandCommonSteps on Command { + final shell = Shell(); + Directory get cwd => Directory.current; + + Pubspec? _pubspec; + + Pubspec get pubspec { + if (_pubspec != null) { + return _pubspec!; + } + + final pubspecFile = File(join(cwd.path, "pubspec.yaml")); + _pubspec = Pubspec.parse(pubspecFile.readAsStringSync()); + + return _pubspec!; + } + + String get versionWithoutBuildNumber { + return "${pubspec.version!.major}.${pubspec.version!.minor}.${pubspec.version!.patch}"; + } + + RegExp get versionVarRegExp => + RegExp(r"\%\{\{SPOTUBE_VERSION\}\}\%", multiLine: true); + + File get dotEnvFile => File(join(cwd.path, ".env")); + + Future bootstrap() async { + await dotEnvFile.create(recursive: true); + + await dotEnvFile.writeAsString( + "${CliEnv.dotenv}\n" + "RELEASE_CHANNEL=${CliEnv.channel.name}\n", + ); + + if (CliEnv.channel == BuildChannel.nightly) { + final pubspecFile = File(join(cwd.path, "pubspec.yaml")); + + pubspecFile.writeAsStringSync( + pubspecFile.readAsStringSync().replaceAll( + "version: ${pubspec.version!.canonicalizedVersion}", + "version: $versionWithoutBuildNumber+${CliEnv.ghRunNumber}", + ), + ); + + _pubspec = null; + pubspec; + } + + await shell.run( + """ + flutter pub get + dart run build_runner build --delete-conflicting-outputs + dart pub global activate flutter_distributor + """, + ); + } +} diff --git a/cli/commands/build/ios.dart b/cli/commands/build/ios.dart new file mode 100644 index 000000000..6460f9edb --- /dev/null +++ b/cli/commands/build/ios.dart @@ -0,0 +1,29 @@ +import 'dart:async'; + +import 'package:args/command_runner.dart'; +import 'package:path/path.dart'; + +import '../../core/env.dart'; +import 'common.dart'; + +class IosBuildCommand extends Command with BuildCommandCommonSteps { + @override + String get description => "iOS build command"; + + @override + String get name => "ios"; + + @override + FutureOr? run() async { + await bootstrap(); + + final buildDirPath = join(cwd.path, "build", "ios", "iphoneos"); + await shell.run( + """ + flutter build ios --release --no-codesign --flavor ${CliEnv.channel.name} + ln -sf $buildDirPath Payload + zip -r9 Spotube-iOS.ipa ${join("Payload", "${CliEnv.channel.name}.app")} + """, + ); + } +} diff --git a/cli/commands/build/linux.dart b/cli/commands/build/linux.dart new file mode 100644 index 000000000..a218720ce --- /dev/null +++ b/cli/commands/build/linux.dart @@ -0,0 +1,106 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:io/io.dart'; +import 'package:args/command_runner.dart'; +import 'package:intl/intl.dart'; +import 'package:path/path.dart'; + +import '../../core/env.dart'; +import 'common.dart'; + +class LinuxBuildCommand extends Command with BuildCommandCommonSteps { + @override + String get description => "Linux build command"; + + @override + String get name => "linux"; + + @override + FutureOr? run() async { + stdout.writeln("Replacing versions"); + + final appDataFile = File( + join(cwd.path, "linux", "com.github.KRTirtho.Spotube.appdata.xml"), + ); + + appDataFile.writeAsStringSync( + appDataFile.readAsStringSync().replaceAll( + versionVarRegExp, + '', + ), + ); + + await bootstrap(); + + await shell.run( + """ + flutter_distributor package --platform=linux --targets=deb + flutter_distributor package --platform=linux --targets=rpm + """, + ); + + final tempDir = join(Directory.systemTemp.path, "spotube-tar"); + + final bundleDirPath = + join(cwd.path, "build", "linux", "x64", "release", "bundle"); + + final tarFile = File(join( + cwd.path, + "dist", + "spotube-linux-" + "${CliEnv.channel == BuildChannel.nightly ? "nightly" : versionWithoutBuildNumber}" + "-x86_64.tar.xz", + )); + + await copyPath(bundleDirPath, tempDir); + await File(join(cwd.path, "linux", "spotube.desktop")).copy( + join(tempDir, "spotube.desktop"), + ); + await File( + join(cwd.path, "linux", "com.github.KRTirtho.Spotube.appdata.xml"), + ).copy( + join(tempDir, "com.github.KRTirtho.Spotube.appdata.xml"), + ); + await File(join(cwd.path, "assets", "spotube-logo.png")).copy( + join(tempDir, "spotube-logo.png"), + ); + + await shell.run( + "tar -cJf ${tarFile.path} -C $tempDir .", + ); + + final ogDeb = File( + join( + cwd.path, + "dist", + pubspec.version.toString(), + "spotube-${pubspec.version}-linux.deb", + ), + ); + + final ogRpm = File( + join( + cwd.path, + "dist", + pubspec.version.toString(), + "spotube-${pubspec.version}-linux.rpm", + ), + ); + + await ogDeb.copy( + join(cwd.path, "dist", "Spotube-linux-x86_64.deb"), + ); + await ogRpm.copy( + join(cwd.path, "dist", "Spotube-linux-x86_64.rpm"), + ); + + await ogDeb.delete(); + await ogRpm.delete(); + + stdout.writeln("✅ Linux building done"); + } +} diff --git a/cli/commands/build/linux_arm.dart b/cli/commands/build/linux_arm.dart new file mode 100644 index 000000000..a09f09808 --- /dev/null +++ b/cli/commands/build/linux_arm.dart @@ -0,0 +1,37 @@ +import 'dart:async'; + +import 'package:args/command_runner.dart'; +import 'package:path/path.dart'; + +import '../../core/env.dart'; +import 'common.dart'; + +class LinuxArmBuildCommand extends Command with BuildCommandCommonSteps { + @override + String get description => "Build Linux Arm"; + + @override + String get name => "linux_arm"; + + @override + FutureOr? run() async { + await bootstrap(); + + await shell.run( + "docker buildx build --platform=linux/arm64 " + "-f ${join(cwd.path, ".github", "Dockerfile")} ${cwd.path} " + "--build-arg FLUTTER_VERSION=${CliEnv.flutterVersion} " + "--build-arg BUILD_VERSION=${CliEnv.channel == BuildChannel.nightly ? "nightly" : versionWithoutBuildNumber} " + "-t krtirtho/spotube_linux_arm:latest " + "--load", + ); + + await shell.run( + """ + docker images ls + docker create --name spotube_linux_arm krtirtho/spotube_linux_arm:latest + docker cp spotube_linux_arm:/app/dist/ dist/ + """, + ); + } +} diff --git a/cli/commands/build/macos.dart b/cli/commands/build/macos.dart new file mode 100644 index 000000000..e8f34b775 --- /dev/null +++ b/cli/commands/build/macos.dart @@ -0,0 +1,42 @@ +import 'dart:async'; +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:path/path.dart'; + +import 'common.dart'; + +class MacosBuildCommand extends Command with BuildCommandCommonSteps { + @override + String get description => "Macos Build command"; + + @override + String get name => "macos"; + + @override + FutureOr? run() async { + await bootstrap(); + + await shell.run( + """ + flutter build macos + appdmg appdmg.json ${join(cwd.path, "build", "Spotube-macos-universal.dmg")} + flutter_distributor package --platform=macos --targets pkg --skip-clean + """, + ); + + final ogPkg = File( + join( + cwd.path, + "dist", + pubspec.version.toString(), + "spotube-${pubspec.version}-macos.pkg", + ), + ); + + await ogPkg.copy( + join(cwd.path, "build", "Spotube-macos-universal.pkg"), + ); + await ogPkg.delete(); + } +} diff --git a/cli/commands/build/windows.dart b/cli/commands/build/windows.dart new file mode 100644 index 000000000..15e0bf170 --- /dev/null +++ b/cli/commands/build/windows.dart @@ -0,0 +1,100 @@ +import 'dart:io'; + +import 'package:args/command_runner.dart'; +import 'package:path/path.dart'; +import 'package:crypto/crypto.dart'; +import 'common.dart'; + +class WindowsBuildCommand extends Command with BuildCommandCommonSteps { + @override + String get description => "Build Windows exe"; + + @override + String get name => "windows"; + + Future innoDependInstall() async { + final innoDependencyPath = join(cwd.path, "build", "inno-depend"); + + await shell.run( + "git clone https://github.com/DomGries/InnoDependencyInstaller.git $innoDependencyPath", + ); + } + + @override + void run() async { + stdout.writeln("Replace versions"); + + final chocoFiles = [ + join(cwd.path, "choco-struct", "tools", "VERIFICATION.txt"), + join(cwd.path, "choco-struct", "spotube.nuspec"), + ]; + + for (final filePath in chocoFiles) { + final file = File(filePath); + final content = file.readAsStringSync(); + final newContent = + content.replaceAll(versionVarRegExp, versionWithoutBuildNumber); + + file.writeAsStringSync(newContent); + } + + await bootstrap(); + await innoDependInstall(); + + await shell.run( + "flutter_distributor package --platform=windows --targets=exe --skip-clean", + ); + + final ogExe = File( + join( + cwd.path, + "dist", + pubspec.version.toString(), + "spotube-${pubspec.version}-windows-setup.exe", + ), + ); + + final exePath = join(cwd.path, "dist", "Spotube-windows-x86_64-setup.exe"); + + await ogExe.copy(exePath); + await ogExe.delete(); + + stdout.writeln("✅ Windows exe built at $exePath"); + + final exeFile = File(exePath); + + final hash = sha256.convert(await exeFile.readAsBytes()).toString(); + + final chocoVerificationFile = File(chocoFiles.first); + + chocoVerificationFile.writeAsStringSync( + chocoVerificationFile.readAsStringSync().replaceAll( + RegExp(r"\%\{\{WIN_SHA256\}\}\%"), + hash, + ), + ); + + await exeFile.copy( + join(cwd.path, "choco-struct", "tools", basename(exeFile.path)), + ); + + await shell.run( + "choco pack ${chocoFiles[1]} --outputdirectory ${join(cwd.path, "dist")}", + ); + + final chocoNupkg = File( + join(cwd.path, "dist", "spotube.$versionWithoutBuildNumber.nupkg"), + ); + + final distNupkgPath = join( + cwd.path, + "dist", + "Spotube-windows-x86_64.nupkg", + ); + + await chocoNupkg.copy(distNupkgPath); + await chocoNupkg.delete(); + + stdout.writeln("✅ Windows nupkg built at $distNupkgPath"); + } +} diff --git a/cli/commands/install-dependencies.dart b/cli/commands/install-dependencies.dart new file mode 100644 index 000000000..75df28dfa --- /dev/null +++ b/cli/commands/install-dependencies.dart @@ -0,0 +1,74 @@ +import 'dart:async'; + +import 'package:args/command_runner.dart'; +import 'package:process_run/shell_run.dart'; + +class InstallDependenciesCommand extends Command { + @override + String get description => "Install platform dependencies"; + + @override + String get name => "install-dependencies"; + + InstallDependenciesCommand() { + argParser.addOption( + "platform", + abbr: "p", + allowed: [ + "windows", + "linux", + "linux_arm", + "macos", + "ios", + "android", + ], + mandatory: true, + ); + } + + @override + FutureOr? run() async { + final shell = Shell(); + + switch (argResults!.option("platform")) { + case "windows": + break; + case "linux": + await shell.run( + """ + sudo apt-get update -y + sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev libsecret-1-0 libjsoncpp25 libsecret-1-dev libjsoncpp-dev libnotify-bin libnotify-dev mpv libmpv-dev + """, + ); + break; + case "linux_arm": + await shell.run( + """ + sudo apt-get update -y + sudo apt-get install -y pkg-config make python3-pip python3-setuptools + """, + ); + break; + case "macos": + await shell.run( + """ + brew install python-setuptools + npm install -g appdmg + """, + ); + break; + case "ios": + break; + case "android": + await shell.run( + """ + sudo apt-get update -y + sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse + """, + ); + break; + default: + break; + } + } +} diff --git a/cli/core/env.dart b/cli/core/env.dart new file mode 100644 index 000000000..33cc5df13 --- /dev/null +++ b/cli/core/env.dart @@ -0,0 +1,24 @@ +import 'dart:io'; + +enum BuildChannel { + stable, + nightly; + + factory BuildChannel.fromEnvironment(String name) { + final channel = Platform.environment[name]!; + if (channel == "stable") { + return BuildChannel.stable; + } else if (channel == "nightly") { + return BuildChannel.nightly; + } else { + throw Exception("Invalid channel: $channel"); + } + } +} + +class CliEnv { + static final channel = BuildChannel.fromEnvironment("CHANNEL"); + static final dotenv = Platform.environment["DOTENV"]!; + static final ghRunNumber = Platform.environment["GITHUB_RUN_NUMBER"]; + static final flutterVersion = Platform.environment["FLUTTER_VERSION"]!; +} diff --git a/lib/collections/env.dart b/lib/collections/env.dart index 14f33b806..89a777b64 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -3,6 +3,11 @@ import 'package:spotube/utils/platform.dart'; part 'env.g.dart'; +enum ReleaseChannel { + nightly, + stable, +} + @Envied(obfuscate: true, requireEnvFile: true, path: ".env") abstract class Env { @EnviedField(varName: 'SPOTIFY_SECRETS') @@ -25,6 +30,13 @@ abstract class Env { @EnviedField(varName: 'ENABLE_UPDATE_CHECK', defaultValue: "1") static final String _enableUpdateChecker = _Env._enableUpdateChecker; + @EnviedField(varName: "RELEASE_CHANNEL", defaultValue: "nightly") + static final String _releaseChannel = _Env._releaseChannel; + + static ReleaseChannel get releaseChannel => _releaseChannel == "stable" + ? ReleaseChannel.stable + : ReleaseChannel.nightly; + static bool get enableUpdateChecker => kIsFlatpak || _enableUpdateChecker == "1"; diff --git a/lib/components/root/update_dialog.dart b/lib/components/root/update_dialog.dart index f5388aa1f..e15903c63 100644 --- a/lib/components/root/update_dialog.dart +++ b/lib/components/root/update_dialog.dart @@ -5,18 +5,23 @@ import 'package:version/version.dart'; class RootAppUpdateDialog extends StatelessWidget { final Version? version; - const RootAppUpdateDialog({super.key, this.version}); + final int? nightlyBuildNum; + + const RootAppUpdateDialog({super.key, this.version}) : nightlyBuildNum = null; + const RootAppUpdateDialog.nightly({super.key, required this.nightlyBuildNum}) + : version = null; @override Widget build(BuildContext context) { const url = "https://spotube.krtirtho.dev/downloads"; + const nightlyUrl = "https://spotube.krtirtho.dev/downloads/nightly"; return AlertDialog( title: const Text("Spotube has an update"), actions: [ FilledButton( child: const Text("Download Now"), onPressed: () => launchUrlString( - url, + nightlyBuildNum != null ? nightlyUrl : url, mode: LaunchMode.externalApplication, ), ), @@ -24,21 +29,26 @@ class RootAppUpdateDialog extends StatelessWidget { content: Column( mainAxisSize: MainAxisSize.min, children: [ - Text("Spotube v$version has been released"), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text("Read the latest "), - AnchorButton( - "release notes", - style: const TextStyle(color: Colors.blue), - onTap: () => launchUrlString( - url, - mode: LaunchMode.externalApplication, - ), - ), - ], + Text( + nightlyBuildNum != null + ? "Spotube Nightly $nightlyBuildNum has been released" + : "Spotube v$version has been released", ), + if (nightlyBuildNum == null) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text("Read the latest "), + AnchorButton( + "release notes", + style: const TextStyle(color: Colors.blue), + onTap: () => launchUrlString( + url, + mode: LaunchMode.externalApplication, + ), + ), + ], + ), ], ), ); diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 21b8117b1..505eecb94 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/env.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/links/hyper_link.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; @@ -72,6 +73,13 @@ class AboutSpotube extends HookConsumerWidget { Text("v${packageInfo.version}") ], ), + TableRow( + children: [ + Text(context.l10n.channel), + colon, + Text(Env.releaseChannel.name) + ], + ), TableRow( children: [ Text(context.l10n.build_number), diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index 30c92e1d7..ec3bb0cbf 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -335,35 +335,59 @@ abstract class ServiceUtils { ) async { if (!Env.enableUpdateChecker) return; if (!ref.read(userPreferencesProvider.select((s) => s.checkUpdate))) return; - final packageInfo = await PackageInfo.fromPlatform(); - final value = await http.get( - Uri.parse( - "https://api.github.com/repos/KRTirtho/spotube/releases/latest", - ), - ); - final tagName = - (jsonDecode(value.body)["tag_name"] as String).replaceAll("v", ""); - final currentVersion = packageInfo.version == "Unknown" - ? null - : Version.parse(packageInfo.version); - final latestVersion = tagName == "nightly" ? null : Version.parse(tagName); - - if (currentVersion == null || - latestVersion == null || - (latestVersion.isPreRelease && !currentVersion.isPreRelease) || - (!latestVersion.isPreRelease && currentVersion.isPreRelease)) return; - - if (latestVersion <= currentVersion || !context.mounted) return; - - showDialog( - context: context, - barrierDismissible: true, - barrierColor: Colors.black26, - builder: (context) { - return RootAppUpdateDialog(version: latestVersion); - }, - ); + if (Env.releaseChannel == ReleaseChannel.nightly) { + final value = await http.get( + Uri.parse( + "https://api.github.com/repos/KRTirtho/spotube/actions/workflows/spotube-release-binary.yml/runs?status=success&per_page=1", + ), + ); + + final buildNum = + jsonDecode(value.body)["workflow_runs"][0]["run_number"] as int; + + if (buildNum <= int.parse(packageInfo.buildNumber) || !context.mounted) { + return; + } + + await showDialog( + context: context, + barrierDismissible: true, + barrierColor: Colors.black26, + builder: (context) { + return RootAppUpdateDialog.nightly(nightlyBuildNum: buildNum); + }, + ); + } else { + final value = await http.get( + Uri.parse( + "https://api.github.com/repos/KRTirtho/spotube/releases/latest", + ), + ); + final tagName = + (jsonDecode(value.body)["tag_name"] as String).replaceAll("v", ""); + final currentVersion = packageInfo.version == "Unknown" + ? null + : Version.parse(packageInfo.version); + final latestVersion = + tagName == "nightly" ? null : Version.parse(tagName); + + if (currentVersion == null || + latestVersion == null || + (latestVersion.isPreRelease && !currentVersion.isPreRelease) || + (!latestVersion.isPreRelease && currentVersion.isPreRelease)) return; + + if (latestVersion <= currentVersion || !context.mounted) return; + + showDialog( + context: context, + barrierDismissible: true, + barrierColor: Colors.black26, + builder: (context) { + return RootAppUpdateDialog(version: latestVersion); + }, + ); + } } } diff --git a/pubspec.lock b/pubspec.lock index 1532bcf75..df623b9e1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -45,10 +45,10 @@ packages: dependency: transitive description: name: archive - sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" + sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265 url: "https://pub.dev" source: hosted - version: "3.4.10" + version: "3.5.1" args: dependency: "direct main" description: @@ -1271,7 +1271,7 @@ packages: source: hosted version: "3.1.14" io: - dependency: transitive + dependency: "direct dev" description: name: io sha256: "2ec25704aba361659e10e3e5f5d672068d332fc8ac516421d483a11e5cbd061e" @@ -1702,14 +1702,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.8" - pointycastle: - dependency: transitive - description: - name: pointycastle - sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333" - url: "https://pub.dev" - source: hosted - version: "3.8.0" pool: dependency: transitive description: @@ -1734,6 +1726,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.2" + process_run: + dependency: "direct dev" + description: + name: process_run + sha256: "8d9c6198b98fbbfb511edd42e7364e24d85c163e47398919871b952dc86a423e" + url: "https://pub.dev" + source: hosted + version: "0.14.2" provider: dependency: transitive description: @@ -2462,7 +2462,7 @@ packages: source: hosted version: "1.0.4" xml: - dependency: transitive + dependency: "direct dev" description: name: xml sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 diff --git a/pubspec.yaml b/pubspec.yaml index 62c20c354..7435e077c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -144,6 +144,9 @@ dev_dependencies: freezed: ^2.5.2 custom_lint: ^0.6.4 riverpod_lint: ^2.3.10 + process_run: ^0.14.2 + xml: ^6.5.0 + io: ^1.0.4 dependency_overrides: uuid: ^4.4.0 diff --git a/windows/CMakeLists.txt b/windows/CMakeLists.txt index 6e1e3cb37..0c638eb75 100644 --- a/windows/CMakeLists.txt +++ b/windows/CMakeLists.txt @@ -1,13 +1,16 @@ +# Project-level configuration. cmake_minimum_required(VERSION 3.14) project(spotube LANGUAGES CXX) +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. set(BINARY_NAME "spotube") -cmake_policy(SET CMP0063 NEW) +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Configure build options. +# Define build configuration option. get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) if(IS_MULTICONFIG) set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" @@ -20,7 +23,7 @@ else() "Debug" "Profile" "Release") endif() endif() - +# Define settings for the Profile build mode. set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") @@ -30,6 +33,10 @@ set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") add_definitions(-DUNICODE -D_UNICODE) # Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. function(APPLY_STANDARD_SETTINGS TARGET) target_compile_features(${TARGET} PUBLIC cxx_std_17) target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") @@ -38,14 +45,14 @@ function(APPLY_STANDARD_SETTINGS TARGET) target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") endfunction() -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") - # Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") add_subdirectory(${FLUTTER_MANAGED_DIR}) -# Application build +# Application build; see runner/CMakeLists.txt. add_subdirectory("runner") + # Generated plugin build rules, which manage building the plugins and adding # them to the application. include(flutter/generated_plugins.cmake) @@ -80,6 +87,12 @@ if(PLUGIN_BUNDLED_LIBRARIES) COMPONENT Runtime) endif() +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + # Fully re-copy the assets directory on each build to avoid having stale files # from a previous install. set(FLUTTER_ASSET_DIR_NAME "flutter_assets") diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index e8fccc8a6..0b586d339 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -60,16 +60,16 @@ IDI_APP_ICON ICON "resources\\app_icon.ico" // Version // -#ifdef FLUTTER_BUILD_NUMBER -#define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD #else -#define VERSION_AS_NUMBER 1,0,0 +#define VERSION_AS_NUMBER 1,0,0,0 #endif -#ifdef FLUTTER_BUILD_NAME -#define VERSION_AS_STRING #FLUTTER_BUILD_NAME +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION #else -#define VERSION_AS_STRING "%{{SPOTUBE_VERSION}}%" +#define VERSION_AS_STRING "3.6.0" #endif VS_VERSION_INFO VERSIONINFO @@ -93,7 +93,7 @@ BEGIN VALUE "FileDescription", "Spotube" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" VALUE "InternalName", "spotube" "\0" - VALUE "LegalCopyright", "Copyright (C) 2022 oss.krtirtho. All rights reserved." "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 oss.krtirtho. All rights reserved." "\0" VALUE "OriginalFilename", "spotube.exe" "\0" VALUE "ProductName", "spotube" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0"