Mixonomer/music/db/part_generator.py

106 lines
3.3 KiB
Python
Raw Normal View History

2019-10-23 14:44:17 +01:00
from music.model.user import User
2020-04-30 14:54:05 +01:00
from music.model.playlist import Playlist
import logging
2021-03-24 10:06:54 +00:00
from typing import List
from google.cloud.firestore import DocumentReference
logger = logging.getLogger(__name__)
class PartGenerator:
2021-03-24 10:06:54 +00:00
"""Resolve a playlists components from other referenced smart playlists
"""
2019-10-29 12:25:49 +00:00
def __init__(self, user: User = None, username: str = None):
2021-03-24 10:06:54 +00:00
"""Initialise with user to resolve for
Args:
user (User, optional): Subject user. Defaults to None.
username (str, optional): Subject username. Defaults to None.
Raises:
LookupError: No user returned when querying for username
NameError: No user provided
"""
self.queried_playlists = []
self.parts = []
2019-10-23 14:44:17 +01:00
if user:
self.user = user
elif username:
2020-04-30 14:54:05 +01:00
pulled_user = User.collection.filter('username', '==', username.strip().lower()).get()
2019-10-23 14:44:17 +01:00
if pulled_user:
self.user = pulled_user
else:
raise LookupError(f'{username} not found')
else:
raise NameError('no user info provided')
def reset(self):
2021-03-24 10:06:54 +00:00
"""Reset internal state for resolved playlists
"""
self.queried_playlists = []
self.parts = []
2021-03-24 10:06:54 +00:00
def get_recursive_parts(self, name: str) -> List[str]:
"""Resolve and return a playlist's component Spotify playlist names
Args:
name (str): Subject smart playlist name
Returns:
List[str]: Resolved list of component playlists
"""
2019-10-23 14:44:17 +01:00
logger.info(f'getting part from {name} for {self.user.username}')
self.reset()
self.process_reference_by_name(name)
2021-03-24 10:06:54 +00:00
return list({i for i in self.parts})
2021-03-24 10:06:54 +00:00
def process_reference_by_name(self, name: str) -> None:
"""Resolve a smart playlist by name, recurses into process_reference_by_reference
Args:
name (str): Subject playlist name
"""
2020-04-30 14:54:05 +01:00
playlist = Playlist.collection.parent(self.user.key).filter('name', '==', name).get()
2019-10-23 14:44:17 +01:00
if playlist is not None:
2020-04-30 14:54:05 +01:00
if playlist.id not in self.queried_playlists:
2019-10-23 14:44:17 +01:00
self.parts += playlist.parts
2020-04-30 14:54:05 +01:00
self.queried_playlists.append(playlist.id)
2019-10-23 14:44:17 +01:00
for i in playlist.playlist_references:
if i.id not in self.queried_playlists:
self.process_reference_by_reference(i)
else:
2019-10-23 14:44:17 +01:00
logger.warning(f'playlist reference {name} already queried')
else:
logger.warning(f'playlist reference {name} not found')
2021-03-24 10:06:54 +00:00
def process_reference_by_reference(self, ref: DocumentReference):
"""Recursive resolution function for walking a playlist's dependencies by DocumentReference
Args:
ref (DocumentReference): Subject Firestore document for resolving
"""
if ref.id not in self.queried_playlists:
playlist_reference_object = ref.get().to_dict()
self.parts += playlist_reference_object['parts']
2020-04-30 14:54:05 +01:00
self.queried_playlists.append(ref.id)
for i in playlist_reference_object['playlist_references']:
self.process_reference_by_reference(i)
else:
logger.warning(f'playlist reference {ref.get().to_dict()["name"]} already queried')