iCourse Check #127
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: iCourse Check | |
| on: | |
| schedule: | |
| # Every day at 19:36 BTC (UTC + 8) | |
| # 设计这个奇怪的时间是为了避免整点时的github队列峰值,避免排队过久。 | |
| - cron: "36 11 * * *" | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 360 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Set up Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Cache Python packages | |
| id: cache-pip | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.pythonLocation }}/lib/python*/site-packages | |
| key: pip-${{ hashFiles('requirements.txt') }} | |
| - name: Install Python dependencies | |
| if: steps.cache-pip.outputs.cache-hit != 'true' | |
| run: pip install -r requirements.txt | |
| - name: Install ffmpeg | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y ffmpeg | |
| - name: Cache ASR models | |
| id: cache-models | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17/ | |
| silero_vad.onnx | |
| key: asr-models-sensevoice-2024-07-17 | |
| - name: Download ASR models | |
| if: steps.cache-models.outputs.cache-hit != 'true' | |
| run: | | |
| wget -q https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2 | |
| tar xf sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2 | |
| rm sherpa-onnx-sense-voice-zh-en-ja-ko-yue-2024-07-17.tar.bz2 | |
| wget -q https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/silero_vad.onnx | |
| - name: Fetch database from data branch | |
| run: | | |
| mkdir -p data | |
| # Try new compressed format first, then fall back to legacy | |
| if curl -fL -o data/icourse.db.gz.enc.tmp \ | |
| "https://raw.githubusercontent.com/${{ github.repository }}/data/data/icourse.db.gz.enc" 2>/dev/null; then | |
| mv data/icourse.db.gz.enc.tmp data/icourse.db.gz.enc | |
| echo "Loaded compressed database from data branch." | |
| elif curl -fL -o data/icourse.db.enc.tmp \ | |
| "https://raw.githubusercontent.com/${{ github.repository }}/data/data/icourse.db.enc" 2>/dev/null; then | |
| mv data/icourse.db.enc.tmp data/icourse.db.enc | |
| echo "Loaded legacy (uncompressed) database from data branch." | |
| else | |
| echo "No database found on data branch, starting fresh." | |
| fi | |
| - name: Decrypt database | |
| if: hashFiles('data/icourse.db.gz.enc') != '' || hashFiles('data/icourse.db.enc') != '' | |
| env: | |
| DB_KEY: ${{ secrets.STUID }}${{ secrets.UISPSW }}${{ secrets.DASHSCOPE_API_KEY }}${{ secrets.SMTP_PASSWORD }} | |
| run: | | |
| if [ -f data/icourse.db.gz.enc ]; then | |
| # New format: decrypt then decompress | |
| if openssl enc -aes-256-cbc -d -pbkdf2 \ | |
| -in data/icourse.db.gz.enc -out data/icourse.db.gz \ | |
| -pass env:DB_KEY 2>/dev/null && \ | |
| gzip -d data/icourse.db.gz; then | |
| echo "Database decrypted and decompressed." | |
| else | |
| echo "::warning::Decryption failed. Starting with fresh database." | |
| rm -f data/icourse.db data/icourse.db.gz | |
| fi | |
| elif [ -f data/icourse.db.enc ]; then | |
| # Legacy format: decrypt only | |
| if openssl enc -aes-256-cbc -d -pbkdf2 \ | |
| -in data/icourse.db.enc -out data/icourse.db \ | |
| -pass env:DB_KEY 2>/dev/null; then | |
| echo "Database decrypted (legacy format)." | |
| else | |
| echo "::warning::Decryption failed. Starting with fresh database." | |
| rm -f data/icourse.db | |
| fi | |
| fi | |
| - name: Record database state | |
| id: db-before | |
| run: | | |
| if [ -f data/icourse.db ]; then | |
| echo "hash=$(md5sum data/icourse.db | cut -d' ' -f1)" >> $GITHUB_OUTPUT | |
| else | |
| echo "hash=none" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Run | |
| timeout-minutes: 350 | |
| env: | |
| StuId: ${{ secrets.STUID }} | |
| UISPsw: ${{ secrets.UISPSW }} | |
| COURSE_IDS: ${{ secrets.COURSE_IDS }} | |
| DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }} | |
| GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }} | |
| SMTP_EMAIL: ${{ secrets.SMTP_EMAIL }} | |
| SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }} | |
| RECEIVER_EMAIL: ${{ secrets.RECEIVER_EMAIL }} | |
| run: python -u main.py | |
| - name: Deploy database to data branch | |
| if: always() | |
| env: | |
| DB_KEY: ${{ secrets.STUID }}${{ secrets.UISPSW }}${{ secrets.DASHSCOPE_API_KEY }}${{ secrets.SMTP_PASSWORD }} | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| if [ ! -f data/icourse.db ]; then | |
| echo "No database file, skipping." | |
| exit 0 | |
| fi | |
| AFTER=$(md5sum data/icourse.db | cut -d' ' -f1) | |
| if [ "$AFTER" = "${{ steps.db-before.outputs.hash }}" ]; then | |
| echo "Database unchanged, skipping commit." | |
| exit 0 | |
| fi | |
| # Re-fetch latest remote DB (may have been updated by concurrent workflow) | |
| DEPLOY_DB=data/icourse.db | |
| git fetch origin data --depth=1 2>/dev/null || echo "No data branch yet." | |
| if git rev-parse origin/data >/dev/null 2>&1; then | |
| # Try new compressed format, then legacy | |
| git show origin/data:data/icourse.db.gz.enc > data/remote.gz.enc 2>/dev/null || true | |
| git show origin/data:data/icourse.db.enc > data/remote.enc 2>/dev/null || true | |
| # Remove empty files from failed git show | |
| find data -name 'remote.*' -empty -delete 2>/dev/null || true | |
| if [ -s data/remote.gz.enc ] && \ | |
| openssl enc -aes-256-cbc -d -pbkdf2 \ | |
| -in data/remote.gz.enc -out data/remote.db.gz \ | |
| -pass env:DB_KEY 2>/dev/null && \ | |
| gzip -d data/remote.db.gz; then | |
| echo "Merging local changes into latest remote database..." | |
| python scripts/merge_db.py data/icourse.db data/remote.db | |
| DEPLOY_DB=data/remote.db | |
| elif [ -s data/remote.enc ] && \ | |
| openssl enc -aes-256-cbc -d -pbkdf2 \ | |
| -in data/remote.enc -out data/remote.db \ | |
| -pass env:DB_KEY 2>/dev/null; then | |
| echo "Merging local changes into latest remote database (legacy)..." | |
| python scripts/merge_db.py data/icourse.db data/remote.db | |
| DEPLOY_DB=data/remote.db | |
| fi | |
| fi | |
| # Compress then encrypt (new format) | |
| gzip -c "$DEPLOY_DB" > data/icourse.db.gz | |
| openssl enc -aes-256-cbc -salt -pbkdf2 \ | |
| -in data/icourse.db.gz -out data/icourse.db.gz.enc \ | |
| -pass env:DB_KEY | |
| echo "Deploying to data branch..." | |
| mkdir -p /tmp/db_deploy/data | |
| cp data/icourse.db.gz.enc /tmp/db_deploy/data/ | |
| cd /tmp/db_deploy | |
| git init | |
| git checkout -b data | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add data/icourse.db.gz.enc | |
| git commit -m "chore: update encrypted database" | |
| git push --force "https://${{ github.actor }}:${GITHUB_TOKEN}@github.com/${{ github.repository }}.git" data |