process albums seperate from tracks

- break populate function into 2
This commit is contained in:
geoffrey45
2022-06-19 14:45:25 +03:00
parent 06ed41d869
commit 3cf44759b5
11 changed files with 100 additions and 220 deletions
+16 -62
View File
@@ -34,32 +34,6 @@ def validate() -> None:
"""
def find_album(albums: List[models.Album], hash: str) -> int | None:
"""
Finds an album by album title and artist.
:param `albums`: List of album objects.
:param `hash`: Hash of album.
:return: Index of album in list.
"""
left = 0
right = len(albums) - 1
while left <= right:
mid = (left + right) // 2
if albums[mid].hash == hash:
return mid
if albums[mid].hash < hash:
left = mid + 1
else:
right = mid - 1
return None
def get_album_duration(album: List[models.Track]) -> int:
"""
Gets the duration of an album.
@@ -81,31 +55,19 @@ def use_defaults() -> str:
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(track: models.Track) -> str:
"""
Gets the image of an album.
"""
for track in album:
img_p = gen_random_path()
img_p = track.albumhash + ".webp"
exists = taglib.extract_thumb(track["filepath"], webp_path=img_p)
success = taglib.extract_thumb(track.filepath, webp_path=img_p)
if exists:
return img_p
if success:
return img_p
return use_defaults()
return None
class GetAlbumTracks:
@@ -122,14 +84,6 @@ class GetAlbumTracks:
def __call__(self):
tracks = helpers.UseBisection(self.tracks, "albumhash", [self.hash])()
pprint(tracks)
# while index is not None:
# track = self.tracks[index]
# tracks.append(track)
# self.tracks.remove(track)
# index = helpers.UseBisection(self.tracks, "albumhash", [self.hash])()
return tracks
@@ -137,23 +91,23 @@ def get_album_tracks(tracklist: List[models.Track], hash: str) -> List:
return GetAlbumTracks(tracklist, hash)()
def create_album(track: dict, tracklist: list[models.Track]) -> dict:
def create_album(track: models.Track) -> dict:
"""
Generates and returns an album object from a track object.
"""
album = {
"title": track["album"],
"artist": track["albumartist"],
"title": track.album,
"artist": track.albumartist,
"hash": track.albumhash,
}
albumhash = helpers.create_album_hash(album["title"], album["artist"])
album_tracks = get_album_tracks(tracklist, albumhash)
if len(album_tracks) == 0:
return None
album["date"] = track.date
album["date"] = album_tracks[0]["date"]
img_p = get_album_image(track)
album["image"] = get_album_image(album_tracks)
# album["image"] = "".join(x for x in albumhash if x not in "\/:*?<>|")
if img_p is not None:
album["image"] = img_p
return album
album["image"] = None
return album
+62 -101
View File
@@ -1,18 +1,17 @@
from dataclasses import dataclass
from pprint import pprint
import time
from concurrent.futures import ThreadPoolExecutor
from typing import List
from app import settings
from app.helpers import create_album_hash
from app.helpers import Get, UseBisection, create_album_hash
from app.helpers import run_fast_scandir
from app.instances import album_instance
from app.instances import tracks_instance
from app.lib.albumslib import create_album
from app.lib.albumslib import find_album
from app.lib.taglib import get_tags
from app.lib.trackslib import find_track
from app.logger import Log
from app.models import Album
from app.models import Album, Track
from tqdm import tqdm
from app import instances
@@ -28,36 +27,15 @@ class Populate:
"""
def __init__(self) -> None:
self.files = []
self.db_tracks = []
self.tagged_tracks = []
self.folders = set()
self.pre_albums = []
self.albums: List[Album] = []
self.files = run_fast_scandir(settings.HOME_DIR, full=True)[1]
self.db_tracks = tracks_instance.get_all_tracks()
self.tag_count = 0
self.exist_count = 0
self.tracks = []
def run(self):
self.check_untagged()
self.tag_untagged()
if len(self.tagged_tracks) == 0:
return
# self.tagged_tracks.sort(key=lambda x: x["albumhash"])
self.pre_albums = self.create_pre_albums(self.tagged_tracks)
self.create_albums(self.pre_albums)
self.albums.sort(key=lambda x: x.hash)
self.create_tracks()
self.save_all()
def check_untagged(self):
"""
Loops through all the tracks in db tracks removing each
@@ -88,97 +66,80 @@ class Populate:
with ThreadPoolExecutor() as executor:
executor.map(self.get_tags, self.files)
tracks_instance.insert_many(self.tagged_tracks)
if len(self.tagged_tracks) > 0:
tracks_instance.insert_many(self.tagged_tracks)
d = time.time() - s
Log(f"Tagged {len(self.tagged_tracks)} files in {d} seconds")
@dataclass
class PreAlbum:
title: str
artist: str
hash: str
class CreateAlbums:
def __init__(self) -> None:
self.db_tracks = Get.get_all_tracks()
self.db_albums = Get.get_all_albums()
prealbums = self.create_pre_albums(self.db_tracks)
prealbums = self.filter_processed(self.db_albums, prealbums)
print(f"📌 {len(prealbums)}")
albums = []
for album in tqdm(prealbums, desc="Creating albums"):
a = self.create_album(album)
albums.append(a)
if len(albums) > 0:
instances.album_instance.insert_many(albums)
@staticmethod
def create_pre_albums(tracks: List[dict]):
"""
Creates pre-albums for the all tagged tracks.
"""
def create_pre_albums(tracks: List[Track]) -> List[PreAlbum]:
prealbums = []
for track in tqdm(tracks, desc="Creating pre-albums"):
album = {"title": track["album"], "artist": track["albumartist"]}
for track in tqdm(tracks, desc="Creating prealbums"):
album = {
"title": track.album,
"artist": track.albumartist,
"hash": track.albumhash,
}
album = PreAlbum(**album)
if album not in prealbums:
prealbums.append(album)
Log(f"Created {len(prealbums)} pre-albums")
return prealbums
def create_album(self, album: dict):
albumhash = create_album_hash(album["title"], album["artist"])
album = instances.album_instance.find_album_by_hash(albumhash)
@staticmethod
def filter_processed(albums: List[Album], prealbums: List[PreAlbum]) -> List[dict]:
to_process = []
if album is not None:
self.albums.append(album)
self.exist_count += 1
return
for p in tqdm(prealbums, desc="Filtering processed albums"):
album = UseBisection(albums, "hash", [p.hash])()[0]
index = find_track(self.tagged_tracks, albumhash)
if album is None:
to_process.append(p)
track = self.tagged_tracks[index]
return to_process
album = create_album(track, self.tagged_tracks)
def create_album(self, album: PreAlbum) -> Album:
hash = album.hash
if album is None:
print("album is none")
return
album = {"image": None}
while album["image"] is None:
track = UseBisection(self.db_tracks, "albumhash", [hash])()[0]
if track is not None:
album = create_album(track)
self.db_tracks.remove(track)
else:
album["image"] = hash
album = Album(album)
self.albums.append(album)
def create_albums(self, albums: List[dict]):
"""
Uses the pre-albums to create new albums and add them to the database.
"""
for album in tqdm(albums, desc="Building albums"):
self.create_album(album)
Log(f"{self.exist_count} of {len(albums)} albums were already in the database")
def create_track(self, track: dict):
"""
Creates a single track object.
"""
albumhash = track["albumhash"]
index = find_album(self.albums, albumhash)
if index is None:
return
try:
album: Album = self.albums[index]
except (TypeError):
"""
😭😭😭
"""
pass
track["image"] = album.image
return track
def create_tracks(self):
"""
Loops through all the tagged tracks creating complete track objects using the `models.Track` model.
"""
with ThreadPoolExecutor() as executor:
iterable = executor.map(self.create_track, self.tagged_tracks)
self.tracks = [t for t in iterable if t is not None]
Log(
f"Added {len(self.tagged_tracks)} new tracks and {len(self.albums)} new albums"
)
def save_all(self):
"""
Saves the albums to the database.
"""
album_instance.insert_many([a.__dict__ for a in self.albums])
tracks_instance.insert_many(self.tracks)
return album
+4 -4
View File
@@ -135,8 +135,8 @@ def parse_track_number(tags):
Parses the track number from an audio file.
"""
try:
track_number = tags["tracknumber"][0]
except (KeyError, IndexError):
track_number = int(tags["tracknumber"][0])
except (KeyError, IndexError, ValueError):
track_number = 1
return track_number
@@ -147,8 +147,8 @@ def parse_disk_number(tags):
Parses the disk number from an audio file.
"""
try:
disk_number = tags["disknumber"][0]
except (KeyError, IndexError):
disk_number = int(tags["disknumber"][0])
except (KeyError, IndexError, ValueError):
disk_number = 1
return disk_number
+1 -1
View File
@@ -44,7 +44,7 @@ def get_track_by_id(trackid: str) -> models.Track:
print("AttributeError")
def find_track(tracks: list, hash: str) -> int or None:
def find_track(tracks: list, hash: str) -> int | None:
"""
Finds an album by album title and artist.
"""