revert to for-loop for creating albums

- use ThreadPoolExecutor to create tracks
This commit is contained in:
geoffrey45
2022-05-10 08:22:41 +03:00
parent 86c2744e07
commit 7c38b0a9f3
5 changed files with 119 additions and 100 deletions
+1
View File
@@ -23,6 +23,7 @@ class Albums(db.Mongo):
""" """
Inserts a new album object into the database. Inserts a new album object into the database.
""" """
album = album.__dict__
return self.collection.update_one( return self.collection.update_one(
{ {
"album": album["title"], "album": album["title"],
+3 -5
View File
@@ -6,6 +6,8 @@ import random
import string import string
from datetime import datetime from datetime import datetime
from tqdm import tqdm
from app import api from app import api
from app import exceptions from app import exceptions
from app import instances from app import instances
@@ -55,14 +57,10 @@ def create_all_playlists():
""" """
playlists = instances.playlist_instance.get_all_playlists() playlists = instances.playlist_instance.get_all_playlists()
_bar = Bar("Creating playlists", max=len(playlists))
for playlist in playlists: for playlist in tqdm(playlists, desc="Creating playlists"):
api.PLAYLISTS.append(models.Playlist(playlist)) api.PLAYLISTS.append(models.Playlist(playlist))
_bar.next()
_bar.finish()
validate_images() validate_images()
+104 -75
View File
@@ -1,5 +1,11 @@
from dataclasses import asdict from concurrent.futures import ThreadPoolExecutor
from copy import deepcopy
from os import path from os import path
import time
from typing import List
from tqdm import tqdm
from app import api from app import api
from app import settings from app import settings
@@ -12,7 +18,8 @@ from app.lib.albumslib import find_album
from app.lib.taglib import get_tags from app.lib.taglib import get_tags
from app.logger import Log from app.logger import Log
from app.models import Album, Track from app.models import Album, Track
from progress.bar import Bar
from app.lib.trackslib import find_track
class Populate: class Populate:
@@ -30,21 +37,30 @@ class Populate:
self.tagged_tracks = [] self.tagged_tracks = []
self.folders = set() self.folders = set()
self.pre_albums = [] self.pre_albums = []
self.albums = [] self.albums: List[Album] = []
self.files = run_fast_scandir(settings.HOME_DIR, [".flac", ".mp3"])[1] self.files = run_fast_scandir(settings.HOME_DIR, [".flac", ".mp3"])[1]
self.db_tracks = tracks_instance.get_all_tracks() self.db_tracks = tracks_instance.get_all_tracks()
self.tag_count = 0
self.exist_count = 0
def run(self): def run(self):
self.check_untagged() self.check_untagged()
self.tag_files() self.tag_all_files()
if len(self.tagged_tracks) == 0: if len(self.tagged_tracks) == 0:
return return
self.tagged_tracks.sort(key=lambda x: x["albumhash"])
self.tracks = deepcopy(self.tagged_tracks)
self.create_pre_albums() self.create_pre_albums()
self.create_albums() self.create_albums()
self.albums.sort(key=lambda x: x.hash)
api.ALBUMS.sort(key=lambda x: x.hash) api.ALBUMS.sort(key=lambda x: x.hash)
self.save_albums()
self.create_tracks() self.create_tracks()
self.create_folders() self.create_folders()
@@ -54,129 +70,142 @@ class Populate:
from the list of tagged tracks if it exists. from the list of tagged tracks if it exists.
We will now only have untagged tracks left in `files`. We will now only have untagged tracks left in `files`.
""" """
bar = Bar("Checking untagged", max=len(self.db_tracks)) for track in tqdm(self.db_tracks, desc="Checking untagged"):
for track in self.db_tracks:
if track["filepath"] in self.files: if track["filepath"] in self.files:
self.files.remove(track["filepath"]) self.files.remove(track["filepath"])
bar.next()
bar.finish()
Log(f"Found {len(self.files)} untagged tracks") Log(f"Found {len(self.files)} untagged tracks")
def tag_files(self): def get_tags(self, file: str):
"""
Loops through all the untagged files and tags them.
"""
bar = Bar("Tagging files", max=len(self.files))
for file in self.files:
tags = get_tags(file) tags = get_tags(file)
folder = path.dirname(file)
self.folders.add(folder)
if tags is not None: if tags is not None:
tags["albumhash"] = create_album_hash( folder = tags["folder"]
tags["album"], tags["albumartist"] self.folders.add(folder)
)
tags["albumhash"] = create_album_hash(tags["album"], tags["albumartist"])
self.tagged_tracks.append(tags) self.tagged_tracks.append(tags)
api.DB_TRACKS.append(tags) api.DB_TRACKS.append(tags)
bar.next() def tag_all_files(self):
bar.finish() """
Log(f"Tagged {len(self.tagged_tracks)} files") Loops through all the untagged files and tags them.
"""
s = time.time()
print(f"Started tagging files")
with ThreadPoolExecutor() as executor:
executor.map(self.get_tags, self.files)
d = time.time() - s
Log(f"Tagged {len(self.tagged_tracks)} files in {d} seconds")
def create_pre_albums(self): def create_pre_albums(self):
""" """
Creates pre-albums for the all tagged tracks. Creates pre-albums for the all tagged tracks.
""" """
bar = Bar("Creating pre-albums", max=len(self.tagged_tracks)) for track in tqdm(self.tagged_tracks, desc="Creating pre-albums"):
for track in self.tagged_tracks:
album = {"title": track["album"], "artist": track["albumartist"]} album = {"title": track["album"], "artist": track["albumartist"]}
if album not in self.pre_albums: if album not in self.pre_albums:
self.pre_albums.append(album) self.pre_albums.append(album)
bar.next()
bar.finish()
Log(f"Created {len(self.pre_albums)} pre-albums") Log(f"Created {len(self.pre_albums)} pre-albums")
def create_album(self, album: dict):
albumhash = create_album_hash(album["title"], album["artist"])
index = find_album(api.ALBUMS, albumhash)
if index is not None:
album = api.ALBUMS[index]
self.albums.append(album)
self.exist_count += 1
return
self.albums.sort(key=lambda x: x.hash)
index = find_track(self.tagged_tracks, albumhash)
if index is None:
return
track = self.tagged_tracks[index]
album = create_album(track, self.tagged_tracks)
if album is None:
print("album is none")
return
album = Album(album)
api.ALBUMS.append(album)
self.albums.append(album)
def create_albums(self): def create_albums(self):
""" """
Uses the pre-albums to create new albums and add them to the database. Uses the pre-albums to create new albums and add them to the database.
""" """
exist_count = 0 for album in tqdm(self.pre_albums, desc="Building albums"):
self.create_album(album)
bar = Bar("Creating albums", max=len(self.pre_albums))
for album in self.pre_albums:
index = find_album(album["title"], album["artist"])
if index is None:
try:
track = [
track
for track in self.tagged_tracks
if track["album"] == album["title"]
and track["albumartist"] == album["artist"]
][0]
album = create_album(track)
api.ALBUMS.append(Album(album))
self.albums.append(album)
album_instance.insert_album(album)
except IndexError:
print("😠\n")
print(album)
else:
exist_count += 1
bar.next()
bar.finish()
Log( Log(
f"{exist_count} of {len(self.pre_albums)} albums were already in the database" f"{self.exist_count} of {len(self.pre_albums)} albums were already in the database"
) )
def create_tracks(self): def create_track(self, track: dict):
""" """
Loops through all the tagged tracks creating complete track objects using the `models.Track` model. Creates a single track object.
""" """
bar = Bar("Creating tracks", max=len(self.tagged_tracks))
failed_count = 0
for track in self.tagged_tracks: albumhash = track["albumhash"]
index = find_album(self.albums, albumhash)
if index is None:
return
try: try:
album_index = find_album(track["album"], track["albumartist"]) album: Album = self.albums[index]
album = api.ALBUMS[album_index] except (TypeError):
"""
😭😭😭
"""
pass
track["image"] = album.image track["image"] = album.image
upsert_id = tracks_instance.insert_song(track) upsert_id = tracks_instance.insert_song(track)
track["_id"] = {"$oid": str(upsert_id)} track["_id"] = {"$oid": str(upsert_id)}
api.TRACKS.append(Track(track)) api.TRACKS.append(Track(track))
except:
# 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. def create_tracks(self):
failed_count += 1 """
bar.next() Loops through all the tagged tracks creating complete track objects using the `models.Track` model.
bar.finish() """
with ThreadPoolExecutor() as executor:
executor.map(self.create_track, self.tagged_tracks)
Log( Log(
f"Added {len(self.tagged_tracks) - failed_count} of {len(self.tagged_tracks)} new tracks and {len(self.albums)} new albums" f"Added {len(self.tagged_tracks)} new tracks and {len(self.albums)} new albums"
) )
def save_albums(self):
"""
Saves the albums to the database.
"""
with ThreadPoolExecutor() as executor:
executor.map(album_instance.insert_album, self.albums)
def create_folders(self): def create_folders(self):
""" """
Creates the folder objects for all the tracks. Creates the folder objects for all the tracks.
""" """
bar = Bar("Creating folders", max=len(self.folders)) for folder in tqdm(self.folders, desc="Creating folders"):
for folder in self.folders:
api.VALID_FOLDERS.add(folder) api.VALID_FOLDERS.add(folder)
fff = folderslib.create_folder(folder) fff = folderslib.create_folder(folder)
api.FOLDERS.append(fff) api.FOLDERS.append(fff)
bar.next()
bar.finish()
Log(f"Created {len(self.folders)} new folders") Log(f"Created {len(self.folders)} new folders")
+2 -11
View File
@@ -8,8 +8,7 @@ from app import api
from app import instances from app import instances
from app import models from app import models
from app.helpers import remove_duplicates from app.helpers import remove_duplicates
from app.lib import albumslib from tqdm import tqdm
from progress.bar import Bar
def create_all_tracks() -> List[models.Track]: def create_all_tracks() -> List[models.Track]:
@@ -18,23 +17,15 @@ def create_all_tracks() -> List[models.Track]:
""" """
tracks: list[models.Track] = [] tracks: list[models.Track] = []
_bar = Bar("Creating tracks", max=len(api.DB_TRACKS)) for track in tqdm(api.DB_TRACKS, desc="Creating tracks"):
for track in api.DB_TRACKS:
try: try:
os.chmod(track["filepath"], 0o755) os.chmod(track["filepath"], 0o755)
except FileNotFoundError: except FileNotFoundError:
instances.tracks_instance.remove_song_by_id(track["_id"]["$oid"]) instances.tracks_instance.remove_song_by_id(track["_id"]["$oid"])
api.DB_TRACKS.remove(track) api.DB_TRACKS.remove(track)
try:
tracks.append(models.Track(track)) tracks.append(models.Track(track))
except KeyError:
print(track)
_bar.next()
_bar.finish()
return tracks return tracks
+1 -1
View File
@@ -58,7 +58,7 @@ def add_track(filepath: str) -> None:
if albumindex is not None: if albumindex is not None:
album = api.ALBUMS[albumindex] album = api.ALBUMS[albumindex]
else: else:
album_data = create_album(tags) album_data = create_album(tags, api.DB_TRACKS)
instances.album_instance.insert_album(album_data) instances.album_instance.insert_album(album_data)
album = models.Album(album_data) album = models.Album(album_data)