263 lines
8.6 KiB
Python
263 lines
8.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Tracking Management Utility for Karaoke Playlist Downloader
|
|
Provides tools to manage and analyze the tracking database.
|
|
"""
|
|
|
|
import argparse
|
|
import json
|
|
from pathlib import Path
|
|
from tracking_manager import TrackingManager, SongStatus
|
|
import sys
|
|
|
|
|
|
def show_statistics(tracker):
|
|
"""Show overall statistics."""
|
|
stats = tracker.get_statistics()
|
|
|
|
print("🎤 Karaoke Downloader Statistics")
|
|
print("=" * 50)
|
|
print(f"📊 Total Songs: {stats['total_songs']}")
|
|
print(f"📁 Total Playlists: {stats['total_playlists']}")
|
|
print(f"✅ Downloaded Songs: {stats['downloaded_songs']}")
|
|
print(f"❌ Failed Songs: {stats['failed_songs']}")
|
|
print(f"⚠️ Partial Downloads: {stats['partial_songs']}")
|
|
print(f"💾 Total Size: {stats['total_size_mb']} MB")
|
|
print(f"🕒 Last Updated: {stats['last_updated']}")
|
|
|
|
if stats['total_songs'] > 0:
|
|
success_rate = (stats['downloaded_songs'] / stats['total_songs']) * 100
|
|
print(f"📈 Success Rate: {success_rate:.1f}%")
|
|
|
|
|
|
def list_playlists(tracker):
|
|
"""List all playlists with their statistics."""
|
|
playlists = tracker.data['playlists']
|
|
|
|
if not playlists:
|
|
print("📭 No playlists found in tracking database.")
|
|
return
|
|
|
|
print("📋 Playlists in Database")
|
|
print("=" * 50)
|
|
|
|
for playlist_id, playlist in playlists.items():
|
|
print(f"\n🎵 {playlist['name']}")
|
|
print(f" ID: {playlist_id}")
|
|
print(f" URL: {playlist['url']}")
|
|
print(f" Songs: {playlist['total_songs']}")
|
|
print(f" Downloaded: {playlist['downloaded_songs']}")
|
|
print(f" Failed: {playlist['failed_songs']}")
|
|
print(f" Added: {playlist['added_date']}")
|
|
print(f" Last Synced: {playlist['last_synced'] or 'Never'}")
|
|
|
|
|
|
def show_playlist_details(tracker, playlist_id):
|
|
"""Show detailed information about a specific playlist."""
|
|
if playlist_id not in tracker.data['playlists']:
|
|
print(f"❌ Playlist '{playlist_id}' not found in tracking database.")
|
|
return
|
|
|
|
playlist = tracker.data['playlists'][playlist_id]
|
|
songs = tracker.get_playlist_songs(playlist_id)
|
|
|
|
print(f"🎵 Playlist Details: {playlist['name']}")
|
|
print("=" * 50)
|
|
print(f"ID: {playlist_id}")
|
|
print(f"URL: {playlist['url']}")
|
|
print(f"Total Songs: {playlist['total_songs']}")
|
|
print(f"Downloaded: {playlist['downloaded_songs']}")
|
|
print(f"Failed: {playlist['failed_songs']}")
|
|
print(f"Added: {playlist['added_date']}")
|
|
print(f"Last Synced: {playlist['last_synced'] or 'Never'}")
|
|
|
|
print(f"\n📝 Songs:")
|
|
for i, song in enumerate(songs, 1):
|
|
status_icon = {
|
|
SongStatus.DOWNLOADED: "✅",
|
|
SongStatus.CONVERTED: "✅",
|
|
SongStatus.DOWNLOADING: "⏳",
|
|
SongStatus.PARTIAL: "⚠️",
|
|
SongStatus.FAILED: "❌",
|
|
SongStatus.NOT_DOWNLOADED: "⏸️"
|
|
}.get(song['status'], "❓")
|
|
|
|
formats = ", ".join(song['formats'].keys()) if song['formats'] else "None"
|
|
print(f" {i:2d}. {status_icon} {song['title']}")
|
|
print(f" Video ID: {song['video_id']}")
|
|
print(f" Status: {song['status']}")
|
|
print(f" Formats: {formats}")
|
|
if song['last_error']:
|
|
print(f" Error: {song['last_error']}")
|
|
print()
|
|
|
|
|
|
def show_failed_songs(tracker, playlist_id=None):
|
|
"""Show all failed songs."""
|
|
if playlist_id:
|
|
songs = tracker.get_failed_songs(playlist_id)
|
|
if not songs:
|
|
print(f"✅ No failed songs found in playlist '{playlist_id}'.")
|
|
return
|
|
print(f"❌ Failed Songs in Playlist: {playlist_id}")
|
|
else:
|
|
songs = [song for song in tracker.data['songs'].values()
|
|
if song['status'] == SongStatus.FAILED]
|
|
if not songs:
|
|
print("✅ No failed songs found in any playlist.")
|
|
return
|
|
print("❌ All Failed Songs")
|
|
|
|
print("=" * 50)
|
|
for song in songs:
|
|
playlist_name = tracker.data['playlists'][song['playlist_id']]['name']
|
|
print(f"\n🎵 {song['title']}")
|
|
print(f" Playlist: {playlist_name}")
|
|
print(f" Video ID: {song['video_id']}")
|
|
print(f" Attempts: {song['download_attempts']}")
|
|
print(f" Error: {song['last_error']}")
|
|
print(f" Last Updated: {song['last_updated']}")
|
|
|
|
|
|
def show_partial_downloads(tracker, playlist_id=None):
|
|
"""Show all partial downloads."""
|
|
if playlist_id:
|
|
songs = tracker.get_partial_downloads(playlist_id)
|
|
if not songs:
|
|
print(f"✅ No partial downloads found in playlist '{playlist_id}'.")
|
|
return
|
|
print(f"⚠️ Partial Downloads in Playlist: {playlist_id}")
|
|
else:
|
|
songs = [song for song in tracker.data['songs'].values()
|
|
if song['status'] == SongStatus.PARTIAL]
|
|
if not songs:
|
|
print("✅ No partial downloads found in any playlist.")
|
|
return
|
|
print("⚠️ All Partial Downloads")
|
|
|
|
print("=" * 50)
|
|
for song in songs:
|
|
playlist_name = tracker.data['playlists'][song['playlist_id']]['name']
|
|
print(f"\n🎵 {song['title']}")
|
|
print(f" Playlist: {playlist_name}")
|
|
print(f" Video ID: {song['video_id']}")
|
|
print(f" Formats: {', '.join(song['formats'].keys())}")
|
|
print(f" Last Updated: {song['last_updated']}")
|
|
|
|
|
|
def cleanup_orphaned_entries(tracker, downloads_dir):
|
|
"""Clean up orphaned tracking entries."""
|
|
orphaned = tracker.cleanup_orphaned_files(downloads_dir)
|
|
|
|
if orphaned:
|
|
print(f"🧹 Cleaned up {len(orphaned)} orphaned tracking entries:")
|
|
for song_id in orphaned:
|
|
song = tracker.data['songs'].get(song_id)
|
|
if song:
|
|
print(f" - {song['title']} (ID: {song['video_id']})")
|
|
else:
|
|
print("✅ No orphaned entries found.")
|
|
|
|
|
|
def export_database(tracker, output_file):
|
|
"""Export the tracking database to a JSON file."""
|
|
try:
|
|
with open(output_file, 'w', encoding='utf-8') as f:
|
|
json.dump(tracker.data, f, indent=2, ensure_ascii=False)
|
|
print(f"💾 Database exported to: {output_file}")
|
|
except Exception as e:
|
|
print(f"❌ Failed to export database: {e}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(
|
|
description="Tracking Management Utility for Karaoke Playlist Downloader",
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
epilog="""
|
|
Examples:
|
|
python manage_tracking.py --stats
|
|
python manage_tracking.py --list-playlists
|
|
python manage_tracking.py --playlist PLAYLIST_ID
|
|
python manage_tracking.py --failed
|
|
python manage_tracking.py --partial
|
|
python manage_tracking.py --cleanup
|
|
python manage_tracking.py --export backup.json
|
|
"""
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--stats', '--statistics',
|
|
action='store_true',
|
|
help='Show overall statistics'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--list-playlists',
|
|
action='store_true',
|
|
help='List all playlists in the database'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--playlist',
|
|
metavar='PLAYLIST_ID',
|
|
help='Show detailed information about a specific playlist'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--failed',
|
|
action='store_true',
|
|
help='Show all failed songs'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--partial',
|
|
action='store_true',
|
|
help='Show all partial downloads'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--cleanup',
|
|
action='store_true',
|
|
help='Clean up orphaned tracking entries'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--export',
|
|
metavar='FILE',
|
|
help='Export tracking database to JSON file'
|
|
)
|
|
|
|
parser.add_argument(
|
|
'--tracking-file',
|
|
default='karaoke_tracking.json',
|
|
help='Path to tracking database file (default: karaoke_tracking.json)'
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
# Initialize tracking manager
|
|
tracker = TrackingManager(args.tracking_file)
|
|
|
|
# Process commands
|
|
if args.stats:
|
|
show_statistics(tracker)
|
|
elif args.list_playlists:
|
|
list_playlists(tracker)
|
|
elif args.playlist:
|
|
show_playlist_details(tracker, args.playlist)
|
|
elif args.failed:
|
|
show_failed_songs(tracker)
|
|
elif args.partial:
|
|
show_partial_downloads(tracker)
|
|
elif args.cleanup:
|
|
downloads_dir = Path("downloads")
|
|
cleanup_orphaned_entries(tracker, downloads_dir)
|
|
elif args.export:
|
|
export_database(tracker, args.export)
|
|
else:
|
|
parser.print_help()
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |