diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..2b1dc71 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,331 @@ +name: Build Application + +on: + push: + branches: [ main, master, develop ] + pull_request: + branches: [ main, master ] + workflow_dispatch: + +env: + PYTHON_VERSION: '3.12' + +jobs: + build-windows: + runs-on: windows-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install system dependencies + run: | + choco install ffmpeg -y + + - name: Cache pip dependencies + uses: actions/cache@v3 + with: + path: ~\AppData\Local\pip\Cache + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pyinstaller + + - name: Create .env file + run: | + echo "PLATFORM=desktop" > .env + echo "HOST=127.0.0.1" >> .env + echo "PORT=6006" >> .env + + - name: Build Windows executable + run: | + pyinstaller --noconfirm --onedir --windowed --icon "assets/icon.ico" --name "StreamCap" --add-data "assets;assets/" --add-data "config;config/" --add-data "locales;locales/" --hidden-import "flet.matplotlib_chart" --hidden-import "flet.plotly_chart" --hidden-import "flet.video" --collect-all "streamget" main.py + + - name: Fix Windows pkg + run: | + mv dist/StreamCap/_internal/config dist/StreamCap/ + mv dist/StreamCap/_internal/locales dist/StreamCap/ + mv dist/StreamCap/_internal/assets dist/StreamCap/ + echo "Folders moved successfully." + + - name: Package Windows build + run: | + Compress-Archive -Path "dist/StreamCap/*" -DestinationPath "StreamCap-Windows.zip" + + - name: Upload Windows artifact + uses: actions/upload-artifact@v4 + with: + name: StreamCap-Windows + path: StreamCap-Windows.zip + retention-days: 30 + + build-macos: + runs-on: macos-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install system dependencies + run: | + # Install FFmpeg + brew install ffmpeg + + - name: Cache pip dependencies + uses: actions/cache@v3 + with: + path: ~/Library/Caches/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + pip install pyinstaller + pip install dmgbuild + + - name: Create .env file + run: | + echo "PLATFORM=desktop" > .env + echo "HOST=127.0.0.1" >> .env + echo "PORT=6006" >> .env + + - name: Build macOS executable + run: | + pyinstaller --noconfirm --onedir --windowed --icon "assets/icon.ico" --name "StreamCap" --add-data "assets:assets/" --add-data "config:config/" --add-data "locales:locales/" --hidden-import "flet.matplotlib_chart" --hidden-import "flet.plotly_chart" --hidden-import "flet.video" --collect-all "streamget" main.py + + - name: Create macOS app bundle + run: | + mkdir -p "StreamCap.app/Contents/MacOS" + mkdir -p "StreamCap.app/Contents/Resources" + + # Create Info.plist + cat > "StreamCap.app/Contents/Info.plist" << EOF + + + + + CFBundleExecutable + StreamCap + CFBundleIdentifier + io.github.ihmily.streamcap + CFBundleName + StreamCap + CFBundleVersion + 1.0.1 + CFBundleShortVersionString + 1.0.1 + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleIconFile + icon + LSMinimumSystemVersion + 10.14 + NSHighResolutionCapable + + + + EOF + + # Copy executable and resources + cp -r dist/StreamCap/* "StreamCap.app/Contents/MacOS/" + cp assets/icon.ico "StreamCap.app/Contents/Resources/icon.ico" + + # Make executable + chmod +x "StreamCap.app/Contents/MacOS/StreamCap" + + - name: Create DMG settings file + run: | + cat > dmg_settings.py << EOF + import os + + # DMG settings + format = 'UDZO' + size = '500M' + files = ['StreamCap.app'] + symlinks = {'Applications': '/Applications'} + badge_icon = 'assets/icons/Appicon.icns' + icon_locations = { + 'StreamCap.app': (150, 120), + 'Applications': (350, 120) + } + background = None + window_rect = ((100, 100), (500, 300)) + default_view = 'icon-view' + show_status_bar = False + show_tab_view = False + show_toolbar = False + show_pathbar = False + show_sidebar = False + sidebar_width = 180 + arrange_by = None + grid_offset = (0, 0) + grid_spacing = 100 + scroll_position = (0, 0) + label_pos = 'bottom' + text_size = 16 + icon_size = 128 + EOF + + - name: Create DMG + run: | + dmgbuild -s dmg_settings.py "StreamCap" "StreamCap-macOS.dmg" + + - name: Upload macOS artifact + uses: actions/upload-artifact@v4 + with: + name: StreamCap-macOS + path: StreamCap-macOS.dmg + retention-days: 30 + + build-linux: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: ${{ env.PYTHON_VERSION }} + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y ffmpeg + + - name: Cache pip dependencies + uses: actions/cache@v3 + with: + path: ~/.cache/pip + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + restore-keys: | + ${{ runner.os }}-pip- + + - name: Install Python dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-web.txt + + - name: Create .env file + run: | + echo "PLATFORM=web" > .env + echo "HOST=0.0.0.0" >> .env + echo "PORT=6006" >> .env + + - name: Test web application + run: | + timeout 30s python main.py --web --host 0.0.0.0 --port 6006 || true + + - name: Package Linux build + run: | + mkdir -p ../package + rsync -av --exclude='.git' --exclude='__pycache__' --exclude='*.pyc' --exclude='*.log' --exclude='.pytest_cache' --exclude='node_modules' --exclude='dist' --exclude='build' --exclude='*.egg-info' . ../package/StreamCap/ + cd ../package + tar -czf StreamCap-Linux.tar.gz StreamCap/ + mv StreamCap-Linux.tar.gz $GITHUB_WORKSPACE/ + + - name: Upload Linux artifact + uses: actions/upload-artifact@v4 + with: + name: StreamCap-Linux + path: StreamCap-Linux.tar.gz + retention-days: 30 + + # 这里提供一个输出 + outputs: + linux-artifact-path: ${{ steps.upload-linux-artifact.outputs.artifact-path }} + + prerelease: + needs: [ build-windows, build-macos, build-linux ] + if: github.event_name != 'pull_request' && github.repository == 'lycorisdeve/streamcap' + runs-on: ubuntu-latest + env: + VERSION: ${{ needs.build-windows.outputs.version }} + steps: + - uses: actions/checkout@v4 + + - name: Download Windows artifact + uses: actions/download-artifact@v4 + with: + name: StreamCap-Windows + path: releases/ + + - name: Download macOS artifact + uses: actions/download-artifact@v4 + with: + name: StreamCap-macOS + path: releases/ + + - name: Download Linux artifact + uses: actions/download-artifact@v4 + with: + name: StreamCap-Linux + path: releases/ + + - name: Check and rename files + run: | + # 检查 Windows 文件是否存在并重命名 + if [ -f "releases/StreamCap-Windows.zip" ]; then + mv releases/StreamCap-Windows.zip "StreamCap_Windows_beta.zip" + else + echo "StreamCap-Windows.zip not found!" + fi + + # 检查 macOS 文件是否存在并重命名 + if [ -f "releases/StreamCap-macOS.dmg" ]; then + mv releases/StreamCap-macOS.dmg "StreamCap_macOS_beta.dmg" + else + echo "StreamCap-macOS.dmg not found!" + fi + + # 检查 Linux 文件是否存在并重命名 + if [ -f "releases/StreamCap-Linux.tar.gz" ]; then + mv releases/StreamCap-Linux.tar.gz "StreamCap_Linux_beta.tar.gz" + else + echo "StreamCap-Linux.tar.gz not found!" + fi + + - name: Delete Pre-Release (if exists) + run: | + if gh release view beta &>/dev/null; then + gh release delete beta -y + fi + env: + GH_TOKEN: ${{ github.token }} + + - name: Create or update beta tag + uses: richardsimko/update-tag@v1 + with: + tag_name: beta + env: + GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} + + - name: Publish Pre-Release + uses: ncipollo/release-action@v1 + with: + name: StreamCap-beta + tag: "beta" + body: "此版本为测试版,可能存在不稳定情况,升级前请务必备份好数据。" + prerelease: true + artifacts: ${{ github.workspace }}/*.zip,${{ github.workspace }}/*.dmg,${{ github.workspace }}/*.tar.gz diff --git a/.github/workflows/release-sync.yml b/.github/workflows/release-sync.yml new file mode 100644 index 0000000..39dd48b --- /dev/null +++ b/.github/workflows/release-sync.yml @@ -0,0 +1,60 @@ +name: Sync Releases + +on: + schedule: + - cron: '0 3 * * *' + workflow_dispatch: + +env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + +jobs: + sync-releases: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v3 + + - name: List upstream releases + run: | + gh release list --repo ihmily/StreamCap --limit 100 > upstream.txt + gh release list --limit 100 > my.txt + + - name: Find new releases + id: find_new + run: | + set +e + cut -f1 -d$'\t' upstream.txt | sort > upstream_tags.txt + cut -f1 -d$'\t' my.txt | sort > my_tags.txt + comm -23 upstream_tags.txt my_tags.txt | grep -vE '^\s*$|^-$' > new_releases.txt + echo "new_releases=$(paste -sd ',' new_releases.txt)" >> $GITHUB_OUTPUT + echo "New releases to sync:" + cat new_releases.txt || echo "(none)" + set -e + + - name: Sync new releases + if: steps.find_new.outputs.new_releases != '' + run: | + for tag in $(cat new_releases.txt); do + echo "Sync release $tag" + release_json=$(gh release view "$tag" --repo ihmily/StreamCap --json name,body,isDraft,isPrerelease) + name=$(echo "$release_json" | jq -r '.name') + body=$(echo "$release_json" | jq -r '.body') + draft=$(echo "$release_json" | jq -r '.isDraft') + prerelease=$(echo "$release_json" | jq -r '.isPrerelease') + + mkdir -p downloads + gh release download "$tag" --repo ihmily/StreamCap --dir downloads || echo "No assets" + + if [ "$(ls -A downloads)" ]; then + gh release create "$tag" downloads/* --title "$name" --notes "$body" $( [ "$draft" == "true" ] && echo "--draft" ) $( [ "$prerelease" == "true" ] && echo "--prerelease" ) + else + gh release create "$tag" --title "$name" --notes "$body" $( [ "$draft" == "true" ] && echo "--draft" ) $( [ "$prerelease" == "true" ] && echo "--prerelease" ) + fi + + rm -rf downloads + echo "Release $tag synced" + done + + - name: Finish + run: echo "Releases sync complete"