Add Doris Schoolhouse and clean pending homelab changes
This commit is contained in:
31
home/doris-schoolhouse/app/scripts/apply_schema.py
Normal file
31
home/doris-schoolhouse/app/scripts/apply_schema.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
schema_path = Path(__file__).resolve().parent.parent / 'db' / 'schema.sql'
|
||||
if not schema_path.exists():
|
||||
print(f'missing schema file: {schema_path}', file=sys.stderr)
|
||||
return 1
|
||||
dsn = os.getenv('DATABASE_URL', '')
|
||||
if not dsn:
|
||||
print('DATABASE_URL is not set', file=sys.stderr)
|
||||
return 1
|
||||
try:
|
||||
import psycopg
|
||||
except Exception:
|
||||
print('psycopg is not installed; cannot apply schema directly', file=sys.stderr)
|
||||
return 1
|
||||
dsn = dsn.replace('postgresql+psycopg://', 'postgresql://')
|
||||
sql = schema_path.read_text()
|
||||
with psycopg.connect(dsn) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(sql)
|
||||
conn.commit()
|
||||
print(f'Applied schema from {schema_path}')
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
raise SystemExit(main())
|
||||
27
home/doris-schoolhouse/app/scripts/bootstrap_state.py
Normal file
27
home/doris-schoolhouse/app/scripts/bootstrap_state.py
Normal file
@@ -0,0 +1,27 @@
|
||||
from pathlib import Path
|
||||
|
||||
from app.config import settings
|
||||
from app.services.d2l import D2LService
|
||||
from app.services.store import JsonStore
|
||||
|
||||
|
||||
def main() -> None:
|
||||
Path(settings.upload_tmp_dir).mkdir(parents=True, exist_ok=True)
|
||||
Path(settings.state_dir).mkdir(parents=True, exist_ok=True)
|
||||
store = JsonStore()
|
||||
for name, default in {
|
||||
'courses': [],
|
||||
'assignments': [],
|
||||
'submissions': [],
|
||||
'recordings': [],
|
||||
'sync_runs': [],
|
||||
}.items():
|
||||
path = Path(settings.state_dir) / f'{name}.json'
|
||||
if not path.exists():
|
||||
store.save(name, default)
|
||||
result = D2LService().sync_to_store()
|
||||
print(result)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
44
home/doris-schoolhouse/app/scripts/process_recording.py
Normal file
44
home/doris-schoolhouse/app/scripts/process_recording.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import argparse
|
||||
import json
|
||||
|
||||
from app.services.media import MediaService
|
||||
from app.services.repository import get_repository
|
||||
from app.services.store import JsonStore
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('recording_id')
|
||||
parser.add_argument('--convert-only', action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
repo = get_repository()
|
||||
store = JsonStore()
|
||||
media = MediaService()
|
||||
|
||||
recordings = repo.list_recordings()
|
||||
current = next((item for item in recordings if str(item.get('id')) == str(args.recording_id)), None)
|
||||
if not current:
|
||||
raise SystemExit(f'recording not found: {args.recording_id}')
|
||||
|
||||
wav_path = current.get('stored_path')
|
||||
mp3_path = current.get('mp3_path') or media.planned_mp3_path(wav_path)
|
||||
result = media.convert_wav_to_mp3(wav_path, mp3_path)
|
||||
|
||||
updates = {
|
||||
'conversion_status': result['status'],
|
||||
'conversion_result': result,
|
||||
'updated_at': store.now(),
|
||||
}
|
||||
if result['status'] == 'ok':
|
||||
updates['mp3_path'] = mp3_path
|
||||
delete_result = media.delete_source_if_requested(wav_path, bool(current.get('delete_wav_after_success')))
|
||||
updates['delete_source_result'] = delete_result
|
||||
if not args.convert_only:
|
||||
updates['status'] = 'converted'
|
||||
repo.update_recording(str(current.get('id')), updates)
|
||||
print(json.dumps({'recording_id': current.get('id'), 'result': result, 'updates': updates}, indent=2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user