Initial clean commit
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
"""
|
||||
Import routes for the Music Round application
|
||||
"""
|
||||
import json
|
||||
import time
|
||||
import random
|
||||
from flask import Blueprint, render_template, redirect, url_for, request, current_app, flash, session, jsonify
|
||||
from musicround.models import Song, db
|
||||
from musicround.routes.import_songs import import_pl, import_track
|
||||
|
||||
import_bp = Blueprint('import', __name__, url_prefix='/import')
|
||||
|
||||
def fetch_all_user_playlists(sp, user_id, limit=50):
|
||||
"""
|
||||
Fetch all playlists from a specific Spotify user account with pagination
|
||||
|
||||
Args:
|
||||
sp: Spotify API client
|
||||
user_id: Spotify user ID to fetch playlists from
|
||||
limit: Number of playlists to fetch per request (max 50)
|
||||
|
||||
Returns:
|
||||
List of all playlists from the specified user
|
||||
"""
|
||||
all_playlists = []
|
||||
offset = 0
|
||||
total = None
|
||||
|
||||
start_time = time.time()
|
||||
current_app.logger.info(f"Started fetching playlists for user '{user_id}'")
|
||||
|
||||
while total is None or offset < total:
|
||||
try:
|
||||
# Use Spotify API to get playlists with pagination
|
||||
results = sp.user_playlists(user_id, limit=limit, offset=offset)
|
||||
|
||||
# If first request, get the total
|
||||
if total is None:
|
||||
total = results['total']
|
||||
current_app.logger.info(f"User '{user_id}' has {total} playlists in total")
|
||||
|
||||
# Add the current batch of playlists to our collection
|
||||
playlists_batch = results.get('items', [])
|
||||
all_playlists.extend(playlists_batch)
|
||||
|
||||
# Update offset for next batch
|
||||
offset += limit
|
||||
|
||||
# Log progress
|
||||
current_app.logger.info(f"Fetched {len(playlists_batch)} playlists for '{user_id}', progress: {len(all_playlists)}/{total}")
|
||||
|
||||
# Break if we've reached the end
|
||||
if not results.get('next'):
|
||||
break
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Error fetching playlists for user '{user_id}' at offset {offset}: {e}")
|
||||
break
|
||||
|
||||
end_time = time.time()
|
||||
duration = int((end_time - start_time) * 1000)
|
||||
current_app.logger.info(f"Completed fetching {len(all_playlists)}/{total} playlists for user '{user_id}' in {duration}ms")
|
||||
|
||||
return all_playlists
|
||||
|
||||
def filter_playlists_by_keywords(playlists, keywords, debug_info=None):
|
||||
"""
|
||||
Filter playlists by checking if any of the keywords are in the playlist name
|
||||
|
||||
Args:
|
||||
playlists: List of playlist objects
|
||||
keywords: List of keywords to filter by
|
||||
debug_info: Optional debug info dictionary to update with filtering stats
|
||||
|
||||
Returns:
|
||||
Filtered list of playlists
|
||||
"""
|
||||
filtered = []
|
||||
keywords_lower = [k.lower() for k in keywords]
|
||||
|
||||
for playlist in playlists:
|
||||
name = playlist.get('name', '').lower()
|
||||
|
||||
# Check if any keyword is in the playlist name
|
||||
if any(keyword in name for keyword in keywords_lower):
|
||||
filtered.append(playlist)
|
||||
|
||||
# Add to debug info if provided
|
||||
if debug_info is not None and 'matched_keywords' in debug_info:
|
||||
matched = [k for k in keywords_lower if k in name]
|
||||
for keyword in matched:
|
||||
if keyword not in debug_info['matched_keywords']:
|
||||
debug_info['matched_keywords'][keyword] = 0
|
||||
debug_info['matched_keywords'][keyword] += 1
|
||||
|
||||
return filtered
|
||||
|
||||
@import_bp.route('/official-playlists', methods=['GET', 'POST'])
|
||||
def import_official_playlists():
|
||||
"""Display and import official Spotify playlists from multiple regional accounts"""
|
||||
if 'access_token' not in session:
|
||||
return redirect(url_for('auth.login'))
|
||||
|
||||
sp = current_app.config['sp']
|
||||
|
||||
# Handle POST request for importing a playlist
|
||||
if request.method == 'POST':
|
||||
playlist_id = request.form['playlist_id']
|
||||
import_pl(playlist_id)
|
||||
flash('Spotify playlist imported successfully!', 'success')
|
||||
return redirect(url_for('core.view_songs'))
|
||||
|
||||
# Get filter keywords from the query string (default to empty list)
|
||||
filter_keywords = request.args.get('filter', '').split(',')
|
||||
filter_keywords = [k.strip() for k in filter_keywords if k.strip()]
|
||||
|
||||
# List of official Spotify user accounts to fetch playlists from
|
||||
spotify_accounts = [
|
||||
'spotify',
|
||||
'spotifycharts',
|
||||
'spotifymaps',
|
||||
'spotifyuk',
|
||||
'spotifyusa',
|
||||
'spotify_germany'
|
||||
]
|
||||
|
||||
# Get selected account from query string or default to all
|
||||
selected_account = request.args.get('account', 'all')
|
||||
|
||||
# Get debug mode parameter
|
||||
debug_mode = request.args.get('debug', 'false').lower() == 'true'
|
||||
|
||||
# Prepare debug info
|
||||
debug_info = {
|
||||
'accounts': {},
|
||||
'total_fetched': 0,
|
||||
'total_filtered': 0,
|
||||
'filtered_out': 0,
|
||||
'matched_keywords': {},
|
||||
'query_time_ms': 0,
|
||||
'duplicates_removed': 0
|
||||
}
|
||||
|
||||
# Initialize playlists list
|
||||
all_playlists = []
|
||||
|
||||
try:
|
||||
start_time = time.time()
|
||||
|
||||
# Process each Spotify account or just the selected one
|
||||
accounts_to_process = [selected_account] if selected_account != 'all' else spotify_accounts
|
||||
|
||||
for account in accounts_to_process:
|
||||
if account not in spotify_accounts and account != 'all':
|
||||
continue
|
||||
|
||||
account_debug = {
|
||||
'total': 0,
|
||||
'fetched': 0,
|
||||
'filtered': 0,
|
||||
'time_ms': 0
|
||||
}
|
||||
|
||||
account_start = time.time()
|
||||
|
||||
# Fetch all playlists for this account
|
||||
account_playlists = fetch_all_user_playlists(sp, account)
|
||||
|
||||
account_end = time.time()
|
||||
account_debug['time_ms'] = int((account_end - account_start) * 1000)
|
||||
|
||||
account_debug['total'] = len(account_playlists)
|
||||
account_debug['fetched'] = len(account_playlists)
|
||||
debug_info['total_fetched'] += len(account_playlists)
|
||||
|
||||
# Apply keyword filtering if keywords provided
|
||||
if filter_keywords:
|
||||
filtered_playlists = filter_playlists_by_keywords(
|
||||
account_playlists,
|
||||
filter_keywords,
|
||||
debug_info
|
||||
)
|
||||
account_debug['filtered'] = len(filtered_playlists)
|
||||
debug_info['filtered_out'] += (len(account_playlists) - len(filtered_playlists))
|
||||
all_playlists.extend(filtered_playlists)
|
||||
else:
|
||||
# No filtering, use all playlists
|
||||
all_playlists.extend(account_playlists)
|
||||
account_debug['filtered'] = len(account_playlists)
|
||||
|
||||
debug_info['accounts'][account] = account_debug
|
||||
|
||||
# Remove duplicates based on playlist ID
|
||||
unique_playlists = []
|
||||
seen_ids = set()
|
||||
for playlist in all_playlists:
|
||||
if playlist['id'] not in seen_ids:
|
||||
seen_ids.add(playlist['id'])
|
||||
unique_playlists.append(playlist)
|
||||
else:
|
||||
debug_info['duplicates_removed'] += 1
|
||||
|
||||
all_playlists = unique_playlists
|
||||
debug_info['total_filtered'] = len(all_playlists)
|
||||
|
||||
end_time = time.time()
|
||||
debug_info['query_time_ms'] = int((end_time - start_time) * 1000)
|
||||
|
||||
# Log summary
|
||||
current_app.logger.info(
|
||||
f"Search summary: Fetched {debug_info['total_fetched']} playlists, "
|
||||
f"filtered to {debug_info['total_filtered']} playlists "
|
||||
f"({debug_info['filtered_out']} filtered out, {debug_info['duplicates_removed']} duplicates removed) "
|
||||
f"in {debug_info['query_time_ms']}ms"
|
||||
)
|
||||
|
||||
# Sort playlists by follower count or name if available
|
||||
all_playlists.sort(key=lambda x: x.get('name', '').lower())
|
||||
|
||||
# Randomize order if no specific sorting
|
||||
if not filter_keywords:
|
||||
random.shuffle(all_playlists)
|
||||
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Error fetching official playlists: {e}")
|
||||
flash('Error retrieving playlists from Spotify', 'danger')
|
||||
all_playlists = []
|
||||
|
||||
# Handle empty result
|
||||
if not all_playlists:
|
||||
flash('No Spotify playlists found matching your criteria', 'warning')
|
||||
|
||||
return render_template(
|
||||
'import_official_playlists.html',
|
||||
playlists=all_playlists,
|
||||
filter_keywords=filter_keywords,
|
||||
selected_account=selected_account,
|
||||
spotify_accounts=spotify_accounts,
|
||||
debug_info=debug_info,
|
||||
debug_mode=debug_mode
|
||||
)
|
||||
Reference in New Issue
Block a user