114 lines
4.2 KiB
Python
114 lines
4.2 KiB
Python
import yaml
|
|
import sys
|
|
import asyncio
|
|
from typing import List, Dict, Any
|
|
|
|
from spotify_to_tidal import auth as _auth
|
|
from spotify_to_tidal import sync as _sync
|
|
from spotify_to_tidal.tidalapi_patch import get_all_playlists
|
|
|
|
def print_menu(playlists: List[Dict[str, Any]]):
|
|
print("\n" + "="*50)
|
|
print(f"🎵 Spotify Playlists Found ({len(playlists)} total) 🎵")
|
|
print("="*50)
|
|
for i, p in enumerate(playlists):
|
|
track_count = p.get('tracks', {}).get('total', 'Unknown')
|
|
print(f"[{i+1:2d}] {p['name']:<35} ({track_count:>3} tracks) | ID: {p['id']}")
|
|
print("="*50)
|
|
print("Enter the numbers of the playlists you want to sync, separated by commas (e.g., 1, 4, 12).")
|
|
print("Enter 'ALL' to sync all playlists.")
|
|
print("Enter 'Q' to quit.")
|
|
|
|
async def main_async():
|
|
# 1. Load config
|
|
try:
|
|
with open('config.yml', 'r') as f:
|
|
config = yaml.safe_load(f)
|
|
except Exception as e:
|
|
sys.exit(f"Failed to load config.yml: {e}")
|
|
|
|
# 2. Authenticate
|
|
print("Authenticating with Spotify...")
|
|
spotify_session = _auth.open_spotify_session(config['spotify'])
|
|
|
|
print("Authenticating with Tidal...")
|
|
tidal_session = _auth.open_tidal_session()
|
|
if not tidal_session.check_login():
|
|
sys.exit("Could not connect to Tidal")
|
|
|
|
# 3. Fetch all Spotify user playlists
|
|
print("\nFetching Spotify playlists...")
|
|
spotify_playlists = await _sync.get_playlists_from_spotify(spotify_session, config)
|
|
|
|
if not spotify_playlists:
|
|
print("No Spotify playlists found!")
|
|
return
|
|
|
|
# 4. Interactive menu loop
|
|
while True:
|
|
print_menu(spotify_playlists)
|
|
choice = input("\nYour choice: ").strip().lower()
|
|
|
|
if choice == 'q':
|
|
print("Exiting...")
|
|
return
|
|
|
|
selected_playlists = []
|
|
if choice == 'all':
|
|
selected_playlists = spotify_playlists
|
|
print(f"Selected ALL {len(selected_playlists)} playlists for synchronization.")
|
|
break
|
|
|
|
else:
|
|
try:
|
|
# Parse comma-separated indices
|
|
indices = [int(x.strip()) - 1 for x in choice.split(',')]
|
|
for idx in indices:
|
|
if 0 <= idx < len(spotify_playlists):
|
|
selected_playlists.append(spotify_playlists[idx])
|
|
else:
|
|
print(f"Warning: Number {idx + 1} is out of range, ignoring.")
|
|
|
|
if not selected_playlists:
|
|
print("No valid playlists selected. Please try again.")
|
|
continue
|
|
|
|
print(f"Selected {len(selected_playlists)} playlists for synchronization.")
|
|
for p in selected_playlists:
|
|
print(f" - {p['name']}")
|
|
|
|
confirm = input("Proceed? (Y/n): ").strip().lower()
|
|
if confirm in ('', 'y', 'yes'):
|
|
break
|
|
except ValueError:
|
|
print("Invalid input. Please enter numbers separated by commas (e.g. 1, 2, 3) or 'ALL'.")
|
|
|
|
# 5. Execute the sync for the selected playlists
|
|
if not selected_playlists:
|
|
return
|
|
|
|
print("\n=== Starting Synchronization ===")
|
|
tidal_playlists = {p.name: p for p in await get_all_playlists(tidal_session.user)}
|
|
|
|
mappings_to_sync = []
|
|
for sp_playlist in selected_playlists:
|
|
mappings_to_sync.append(_sync.pick_tidal_playlist_for_spotify_playlist(sp_playlist, tidal_playlists))
|
|
|
|
for index, (sp_playlist, td_playlist) in enumerate(mappings_to_sync):
|
|
print(f"\n[{index+1}/{len(mappings_to_sync)}] Syncing playlist: {sp_playlist['name']}")
|
|
await _sync.sync_playlist(spotify_session, tidal_session, sp_playlist, td_playlist, config)
|
|
|
|
print("\n=== Synchronization Complete ===")
|
|
|
|
# Optionally sync favorites if enabled in config
|
|
if config.get('sync_favorites_default', True):
|
|
fav_confirm = input("\nWould you like to sync your 'Liked Songs' as well? (Y/n): ").strip().lower()
|
|
if fav_confirm in ('', 'y', 'yes'):
|
|
await _sync.sync_favorites(spotify_session, tidal_session, config)
|
|
|
|
def main():
|
|
asyncio.run(main_async())
|
|
|
|
if __name__ == "__main__":
|
|
main()
|