refactor most things to use the database directly

This commit is contained in:
geoffrey45
2022-06-13 14:45:18 +03:00
parent f1ec6309ba
commit 030ab8a379
18 changed files with 237 additions and 365 deletions
-18
View File
@@ -3,25 +3,10 @@ This module contains all the Flask Blueprints and API routes. It also contains a
that are used through-out the app. It handles the initialization of the watchdog,
checking and creating config dirs and starting the re-indexing process using a background thread.
"""
from typing import List
from typing import Set
from app import functions
from app import helpers
from app import instances
from app import models
from app import prep
from app.lib import albumslib
from app.lib import folderslib
from app.lib import playlistlib
DB_TRACKS = instances.tracks_instance.get_all_tracks()
VALID_FOLDERS: Set[str] = set()
ALBUMS: List[models.Album] = []
TRACKS: List[models.Track] = []
PLAYLISTS: List[models.Playlist] = []
FOLDERS: List[models.Folder] = List
@helpers.background
@@ -31,9 +16,6 @@ def initialize() -> None:
"""
functions.start_watchdog()
prep.create_config_dir()
albumslib.create_everything()
folderslib.run_scandir()
playlistlib.create_all_playlists()
functions.reindex_tracks()
+20 -22
View File
@@ -1,16 +1,17 @@
"""
Contains all the album routes.
"""
from pprint import pprint
from typing import List
from app import api
from app import helpers
from app import models
from app.lib import albumslib
from app.lib import trackslib
from flask import Blueprint
from flask import request
from app.functions import FetchAlbumBio
from app import instances
album_bp = Blueprint("album", __name__, url_prefix="")
@@ -35,31 +36,31 @@ def get_albums():
return {"albums": albums}
@album_bp.route("/album/tracks", methods=["POST"])
@album_bp.route("/album", methods=["POST"])
def get_album():
"""Returns all the tracks in the given album."""
data = request.get_json()
album = data["album"]
artist = data["artist"]
songs = trackslib.get_album_tracks(album, artist)
album, artist = data["album"], data["artist"]
albumhash = helpers.create_album_hash(album, artist)
index = albumslib.find_album(api.ALBUMS, albumhash)
album: models.Album = api.ALBUMS[index]
album.count = len(songs)
album.duration = albumslib.get_album_duration(songs)
tracks = instances.tracks_instance.find_tracks_by_hash(albumhash)
tracks = [models.Track(t) for t in tracks]
album = instances.album_instance.find_album_by_hash(albumhash)
album = models.Album(album)
album.count = len(tracks)
album.duration = albumslib.get_album_duration(tracks)
if (
album.count == 1
and songs[0].title == album.title
and songs[0].tracknumber == 1
and songs[0].disknumber == 1
and tracks[0].title == album.title
and tracks[0].tracknumber == 1
and tracks[0].disknumber == 1
):
album.is_single = True
return {"songs": songs, "info": album}
return {"tracks": tracks, "info": album}
@album_bp.route("/album/bio", methods=["POST"])
@@ -80,14 +81,11 @@ def get_albumartists():
"""Returns a list of artists featured in a given album."""
data = request.get_json()
album = data["album"]
artist = data["artist"]
album, artist = data["album"], data["artist"]
albumhash = helpers.create_album_hash(album, artist)
tracks: List[models.Track] = []
for track in api.TRACKS:
if track.album == album and track.albumartist == artist:
tracks.append(track)
tracks = instances.tracks_instance.find_tracks_by_hash(albumhash)
tracks = [models.Track(t) for t in tracks]
artists = []
+32 -33
View File
@@ -22,8 +22,12 @@ TrackExistsInPlaylist = exceptions.TrackExistsInPlaylist
@playlist_bp.route("/playlists", methods=["GET"])
def get_all_playlists():
"""Returns all the playlists."""
dbplaylists = instances.playlist_instance.get_all_playlists()
dbplaylists = [models.Playlist(p) for p in dbplaylists]
playlists = [
serializer.Playlist(p, construct_last_updated=False) for p in api.PLAYLISTS
serializer.Playlist(p, construct_last_updated=False) for p in dbplaylists
]
playlists.sort(
key=lambda p: datetime.strptime(p.lastUpdated, "%Y-%m-%d %H:%M:%S"),
@@ -36,7 +40,7 @@ def get_all_playlists():
def create_playlist():
data = request.get_json()
playlist = {
data = {
"name": data["name"],
"description": "",
"pre_tracks": [],
@@ -45,21 +49,16 @@ def create_playlist():
"thumb": "",
}
try:
for pl in api.PLAYLISTS:
if pl.name == playlist["name"]:
raise PlaylistExists("Playlist already exists.")
dbp = instances.playlist_instance.get_playlist_by_name(data["name"])
except PlaylistExists as e:
return {"error": str(e)}, 409
if dbp is not None:
return {"message": "Playlist already exists."}, 409
upsert_id = instances.playlist_instance.insert_playlist(playlist)
upsert_id = instances.playlist_instance.insert_playlist(data)
p = instances.playlist_instance.get_playlist_by_id(upsert_id)
pp = models.Playlist(p)
playlist = models.Playlist(p)
api.PLAYLISTS.append(pp)
return {"playlist": pp}, 201
return {"playlist": playlist}, 201
@playlist_bp.route("/playlist/<playlist_id>/add", methods=["POST"])
@@ -70,22 +69,22 @@ def add_track_to_playlist(playlist_id: str):
try:
playlistlib.add_track(playlist_id, trackid)
except TrackExistsInPlaylist as e:
except TrackExistsInPlaylist:
return {"error": "Track already exists in playlist"}, 409
return {"msg": "I think It's done"}, 200
@playlist_bp.route("/playlist/<playlistid>")
def get_single_p_info(playlistid: str):
p = UseBisection(api.PLAYLISTS, "playlistid", [playlistid])()
playlist: models.Playlist = p[0]
def get_playlist(playlistid: str):
p = instances.playlist_instance.get_playlist_by_id(playlistid)
if p is None:
return {"info": {}, "tracks": []}
if playlist is not None:
tracks = playlist.get_tracks()
return {"info": serializer.Playlist(playlist), "tracks": tracks}
playlist = models.Playlist(p)
return {"info": {}, "tracks": []}
tracks = playlistlib.create_playlist_tracks(playlist.pretracks)
return {"info": serializer.Playlist(playlist), "tracks": tracks}
@playlist_bp.route("/playlist/<playlistid>/update", methods=["PUT"])
@@ -109,21 +108,21 @@ def update_playlist(playlistid: str):
p: models.Playlist = p[0]
if playlist is not None:
if image:
image_, thumb_ = playlistlib.save_p_image(image, playlistid)
playlist["image"] = image_
playlist["thumb"] = thumb_
if image:
image_, thumb_ = playlistlib.save_p_image(image, playlistid)
playlist["image"] = image_
playlist["thumb"] = thumb_
else:
playlist["image"] = p.image.split("/")[-1]
playlist["thumb"] = p.thumb.split("/")[-1]
else:
playlist["image"] = p.image.split("/")[-1]
playlist["thumb"] = p.thumb.split("/")[-1]
p.update_playlist(playlist)
instances.playlist_instance.update_playlist(playlistid, playlist)
p.update_playlist(playlist)
instances.playlist_instance.update_playlist(playlistid, playlist)
return {
"data": serializer.Playlist(p),
}
return {
"data": serializer.Playlist(p),
}
return {"msg": "Something shady happened"}, 500
+6 -15
View File
@@ -95,18 +95,9 @@ def search():
return {
"data": [
{
"tracks": tracks[:5],
"more": len(tracks) > 5
},
{
"albums": albums[:6],
"more": len(albums) > 6
},
{
"artists": artists_dicts[:6],
"more": len(artists_dicts) > 6
},
{"tracks": tracks[:5], "more": len(tracks) > 5},
{"albums": albums[:6], "more": len(albums) > 6},
{"artists": artists_dicts[:6], "more": len(artists_dicts) > 6},
]
}
@@ -121,18 +112,18 @@ def search_load_more():
if type == "tracks":
return {
"tracks": SEARCH_RESULTS["tracks"][index:index + 5],
"tracks": SEARCH_RESULTS["tracks"][index : index + 5],
"more": len(SEARCH_RESULTS["tracks"]) > index + 5,
}
elif type == "albums":
return {
"albums": SEARCH_RESULTS["albums"][index:index + 6],
"albums": SEARCH_RESULTS["albums"][index : index + 6],
"more": len(SEARCH_RESULTS["albums"]) > index + 6,
}
elif type == "artists":
return {
"artists": SEARCH_RESULTS["artists"][index:index + 6],
"artists": SEARCH_RESULTS["artists"][index : index + 6],
"more": len(SEARCH_RESULTS["artists"]) > index + 6,
}
+8 -12
View File
@@ -6,6 +6,8 @@ from app import instances
from flask import Blueprint
from flask import send_file
from app import models
track_bp = Blueprint("track", __name__, url_prefix="/")
@@ -14,21 +16,15 @@ def send_track_file(trackid):
"""
Returns an audio file that matches the passed id to the client.
"""
try:
files = []
for f in api.DB_TRACKS:
try:
if f["_id"]["$oid"] == trackid:
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
track = instances.tracks_instance.get_track_by_id(trackid)
filepath = files[0]
except IndexError:
if track is None:
return "File not found", 404
return send_file(filepath, mimetype="audio/mp3")
track = models.Track(track)
type = track.filepath.split(".")[-1]
return send_file(track.filepath, mimetype=f"audio/{type}")
@track_bp.route("/sample")
+12
View File
@@ -200,3 +200,15 @@ class TrackMethods:
Removes a track from the database. Returns a boolean indicating success or failure of the operation.
"""
pass
def find_tracks_by_hash():
"""
Returns all the tracks matching the passed hash.
"""
pass
def find_tracks_inside_path_regex():
"""
Returns a list of all the tracks matching the path in the query params.
"""
pass
+11 -10
View File
@@ -21,16 +21,17 @@ class Albums(MongoAlbums):
"""
album = album.__dict__
return self.collection.update_one(
{
"album": album["title"],
"artist": album["artist"]
},
{
"$set": album
},
{"album": album["title"], "artist": album["artist"]},
{"$set": album},
upsert=True,
).upserted_id
def insert_many(self, albums: list):
"""
Inserts multiple albums into the database.
"""
return self.collection.insert_many(albums)
def get_all_albums(self) -> list:
"""
Returns all the albums in the database.
@@ -52,9 +53,9 @@ class Albums(MongoAlbums):
album = self.collection.find_one({"album": name, "artist": artist})
return convert_one(album)
def get_album_by_artist(self, name: str) -> dict:
def find_album_by_hash(self, hash: str) -> dict:
"""
Returns a single album matching the artist in the query params.
Returns a single album matching the hash in the query params.
"""
album = self.collection.find_one({"albumartist": name})
album = self.collection.find_one({"hash": hash})
return convert_one(album)
+15 -16
View File
@@ -18,12 +18,8 @@ class Playlists(MongoPlaylists):
Inserts a new playlist object into the database.
"""
return self.collection.update_one(
{
"name": playlist["name"]
},
{
"$set": playlist
},
{"name": playlist["name"]},
{"$set": playlist},
upsert=True,
).upserted_id
@@ -41,25 +37,28 @@ class Playlists(MongoPlaylists):
playlist = self.collection.find_one({"_id": ObjectId(id)})
return convert_one(playlist)
def add_track_to_playlist(self, playlistid: str, track: dict) -> None:
def set_last_updated(self, playlistid: str) -> None:
"""
Adds a track to a playlist.
Sets the lastUpdated field to the current date.
"""
date = create_new_date()
return self.collection.update_one(
{"_id": ObjectId(playlistid)},
{"$set": {"lastUpdated": date}},
)
def add_track_to_playlist(self, playlistid: str, track: dict) -> None:
"""
Adds a track to a playlist.
"""
self.collection.update_one(
{
"_id": ObjectId(playlistid),
},
{
"$push": {
"pre_tracks": track
},
"$set": {
"lastUpdated": date
}
},
{"$push": {"pre_tracks": track}},
)
self.set_last_updated(playlistid)
def get_playlist_by_name(self, name: str) -> dict:
"""
+37 -6
View File
@@ -2,9 +2,7 @@
This file contains the AllSongs class for interacting with track documents in MongoDB.
"""
import pymongo
from app.db.mongodb import convert_many
from app.db.mongodb import convert_one
from app.db.mongodb import MongoTracks
from app.db.mongodb import MongoTracks, convert_many, convert_one
from bson import ObjectId
@@ -24,17 +22,23 @@ class Tracks(MongoTracks):
{"filepath": song_obj["filepath"]}, {"$set": song_obj}, upsert=True
).upserted_id
def insert_many(self, songs: list):
"""
Inserts multiple songs into the database.
"""
return self.collection.insert_many(songs)
def get_all_tracks(self) -> list:
"""
Returns all tracks in the database.
"""
return convert_many(self.collection.find())
def get_song_by_id(self, file_id: str) -> dict:
def get_track_by_id(self, id: str) -> dict:
"""
Returns a track object by its mongodb id.
"""
song = self.collection.find_one({"_id": ObjectId(file_id)})
song = self.collection.find_one({"_id": ObjectId(id)})
return convert_one(song)
def get_song_by_album(self, name: str, artist: str) -> dict:
@@ -81,11 +85,20 @@ class Tracks(MongoTracks):
def find_songs_by_folder_og(self, query: str) -> list:
"""
Returns an unsorted list of all the tracks exactly matching the folder in the query params
Returns an unsorted list of all the track matching the folder in the query params
"""
songs = self.collection.find({"folder": query})
return convert_many(songs)
def find_tracks_inside_path_regex(self, path: str) -> list:
"""
Returns a list of all the tracks matching the path in the query params.
"""
songs = self.collection.find(
{"filepath": {"$regex": f"^{path}", "$options": "i"}}
)
return convert_many(songs)
def find_songs_by_artist(self, query: str) -> list:
"""
Returns a list of all the tracks exactly matching the artists in the query params.
@@ -128,3 +141,21 @@ class Tracks(MongoTracks):
return True
except:
return False
def find_tracks_by_hash(self, hash: str) -> list:
"""
Returns a list of all the tracks matching the hash in the query params.
"""
songs = self.collection.find({"albumhash": hash})
return convert_many(songs)
def find_track_by_title_artists_album(
self, title: str, artist: str, album: str
) -> dict:
"""
Returns a single track matching the title, artist, and album in the query params.
"""
song = self.collection.find_one(
{"title": title, "artists": artist, "album": album}
)
return convert_one(song)
+9 -9
View File
@@ -14,7 +14,9 @@ from app.lib.populate import Populate
from PIL import Image
from concurrent.futures import ThreadPoolExecutor
from app.lib.trackslib import create_all_tracks
from app.lib.trackslib import validate_tracks
from app.lib import trackslib
from server.app import instances, models
@helpers.background
@@ -24,6 +26,8 @@ def reindex_tracks():
"""
while True:
trackslib.validate_tracks()
populate()
CheckArtistImages()()
@@ -42,10 +46,6 @@ def populate():
pop = Populate()
pop.run()
tracks = create_all_tracks()
api.TRACKS.clear()
api.TRACKS.extend(tracks)
class getArtistImage:
"""
@@ -104,11 +104,11 @@ class CheckArtistImages:
"""
Loops through all the tracks and gathers all the artists.
"""
ar = instances.tracks_instance.get_all_tracks()
tracks = [models.Track(t) for t in ar]
for song in api.DB_TRACKS:
this_artists: list = song["artists"].split(", ")
for artist in this_artists:
for t in tracks:
for artist in t.artists:
if artist not in self.artists:
self.artists.append(artist)
+3 -18
View File
@@ -4,12 +4,8 @@ This library contains all the functions related to albums.
import random
from typing import List
from app import api
from app import helpers
from app import instances
from app import models
from app.lib import taglib
from app.lib import trackslib
from app import api, helpers, instances, models
from app.lib import taglib, trackslib
from tqdm import tqdm
@@ -30,21 +26,12 @@ def get_all_albums() -> List[models.Album]:
return albums
def create_everything() -> List[models.Track]:
def validate() -> None:
"""
Creates album objects for all albums and returns
a list of track objects
"""
albums: list[models.Album] = get_all_albums()
api.ALBUMS = albums
api.ALBUMS.sort(key=lambda x: x.hash)
tracks = trackslib.create_all_tracks()
api.TRACKS.clear()
api.TRACKS.extend(tracks)
api.TRACKS.sort(key=lambda x: x.title)
def find_album(albums: List[models.Album], hash: str) -> int | None:
@@ -142,8 +129,6 @@ class GetAlbumTracks:
self.tracks.remove(track)
index = trackslib.find_track(self.tracks, self.hash)
# self.tracks.extend(tracks)
# self.tracks.sort(key=lambda x: x["albumhash"])
return tracks
+7 -71
View File
@@ -1,15 +1,11 @@
from dataclasses import dataclass
from os import scandir
from time import time
from typing import List
from typing import Set
from typing import Tuple
from app import api
from app import helpers
from app.models import Folder
from app.models import Track
from tqdm import tqdm
from app import instances
@dataclass
@@ -18,20 +14,12 @@ class Dir:
is_sym: bool
def get_valid_folders() -> None:
for track in api.TRACKS:
api.VALID_FOLDERS.add(track.folder)
def get_folder_track_count(foldername: str) -> int:
"""
Returns the number of files associated with a folder.
"""
count = 0
for track in api.TRACKS:
if foldername in track.folder:
count += 1
return count
tracks = instances.tracks_instance.find_tracks_inside_path_regex(foldername)
return len(tracks)
def create_folder(dir: Dir) -> Folder:
@@ -46,51 +34,6 @@ def create_folder(dir: Dir) -> Folder:
return Folder(folder)
def create_all_folders() -> Set[Folder]:
folders: List[Folder] = []
for foldername in tqdm(api.VALID_FOLDERS, desc="Creating folders"):
folder = create_folder(foldername)
folders.append(folder)
return folders
def get_subdirs(foldername: str) -> List[Folder]:
"""
Finds and Creates Folder objects for each sub-directory string in the foldername passed.
"""
subdirs = set()
for folder in api.VALID_FOLDERS:
if foldername in folder:
str0 = folder.replace(foldername, "")
try:
str1 = str0.split("/")[1]
except IndexError:
str1 = None
if str1 is not None:
subdirs.add(foldername + "/" + str1)
return [create_folder(dir) for dir in subdirs]
@helpers.background
def run_scandir():
"""
Initiates the creation of all folder objects for each folder with a track in it.
Runs in a background thread after every 5 minutes.
It calls the
"""
get_valid_folders()
# folders_ = create_all_folders()
"""Create all the folder objects before clearing api.FOLDERS"""
# api.FOLDERS = folders_
class getFnF:
"""
Get files and folders from a directory.
@@ -99,15 +42,6 @@ class getFnF:
def __init__(self, path: str) -> None:
self.path = path
@classmethod
def get_tracks(cls, files: List[str]) -> List[Track]:
"""
Returns a list of Track objects for each file in the given list.
"""
tracks = helpers.UseBisection(api.TRACKS, "filepath", files)()
tracks = filter(lambda t: t is not None, tracks)
return list(tracks)
def __call__(self) -> Tuple[Track, Folder]:
try:
all = scandir(self.path)
@@ -125,9 +59,11 @@ class getFnF:
dirs.append(Dir(**dir))
elif entry.is_file() and entry.name.endswith((".mp3", ".flac")):
files.append(entry.path)
tracks = self.get_tracks(files)
tracks = instances.tracks_instance.find_songs_by_folder(self.path)
tracks = [Track(track) for track in tracks]
folders = [create_folder(dir) for dir in dirs]
folders = filter(lambda f: f.trackcount > 0, folders)
return tracks, folders
+38 -41
View File
@@ -5,6 +5,7 @@ import os
import random
import string
from datetime import datetime
from typing import List
from tqdm import tqdm
@@ -13,55 +14,37 @@ from app import exceptions
from app import instances
from app import models
from app import settings
from app.lib import trackslib
from PIL import Image
from PIL import ImageSequence
from progress.bar import Bar
from werkzeug import datastructures
from app.lib import trackslib
TrackExistsInPlaylist = exceptions.TrackExistsInPlaylist
def add_track(playlistid: str, trackid: str):
"""
Adds a track to a playlist in the api.PLAYLISTS dict and to the database.
Adds a track to a playlist to the database.
"""
for playlist in api.PLAYLISTS:
if playlist.playlistid == playlistid:
tt = trackslib.get_track_by_id(trackid)
tt = instances.tracks_instance.get_track_by_id(trackid)
track = {
"title": tt.title,
"artists": tt.artists,
"album": tt.album,
}
if tt is None:
return
try:
playlist.add_track(track)
instances.playlist_instance.add_track_to_playlist(
playlistid, track)
return
except TrackExistsInPlaylist as error:
raise error
track = models.Track(tt)
playlist = instances.playlist_instance.get_playlist_by_id(playlistid)
def get_playlist_tracks(pid: str):
for p in api.PLAYLISTS:
if p.playlistid == pid:
return p.tracks
track = {
"title": track.title,
"artists": tt["artists"],
"album": track.album,
}
if track in playlist["pre_tracks"]:
raise TrackExistsInPlaylist
def create_all_playlists():
"""
Gets all playlists from the database.
"""
playlists = instances.playlist_instance.get_all_playlists()
for playlist in tqdm(playlists, desc="Creating playlists"):
api.PLAYLISTS.append(models.Playlist(playlist))
validate_images()
instances.playlist_instance.add_track_to_playlist(playlistid, track)
def create_thumbnail(image: any, img_path: str) -> str:
@@ -69,8 +52,7 @@ def create_thumbnail(image: any, img_path: str) -> str:
Creates a 250 x 250 thumbnail from a playlist image
"""
thumb_path = "thumb_" + img_path
full_thumb_path = os.path.join(settings.APP_DIR, "images", "playlists",
thumb_path)
full_thumb_path = os.path.join(settings.APP_DIR, "images", "playlists", thumb_path)
aspect_ratio = image.width / image.height
@@ -88,13 +70,11 @@ def save_p_image(file: datastructures.FileStorage, pid: str):
"""
img = Image.open(file)
random_str = "".join(
random.choices(string.ascii_letters + string.digits, k=5))
random_str = "".join(random.choices(string.ascii_letters + string.digits, k=5))
img_path = pid + str(random_str) + ".webp"
full_img_path = os.path.join(settings.APP_DIR, "images", "playlists",
img_path)
full_img_path = os.path.join(settings.APP_DIR, "images", "playlists", img_path)
if file.content_type == "image/gif":
frames = []
@@ -118,8 +98,10 @@ def validate_images():
Removes all unused images in the images/playlists folder.
"""
images = []
p = instances.playlist_instance.get_all_playlists()
playlists = [models.Playlist(p) for p in p]
for playlist in api.PLAYLISTS:
for playlist in playlists:
if playlist.image:
img_path = playlist.image.split("/")[-1]
thumb_path = playlist.thumb.split("/")[-1]
@@ -136,3 +118,18 @@ def validate_images():
def create_new_date():
return datetime.now()
def create_playlist_tracks(playlist_tracks: List) -> List[models.Track]:
"""
Creates a list of model.Track objects from a list of playlist track dicts.
"""
tracks: List[models.Track] = []
for t in playlist_tracks:
track = trackslib.get_p_track(t)
if track is not None:
tracks.append(models.Track(track))
return tracks
+16 -43
View File
@@ -1,4 +1,5 @@
import os
from pprint import pprint
import time
from concurrent.futures import ThreadPoolExecutor
from copy import deepcopy
@@ -12,7 +13,6 @@ from app.helpers import 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 import folderslib
from app.lib.albumslib import create_album
from app.lib.albumslib import find_album
from app.lib.taglib import get_tags
@@ -44,6 +44,7 @@ class Populate:
self.db_tracks = tracks_instance.get_all_tracks()
self.tag_count = 0
self.exist_count = 0
self.tracks = []
def run(self):
self.check_untagged()
@@ -53,17 +54,14 @@ class Populate:
return
self.tagged_tracks.sort(key=lambda x: x["albumhash"])
self.tracks = deepcopy(self.tagged_tracks)
self.pre_albums = self.create_pre_albums(self.tagged_tracks)
self.create_albums(self.pre_albums)
self.albums.sort(key=lambda x: x.hash)
api.ALBUMS.sort(key=lambda x: x.hash)
self.save_albums()
self.create_tracks()
# self.create_folders()
self.save_all()
def check_untagged(self):
"""
@@ -84,7 +82,6 @@ class Populate:
t["albumhash"] = create_album_hash(t["album"], t["albumartist"])
self.tagged_tracks.append(t)
api.DB_TRACKS.append(t)
self.folders.add(t["folder"])
@@ -95,8 +92,7 @@ class Populate:
folder = tags["folder"]
self.folders.add(folder)
tags["albumhash"] = create_album_hash(tags["album"],
tags["albumartist"])
tags["albumhash"] = create_album_hash(tags["album"], tags["albumartist"])
self.tagged_tracks.append(tags)
api.DB_TRACKS.append(tags)
@@ -110,13 +106,6 @@ class Populate:
with ThreadPoolExecutor() as executor:
executor.map(self.get_tags, self.files)
# with Pool(maxtasksperchild=10, processes=10) as p:
# tags = p.map(get_tags, tqdm(self.files))
# self.process_tags(tags)
# for t in tqdm(self.files):
# self.get_tags(t)
d = time.time() - s
Log(f"Tagged {len(self.tagged_tracks)} files in {d} seconds")
@@ -147,7 +136,6 @@ class Populate:
self.exist_count += 1
return
self.albums.sort(key=lambda x: x.hash)
index = find_track(self.tagged_tracks, albumhash)
if index is None:
@@ -163,7 +151,6 @@ class Populate:
album = Album(album)
api.ALBUMS.append(album)
self.albums.append(album)
def create_albums(self, albums: List[dict]):
@@ -173,8 +160,7 @@ class Populate:
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"
)
Log(f"{self.exist_count} of {len(albums)} albums were already in the database")
def create_track(self, track: dict):
"""
@@ -196,38 +182,25 @@ class Populate:
pass
track["image"] = album.image
upsert_id = tracks_instance.insert_song(track)
track["_id"] = {"$oid": str(upsert_id)}
api.TRACKS.append(Track(track))
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:
executor.map(self.create_track, self.tagged_tracks)
iterable = executor.map(self.create_track, self.tagged_tracks)
Log(f"Added {len(self.tagged_tracks)} new tracks and {len(self.albums)} new albums"
)
self.tracks = [t for t in iterable if t is not None]
def save_albums(self):
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.
"""
with ThreadPoolExecutor() as executor:
executor.map(album_instance.insert_album, self.albums)
# def create_folders(self):
# """
# Creates the folder objects for all the tracks.
# """
# for folder in tqdm(self.folders, desc="Creating folders"):
# api.VALID_FOLDERS.add(folder)
# fff = folderslib.create_folder(folder)
# api.FOLDERS.append(fff)
# Log(f"Created {len(self.folders)} new folders")
album_instance.insert_many([a.__dict__ for a in self.albums])
tracks_instance.insert_many(self.tracks)
+11 -12
View File
@@ -2,31 +2,25 @@
This library contains all the functions related to tracks.
"""
import os
from pprint import pprint
from typing import List
from app import api
from app import instances
from app import models
from app import api, instances, models
from app.helpers import remove_duplicates
from tqdm import tqdm
def create_all_tracks() -> List[models.Track]:
def validate_tracks() -> None:
"""
Gets all songs under the ~/ directory.
"""
tracks: list[models.Track] = []
entries = instances.tracks_instance.get_all_tracks()
for track in tqdm(api.DB_TRACKS, desc="Creating tracks"):
for track in tqdm(entries, desc="Validating tracks"):
try:
os.chmod(track["filepath"], 0o755)
except FileNotFoundError:
instances.tracks_instance.remove_song_by_id(track["_id"]["$oid"])
api.DB_TRACKS.remove(track)
tracks.append(models.Track(track))
return tracks
def get_album_tracks(albumname, artist):
@@ -48,7 +42,6 @@ def get_track_by_id(trackid: str) -> models.Track:
return track
except AttributeError:
print("AttributeError")
print(track)
def find_track(tracks: list, hash: str) -> int or None:
@@ -73,3 +66,9 @@ def find_track(tracks: list, hash: str) -> int or None:
right = mid - 1
return None
def get_p_track(ptrack):
return instances.tracks_instance.find_track_by_title_artists_album(
ptrack["title"], ptrack["artists"], ptrack["album"]
)
+7 -36
View File
@@ -4,7 +4,7 @@ Contains all the models for objects generation and typing.
from dataclasses import dataclass, field
from typing import List
from app import api, helpers
from app import helpers
from app.exceptions import TrackExistsInPlaylist
@@ -117,30 +117,6 @@ class Album:
return self.artist.lower() == "various artists"
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
):
return track
def create_playlist_tracks(playlist_tracks: List) -> List[Track]:
"""
Creates a list of model.Track objects from a list of playlist track dicts.
"""
tracks: List[Track] = []
for t in playlist_tracks:
track = get_p_track(t)
if track is not None:
tracks.append(track)
return tracks
@dataclass
class Playlist:
"""Creates playlist objects"""
@@ -148,7 +124,7 @@ class Playlist:
playlistid: str
name: str
tracks: List[Track]
_pre_tracks: list = field(init=False, repr=False)
pretracks: list = field(init=False, repr=False)
lastUpdated: int
image: str
thumb: str
@@ -162,16 +138,11 @@ class Playlist:
self.description = data["description"]
self.image = self.create_img_link(data["image"])
self.thumb = self.create_img_link(data["thumb"])
self._pre_tracks = data["pre_tracks"]
self.pretracks = data["pre_tracks"]
self.tracks = []
self.lastUpdated = data["lastUpdated"]
self.count = len(self._pre_tracks)
self.count = len(self.pretracks)
def get_tracks(self) -> List[Track]:
"""
Generates and returns Track objects from pre_tracks
"""
return create_playlist_tracks(self._pre_tracks)
def create_img_link(self, image: str):
if image:
@@ -180,11 +151,11 @@ class Playlist:
return "default.webp"
def update_count(self):
self.count = len(self._pre_tracks)
self.count = len(self.pretracks)
def add_track(self, track):
if track not in self._pre_tracks:
self._pre_tracks.append(track)
if track not in self.pretracks:
self.pretracks.append(track)
self.update_count()
self.lastUpdated = helpers.create_new_date()
else:
+3 -1
View File
@@ -11,7 +11,8 @@ CONFIG_FOLDER = ".alice"
HOME_DIR = os.path.expanduser("~")
APP_DIR = os.path.join(HOME_DIR, CONFIG_FOLDER)
THUMBS_PATH = os.path.join(APP_DIR, "images", "thumbnails")
TEST_DIR = "/home/cwilvx/Music/Link to Music/Chill"
TEST_DIR = "/home/cwilvx/Music/Link to Music/Chill/Wolftyla Radio"
HOME_DIR = TEST_DIR
# URL
IMG_BASE_URI = "http://127.0.0.1:8900/images/"
IMG_ARTIST_URI = IMG_BASE_URI + "artists/"
@@ -38,6 +39,7 @@ P_COLORS = [
CPU_COUNT = multiprocessing.cpu_count()
class logger:
enable = True