wrong yt-dlp path #88
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Test | |
| on: | |
| push: | |
| branches: | |
| - flutter | |
| paths-ignore: | |
| - "**.md" | |
| - ".gitignore" | |
| - "LICENSE" | |
| pull_request: | |
| branches: | |
| - flutter | |
| paths-ignore: | |
| - "**.md" | |
| - ".gitignore" | |
| - "LICENSE" | |
| permissions: | |
| contents: read | |
| checks: write | |
| pull-requests: write | |
| jobs: | |
| analyze: | |
| name: Analyze & Test | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: "3.x" | |
| channel: stable | |
| cache: true | |
| - name: Install dependencies | |
| run: flutter pub get | |
| - name: Dart analyze | |
| run: flutter analyze --no-fatal-infos | |
| - name: Run unit tests | |
| run: flutter test --reporter=github | |
| continue-on-error: true | |
| prepare-dummy-binaries: | |
| name: Prepare dummy binaries | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Create dummy binary placeholders | |
| run: | | |
| mkdir -p assets/binaries/windows | |
| mkdir -p assets/binaries/linux | |
| mkdir -p assets/binaries/android/arm64-v8a | |
| mkdir -p assets/binaries/android/armeabi-v7a | |
| mkdir -p assets/binaries/android/x86_64 | |
| # Windows | |
| printf '\x4D\x5A' > assets/binaries/windows/ffmpeg.exe | |
| printf '\x4D\x5A' > assets/binaries/windows/ffprobe.exe | |
| printf '\x4D\x5A' > assets/binaries/windows/yt-dlp.exe | |
| # Linux | |
| printf '\x7fELF' > assets/binaries/linux/ffmpeg | |
| printf '\x7fELF' > assets/binaries/linux/ffprobe | |
| printf '\x7fELF' > assets/binaries/linux/yt-dlp | |
| chmod +x assets/binaries/linux/* | |
| # Android | |
| printf '\x7fELF' > assets/binaries/android/arm64-v8a/yt-dlp | |
| printf '\x7fELF' > assets/binaries/android/armeabi-v7a/yt-dlp | |
| printf '\x7fELF' > assets/binaries/android/x86_64/yt-dlp | |
| find assets/binaries -type f | sort | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: dummy-binaries | |
| path: assets/binaries | |
| retention-days: 1 | |
| # Linux | |
| test-linux: | |
| name: Build Test — Linux (deb + AppImage + portable) | |
| needs: [analyze, prepare-dummy-binaries] | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install system dependencies | |
| run: | | |
| sudo apt-get update -y | |
| sudo apt-get install -y \ | |
| clang cmake ninja-build pkg-config \ | |
| libgtk-3-dev liblzma-dev libstdc++-12-dev \ | |
| dpkg-dev fakeroot wget file | |
| - name: Download dummy binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dummy-binaries | |
| path: assets/binaries | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: "3.x" | |
| channel: stable | |
| cache: true | |
| - name: Get Flutter dependencies | |
| run: flutter pub get | |
| # Installer (deb) | |
| - name: Build Linux release (installer) | |
| run: flutter build linux --release --dart-define=PORTABLE=false | |
| - name: Inject binaries | |
| run: | | |
| mkdir -p build/linux/x64/release/bundle/bin | |
| cp assets/binaries/linux/ffmpeg build/linux/x64/release/bundle/bin/ | |
| cp assets/binaries/linux/yt-dlp build/linux/x64/release/bundle/bin/ | |
| chmod +x build/linux/x64/release/bundle/bin/* | |
| - name: Build .deb package | |
| run: | | |
| VERSION="0.0.0-test" | |
| PKG="frameextractor_${VERSION}_amd64" | |
| BUNDLE="build/linux/x64/release/bundle" | |
| mkdir -p "$PKG/DEBIAN" | |
| mkdir -p "$PKG/opt/frameextractor" | |
| mkdir -p "$PKG/usr/bin" | |
| mkdir -p "$PKG/usr/share/applications" | |
| mkdir -p "$PKG/usr/share/icons/hicolor/256x256/apps" | |
| cp -r "$BUNDLE/." "$PKG/opt/frameextractor/" | |
| EXE=$(find "$PKG/opt/frameextractor" -maxdepth 1 -type f ! -name "*.so" ! -name "*.desktop" | head -1) | |
| EXE_NAME=$(basename "$EXE") | |
| [ "$EXE_NAME" != "frameextractor" ] && mv "$EXE" "$PKG/opt/frameextractor/frameextractor" | |
| ln -s /opt/frameextractor/frameextractor "$PKG/usr/bin/frameextractor" | |
| cat > "$PKG/usr/share/applications/frameextractor.desktop" << 'DESKTOP' | |
| [Desktop Entry] | |
| Version=1.0 | |
| Type=Application | |
| Name=FrameExtractor | |
| Exec=/opt/frameextractor/frameextractor | |
| Icon=frameextractor | |
| Categories=Video;AudioVideo; | |
| Terminal=false | |
| DESKTOP | |
| [ -f "assets/icons/icon_256.png" ] && \ | |
| cp "assets/icons/icon_256.png" "$PKG/usr/share/icons/hicolor/256x256/apps/frameextractor.png" | |
| cat > "$PKG/DEBIAN/control" << CTRL | |
| Package: frameextractor | |
| Version: ${VERSION} | |
| Architecture: amd64 | |
| Maintainer: nokarin <contact@nokarin.my.id> | |
| Description: Effortless video frame extraction | |
| Depends: libgtk-3-0, libblkid1, liblzma5 | |
| Section: video | |
| Priority: optional | |
| CTRL | |
| printf '#!/bin/sh\nchmod +x /opt/frameextractor/frameextractor 2>/dev/null||true\nexit 0' \ | |
| > "$PKG/DEBIAN/postinst" | |
| chmod 755 "$PKG/DEBIAN/postinst" | |
| fakeroot dpkg-deb --build "$PKG" | |
| echo "✓ .deb built: $(du -h ${PKG}.deb | cut -f1)" | |
| dpkg-deb --info "${PKG}.deb" | |
| - name: Build .AppImage | |
| run: | | |
| BUNDLE="build/linux/x64/release/bundle" | |
| wget -q "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage" \ | |
| -O /tmp/appimagetool.AppImage | |
| chmod +x /tmp/appimagetool.AppImage | |
| cd /tmp && ./appimagetool.AppImage --appimage-extract > /dev/null 2>&1 | |
| APPIMAGETOOL="/tmp/squashfs-root/AppRun" | |
| cd "$GITHUB_WORKSPACE" | |
| mkdir -p AppDir/app | |
| mkdir -p AppDir/usr/share/icons/hicolor/256x256/apps | |
| cp -r "$BUNDLE/." AppDir/app/ | |
| [ -f "assets/icons/icon_256.png" ] \ | |
| && cp "assets/icons/icon_256.png" AppDir/usr/share/icons/hicolor/256x256/apps/frameextractor.png \ | |
| && cp "assets/icons/icon_64.png" AppDir/frameextractor.png \ | |
| || printf 'PNG' > AppDir/frameextractor.png | |
| cat > AppDir/frameextractor.desktop << 'DESKTOP' | |
| [Desktop Entry] | |
| Type=Application | |
| Name=FrameExtractor | |
| Exec=frameextractor | |
| Icon=frameextractor | |
| Categories=Video;AudioVideo; | |
| Terminal=false | |
| DESKTOP | |
| cat > AppDir/AppRun << 'APPRUN' | |
| #!/bin/sh | |
| APPDIR="$(dirname "$(readlink -f "$0")")" | |
| export PATH="$APPDIR/app/bin:$PATH" | |
| export LD_LIBRARY_PATH="$APPDIR/app/lib:$LD_LIBRARY_PATH" | |
| EXE_NAME=$(find "$APPDIR/app" -maxdepth 1 -type f ! -name "*.so" ! -name "*.desktop" \ | |
| | xargs -I{} basename {} | head -1) | |
| [ -z "$EXE_NAME" ] && echo "Executable not found" >&2 && exit 1 | |
| cd "$APPDIR/app" | |
| exec "./$EXE_NAME" "$@" | |
| APPRUN | |
| chmod +x AppDir/AppRun | |
| ARCH=x86_64 "$APPIMAGETOOL" --no-appstream AppDir "FrameExtractor-linux.AppImage" | |
| echo "✓ AppImage built: $(du -h FrameExtractor-linux.AppImage | cut -f1)" | |
| # Portable | |
| - name: Build Linux release (portable) | |
| run: flutter build linux --release --dart-define=PORTABLE=true | |
| - name: Inject binaries (portable) | |
| run: | | |
| mkdir -p build/linux/x64/release/bundle/bin | |
| cp assets/binaries/linux/ffmpeg build/linux/x64/release/bundle/bin/ | |
| cp assets/binaries/linux/yt-dlp build/linux/x64/release/bundle/bin/ | |
| chmod +x build/linux/x64/release/bundle/bin/* | |
| - name: Package portable (.tar.gz) | |
| run: | | |
| tar -czf FrameExtractor-linux-portable.tar.gz \ | |
| -C build/linux/x64/release/bundle . | |
| echo "✓ portable tarball: $(du -h FrameExtractor-linux-portable.tar.gz | cut -f1)" | |
| - name: Verify all Linux artifacts | |
| run: | | |
| echo "=== Linux build artifacts ===" | |
| ls -lh frameextractor_*_amd64.deb FrameExtractor-linux.AppImage FrameExtractor-linux-portable.tar.gz | |
| echo "✓ All Linux builds OK" | |
| # Linux (RPM) | |
| test-linux-rpm: | |
| name: Build Test — Linux (RPM) | |
| needs: [analyze, prepare-dummy-binaries] | |
| runs-on: ubuntu-latest | |
| container: | |
| image: fedora:latest | |
| env: | |
| GIT_CONFIG_GLOBAL: /root/.gitconfig-ci | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install build dependencies | |
| run: | | |
| sudo dnf install -y @development-tools \ | |
| clang cmake ninja-build pkg-config \ | |
| gtk3-devel xz-devel libstdc++-devel \ | |
| rpm-build jq which | |
| - name: Configure Git safe directory | |
| run: | | |
| git config --global --add safe.directory '*' | |
| - name: Download dummy binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dummy-binaries | |
| path: assets/binaries | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: "3.x" | |
| channel: stable | |
| cache: true | |
| - name: Get Flutter dependencies | |
| run: flutter pub get | |
| - name: Build Linux (debug) | |
| run: flutter build linux --debug --dart-define=PORTABLE=false | |
| - name: Inject binaries | |
| run: | | |
| mkdir -p build/linux/x64/debug/bundle/bin | |
| cp assets/binaries/linux/ffmpeg build/linux/x64/debug/bundle/bin/ | |
| cp assets/binaries/linux/yt-dlp build/linux/x64/debug/bundle/bin/ | |
| chmod +x build/linux/x64/debug/bundle/bin/* | |
| - name: Build .rpm package | |
| run: | | |
| VERSION="0.0.0" | |
| BUNDLE_DIR="$GITHUB_WORKSPACE/build/linux/x64/debug/bundle" | |
| RPMROOT="$GITHUB_WORKSPACE/rpmbuild" | |
| mkdir -p "$RPMROOT"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} | |
| echo "$BUNDLE_DIR" > "$RPMROOT/SOURCES/bundle_path.txt" | |
| [ -f "$GITHUB_WORKSPACE/assets/icons/icon_256.png" ] && \ | |
| cp "$GITHUB_WORKSPACE/assets/icons/icon_256.png" "$RPMROOT/SOURCES/frameextractor.png" | |
| cat > "$RPMROOT/SOURCES/frameextractor.desktop" << 'DESKTOP' | |
| [Desktop Entry] | |
| Type=Application | |
| Name=FrameExtractor | |
| Exec=/opt/frameextractor/frameextractor | |
| Icon=frameextractor | |
| Categories=Video;AudioVideo; | |
| Terminal=false | |
| DESKTOP | |
| cat > "$RPMROOT/SPECS/frameextractor.spec" << SPEC | |
| Name: FrameExtractor | |
| Version: ${VERSION} | |
| Release: 1%{?dist} | |
| Summary: Effortless video frame extraction | |
| License: GPLv3 | |
| BuildArch: x86_64 | |
| Requires: gtk3, xz-libs | |
| %description | |
| FrameExtractor — effortless video frame extraction. | |
| %install | |
| BUNDLE=\$(cat $RPMROOT/SOURCES/bundle_path.txt) | |
| mkdir -p %{buildroot}/opt/frameextractor | |
| mkdir -p %{buildroot}/usr/bin | |
| mkdir -p %{buildroot}/usr/share/applications | |
| mkdir -p %{buildroot}/usr/share/icons/hicolor/256x256/apps | |
| cp -r \$BUNDLE/. %{buildroot}/opt/frameextractor/ | |
| EXE=\$(find %{buildroot}/opt/frameextractor -maxdepth 1 -type f ! -name "*.so" ! -name "*.desktop" | head -1) | |
| EXE_NAME=\$(basename \$EXE) | |
| [ "\$EXE_NAME" != "frameextractor" ] && \ | |
| mv "\$EXE" %{buildroot}/opt/frameextractor/frameextractor | |
| chmod +x %{buildroot}/opt/frameextractor/frameextractor | |
| ln -s /opt/frameextractor/frameextractor %{buildroot}/usr/bin/frameextractor | |
| cp $RPMROOT/SOURCES/frameextractor.desktop \ | |
| %{buildroot}/usr/share/applications/frameextractor.desktop | |
| if [ -f "$RPMROOT/SOURCES/frameextractor.png" ]; then | |
| cp $RPMROOT/SOURCES/frameextractor.png \ | |
| %{buildroot}/usr/share/icons/hicolor/256x256/apps/frameextractor.png | |
| fi | |
| %files | |
| %attr(0755, root, root) /usr/bin/frameextractor | |
| /opt/frameextractor/* | |
| /usr/share/applications/frameextractor.desktop | |
| /usr/share/icons/hicolor/256x256/apps/frameextractor.png | |
| SPEC | |
| rpmbuild -bb \ | |
| --define "_topdir $RPMROOT" \ | |
| --define "_builddir $RPMROOT/BUILD" \ | |
| --define "__os_install_post %{nil}" \ | |
| "$RPMROOT/SPECS/frameextractor.spec" | |
| - name: Verify RPM | |
| run: | | |
| find $GITHUB_WORKSPACE/rpmbuild/RPMS -name "*.rpm" | grep . \ | |
| && echo "✓ RPM build OK" \ | |
| || (echo "✗ RPM not found" && exit 1) | |
| # Windows | |
| test-windows: | |
| name: Build Test — Windows (installer + portable) | |
| needs: [analyze, prepare-dummy-binaries] | |
| runs-on: windows-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download dummy binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dummy-binaries | |
| path: assets/binaries | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: "3.x" | |
| channel: stable | |
| cache: true | |
| - name: Get Flutter dependencies | |
| run: flutter pub get | |
| # Installer | |
| - name: Build Windows release (installer) | |
| run: flutter build windows --release --dart-define=PORTABLE=false | |
| - name: Inject binaries — installer | |
| shell: pwsh | |
| run: | | |
| $dest = "build\windows\x64\runner\Release\bin" | |
| New-Item -ItemType Directory -Force -Path $dest | Out-Null | |
| Copy-Item "assets\binaries\windows\ffmpeg.exe" $dest | |
| Copy-Item "assets\binaries\windows\yt-dlp.exe" $dest | |
| - name: Create Inno Setup script | |
| shell: pwsh | |
| run: | | |
| @" | |
| [Setup] | |
| AppName=Frame Extractor | |
| AppVersion=0.0.0-test | |
| AppPublisher=nokarin | |
| DefaultDirName={localappdata}\FrameExtractor | |
| DefaultGroupName=FrameExtractor | |
| AllowNoIcons=yes | |
| OutputDir=. | |
| OutputBaseFilename=FrameExtractor-windows-installer | |
| Compression=lzma2/ultra64 | |
| SolidCompression=yes | |
| WizardStyle=modern | |
| PrivilegesRequired=lowest | |
| PrivilegesRequiredOverridesAllowed=dialog | |
| UninstallDisplayIcon={app}\frameextractor.exe | |
| [Languages] | |
| Name: "english"; MessagesFile: "compiler:Default.isl" | |
| [Files] | |
| Source: "build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs | |
| [Icons] | |
| Name: "{userprograms}\Frame Extractor"; Filename: "{app}\frameextractor.exe" | |
| "@ | Out-File -FilePath "installer.iss" -Encoding UTF8 | |
| - name: Compile Inno Setup installer | |
| shell: pwsh | |
| run: | | |
| & "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "installer.iss" | |
| if (!(Test-Path "FrameExtractor-windows-installer.exe")) { | |
| Write-Error "Installer .exe not produced"; exit 1 | |
| } | |
| Write-Host "✓ Installer: $('{0:N1} MB' -f ((Get-Item 'FrameExtractor-windows-installer.exe').Length / 1MB))" | |
| # Portable | |
| - name: Build Windows release (portable) | |
| run: flutter build windows --release --dart-define=PORTABLE=true | |
| - name: Inject binaries — portable | |
| shell: pwsh | |
| run: | | |
| $dest = "build\windows\x64\runner\Release\bin" | |
| New-Item -ItemType Directory -Force -Path $dest | Out-Null | |
| Copy-Item "assets\binaries\windows\ffmpeg.exe" $dest | |
| Copy-Item "assets\binaries\windows\yt-dlp.exe" $dest | |
| - name: Package Windows portable | |
| shell: pwsh | |
| run: | | |
| Compress-Archive -Path "build\windows\x64\runner\Release\*" ` | |
| -DestinationPath "FrameExtractor-windows-portable.zip" | |
| Write-Host "✓ Portable: $('{0:N1} MB' -f ((Get-Item 'FrameExtractor-windows-portable.zip').Length / 1MB))" | |
| - name: Verify Windows artifacts | |
| shell: pwsh | |
| run: | | |
| $ok = $true | |
| @("FrameExtractor-windows-installer.exe", "FrameExtractor-windows-portable.zip") | ForEach-Object { | |
| if (Test-Path $_) { Write-Host "✓ $_" } | |
| else { Write-Error "✗ $_ missing"; $ok = $false } | |
| } | |
| if (!$ok) { exit 1 } | |
| # Android | |
| test-android: | |
| name: Build Test — Android (arm64 & arm32 & x86_64) | |
| needs: [analyze, prepare-dummy-binaries] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download dummy binaries | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: dummy-binaries | |
| path: assets/binaries | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "17" | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| flutter-version: "3.x" | |
| channel: stable | |
| cache: true | |
| - name: Get Flutter dependencies | |
| run: flutter pub get | |
| - name: Build split APKs (debug) | |
| run: flutter build apk --debug --dart-define=PORTABLE=false --split-per-abi | |
| - name: Verify all three APK ABIs | |
| run: | | |
| ok=true | |
| for abi in arm64-v8a armeabi-v7a x86_64; do | |
| APK="build/app/outputs/flutter-apk/app-${abi}-debug.apk" | |
| if [ -f "$APK" ]; then | |
| echo "✓ $abi — $(du -h $APK | cut -f1)" | |
| else | |
| echo "✗ $abi — NOT FOUND" | |
| ok=false | |
| fi | |
| done | |
| $ok || exit 1 | |
| # Gate | |
| all-tests-pass: | |
| name: All build tests passed | |
| needs: [analyze, test-linux, test-linux-rpm, test-windows, test-android] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - name: Check all jobs | |
| run: | | |
| echo "analyze: ${{ needs.analyze.result }}" | |
| echo "test-linux: ${{ needs.test-linux.result }}" | |
| echo "test-linux-rpm: ${{ needs.test-linux-rpm.result }}" | |
| echo "test-windows: ${{ needs.test-windows.result }}" | |
| echo "test-android: ${{ needs.test-android.result }}" | |
| if [[ \ | |
| "${{ needs.analyze.result }}" == "success" && \ | |
| "${{ needs.test-linux.result }}" == "success" && \ | |
| "${{ needs.test-linux-rpm.result }}" == "success" && \ | |
| "${{ needs.test-windows.result }}" == "success" && \ | |
| "${{ needs.test-android.result }}" == "success" \ | |
| ]]; then | |
| echo "✅ All build tests passed." | |
| else | |
| echo "❌ One or more build tests failed." | |
| exit 1 | |
| fi |