190 lines
5.8 KiB
Python
190 lines
5.8 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Helper script to add manual videos to the manual videos collection.
|
|
"""
|
|
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Dict, List, Optional
|
|
|
|
def extract_video_id(url: str) -> Optional[str]:
|
|
"""Extract video ID from YouTube URL."""
|
|
patterns = [
|
|
r'(?:youtube\.com/watch\?v=|youtu\.be/|youtube\.com/embed/)([a-zA-Z0-9_-]{11})',
|
|
r'youtube\.com/watch\?.*v=([a-zA-Z0-9_-]{11})'
|
|
]
|
|
|
|
for pattern in patterns:
|
|
match = re.search(pattern, url)
|
|
if match:
|
|
return match.group(1)
|
|
return None
|
|
|
|
def add_manual_video(title: str, url: str, manual_file: str = "data/manual_videos.json"):
|
|
"""
|
|
Add a manual video to the collection.
|
|
|
|
Args:
|
|
title: Video title (e.g., "Artist - Song (Karaoke Version)")
|
|
url: YouTube URL
|
|
manual_file: Path to manual videos JSON file
|
|
"""
|
|
manual_path = Path(manual_file)
|
|
|
|
# Load existing data or create new
|
|
if manual_path.exists():
|
|
with open(manual_path, 'r', encoding='utf-8') as f:
|
|
data = json.load(f)
|
|
else:
|
|
data = {
|
|
"channel_name": "@ManualVideos",
|
|
"channel_url": "manual://static",
|
|
"description": "Manual collection of individual karaoke videos",
|
|
"videos": [],
|
|
"parsing_rules": {
|
|
"format": "artist_title_separator",
|
|
"separator": " - ",
|
|
"artist_first": true,
|
|
"title_cleanup": {
|
|
"remove_suffix": {
|
|
"suffixes": ["(Karaoke)", "(Karaoke Version)", "(Karaoke Version) Lyrics"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Extract video ID
|
|
video_id = extract_video_id(url)
|
|
if not video_id:
|
|
print(f"❌ Could not extract video ID from URL: {url}")
|
|
return False
|
|
|
|
# Check if video already exists
|
|
existing_ids = [video.get("id") for video in data["videos"]]
|
|
if video_id in existing_ids:
|
|
print(f"⚠️ Video already exists: {title}")
|
|
return False
|
|
|
|
# Add new video
|
|
new_video = {
|
|
"title": title,
|
|
"url": url,
|
|
"id": video_id,
|
|
"upload_date": "2024-01-01", # Default date
|
|
"duration": 180, # Default duration
|
|
"view_count": 1000 # Default view count
|
|
}
|
|
|
|
data["videos"].append(new_video)
|
|
|
|
# Save updated data
|
|
manual_path.parent.mkdir(parents=True, exist_ok=True)
|
|
with open(manual_path, 'w', encoding='utf-8') as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
|
|
print(f"✅ Added video: {title}")
|
|
print(f" URL: {url}")
|
|
print(f" ID: {video_id}")
|
|
return True
|
|
|
|
def list_manual_videos(manual_file: str = "data/manual_videos.json"):
|
|
"""List all manual videos."""
|
|
manual_path = Path(manual_file)
|
|
|
|
if not manual_path.exists():
|
|
print("❌ No manual videos file found")
|
|
return
|
|
|
|
with open(manual_path, 'r', encoding='utf-8') as f:
|
|
data = json.load(f)
|
|
|
|
print(f"📋 Manual Videos ({len(data['videos'])} videos):")
|
|
print("=" * 60)
|
|
|
|
for i, video in enumerate(data['videos'], 1):
|
|
print(f"{i:2d}. {video['title']}")
|
|
print(f" URL: {video['url']}")
|
|
print(f" ID: {video['id']}")
|
|
print()
|
|
|
|
def remove_manual_video(video_id: str, manual_file: str = "data/manual_videos.json"):
|
|
"""Remove a manual video by ID."""
|
|
manual_path = Path(manual_file)
|
|
|
|
if not manual_path.exists():
|
|
print("❌ No manual videos file found")
|
|
return False
|
|
|
|
with open(manual_path, 'r', encoding='utf-8') as f:
|
|
data = json.load(f)
|
|
|
|
# Find and remove video
|
|
for i, video in enumerate(data['videos']):
|
|
if video['id'] == video_id:
|
|
removed_video = data['videos'].pop(i)
|
|
with open(manual_path, 'w', encoding='utf-8') as f:
|
|
json.dump(data, f, indent=2, ensure_ascii=False)
|
|
print(f"✅ Removed video: {removed_video['title']}")
|
|
return True
|
|
|
|
print(f"❌ Video with ID '{video_id}' not found")
|
|
return False
|
|
|
|
def main():
|
|
"""Interactive mode for adding manual videos."""
|
|
print("🎤 Manual Video Manager")
|
|
print("=" * 30)
|
|
print("1. Add video")
|
|
print("2. List videos")
|
|
print("3. Remove video")
|
|
print("4. Exit")
|
|
|
|
while True:
|
|
choice = input("\nSelect option (1-4): ").strip()
|
|
|
|
if choice == "1":
|
|
title = input("Enter video title (e.g., 'Artist - Song (Karaoke Version)'): ").strip()
|
|
url = input("Enter YouTube URL: ").strip()
|
|
|
|
if title and url:
|
|
add_manual_video(title, url)
|
|
else:
|
|
print("❌ Title and URL are required")
|
|
|
|
elif choice == "2":
|
|
list_manual_videos()
|
|
|
|
elif choice == "3":
|
|
video_id = input("Enter video ID to remove: ").strip()
|
|
if video_id:
|
|
remove_manual_video(video_id)
|
|
else:
|
|
print("❌ Video ID is required")
|
|
|
|
elif choice == "4":
|
|
print("👋 Goodbye!")
|
|
break
|
|
|
|
else:
|
|
print("❌ Invalid option")
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
if len(sys.argv) > 1:
|
|
# Command line mode
|
|
if sys.argv[1] == "add" and len(sys.argv) >= 4:
|
|
add_manual_video(sys.argv[2], sys.argv[3])
|
|
elif sys.argv[1] == "list":
|
|
list_manual_videos()
|
|
elif sys.argv[1] == "remove" and len(sys.argv) >= 3:
|
|
remove_manual_video(sys.argv[2])
|
|
else:
|
|
print("Usage:")
|
|
print(" python add_manual_video.py add 'Title' 'URL'")
|
|
print(" python add_manual_video.py list")
|
|
print(" python add_manual_video.py remove VIDEO_ID")
|
|
else:
|
|
# Interactive mode
|
|
main() |