152 lines
4.6 KiB
Python
152 lines
4.6 KiB
Python
|
|
#!/usr/bin/env python3
|
||
|
|
"""
|
||
|
|
CLI for managing recordings database.
|
||
|
|
|
||
|
|
Usage:
|
||
|
|
python cli.py import-transcriptions /path/to/transcriptions --source phone
|
||
|
|
python cli.py import-audio /path/to/audio --source portable
|
||
|
|
python cli.py link-audio /path/to/audio
|
||
|
|
python cli.py list [--source phone] [--limit 10]
|
||
|
|
python cli.py stats
|
||
|
|
"""
|
||
|
|
|
||
|
|
import argparse
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
import database
|
||
|
|
import importer
|
||
|
|
|
||
|
|
|
||
|
|
def cmd_import_transcriptions(args):
|
||
|
|
"""Import transcription JSON files."""
|
||
|
|
database.init_db()
|
||
|
|
|
||
|
|
path = Path(args.path)
|
||
|
|
audio_path = Path(args.audio_path) if args.audio_path else None
|
||
|
|
|
||
|
|
if path.is_file():
|
||
|
|
result = importer.import_transcription_json(
|
||
|
|
path,
|
||
|
|
source_name=args.source,
|
||
|
|
audio_base_path=audio_path,
|
||
|
|
)
|
||
|
|
print(f"{result['status']}: {result['message']}")
|
||
|
|
else:
|
||
|
|
result = importer.import_transcription_directory(
|
||
|
|
path,
|
||
|
|
source_name=args.source,
|
||
|
|
audio_base_path=audio_path,
|
||
|
|
)
|
||
|
|
print(f"Import complete:")
|
||
|
|
print(f" Created: {result['created']}")
|
||
|
|
print(f" Already existed: {result['exists']}")
|
||
|
|
print(f" Errors: {result['errors']}")
|
||
|
|
|
||
|
|
if args.verbose:
|
||
|
|
for d in result['details']:
|
||
|
|
print(f" - {d['file']}: {d['status']}")
|
||
|
|
|
||
|
|
|
||
|
|
def cmd_import_audio(args):
|
||
|
|
"""Import audio files without transcriptions."""
|
||
|
|
database.init_db()
|
||
|
|
|
||
|
|
path = Path(args.path)
|
||
|
|
|
||
|
|
if path.is_file():
|
||
|
|
result = importer.import_audio_file(path, source_name=args.source)
|
||
|
|
print(f"{result['status']}: {result['message']}")
|
||
|
|
else:
|
||
|
|
result = importer.import_audio_directory(path, source_name=args.source)
|
||
|
|
print(f"Import complete:")
|
||
|
|
print(f" Created: {result['created']}")
|
||
|
|
print(f" Already existed: {result['exists']}")
|
||
|
|
print(f" Errors: {result['errors']}")
|
||
|
|
|
||
|
|
|
||
|
|
def cmd_link_audio(args):
|
||
|
|
"""Link audio files to existing transcription records."""
|
||
|
|
database.init_db()
|
||
|
|
|
||
|
|
path = Path(args.path)
|
||
|
|
result = importer.link_audio_to_transcriptions(path)
|
||
|
|
print(result['message'])
|
||
|
|
|
||
|
|
|
||
|
|
def cmd_list(args):
|
||
|
|
"""List recordings in database."""
|
||
|
|
database.init_db()
|
||
|
|
|
||
|
|
recordings = database.list_recordings(
|
||
|
|
source_name=args.source,
|
||
|
|
limit=args.limit,
|
||
|
|
)
|
||
|
|
|
||
|
|
if not recordings:
|
||
|
|
print("No recordings found.")
|
||
|
|
return
|
||
|
|
|
||
|
|
print(f"{'ID':>4} {'Source':<10} {'Duration':>8} {'Recorded':<20} Filename")
|
||
|
|
print("-" * 80)
|
||
|
|
|
||
|
|
for r in recordings:
|
||
|
|
duration = f"{r['duration']/60:.1f}m" if r['duration'] else "?"
|
||
|
|
recorded = r['recorded_at'][:19] if r['recorded_at'] else "?"
|
||
|
|
print(f"{r['id']:>4} {r['source_name']:<10} {duration:>8} {recorded:<20} {r['filename']}")
|
||
|
|
|
||
|
|
|
||
|
|
def cmd_stats(args):
|
||
|
|
"""Show database statistics."""
|
||
|
|
database.init_db()
|
||
|
|
|
||
|
|
total = database.get_recordings_count()
|
||
|
|
sources = database.list_sources()
|
||
|
|
|
||
|
|
print(f"Total recordings: {total}")
|
||
|
|
print()
|
||
|
|
print("By source:")
|
||
|
|
for s in sources:
|
||
|
|
hours = s['total_hours'] or 0
|
||
|
|
print(f" {s['source_name']}: {s['recording_count']} recordings, {hours:.1f} hours")
|
||
|
|
|
||
|
|
|
||
|
|
def main():
|
||
|
|
parser = argparse.ArgumentParser(description="Recordings database CLI")
|
||
|
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
||
|
|
|
||
|
|
# import-transcriptions
|
||
|
|
p = subparsers.add_parser("import-transcriptions", help="Import transcription JSON files")
|
||
|
|
p.add_argument("path", help="Path to JSON file or directory")
|
||
|
|
p.add_argument("--source", "-s", default="phone", help="Source name (default: phone)")
|
||
|
|
p.add_argument("--audio-path", "-a", help="Path to audio files")
|
||
|
|
p.add_argument("--verbose", "-v", action="store_true")
|
||
|
|
p.set_defaults(func=cmd_import_transcriptions)
|
||
|
|
|
||
|
|
# import-audio
|
||
|
|
p = subparsers.add_parser("import-audio", help="Import audio files")
|
||
|
|
p.add_argument("path", help="Path to audio file or directory")
|
||
|
|
p.add_argument("--source", "-s", required=True, help="Source name")
|
||
|
|
p.set_defaults(func=cmd_import_audio)
|
||
|
|
|
||
|
|
# link-audio
|
||
|
|
p = subparsers.add_parser("link-audio", help="Link audio files to transcriptions")
|
||
|
|
p.add_argument("path", help="Directory containing audio files")
|
||
|
|
p.set_defaults(func=cmd_link_audio)
|
||
|
|
|
||
|
|
# list
|
||
|
|
p = subparsers.add_parser("list", help="List recordings")
|
||
|
|
p.add_argument("--source", "-s", help="Filter by source")
|
||
|
|
p.add_argument("--limit", "-n", type=int, default=20)
|
||
|
|
p.set_defaults(func=cmd_list)
|
||
|
|
|
||
|
|
# stats
|
||
|
|
p = subparsers.add_parser("stats", help="Show statistics")
|
||
|
|
p.set_defaults(func=cmd_stats)
|
||
|
|
|
||
|
|
args = parser.parse_args()
|
||
|
|
args.func(args)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
main()
|