music on atproto
plyr.fm
1# export platform costs to R2 for public dashboard
2#
3# runs hourly to update the costs.json file in R2
4# the frontend /costs page fetches this static JSON
5#
6# AudD costs are derived from track duration (1 request = 12s of audio)
7# so this gives near real-time cost visibility as uploads happen
8#
9# required secrets:
10# NEON_DATABASE_URL_PRD - production database URL
11# AWS_ACCESS_KEY_ID - R2 access key
12# AWS_SECRET_ACCESS_KEY - R2 secret key
13# R2_ENDPOINT_URL - R2 endpoint
14# R2_BUCKET - R2 bucket name
15# R2_PUBLIC_BUCKET_URL - public R2 URL
16
17name: export costs
18
19on:
20 schedule:
21 - cron: "0 * * * *" # hourly
22 workflow_dispatch:
23 inputs:
24 dry_run:
25 description: "dry run (print JSON, don't upload)"
26 type: boolean
27 default: false
28
29jobs:
30 export:
31 runs-on: ubuntu-latest
32
33 steps:
34 - uses: actions/checkout@v4
35
36 - uses: astral-sh/setup-uv@v4
37
38 - name: Export costs to R2
39 run: |
40 ARGS=""
41 if [ "${{ inputs.dry_run }}" = "true" ]; then
42 ARGS="--dry-run"
43 fi
44
45 uv run scripts/costs/export_costs.py $ARGS
46 env:
47 NEON_DATABASE_URL_PRD: ${{ secrets.NEON_DATABASE_URL_PRD }}
48 AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
49 AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
50 R2_ENDPOINT_URL: ${{ secrets.R2_ENDPOINT_URL }}
51 R2_BUCKET: ${{ secrets.R2_BUCKET }}
52 R2_PUBLIC_BUCKET_URL: ${{ secrets.R2_PUBLIC_BUCKET_URL }}