added tags and tag update

This commit is contained in:
aj 2020-02-03 09:44:33 +00:00
parent 2acbad120c
commit 1aee2feb16
4 changed files with 317 additions and 0 deletions

21
main.py
View File

@ -1,6 +1,27 @@
from music import app
from music.tasks.update_tag import update_tag as do_update_tag
app = app
def update_tag(event, context):
import base64
import logging
import json
logger = logging.getLogger('music')
if 'data' in event:
body = json.loads(base64.b64decode(event['data']).decode('utf-8'))
if 'username' not in body or 'tag_id' not in body:
logger.error('malformed body')
return
do_update_tag(username=body["username"], tag_id=body["tag_id"])
else:
logger.error('no data in event')
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8080, debug=True)

View File

@ -9,6 +9,7 @@ from fmframework.net.network import Network as FmNetwork
from music.db.user import DatabaseUser
from music.model.user import User
from music.model.playlist import Playlist, RecentsPlaylist, LastFMChartPlaylist, Sort
from music.model.tag import Tag
db = firestore.Client()
@ -324,3 +325,98 @@ def delete_playlist(username: str, name: str) -> None:
playlist.db_ref.delete()
else:
logger.error(f'playlist {name} not found for {username}')
def get_user_tags(username: str) -> List[Tag]:
logger.info(f'getting tags for {username}')
user = get_user(username)
if user:
tag_refs = [i for i in user.db_ref.collection(u'tags').stream()]
return [parse_tag_reference(username=username, tag_snapshot=i) for i in tag_refs]
else:
logger.error(f'user {username} not found')
def get_tag(username: str = None, tag_id: str = None) -> Optional[Tag]:
logger.info(f'retrieving {tag_id} for {username}')
user = get_user(username)
if user:
tags = [i for i in user.db_ref.collection(u'tags').where(u'tag_id', u'==', tag_id).stream()]
if len(tags) == 0:
logger.error(f'tag {tag_id} for {user} not found')
return None
if len(tags) > 1:
logger.critical(f"multiple {tag_id}'s for {user} found")
return None
return parse_tag_reference(username=username, tag_snapshot=tags[0])
else:
logger.error(f'user {username} not found')
def parse_tag_reference(username, tag_ref=None, tag_snapshot=None) -> Tag:
if tag_ref is None and tag_snapshot is None:
raise ValueError('no tag object supplied')
if tag_ref is None:
tag_ref = tag_snapshot.reference
if tag_snapshot is None:
tag_snapshot = tag_ref.get()
tag_dict = tag_snapshot.to_dict()
return Tag(tag_id=tag_dict['tag_id'],
name=tag_dict.get('name', 'n/a'),
username=username,
db_ref=tag_ref,
tracks=tag_dict.get('tracks', []),
albums=tag_dict.get('albums', []),
artists=tag_dict.get('artists', []),
count=tag_dict.get('count', 0),
proportion=tag_dict.get('proportion', 0.0),
total_user_scrobbles=tag_dict.get('total_user_scrobbles', 0),
last_updated=tag_dict.get('last_updated'))
def update_tag(username: str, tag_id: str, updates: dict) -> None:
if len(updates) > 0:
logger.debug(f'updating {tag_id} for {username}')
user = get_user(username)
tags = [i for i in user.db_ref.collection(u'tags').where(u'tag_id', u'==', tag_id).stream()]
if len(tags) == 0:
logger.error(f'tag {tag_id} for {username} not found')
return None
if len(tags) > 1:
logger.critical(f"multiple {tag_id}'s for {username} found")
return None
tag = tags[0].reference
tag.update(updates)
else:
logger.debug(f'nothing to update for {tag_id} for {username}')
def delete_tag(username: str, tag_id: str) -> None:
logger.info(f'deleting {tag_id} for {username}')
tag = get_tag(username=username, tag_id=tag_id)
if tag:
tag.db_ref.delete()
else:
logger.error(f'playlist {tag_id} not found for {username}')

128
music/model/tag.py Normal file
View File

@ -0,0 +1,128 @@
from datetime import datetime
import music.db.database as db
class Tag:
def __init__(self,
tag_id: str,
name: str,
username: str,
db_ref,
tracks,
albums,
artists,
count: int,
proportion: float,
total_user_scrobbles: int,
last_updated: datetime):
self.tag_id = tag_id
self._name = name
self.username = username
self.db_ref = db_ref
self._tracks = tracks
self._albums = albums
self._artists = artists
self._count = count
self._proportion = proportion
self._total_user_scrobbles = total_user_scrobbles
self._last_updated = last_updated
def to_dict(self):
return {
'tag_id': self.tag_id,
'name': self.name,
'username': self.username,
'tracks': self.tracks,
'albums': self.albums,
'artists': self.artists,
'count': self.count,
'proportion': self.proportion,
'last_updated': self.last_updated
}
def update_database(self, updates):
db.update_tag(username=self.username, tag_id=self.tag_id, updates=updates)
@property
def name(self):
return self._name
@name.setter
def name(self, value):
db.update_tag(username=self.username, tag_id=self.tag_id, updates={'name': value})
self._name = value
@property
def tracks(self):
return self._tracks
@tracks.setter
def tracks(self, value):
db.update_tag(username=self.username, tag_id=self.tag_id, updates={'tracks': value})
self._tracks = value
@property
def albums(self):
return self._albums
@albums.setter
def albums(self, value):
db.update_tag(username=self.username, tag_id=self.tag_id, updates={'albums': value})
self._albums = value
@property
def artists(self):
return self._artists
@artists.setter
def artists(self, value):
db.update_tag(username=self.username, tag_id=self.tag_id, updates={'artists': value})
self._artists = value
@property
def count(self):
return self._count
@count.setter
def count(self, value):
db.update_tag(username=self.username, tag_id=self.tag_id, updates={'count': value})
self._count = value
@property
def proportion(self):
return self._proportion
@proportion.setter
def proportion(self, value):
db.update_tag(username=self.username, tag_id=self.tag_id, updates={'proportion': value})
self._proportion = value
@property
def total_user_scrobbles(self):
return self._total_user_scrobbles
@total_user_scrobbles.setter
def total_user_scrobbles(self, value):
db.update_tag(username=self.username, tag_id=self.tag_id, updates={'total_user_scrobbles': value})
self._total_user_scrobbles = value
@property
def last_updated(self):
return self._last_updated
@last_updated.setter
def last_updated(self, value):
db.update_tag(username=self.username, tag_id=self.tag_id, updates={'last_updated': value})
self._last_updated = value

72
music/tasks/update_tag.py Normal file
View File

@ -0,0 +1,72 @@
import logging
from datetime import datetime
import music.db.database as database
logger = logging.getLogger(__name__)
def update_tag(username, tag_id):
logger.info(f'updating {username} / {tag_id}')
tag = database.get_tag(username=username, tag_id=tag_id)
if tag is None:
logger.error(f'{tag_id} for {username} not found')
return
user = database.get_user(username)
if user.lastfm_username is None or len(user.lastfm_username) == 0:
logger.error(f'{username} has no last.fm username')
return
net = database.get_authed_lastfm_network(username=username)
tag_count = 0
user_scrobbles = net.get_user_scrobble_count()
artists = []
for artist in tag.artists:
net_artist = net.get_artist(name=artist['name'])
if net_artist is not None:
artist['count'] = net_artist.user_scrobbles
tag_count += net_artist.user_scrobbles
artists.append(artist)
albums = []
for album in tag.albums:
net_album = net.get_album(name=album['name'], artist=album['artist'])
if net_album is not None:
album['count'] = net_album.user_scrobbles
if album['artist'].lower() not in [i.lower() for i in [j['name'] for j in artists]]:
tag_count += net_album.user_scrobbles
albums.append(album)
tracks = []
for track in tag.tracks:
net_track = net.get_track(name=track['name'], artist=track['artist'])
if net_track is not None:
track['count'] = net_track.user_scrobbles
if track['artist'].lower() not in [i.lower() for i in [j['name'] for j in artists]]:
tag_count += net_track.user_scrobbles
tracks.append(track)
tag.update_database({
'tracks': tracks,
'albums': albums,
'artists': artists,
'total_user_scrobbles': user_scrobbles,
'count': tag_count,
'proportion': (tag_count / user_scrobbles) * 100,
'last_updated': datetime.utcnow()
})