fix messed up bisection search

This commit is contained in:
geoffrey45
2022-05-07 14:45:16 +03:00
parent d6a01cd35e
commit fb67f568ad
8 changed files with 137 additions and 59 deletions
+17 -10
View File
@@ -1,5 +1,5 @@
"""
This module contains mimi functions for the server.
This module contains mini functions for the server.
"""
import datetime
import os
@@ -27,9 +27,7 @@ def background(func):
return background_func
def run_fast_scandir(__dir: str,
ext: list,
full=False) -> Dict[List[str], List[str]]:
def run_fast_scandir(__dir: str, ext: list, full=False) -> Dict[List[str], List[str]]:
"""
Scans a directory for files with a specific extension. Returns a list of files and folders in the directory.
"""
@@ -62,10 +60,12 @@ def remove_duplicates(tracklist: List[models.Track]) -> List[models.Track]:
while song_num < len(tracklist) - 1:
for index, song in enumerate(tracklist):
if (tracklist[song_num].title == song.title
and tracklist[song_num].album == song.album
and tracklist[song_num].artists == song.artists
and index != song_num):
if (
tracklist[song_num].title == song.title
and tracklist[song_num].album == song.album
and tracklist[song_num].artists == song.artists
and index != song_num
):
tracklist.remove(song)
song_num += 1
@@ -108,8 +108,7 @@ def check_artist_image(image: str) -> str:
"""
img_name = image.replace("/", "::") + ".webp"
if not os.path.exists(os.path.join(app_dir, "images", "artists",
img_name)):
if not os.path.exists(os.path.join(app_dir, "images", "artists", img_name)):
return use_memoji()
else:
return img_name
@@ -125,3 +124,11 @@ class Timer:
def stop(self):
self.end = time.time()
print(str(datetime.timedelta(seconds=round(self.end - self.begin))))
def create_album_hash(title: str, artist: str) -> str:
"""
Creates a simple hash for an album
"""
return (title + artist).replace(" ", "").lower()
-1
View File
@@ -37,7 +37,6 @@ def send_thumbnail(imgpath: str):
@app.route("/a/<imgpath>")
def send_artist_image(imgpath: str):
print(ARTIST_PATH)
fpath = join(ARTIST_PATH, imgpath)
exists = path.exists(fpath)
+44 -23
View File
@@ -1,20 +1,20 @@
"""
This library contains all the functions related to albums.
"""
from copy import deepcopy
import random
import urllib
from pprint import pprint
from typing import List
from app import api
from app import functions
from app import instances
from app import models
from app import settings
from app.lib import taglib
from app.lib import trackslib
from progress.bar import Bar
from app import helpers
def get_all_albums() -> List[models.Album]:
"""
@@ -23,6 +23,7 @@ def get_all_albums() -> List[models.Album]:
print("Getting all albums...")
albums: List[models.Album] = []
db_albums = instances.album_instance.get_all_albums()
_bar = Bar("Creating albums", max=len(db_albums))
@@ -44,7 +45,7 @@ def create_everything() -> List[models.Track]:
albums: list[models.Album] = get_all_albums()
api.ALBUMS = albums
api.ALBUMS.sort(key=lambda x: x.title)
api.ALBUMS.sort(key=lambda x: x.hash)
tracks = trackslib.create_all_tracks()
@@ -57,6 +58,7 @@ def find_album(albumtitle: str, artist: str) -> int or None:
"""
Finds an album by album title and artist.
"""
left = 0
right = len(api.ALBUMS) - 1
iter = 0
@@ -64,12 +66,15 @@ def find_album(albumtitle: str, artist: str) -> int or None:
while left <= right:
iter += 1
mid = (left + right) // 2
hash = helpers.create_album_hash(albumtitle, artist)
if api.ALBUMS[mid].title == albumtitle and api.ALBUMS[
mid].artist == artist:
return mid
try:
if api.ALBUMS[mid].hash == hash:
return mid
except:
print(api.ALBUMS[mid])
if api.ALBUMS[mid].title < albumtitle:
if api.ALBUMS[mid].hash < hash:
left = mid + 1
else:
right = mid - 1
@@ -125,18 +130,33 @@ def get_album_image(album: list) -> str:
return use_defaults()
class GetAlbumTracks:
"""
Finds all the tracks that match a specific album, given the album title
and album artist.
"""
def __init__(self, album: str, artist: str) -> None:
self.hash = helpers.create_album_hash(album, artist)
self.tracks = api.DB_TRACKS
self.tracks.sort(key=lambda x: x["albumhash"])
def find_tracks(self):
tracks = []
index = trackslib.find_track(self.tracks, self.hash)
while index is not None:
track = self.tracks[index]
tracks.append(track)
self.tracks.remove(track)
index = trackslib.find_track(self.tracks, self.hash)
api.DB_TRACKS.extend(tracks)
return tracks
def get_album_tracks(album: str, artist: str) -> List:
tracks = []
for track in api.DB_TRACKS:
try:
if track["album"] == album and track["albumartist"] == artist:
tracks.append(track)
except TypeError:
pprint(track, indent=4)
print(album, artist)
return tracks
return GetAlbumTracks(album, artist).find_tracks()
def create_album(track) -> models.Album:
@@ -144,20 +164,21 @@ def create_album(track) -> models.Album:
Generates and returns an album object from a track object.
"""
album = {
"album": track["album"],
"title": track["album"],
"artist": track["albumartist"],
}
album_tracks = get_album_tracks(album["album"], album["artist"])
album_tracks = get_album_tracks(album["title"], album["artist"])
album["date"] = album_tracks[0]["date"]
album["artistimage"] = urllib.parse.quote_plus(
album_tracks[0]["albumartist"] + ".webp")
album_tracks[0]["albumartist"] + ".webp"
)
album["image"] = get_album_image(album_tracks)
return models.Album(album)
return album
def search_albums_by_name(query: str) -> List[models.Album]:
+21 -10
View File
@@ -3,7 +3,7 @@ from os import path
from app import api
from app import settings
from app.helpers import run_fast_scandir
from app.helpers import create_album_hash, run_fast_scandir
from app.instances import album_instance
from app.instances import tracks_instance
from app.lib import folderslib
@@ -11,7 +11,7 @@ from app.lib.albumslib import create_album
from app.lib.albumslib import find_album
from app.lib.taglib import get_tags
from app.logger import Log
from app.models import Track
from app.models import Album, Track
from progress.bar import Bar
@@ -44,6 +44,7 @@ class Populate:
self.tag_files()
self.create_pre_albums()
self.create_albums()
api.ALBUMS.sort(key=lambda x: x.hash)
self.create_tracks()
self.create_folders()
@@ -73,6 +74,9 @@ class Populate:
self.folders.add(folder)
if tags is not None:
tags["albumhash"] = create_album_hash(
tags["album"], tags["albumartist"]
)
self.tagged_tracks.append(tags)
api.DB_TRACKS.append(tags)
@@ -108,16 +112,17 @@ class Populate:
if index is None:
try:
track = [
track for track in self.tagged_tracks
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)
api.ALBUMS.append(Album(album))
self.albums.append(album)
album_instance.insert_album(asdict(album))
album_instance.insert_album(album)
except IndexError:
print("😠\n")
@@ -128,8 +133,9 @@ class Populate:
bar.next()
bar.finish()
Log(f"{exist_count} of {len(self.pre_albums)} albums were already in the database"
)
Log(
f"{exist_count} of {len(self.pre_albums)} albums were already in the database"
)
def create_tracks(self):
"""
@@ -137,13 +143,16 @@ class Populate:
"""
bar = Bar("Creating tracks", max=len(self.tagged_tracks))
failed_count = 0
for track in self.tagged_tracks:
try:
album_index = find_album(track["album"], track["albumartist"])
album = api.ALBUMS[album_index]
track["image"] = album.image
upsert_id = tracks_instance.insert_song(track)
track["_id"] = {"$oid": str(upsert_id)}
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.
@@ -151,19 +160,21 @@ class Populate:
bar.next()
bar.finish()
Log(f"Added {len(self.tagged_tracks) - failed_count} of {len(self.tagged_tracks)} new tracks and {len(self.albums)} new albums"
)
Log(
f"Added {len(self.tagged_tracks) - failed_count} of {len(self.tagged_tracks)} new tracks and {len(self.albums)} new albums"
)
def create_folders(self):
"""
Creates the folder objects for all the tracks.
"""
bar = Bar("Creating folders", max=len(self.folders))
old_f_count = len(api.FOLDERS)
for folder in self.folders:
api.VALID_FOLDERS.add(folder)
fff = folderslib.create_folder(folder)
api.FOLDERS.append(fff)
bar.next()
bar.finish()
+25
View File
@@ -26,6 +26,7 @@ def create_all_tracks() -> List[models.Track]:
except FileNotFoundError:
instances.tracks_instance.remove_song_by_id(track["_id"]["$oid"])
api.DB_TRACKS.remove(track)
try:
tracks.append(models.Track(track))
except KeyError:
@@ -54,3 +55,27 @@ def get_track_by_id(trackid: str) -> models.Track:
for track in api.TRACKS:
if track.trackid == trackid:
return track
def find_track(tracks: list, hash: str) -> int or None:
"""
Finds an album by album title and artist.
"""
left = 0
right = len(tracks) - 1
iter = 0
while left <= right:
iter += 1
mid = (left + right) // 2
if tracks[mid]["albumhash"] == hash:
return mid
if tracks[mid]["albumhash"] < hash:
left = mid + 1
else:
right = mid - 1
return None
+19 -8
View File
@@ -8,11 +8,13 @@ from app import api
from app import instances
from app import models
from app.lib import folderslib
from app.lib.albumslib import create_album
from app.lib.albumslib import create_album, find_album
from app.lib.taglib import get_tags
from watchdog.events import PatternMatchingEventHandler
from watchdog.observers import Observer
from app.helpers import create_album_hash
class OnMyWatch:
"""
@@ -48,14 +50,24 @@ def add_track(filepath: str) -> None:
tags = get_tags(filepath)
if tags is not None:
instances.tracks_instance.insert_song(tags)
tags = instances.tracks_instance.get_song_by_path(tags["filepath"])
tags["albumhash"] = create_album_hash(tags["album"], tags["albumartist"])
api.DB_TRACKS.append(tags)
album = create_album(tags)
api.ALBUMS.append(album)
albumindex = find_album(tags["album"], tags["albumartist"])
if albumindex is not None:
album = api.ALBUMS[albumindex]
else:
album_data = create_album(tags)
instances.album_instance.insert_album(album_data)
album = models.Album(album_data)
api.ALBUMS.append(album)
tags["image"] = album.image
upsert_id = instances.tracks_instance.insert_song(tags)
tags["_id"] = {"$oid": str(upsert_id)}
api.TRACKS.append(models.Track(tags))
folder = tags["folder"]
@@ -74,8 +86,7 @@ def remove_track(filepath: str) -> None:
fpath = filepath.replace(fname, "")
try:
trackid = instances.tracks_instance.get_song_by_path(
filepath)["_id"]["$oid"]
trackid = instances.tracks_instance.get_song_by_path(filepath)["_id"]["$oid"]
except TypeError:
print(f"💙 Watchdog Error: Error removing track {filepath} TypeError")
return
+11 -6
View File
@@ -3,12 +3,11 @@ Contains all the models for objects generation and typing.
"""
from dataclasses import dataclass
from dataclasses import field
from datetime import date
from typing import List
from app import api
from app import settings
from app.exceptions import TrackExistsInPlaylist
from app import helpers
@dataclass
@@ -30,6 +29,7 @@ class Track:
image: str
tracknumber: int
discnumber: int
albumhash: str
def __init__(self, tags):
@@ -46,6 +46,7 @@ class Track:
self.image = tags["image"]
self.tracknumber = tags["tracknumber"]
self.discnumber = tags["discnumber"]
self.albumhash = tags['albumhash']
@dataclass
@@ -59,22 +60,26 @@ class Album:
date: int
artistimage: str
image: str
hash: str
count: int = 0
duration: int = 0
def __init__(self, tags):
self.title = tags["album"]
self.title = tags["title"]
self.artist = tags["artist"]
self.date = tags["date"]
self.artistimage = tags["artistimage"]
self.image = tags["image"]
self.hash = helpers.create_album_hash(self.title, self.artist)
def get_p_track(ptrack):
for track in api.TRACKS:
if (track.title == ptrack["title"]
and track.artists == ptrack["artists"]
and ptrack["album"] == track.album):
if (
track.title == ptrack["title"]
and track.artists == ptrack["artists"]
and ptrack["album"] == track.album
):
return track
-1
View File
@@ -13,7 +13,6 @@ def create_config_dir() -> None:
_home_dir = os.path.expanduser("~")
config_folder = os.path.join(_home_dir, settings.CONFIG_FOLDER)
print(config_folder)
dirs = [
"",