Improve Catalog
ci / checks (push) Successful in 46m42s

This commit is contained in:
khodowany
2026-09-27 11:03:43 -05:00
parent a416a80dd9
commit 142d843fac
418 changed files with 440 additions and 324488 deletions
+15 -34
View File
@@ -8,7 +8,7 @@ import sqlite3
import tempfile
APPLICATION_ID = 0x56414D50
COMMON_COLUMNS = """
SONG_COLUMNS = """
id TEXT PRIMARY KEY NOT NULL CHECK(length(trim(id)) BETWEEN 1 AND 160),
title TEXT NOT NULL CHECK(length(trim(title)) BETWEEN 1 AND 200),
composer TEXT NOT NULL,
@@ -48,43 +48,24 @@ def metadata(path: pathlib.Path, root: pathlib.Path) -> dict:
def populate(connection: sqlite3.Connection, root: pathlib.Path) -> None:
if not root.is_dir():
raise ValueError(f'{root}: score asset directory not found')
connection.executescript(f'''
PRAGMA application_id = {APPLICATION_ID};
CREATE TABLE songs ({COMMON_COLUMNS}, part TEXT NOT NULL) STRICT;
CREATE TABLE practice_exercises ({COMMON_COLUMNS}, exercise_id TEXT NOT NULL, part TEXT NOT NULL) STRICT;
CREATE INDEX songs_menu ON songs(title COLLATE NOCASE, composer COLLATE NOCASE, part COLLATE NOCASE);
CREATE INDEX practice_menu ON practice_exercises(exercise_id, id);
''')
practice_parts = {}
for category, table, depth in (('songs', 'songs', 1), ('practice', 'practice_exercises', 2)):
folder = root / category
if (folder.exists() or folder.is_symlink()) and not folder.is_dir():
raise ValueError(f'{folder}: score asset directory not found')
for path in sorted((root / category).rglob('*.json')):
folder = root / 'songs'
if (folder.exists() or folder.is_symlink()) and not folder.is_dir():
raise ValueError(f'{folder}: score asset directory not found')
with connection:
connection.execute('BEGIN')
connection.execute(f'PRAGMA application_id = {APPLICATION_ID}')
connection.execute(f'CREATE TABLE songs ({SONG_COLUMNS}, part TEXT NOT NULL) STRICT')
connection.execute('CREATE INDEX songs_menu ON songs(title, composer, part, id)')
for path in sorted(folder.rglob('*.json')):
try:
parts = path.relative_to(root / category).parts
if len(parts) != depth:
raise ValueError(f'unexpected {category} score path')
if path.parent != folder:
raise ValueError('unexpected songs score path')
row = metadata(path, root)
if category == 'practice':
identity = parts[0]
if path.stem not in ('acoustic', 'electric', 'vocal') or row['part'] != path.stem.capitalize():
raise ValueError('practice requires an acoustic, electric, or vocal part')
identity_metadata = (row['title'], row['composer'], row['key_signature'])
group = practice_parts.setdefault(identity, (identity_metadata, set()))
if group[0] != identity_metadata:
raise ValueError(f'practice parts disagree on metadata: {identity}')
group[1].add(path.stem)
row.update(id=identity + '-' + path.stem, exercise_id=identity)
connection.execute(f'INSERT INTO {table} ({", ".join(row)}) VALUES ({", ".join("?" for _ in row)})', tuple(row.values()))
connection.execute(f'INSERT INTO songs ({", ".join(row)}) VALUES ({", ".join("?" for _ in row)})', tuple(row.values()))
except (ValueError, KeyError, TypeError, sqlite3.Error) as error:
raise ValueError(f'{path}: {error}') from error
for identity, (_, parts) in practice_parts.items():
if parts != {'acoustic', 'electric', 'vocal'}:
raise ValueError(f'practice exercise requires all three parts: {identity}')
connection.commit()
if connection.execute('PRAGMA integrity_check').fetchall() != [('ok',)]:
raise ValueError('catalog integrity check failed')
if connection.execute('PRAGMA integrity_check').fetchall() != [('ok',)]:
raise ValueError('catalog integrity check failed')
def build_catalog(root: pathlib.Path, destination: pathlib.Path | None = None) -> pathlib.Path:
if not root.is_dir():