create albums from pre-albums instead of individual tracks

This commit is contained in:
geoffrey45
2022-04-25 11:59:36 +03:00
parent c6e3bd9f94
commit 6527b3abc5
6 changed files with 106 additions and 45 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ VALID_FOLDERS: Set[str] = set()
ALBUMS: List[models.Album] = [] ALBUMS: List[models.Album] = []
TRACKS: List[models.Track] = [] TRACKS: List[models.Track] = []
PLAYLISTS: List[models.Playlist] = [] PLAYLISTS: List[models.Playlist] = []
FOLDERS: Set[models.Folder] = set() FOLDERS: List[models.Folder] = List
@helpers.background @helpers.background
+14 -7
View File
@@ -15,11 +15,17 @@ def send_track_file(trackid):
Returns an audio file that matches the passed id to the client. Returns an audio file that matches the passed id to the client.
""" """
try: try:
filepath = [ files = []
file["filepath"] for file in api.DB_TRACKS for f in api.DB_TRACKS:
if file["_id"]["$oid"] == trackid try:
][0] if f["_id"]["$oid"] == trackid:
except (FileNotFoundError, IndexError) as e: files.append(f["filepath"])
except KeyError:
# Bug: some albums are not found although they exist in `api.ALBUMS`. It has something to do with the bisection method used or sorting. Not sure yet.
pass
filepath = files[0]
except IndexError:
return "File not found", 404 return "File not found", 404
return send_file(filepath, mimetype="audio/mp3") return send_file(filepath, mimetype="audio/mp3")
@@ -31,5 +37,6 @@ def get_sample_track():
Returns a sample track object. Returns a sample track object.
""" """
return instances.tracks_instance.get_song_by_album("Legends Never Die", return instances.tracks_instance.get_song_by_album(
"Juice WRLD") "Legends Never Die", "Juice WRLD"
)
+59 -20
View File
@@ -3,11 +3,12 @@ This module contains functions for the server
""" """
import datetime import datetime
import os import os
from pprint import pprint
import random import random
import time import time
from dataclasses import asdict from dataclasses import asdict
from io import BytesIO from io import BytesIO
from typing import List from typing import List, Type
import requests import requests
from app import api from app import api
@@ -60,8 +61,7 @@ def populate():
albums = [] albums = []
folders = set() folders = set()
files = helpers.run_fast_scandir(settings.HOME_DIR, [".flac", ".mp3"], files = helpers.run_fast_scandir(settings.HOME_DIR, [".flac", ".mp3"], full=True)[1]
full=True)[1]
_bar = Bar("Checking files", max=len(files)) _bar = Bar("Checking files", max=len(files))
for track in db_tracks: for track in db_tracks:
@@ -88,24 +88,59 @@ def populate():
Log(f"Tagged {len(tagged_tracks)} tracks") Log(f"Tagged {len(tagged_tracks)} tracks")
_bar = Bar("Creating stuff", max=len(tagged_tracks)) pre_albums = []
for track in tagged_tracks:
albumindex = albumslib.find_album(track["album"], track["albumartist"]) for t in tagged_tracks:
album = None a = {
"title": t["album"],
"artist": t["albumartist"],
}
if a not in pre_albums:
pre_albums.append(a)
exist_count = 0
_bar = Bar("Creating albums", max=len(pre_albums))
for aa in pre_albums:
albumindex = albumslib.find_album(aa["title"], aa["artist"])
if albumindex is None: if albumindex is None:
track = [
track
for track in tagged_tracks
if track["album"] == aa["title"]
and track["albumartist"] == aa["artist"]
][0]
album = albumslib.create_album(track) album = albumslib.create_album(track)
api.ALBUMS.append(album) api.ALBUMS.append(album)
albums.append(album) albums.append(album)
instances.album_instance.insert_album(asdict(album)) instances.album_instance.insert_album(asdict(album))
else: else:
album = api.ALBUMS[albumindex] exist_count += 1
track["image"] = album.image _bar.next()
upsert_id = instances.tracks_instance.insert_song(track)
track["_id"] = {"$oid": str(upsert_id)} _bar.finish()
api.TRACKS.append(models.Track(track))
Log(f"{exist_count} of {len(albums)} were already in the database")
_bar = Bar("Creating tracks", max=len(tagged_tracks))
for track in tagged_tracks:
try:
album_index = albumslib.find_album(track["album"], track["albumartist"])
album = api.ALBUMS[album_index]
track["image"] = album.image
upsert_id = instances.tracks_instance.insert_song(track)
track["_id"] = {"$oid": str(upsert_id)}
api.TRACKS.append(models.Track(track))
except TypeError:
# Bug: some albums are not found although they exist in `api.ALBUMS`. It has something to do with the bisection method used or sorting. Not sure yet.
pass
_bar.next() _bar.next()
@@ -118,7 +153,7 @@ def populate():
if folder not in api.VALID_FOLDERS: if folder not in api.VALID_FOLDERS:
api.VALID_FOLDERS.add(folder) api.VALID_FOLDERS.add(folder)
fff = folderslib.create_folder(folder) fff = folderslib.create_folder(folder)
api.FOLDERS.add(fff) api.FOLDERS.append(fff)
_bar.next() _bar.next()
@@ -129,8 +164,11 @@ def populate():
end = time.time() end = time.time()
print( print(
str(datetime.timedelta(seconds=round(end - start))) + " elapsed for " + str(datetime.timedelta(seconds=round(end - start)))
str(len(files)) + " files") + " elapsed for "
+ str(len(files))
+ " files"
)
def fetch_image_path(artist: str) -> str or None: def fetch_image_path(artist: str) -> str or None:
@@ -165,8 +203,9 @@ def fetch_artist_images():
_bar = Bar("Processing images", max=len(artists)) _bar = Bar("Processing images", max=len(artists))
for artist in artists: for artist in artists:
file_path = (helpers.app_dir + "/images/artists/" + file_path = (
artist.replace("/", "::") + ".webp") helpers.app_dir + "/images/artists/" + artist.replace("/", "::") + ".webp"
)
if not os.path.exists(file_path): if not os.path.exists(file_path):
img_path = fetch_image_path(artist) img_path = fetch_image_path(artist)
@@ -188,7 +227,8 @@ def fetch_album_bio(title: str, albumartist: str):
Returns the album bio for a given album. Returns the album bio for a given album.
""" """
last_fm_url = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key={}&artist={}&album={}&format=json".format( last_fm_url = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key={}&artist={}&album={}&format=json".format(
settings.LAST_FM_API_KEY, albumartist, title) settings.LAST_FM_API_KEY, albumartist, title
)
try: try:
response = requests.get(last_fm_url) response = requests.get(last_fm_url)
@@ -197,8 +237,7 @@ def fetch_album_bio(title: str, albumartist: str):
return None return None
try: try:
bio = data["album"]["wiki"]["summary"].split( bio = data["album"]["wiki"]["summary"].split('<a href="https://www.last.fm/')[0]
'<a href="https://www.last.fm/')[0]
except KeyError: except KeyError:
bio = None bio = None
+26 -10
View File
@@ -13,6 +13,9 @@ from app import models
from app.lib import trackslib from app.lib import trackslib
from progress.bar import Bar from progress.bar import Bar
from app.lib import taglib
from app import settings
def get_all_albums() -> List[models.Album]: def get_all_albums() -> List[models.Album]:
""" """
@@ -51,7 +54,7 @@ def create_everything() -> List[models.Track]:
api.TRACKS.sort(key=lambda x: x.title) api.TRACKS.sort(key=lambda x: x.title)
def find_album(albumtitle: str, artist: str) -> models.Album: def find_album(albumtitle: str, artist: str) -> int or None:
""" """
Finds an album by album title and artist. Finds an album by album title and artist.
""" """
@@ -63,8 +66,7 @@ def find_album(albumtitle: str, artist: str) -> models.Album:
iter += 1 iter += 1
mid = (left + right) // 2 mid = (left + right) // 2
if api.ALBUMS[mid].title == albumtitle and api.ALBUMS[ if api.ALBUMS[mid].title == albumtitle and api.ALBUMS[mid].artist == artist:
mid].artist == artist:
return mid return mid
if api.ALBUMS[mid].title < albumtitle: if api.ALBUMS[mid].title < albumtitle:
@@ -96,20 +98,33 @@ def use_defaults() -> str:
return path return path
def gen_random_path() -> str:
"""
Generates a random image file path for an album image.
"""
choices = "abcdefghijklmnopqrstuvwxyz0123456789"
path = "".join(random.choice(choices) for i in range(20))
path += ".webp"
return path
def get_album_image(album: list) -> str: def get_album_image(album: list) -> str:
""" """
Gets the image of an album. Gets the image of an album.
""" """
uri = settings.IMG_THUMB_URI
for track in album: for track in album:
img_p = (track["album"] + track["albumartist"] + ".webp").replace( img_p = gen_random_path()
"/", "::")
img = functions.extract_thumb(track["filepath"], webp_path=img_p)
if img is not None: exists = taglib.extract_thumb(track["filepath"], webp_path=img_p)
return img
return use_defaults() if exists:
return uri + img_p
return uri + use_defaults()
def get_album_tracks(album: str, artist: str) -> List: def get_album_tracks(album: str, artist: str) -> List:
@@ -142,7 +157,8 @@ def create_album(track) -> models.Album:
album["date"] = album_tracks[0]["date"] album["date"] = album_tracks[0]["date"]
album["artistimage"] = urllib.parse.quote_plus( album["artistimage"] = urllib.parse.quote_plus(
album_tracks[0]["albumartist"] + ".webp") album_tracks[0]["albumartist"] + ".webp"
)
album["image"] = get_album_image(album_tracks) album["image"] = get_album_image(album_tracks)
+5 -6
View File
@@ -1,5 +1,4 @@
import os import os
import urllib
from io import BytesIO from io import BytesIO
import mutagen import mutagen
@@ -29,14 +28,14 @@ def return_album_art(filepath: str):
return None return None
def extract_thumb(audio_file_path: str, webp_path: str) -> str: def extract_thumb(audio_file_path: str, webp_path: str) -> bool:
""" """
Extracts the thumbnail from an audio file. Returns the path to the thumbnail. Extracts the thumbnail from an audio file. Returns the path to the thumbnail.
""" """
img_path = os.path.join(settings.THUMBS_PATH, webp_path) img_path = os.path.join(settings.THUMBS_PATH, webp_path)
if os.path.exists(img_path): if os.path.exists(img_path):
return urllib.parse.quote(webp_path) return True
album_art = return_album_art(audio_file_path) album_art = return_album_art(audio_file_path)
@@ -52,11 +51,11 @@ def extract_thumb(audio_file_path: str, webp_path: str) -> str:
small_img = png.resize((250, 250), Image.ANTIALIAS) small_img = png.resize((250, 250), Image.ANTIALIAS)
small_img.save(webp_path, format="webp") small_img.save(webp_path, format="webp")
except: except:
return None return False
return urllib.parse.quote(webp_path) return True
else: else:
return None return False
def parse_artist_tag(audio): def parse_artist_tag(audio):
+1 -1
View File
@@ -63,7 +63,7 @@ def add_track(filepath: str) -> None:
if folder not in api.VALID_FOLDERS: if folder not in api.VALID_FOLDERS:
api.VALID_FOLDERS.add(folder) api.VALID_FOLDERS.add(folder)
f = folderslib.create_folder(folder) f = folderslib.create_folder(folder)
api.FOLDERS.add(f) api.FOLDERS.append(f)
def remove_track(filepath: str) -> None: def remove_track(filepath: str) -> None: