Export Course Summaries #41
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: Export Course Summaries | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| course_id: | |
| description: "Course ID(s) to export, comma-separated (e.g. 30004 or 30004,30005)" | |
| required: true | |
| type: string | |
| export_type: | |
| description: "Choose export type,if use HTML email,there will be no attachment, just the email body." | |
| type: choice | |
| options: | |
| - HTML | |
| - Markdown | |
| default: 'HTML' | |
| sub_ids: | |
| description: "Optional comma-separated lecture sub_ids to filter (default: all summarized lectures)" | |
| required: false | |
| type: string | |
| default: "" | |
| permissions: | |
| contents: read | |
| jobs: | |
| export: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| 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 PDF dependencies | |
| if: inputs.export_type == 'PDF' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y fonts-noto-cjk libpango-1.0-0 libcairo2 | |
| pip install weasyprint pygments | |
| sudo mkdir -p /usr/local/share/fonts/custom | |
| sudo cp assets/MSYH.TTC /usr/local/share/fonts/custom/ | |
| sudo cp assets/MSYHBD.TTC /usr/local/share/fonts/custom/ | |
| sudo cp assets/MSYHL.TTC /usr/local/share/fonts/custom/ | |
| sudo fc-cache -fv | |
| - name: Fetch database from data branch | |
| run: | | |
| mkdir -p data | |
| git fetch origin data --depth=1 | |
| if git cat-file -e origin/data:data/icourse-index.enc 2>/dev/null; then | |
| mkdir -p data/sharded/shards | |
| git show origin/data:data/icourse-index.enc > data/sharded/icourse-index.enc | |
| shard_paths=$(git ls-tree -r --name-only origin/data | grep '^data/shards/' || true) | |
| for path in $shard_paths; do | |
| base=$(basename "$path") | |
| git show "origin/data:$path" > "data/sharded/shards/$base" | |
| done | |
| echo "Loaded $(ls data/sharded/shards 2>/dev/null | wc -l) shard(s)." | |
| elif git cat-file -e origin/data:data/icourse.db.gz.enc 2>/dev/null; then | |
| git show origin/data:data/icourse.db.gz.enc > data/icourse.db.gz.enc | |
| echo "Loaded legacy compressed database." | |
| elif git cat-file -e origin/data:data/icourse.db.enc 2>/dev/null; then | |
| git show origin/data:data/icourse.db.enc > data/icourse.db.enc | |
| echo "Loaded legacy uncompressed database." | |
| else | |
| echo "::error::No database found on data branch." | |
| exit 1 | |
| fi | |
| - name: Decode database | |
| env: | |
| STUID: ${{ secrets.STUID }} | |
| UISPSW: ${{ secrets.UISPSW }} | |
| DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }} | |
| SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }} | |
| run: | | |
| if [ -f data/sharded/icourse-index.enc ]; then | |
| python scripts/db_shard.py reassemble data/sharded data/icourse.db | |
| echo "Reassembled sharded database." | |
| exit 0 | |
| fi | |
| NEW_KEY=$(printf '%s' "ICSv2:${STUID}:${UISPSW}" | sha256sum | cut -d' ' -f1) | |
| LEGACY_KEY="${STUID}${UISPSW}${DASHSCOPE_API_KEY}${SMTP_PASSWORD}" | |
| decrypt_blob() { | |
| local in_path="$1" | |
| local out_path="$2" | |
| if openssl enc -aes-256-cbc -d -pbkdf2 -iter 100000 \ | |
| -in "$in_path" -out "$out_path" \ | |
| -pass pass:"$NEW_KEY" 2>/dev/null; then | |
| return 0 | |
| fi | |
| openssl enc -aes-256-cbc -d -pbkdf2 \ | |
| -in "$in_path" -out "$out_path" \ | |
| -pass pass:"$LEGACY_KEY" 2>/dev/null | |
| } | |
| if [ -f data/icourse.db.gz.enc ]; then | |
| decrypt_blob data/icourse.db.gz.enc data/icourse.db.gz | |
| gzip -d data/icourse.db.gz | |
| else | |
| decrypt_blob data/icourse.db.enc data/icourse.db | |
| fi | |
| echo "Database decrypted." | |
| - name: Export course summaries | |
| env: | |
| SMTP_EMAIL: ${{ secrets.SMTP_EMAIL }} | |
| SMTP_PASSWORD: ${{ secrets.SMTP_PASSWORD }} | |
| RECEIVER_EMAIL: ${{ secrets.RECEIVER_EMAIL }} | |
| EXPORT_COURSE_ID: ${{ inputs.course_id }} | |
| EXPORT_SUB_IDS: ${{ inputs.sub_ids }} | |
| run: | | |
| case "${{ inputs.export_type }}" in | |
| "HTML") | |
| EXPORT_FLAG="" | |
| ;; | |
| "PDF") | |
| EXPORT_FLAG="--pdf" | |
| ;; | |
| "Markdown") | |
| EXPORT_FLAG="--md" | |
| ;; | |
| esac | |
| if [ -n "$EXPORT_SUB_IDS" ]; then | |
| python scripts/export_course.py --course-id "$EXPORT_COURSE_ID" --sub-ids "$EXPORT_SUB_IDS" $EXPORT_FLAG | |
| else | |
| python scripts/export_course.py --course-id "$EXPORT_COURSE_ID" $EXPORT_FLAG | |
| fi |