Skip to content

feat: added export log, added batch panel, and more. #89

feat: added export log, added batch panel, and more.

feat: added export log, added batch panel, and more. #89

Workflow file for this run

name: Build & Release
on:
push:
tags:
- "v*"
permissions:
contents: write
actions: read
jobs:
# Download ffmpeg & yt-dlp
prepare-binaries:
name: Download ffmpeg & yt-dlp
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache binaries
id: cache-bins
uses: actions/cache@v4
with:
path: assets/binaries
key: binaries-${{ hashFiles('scripts/prepare_binaries.py') }}-v1
- name: Download binaries
if: steps.cache-bins.outputs.cache-hit != 'true'
run: python3 scripts/prepare_binaries.py --all
- name: Upload binary artifacts
uses: actions/upload-artifact@v4
with:
name: binaries
path: assets/binaries
retention-days: 1
# Windows
build-windows:
name: Windows
needs: prepare-binaries
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
- name: Download binaries
uses: actions/download-artifact@v4
with:
name: binaries
path: assets/binaries
- name: Set up Flutter
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 (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: Generate app_icon.ico from PNG
shell: pwsh
run: |
magick convert `
assets/icons/icon_256.png `
-define icon:auto-resize=256,128,64,48,32,16 `
windows/runner/resources/app_icon.ico
Write-Host "✓ app_icon.ico generated"
- name: Create Inno Setup script
shell: pwsh
run: |
$version = (Get-Content pubspec.yaml |
Select-String "^version:" |
ForEach-Object { ($_ -replace "version:\s*","") -replace "\+.*","" }).Trim()
@"
[Setup]
AppName=Frame Extractor
AppVersion=$version
AppPublisher=nokarin
AppPublisherURL=https://github.com/nokarin-dev/frameextractor
AppSupportURL=https://github.com/nokarin-dev/frameextractor/issues
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
SetupIconFile=windows\runner\resources\app_icon.ico
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
[Files]
Source: "build\windows\x64\runner\Release\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs
[Icons]
Name: "{userprograms}\Frame Extractor"; Filename: "{app}\frameextractor.exe"
Name: "{userprograms}\Uninstall Frame Extractor"; Filename: "{uninstallexe}"
Name: "{userdesktop}\Frame Extractor"; Filename: "{app}\frameextractor.exe"; Tasks: desktopicon
[Run]
Filename: "{app}\frameextractor.exe"; Description: "{cm:LaunchProgram,Frame Extractor}"; Flags: nowait postinstall skipifsilent
"@ | Out-File -FilePath "installer.iss" -Encoding UTF8
Write-Host "Inno Setup script created for v$version"
- name: Compile 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 built: FrameExtractor-windows-installer.exe"
# Portable
- name: Build Windows (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"
- uses: actions/upload-artifact@v4
with:
name: windows-builds
path: |
FrameExtractor-windows-installer.exe
FrameExtractor-windows-portable.zip
# Linux
build-linux:
name: Linux
needs: prepare-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
- name: Download dummy binaries
uses: actions/download-artifact@v4
with:
name: binaries
path: assets/binaries
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.x"
channel: stable
cache: true
- name: Get Flutter dependencies
run: flutter pub get
# Release build
- name: Build Linux release
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: Get version
run: |
echo "VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //;s/+.*//')" >> $GITHUB_ENV
# deb package
- name: Build .deb package
run: |
PKG="frameextractor_${{ env.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")
if [ "$EXE_NAME" != "frameextractor" ]; then
mv "$EXE" "$PKG/opt/frameextractor/frameextractor"
echo "Renamed $EXE_NAME → frameextractor"
fi
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
GenericName=Video Frame Extractor
Comment=Extract frames from video files using ffmpeg
Exec=/opt/frameextractor/frameextractor
Icon=frameextractor
Categories=Video;AudioVideo;FrameExtraction;FrameExtractor;
Terminal=false
StartupWMClass=frameextractor
DESKTOP
if [ -f "assets/icons/icon_256.png" ]; then
cp "assets/icons/icon_256.png" "$PKG/usr/share/icons/hicolor/256x256/apps/frameextractor.png"
fi
cat > "$PKG/DEBIAN/control" << EOF
Package: frameextractor
Version: ${{ env.VERSION }}
Architecture: amd64
Maintainer: nokarin <contact@nokarin.my.id>
Description: FrameExtractor is a modern, cross-platform video frame extractor with a clean UI built with Flutter, powered by ffmpeg and yt-dlp. Supports local video files and direct YouTube URL extraction.
Depends: libgtk-3-0, libblkid1, liblzma5
Section: video
Priority: optional
Homepage: https://github.com/nokarin-dev/frameextractor
EOF
cat > "$PKG/DEBIAN/postinst" << 'POSTINST'
#!/bin/sh
chmod +x /opt/frameextractor/frameextractor 2>/dev/null || true
chmod +x /opt/frameextractor/bin/ffmpeg 2>/dev/null || true
chmod +x /opt/frameextractor/bin/yt-dlp 2>/dev/null || true
update-desktop-database /usr/share/applications 2>/dev/null || true
exit 0
POSTINST
chmod 755 "$PKG/DEBIAN/postinst"
cat > "$PKG/DEBIAN/postrm" << 'POSTRM'
#!/bin/sh
update-desktop-database /usr/share/applications 2>/dev/null || true
exit 0
POSTRM
chmod 755 "$PKG/DEBIAN/postrm"
fakeroot dpkg-deb --build "$PKG"
mv "$PKG.deb" "FrameExtractor-linux-installer.deb"
echo "✓ .deb built"
dpkg-deb --info "FrameExtractor-linux-installer.deb"
# AppImage
- 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/applications
mkdir -p AppDir/usr/share/icons/hicolor/256x256/apps
cp -r "$BUNDLE/." AppDir/app/
chmod +x AppDir/app/bin/ffmpeg AppDir/app/bin/yt-dlp
if [ -f "assets/icons/icon_256.png" ]; then
cp "assets/icons/icon_256.png" AppDir/usr/share/icons/hicolor/256x256/apps/frameextractor.png
cp "assets/icons/icon_64.png" AppDir/frameextractor.png
else
printf 'PNG' > AppDir/frameextractor.png
fi
cat > AppDir/frameextractor.desktop << 'DESKTOP'
[Desktop Entry]
Version=1.0
Type=Application
Name=FrameExtractor
GenericName=Video Frame Extractor
Comment=Extract frames from video files using ffmpeg
Exec=frameextractor
Icon=frameextractor
Categories=Video;AudioVideo;Development;Utility;
Terminal=false
DESKTOP
# AppRun
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)
if [ -z "$EXE_NAME" ]; then
echo "FrameExtractor: could not find executable in $APPDIR/app/" >&2
exit 1
fi
cd "$APPDIR/app"
exec "./$EXE_NAME" "$@"
APPRUN
chmod +x AppDir/AppRun
ARCH=x86_64 "$APPIMAGETOOL" --no-appstream AppDir "FrameExtractor-linux.AppImage"
chmod +x "FrameExtractor-linux.AppImage"
echo "✓ AppImage built"
# Portable tarball
- name: Build Linux (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 .
- uses: actions/upload-artifact@v4
with:
name: linux-builds
path: |
FrameExtractor-linux-installer.deb
FrameExtractor-linux-installer.rpm
FrameExtractor-linux.AppImage
FrameExtractor-linux-portable.tar.gz
# Linux (RPM)
build-linux-rpm:
name: Linux (RPM)
needs: prepare-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 desktop-file-utils hicolor-icon-theme jq which
- name: Configure Git safe directory
run: |
git config --global --add safe.directory '*'
cat /root/.gitconfig-ci
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.x"
channel: stable
cache: true
- name: Download binaries
uses: actions/download-artifact@v4
with:
name: binaries
path: assets/binaries
- name: Get Flutter dependencies
run: flutter pub get
- name: Get version
run: |
echo "VERSION=$(grep '^version:' pubspec.yaml | sed 's/version: //;s/+.*//')" >> $GITHUB_ENV
- name: Build Linux (release)
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/*
# rpm package
- name: Build .rpm package
run: |
VERSION="${{ env.VERSION }}"
BUNDLE_DIR="$GITHUB_WORKSPACE/build/linux/x64/release/bundle"
RPMROOT="$GITHUB_WORKSPACE/rpmbuild"
mkdir -p "$RPMROOT"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
echo "$BUNDLE_DIR" > "$RPMROOT/SOURCES/bundle_path.txt"
mkdir -p "$RPMROOT/SOURCES"
cat > "$RPMROOT/SOURCES/frameextractor.desktop" << 'DESKTOP'
[Desktop Entry]
Version=1.0
Type=Application
Name=FrameExtractor
Exec=/opt/frameextractor/frameextractor
Icon=frameextractor
Categories=Video;AudioVideo;Development;Utility;
Terminal=false
StartupWMClass=frameextractor
DESKTOP
if [ -f "$GITHUB_WORKSPACE/assets/icons/icon_256.png" ]; then
cp "$GITHUB_WORKSPACE/assets/icons/icon_256.png" \
"$RPMROOT/SOURCES/frameextractor.png"
fi
cat > "$RPMROOT/SPECS/frameextractor.spec" << SPEC
Name: FrameExtractor
Version: ${VERSION}
Release: 1%{?dist}
Summary: Effortless video frame extraction
License: GPLv3
URL: https://github.com/nokarin-dev/frameextractor
BuildArch: x86_64
Requires: gtk3, xz-libs
%description
FrameExtractor is a modern, cross-platform video frame extractor
with a clean UI built with Flutter, powered by ffmpeg and yt-dlp.
Supports local video files and direct YouTube URL 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)
if [ "\$EXE_NAME" != "frameextractor" ]; then
mv "\$EXE" %{buildroot}/opt/frameextractor/frameextractor
fi
chmod +x %{buildroot}/opt/frameextractor/frameextractor
chmod +x %{buildroot}/opt/frameextractor/bin/ffmpeg 2>/dev/null || true
chmod +x %{buildroot}/opt/frameextractor/bin/yt-dlp 2>/dev/null || true
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
%post
chmod +x /opt/frameextractor/frameextractor 2>/dev/null || true
chmod +x /opt/frameextractor/bin/ffmpeg 2>/dev/null || true
chmod +x /opt/frameextractor/bin/yt-dlp 2>/dev/null || true
update-desktop-database /usr/share/applications 2>/dev/null || true
/usr/bin/gtk-update-icon-cache /usr/share/icons/hicolor 2>/dev/null || true
exit 0
%postun
update-desktop-database /usr/share/applications 2>/dev/null || true
/usr/bin/gtk-update-icon-cache /usr/share/icons/hicolor 2>/dev/null || true
exit 0
%files
%attr(0755, root, root) /usr/bin/frameextractor
/opt/frameextractor/*
/usr/share/applications/frameextractor.desktop
/usr/share/icons/hicolor/256x256/apps/frameextractor.png
SPEC
cat "$RPMROOT/SPECS/frameextractor.spec"
rpmbuild -bb \
--define "_topdir $RPMROOT" \
--define "_builddir $RPMROOT/BUILD" \
--define "__os_install_post %{nil}" \
"$RPMROOT/SPECS/frameextractor.spec"
RPM_FILE=$(find "$RPMROOT/RPMS/x86_64" -name "*.rpm" | head -1)
[ -z "$RPM_FILE" ] && echo "✗ RPM not found!" && exit 1
cp "$RPM_FILE" "$GITHUB_WORKSPACE/FrameExtractor-linux-installer.rpm"
echo "✓ RPM built: FrameExtractor-linux-installer.rpm"
rpm -qip "$GITHUB_WORKSPACE/FrameExtractor-linux-installer.rpm"
- uses: actions/upload-artifact@v4
with:
name: linux-rpm-build
path: FrameExtractor-linux-installer.rpm
# Android
build-android:
name: Android
needs: prepare-binaries
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Download binaries
uses: actions/download-artifact@v4
with:
name: binaries
path: assets/binaries
- name: Set up Java
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: "17"
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
flutter-version: "3.x"
channel: stable
cache: true
- name: Get Flutter dependencies
run: flutter pub get
- name: Setup release signing
env:
KEYSTORE_B64: ${{ secrets.KEYSTORE_BASE64 }}
if: env.KEYSTORE_B64 != ''
run: |
echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 -d > android/app/keystore.jks
cat > android/key.properties << EOF
storePassword=${{ secrets.STORE_PASSWORD }}
keyPassword=${{ secrets.KEY_PASSWORD }}
keyAlias=${{ secrets.KEY_ALIAS }}
storeFile=keystore.jks
EOF
echo "SIGNING_CONFIGURED=true" >> $GITHUB_ENV
- name: Build split APKs
run: |
flutter build apk --release --dart-define=PORTABLE=false --split-per-abi
- name: Verify APK signing
if: env.SIGNING_CONFIGURED == 'true'
run: |
for apk in \
build/app/outputs/flutter-apk/app-arm64-v8a-release.apk \
build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk \
build/app/outputs/flutter-apk/app-x86_64-release.apk; do
echo "Verifying $apk..."
$ANDROID_HOME/build-tools/$(ls $ANDROID_HOME/build-tools | tail -1)/apksigner \
verify --verbose "$apk" 2>&1 | grep -E "Verified|error" || true
done
echo "✓ APK signing verified"
- name: Rename APKs
run: |
cp build/app/outputs/flutter-apk/app-arm64-v8a-release.apk FrameExtractor-android-arm64.apk
cp build/app/outputs/flutter-apk/app-armeabi-v7a-release.apk FrameExtractor-android-arm32.apk
cp build/app/outputs/flutter-apk/app-x86_64-release.apk FrameExtractor-android-x86_64.apk
- uses: actions/upload-artifact@v4
with:
name: android-build
path: |
FrameExtractor-android-arm64.apk
FrameExtractor-android-arm32.apk
FrameExtractor-android-x86_64.apk
# Create GitHub Release
release:
name: Create Release
needs: [build-windows, build-linux, build-linux-rpm, build-android]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: dist
pattern: "*-build*"
merge-multiple: true
- name: Generate changelog
run: |
VERSION="${{ github.ref_name }}"
VERSION_BARE="${VERSION#v}"
SECTION=$(awk \
"/^## \[$VERSION_BARE\]/{found=1; next} found && /^## \[/{exit} found{print}" \
changelog.md)
if [ -z "$SECTION" ]; then
PREV_TAG=$(git tag --sort=-version:refname | sed -n '2p')
if [ -z "$PREV_TAG" ]; then
SECTION=$(git log --oneline --no-decorate | head -20)
else
SECTION=$(git log --oneline --no-decorate ${PREV_TAG}..HEAD)
fi
fi
echo "CHANGELOG<<EOF" >> $GITHUB_ENV
echo "$SECTION" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: "Frame Extractor ${{ github.ref_name }}"
body: |
<img width="1536" height="100" alt="Changelog" src="https://github.com/user-attachments/assets/9e9b3837-cfbc-4b17-8dfd-03deae7c67c5" />
${{ env.CHANGELOG }}
---
<img width="1536" height="100" alt="Downloads" src="https://github.com/user-attachments/assets/fdc58dff-3ba3-4b2a-98aa-d2992f02c1c0" />
## Downloads
### Windows
[![Windows-Installer](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-windows-installer.exe?displayAssetName=true&style=for-the-badge&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA40lEQVR4nO3RgQkAIRDAsNt%2FaX8HebBKMkGhMwAAADErbi7vNeQwQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMeW0IAOxacXN5ryGHGRJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjyGtDAAAA5l8fzPuhzmfqIykAAAAASUVORK5CYII%3D&label=%20&color=blue)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-windows-installer.exe) [![Windows-Portable](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-windows-portable.zip?displayAssetName=true&style=for-the-badge&logo=data%3Aimage%2Fpng%3Bbase64%2CiVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA40lEQVR4nO3RgQkAIRDAsNt%2FaX8HebBKMkGhMwAAADErbi7vNeQwQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMiTEkxpAYQ2IMeW0IAOxacXN5ryGHGRJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjSIwhMYbEGBJjyGtDAAAA5l8fzPuhzmfqIykAAAAASUVORK5CYII%3D&label=%20&color=blue)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-windows-portable.zip)
### Linux
[![Linux-Debian](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-linux-installer.deb?displayAssetName=true&style=for-the-badge&logo=linux&logoColor=white&label=%20&color=e07334)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-linux-installer.deb) [![Linux-RPM](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-linux-installer.rpm?displayAssetName=true&style=for-the-badge&logo=linux&logoColor=white&label=%20&color=e07334)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-linux-installer.rpm) [![Linux-AppImage](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-linux.AppImage?displayAssetName=true&style=for-the-badge&logo=linux&logoColor=white&label=%20&color=e07334)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-linux.AppImage) [![Linux-Portable](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-linux-portable.tar.gz?displayAssetName=true&style=for-the-badge&logo=linux&logoColor=white&label=%20&color=e07334)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-linux-portable.tar.gz)
### Android
[![Android-ARM64](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-android-arm64.apk?displayAssetName=true&style=for-the-badge&logo=android&logoColor=white&label=%20&color=dark-green)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-android-arm64.apk) [![Android-ARM32](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-android-arm32.apk?displayAssetName=true&style=for-the-badge&logo=android&logoColor=white&label=%20&color=dark-green)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-android-arm32.apk) [![Android-X86_64](https://img.shields.io/github/downloads/nokarin-dev/frameextractor/${{ github.ref_name }}/FrameExtractor-android-x86_64.apk?displayAssetName=true&style=for-the-badge&logo=android&logoColor=white&label=%20&color=dark-green)](https://github.com/nokarin-dev/FrameExtractor/releases/download/${{ github.ref_name }}/FrameExtractor-android-x86_64.apk)
draft: false
prerelease: ${{ contains(github.ref_name, '-') }}
files: |
dist/FrameExtractor-windows-installer.exe
dist/FrameExtractor-windows-portable.zip
dist/FrameExtractor-linux-installer.deb
dist/FrameExtractor-linux-installer.rpm
dist/FrameExtractor-linux.AppImage
dist/FrameExtractor-linux-portable.tar.gz
dist/FrameExtractor-android-arm64.apk
dist/FrameExtractor-android-arm32.apk
dist/FrameExtractor-android-x86_64.apk
fail_on_unmatched_files: false
token: ${{ secrets.GITHUB_TOKEN }}