add docstrings to python code

This commit is contained in:
geoffrey45
2022-02-06 23:26:22 +03:00
parent 195a50382a
commit 60ba512e64
13 changed files with 407 additions and 277 deletions
+106 -98
View File
@@ -1,13 +1,14 @@
import os import os
import urllib import urllib
from typing import List
from flask import Blueprint, request from flask import Blueprint, request
from app import functions, instances, helpers, cache from app import functions, instances, helpers, cache
bp = Blueprint('api', __name__, url_prefix='') bp = Blueprint("api", __name__, url_prefix="")
home_dir = helpers.home_dir home_dir = helpers.home_dir
all_the_f_music = helpers.getAllSongs() all_the_f_music = helpers.get_all_songs()
def initialize() -> None: def initialize() -> None:
@@ -15,45 +16,58 @@ def initialize() -> None:
Runs all the necessary setup functions. Runs all the necessary setup functions.
""" """
helpers.create_config_dir() helpers.create_config_dir()
# helpers.check_for_new_songs() helpers.check_for_new_songs()
initialize() initialize()
@bp.route('/') @bp.route("/")
def adutsfsd(): def say_hi():
"""Returns some text for the default route"""
return "^ _ ^" return "^ _ ^"
@bp.route('/search') def get_tracks(query: str) -> List:
"""
Gets all songs with a given title.
"""
return [track for track in all_the_f_music if query.lower() in track.title.lower()]
def get_search_albums(query: str) -> List:
"""
Gets all songs with a given album.
"""
return [track for track in all_the_f_music if query.lower() in track.album.lower()]
def get_artists(artist: str) -> List:
"""
Gets all songs with a given artist.
"""
return [
track
for track in all_the_f_music
if artist.lower() in str(track.artists).lower()
]
@bp.route("/search")
def search_by_title(): def search_by_title():
if not request.args.get('q'): """
query:str = "mexican girl" Returns a list of songs, albums and artists that match the search query.
else: """
query:str = str(request.args.get('q')) query = request.args.get("q") or "Mexican girl"
albums = []
artists = []
tracks = []
albums = get_search_albums(query)
albums_dicts = [] albums_dicts = []
artists_dicts = [] artists_dicts = []
for track in all_the_f_music:
if query.lower() in track.title.lower():
tracks.append(track)
if query.lower() in track.album.lower():
albums.append(track)
if query.lower() in str(track.artists).lower():
artists.append(track)
for song in albums: for song in albums:
album_obj = { album_obj = {
"name": song.album, "name": song.album,
"artist": song.album_artist, "artist": song.albumartist,
} }
if album_obj not in albums_dicts: if album_obj not in albums_dicts:
@@ -61,61 +75,52 @@ def search_by_title():
for album in albums_dicts: for album in albums_dicts:
for track in albums: for track in albums:
if album['name'] == track.album: if album["name"] == track.album:
album['image'] = track.image album["image"] = track.image
for song in artists: for song in get_artists(query):
for artist in song.artists: for artist in song.artists:
if query.lower() in artist.lower(): if query.lower() in artist.lower():
artist_obj = { artist_obj = {
"name": artist, "name": artist,
"image": "http://0.0.0.0:8900/images/artists/" + artist.replace("/", "::") + ".webp" "image": "http://0.0.0.0:8900/images/artists/"
+ artist.replace("/", "::")
+ ".webp",
} }
if artist_obj not in artists_dicts: if artist_obj not in artists_dicts:
artists_dicts.append(artist_obj) artists_dicts.append(artist_obj)
tracks = helpers.remove_duplicates(tracks) tracks = helpers.remove_duplicates(get_tracks(query))
if len(tracks) > 5: return {
more_tracks = True "data": [
else: {"tracks": tracks[:5], "more": len(tracks) > 5},
more_tracks = False {"albums": albums_dicts[:6], "more": len(albums_dicts) > 6},
{"artists": artists_dicts[:6], "more": len(artists_dicts) > 6},
if len(artists_dicts) > 6: ]
more_artists = True }
else:
more_artists = False
if len(albums_dicts) > 6:
more_albums = True
else:
more_albums = False
return {'data': [
{'tracks': tracks[:5], 'more': more_tracks},
{'albums': albums_dicts[:6], 'more': more_albums},
{'artists': artists_dicts[:6], 'more': more_artists}
]}
@bp.route('/populate') @bp.route("/populate")
def x(): def find_tracks():
"""call the populate function"""
functions.populate() functions.populate()
return "🎸" return "🎸"
@bp.route("/album/<album>/<artist>/artists") @bp.route("/album/<album>/<artist>/artists")
@cache.cached() @cache.cached()
def get_album_artists(album, artist): def get_albumartists(album, artist):
album = album.replace('|', '/') """Returns a list of artists featured in a given album."""
artist = artist.replace('|', '/') album = album.replace("|", "/")
artist = artist.replace("|", "/")
tracks = [] tracks = []
for track in all_the_f_music: for track in all_the_f_music:
if track.album == album and track.album_artist == artist: if track.album == album and track.albumartist == artist:
tracks.append(track) tracks.append(track)
artists = [] artists = []
@@ -129,11 +134,13 @@ def get_album_artists(album, artist):
for artist in artists: for artist in artists:
artist_obj = { artist_obj = {
"name": artist, "name": artist,
"image": "http://0.0.0.0:8900/images/artists/" + artist.replace('/', '::') + ".webp" "image": "http://0.0.0.0:8900/images/artists/"
+ artist.replace("/", "::")
+ ".webp",
} }
final_artists.append(artist_obj) final_artists.append(artist_obj)
return {'artists': final_artists} return {"artists": final_artists}
@bp.route("/populate/images") @bp.route("/populate/images")
@@ -144,55 +151,54 @@ def populate_images():
@bp.route("/artist/<artist>") @bp.route("/artist/<artist>")
@cache.cached() @cache.cached()
def getArtistData(artist: str): def get_artist_data(artist: str):
print(artist) """Returns the artist's data, tracks and albums"""
artist = urllib.parse.unquote(artist) artist = urllib.parse.unquote(artist)
artist_obj = instances.artist_instance.get_artists_by_name(artist) artist_obj = instances.artist_instance.get_artists_by_name(artist)
def getArtistSongs(): def get_artist_tracks():
songs = instances.songs_instance.find_songs_by_artist(artist) songs = instances.songs_instance.find_songs_by_artist(artist)
return songs return songs
artist_songs = getArtistSongs() artist_songs = get_artist_tracks()
songs = helpers.remove_duplicates(artist_songs) songs = helpers.remove_duplicates(artist_songs)
def getArtistAlbums(): def get_artist_albums():
artist_albums = [] artist_albums = []
albums_with_count = [] albums_with_count = []
albums = instances.songs_instance.find_songs_by_album_artist(artist) albums = instances.songs_instance.find_songs_by_albumartist(artist)
for song in albums: for song in albums:
if song['album'] not in artist_albums: if song["album"] not in artist_albums:
artist_albums.append(song['album']) artist_albums.append(song["album"])
for album in artist_albums: for album in artist_albums:
count = 0 count = 0
length = 0 length = 0
for song in artist_songs: for song in artist_songs:
if song['album'] == album: if song["album"] == album:
count = count + 1 count = count + 1
length = length + song['length'] length = length + song["length"]
album_ = { album_ = {"title": album, "count": count, "length": length}
"title": album,
"count": count,
"length": length
}
albums_with_count.append(album_) albums_with_count.append(album_)
return albums_with_count return albums_with_count
return {'artist': artist_obj, 'songs': songs, 'albums': getArtistAlbums()} return {"artist": artist_obj, "songs": songs, "albums": get_artist_albums()}
@bp.route("/f/<folder>") @bp.route("/f/<folder>")
@cache.cached() @cache.cached()
def getFolderTree(folder: str): def get_folder_tree(folder: str):
req_dir = folder.replace('|', '/') """
Returns a list of all the folders and tracks in the given folder.
"""
req_dir = folder.replace("|", "/")
if folder == "home": if folder == "home":
req_dir = home_dir req_dir = home_dir
@@ -202,9 +208,8 @@ def getFolderTree(folder: str):
folders = [] folders = []
for entry in dir_content: for entry in dir_content:
if entry.is_dir() and not entry.name.startswith('.'): if entry.is_dir() and not entry.name.startswith("."):
files_in_dir = helpers.run_fast_scandir( files_in_dir = helpers.run_fast_scandir(entry.path, [".flac", ".mp3"])[1]
entry.path, [".flac", ".mp3"])[1]
if len(files_in_dir) != 0: if len(files_in_dir) != 0:
_dir = { _dir = {
@@ -221,35 +226,36 @@ def getFolderTree(folder: str):
if track.folder == req_dir: if track.folder == req_dir:
songs.append(track) songs.append(track)
return {"files": helpers.remove_duplicates(songs), "folders": sorted(folders, key=lambda i: i['name'])} return {
"files": helpers.remove_duplicates(songs),
"folders": sorted(folders, key=lambda i: i["name"]),
}
@bp.route("/albums")
@bp.route('/albums') def get_albums():
def getAlbums(): """returns all the albums"""
s = instances.songs_instance.get_all_songs() s = instances.songs_instance.get_all_songs()
albums = [] albums = []
for song in s: for song in s:
al_obj = { al_obj = {"name": song["album"], "artist": song["artists"]}
"name": song['album'],
"artist": song['artists']
}
if al_obj not in albums: if al_obj not in albums:
albums.append(al_obj) albums.append(al_obj)
return {'albums': albums} return {"albums": albums}
@bp.route('/album/<title>/<artist>/tracks') @bp.route("/album/<title>/<artist>/tracks")
@cache.cached() @cache.cached()
def get_album_tracks(title: str, artist: str): def get_album_tracks(title: str, artist: str):
"""Returns all the tracks in the given album."""
songs = [] songs = []
for track in all_the_f_music: for track in all_the_f_music:
if track.album_artist == artist and track.album == title: if track.albumartist == artist and track.album == title:
songs.append(track) songs.append(track)
songs = helpers.remove_duplicates(songs) songs = helpers.remove_duplicates(songs)
@@ -259,16 +265,18 @@ def get_album_tracks(title:str, artist:str):
"count": len(songs), "count": len(songs),
"duration": "56 Minutes", "duration": "56 Minutes",
"image": songs[0].image, "image": songs[0].image,
"artist": songs[0].album_artist, "artist": songs[0].albumartist,
"artist_image": "http://127.0.0.1:8900/images/artists/" + songs[0].album_artist.replace('/', '::') + ".webp" "artist_image": "http://127.0.0.1:8900/images/artists/"
+ songs[0].albumartist.replace("/", "::")
+ ".webp",
} }
return {'songs': songs, 'info': album_obj} return {"songs": songs, "info": album_obj}
@bp.route('/album/<title>/<artist>/bio') @bp.route("/album/<title>/<artist>/bio")
@cache.cached() @cache.cached()
def drop_db(title, artist): def get_album_bio(title, artist):
bio = functions.getAlbumBio(title, artist) """Returns the album bio for the given album."""
return {'bio': bio}, 200 bio = functions.get_album_bio(title, artist)
return {"bio": bio}, 200
+153 -106
View File
@@ -4,17 +4,17 @@ This module contains larger functions for the server
import time import time
import os import os
import requests from io import BytesIO
import random import random
import datetime import datetime
import mutagen
import requests
from mutagen.flac import MutagenError from mutagen.flac import MutagenError
from mutagen.mp3 import MP3
from mutagen.id3 import ID3 from mutagen.id3 import ID3
from mutagen.flac import FLAC from mutagen.flac import FLAC
from progress.bar import Bar from progress.bar import Bar
from PIL import Image from PIL import Image
from io import BytesIO
from app import helpers from app import helpers
from app import instances from app import instances
@@ -30,17 +30,30 @@ def populate():
also checks if the album art exists in the image path, if not tries to also checks if the album art exists in the image path, if not tries to
extract it. extract it.
""" """
start = time.time()
print("\nchecking for new tracks") print("\nchecking for new tracks")
files = helpers.run_fast_scandir(helpers.home_dir, [".flac", ".mp3"])[1] files = helpers.run_fast_scandir(helpers.home_dir, [".flac", ".mp3"])[1]
for file in files: for file in files:
getTags(file) tags = get_tags(file)
api.all_the_f_music = helpers.getAllSongs() if tags is not None:
instances.songs_instance.insert_song(tags)
api.all_the_f_music = helpers.get_all_songs()
print("\n check done") print("\n check done")
end = time.time()
print(
str(datetime.timedelta(seconds=round(end - start)))
+ " elapsed for "
+ str(len(files))
+ " files"
)
def populate_images(): def populate_images():
"""populates the artists images"""
all_songs = instances.songs_instance.get_all_songs() all_songs = instances.songs_instance.get_all_songs()
artists = [] artists = []
@@ -52,7 +65,7 @@ def populate_images():
if artist not in artists: if artist not in artists:
artists.append(artist) artists.append(artist)
bar = Bar("Processing images", max=len(artists)) _bar = Bar("Processing images", max=len(artists))
for artist in artists: for artist in artists:
file_path = ( file_path = (
helpers.app_dir + "/images/artists/" + artist.replace("/", "::") + ".webp" helpers.app_dir + "/images/artists/" + artist.replace("/", "::") + ".webp"
@@ -81,9 +94,17 @@ def populate_images():
time.sleep(5) time.sleep(5)
try_save_image() try_save_image()
bar.next() _bar.next()
bar.finish() _bar.finish()
def use_defaults() -> str:
"""
Returns a path to a random image in the defaults directory.
"""
path = str(random.randint(0, 10)) + ".webp"
return path
def extract_thumb(audio_file_path: str) -> str: def extract_thumb(audio_file_path: str) -> str:
@@ -93,13 +114,6 @@ def extract_thumb(audio_file_path: str) -> str:
album_art = None album_art = None
def use_defaults() -> str:
"""
Returns a path to a random image in the defaults directory.
"""
path = str(random.randint(0, 10)) + ".webp"
return path
webp_path = audio_file_path.split("/")[-1] + ".webp" webp_path = audio_file_path.split("/")[-1] + ".webp"
img_path = os.path.join(helpers.app_dir, "images", "thumbnails", webp_path) img_path = os.path.join(helpers.app_dir, "images", "thumbnails", webp_path)
@@ -138,110 +152,138 @@ def extract_thumb(audio_file_path: str) -> str:
return use_defaults() return use_defaults()
def getTags(full_path: str) -> dict: def parse_artist_tag(audio):
"""
Parses the artist tag from an audio file.
"""
try:
artists = audio["artist"][0]
except (KeyError, IndexError):
artists = "Unknown"
return artists
def parse_title_tag(audio, full_path: str):
"""
Parses the title tag from an audio file.
"""
try:
title = audio["title"][0]
except (KeyError, IndexError):
title = full_path.split("/")[-1]
return title
def parse_album_artist_tag(audio):
"""
Parses the album artist tag from an audio file.
"""
try:
albumartist = audio["albumartist"][0]
except (KeyError, IndexError):
albumartist = "Unknown"
return albumartist
def parse_album_tag(audio):
"""
Parses the album tag from an audio file.
"""
try:
album = audio["album"][0]
except (KeyError, IndexError):
album = "Unknown"
return album
def parse_genre_tag(audio):
"""
Parses the genre tag from an audio file.
"""
try:
genre = audio["genre"][0]
except (KeyError, IndexError):
genre = "Unknown"
return genre
def parse_date_tag(audio):
"""
Parses the date tag from an audio file.
"""
try:
date = audio["date"][0]
except (KeyError, IndexError):
date = "Unknown"
return date
def parse_track_number(audio):
"""
Parses the track number from an audio file.
"""
try:
track_number = audio["tracknumber"][0]
except (KeyError, IndexError):
track_number = "Unknown"
return track_number
def parse_disk_number(audio):
"""
Parses the disk number from an audio file.
"""
try:
disk_number = audio["discnumber"][0]
except (KeyError, IndexError):
disk_number = "Unknown"
return disk_number
def get_tags(full_path: str) -> dict:
""" """
Returns a dictionary of tags for a given file. Returns a dictionary of tags for a given file.
""" """
if full_path.endswith(".flac"):
try: try:
audio = FLAC(full_path) audio = mutagen.File(full_path, easy=True)
except MutagenError: except MutagenError:
return return None
elif full_path.endswith(".mp3"):
try:
audio = MP3(full_path)
except MutagenError:
return
try:
artists = audio["artist"][0]
except KeyError:
try:
artists = audio["TPE1"][0]
except:
artists = "Unknown"
except IndexError:
artists = "Unknown"
try:
album_artist = audio["albumartist"][0]
except KeyError:
try:
album_artist = audio["TPE2"][0]
except:
album_artist = "Unknown"
except IndexError:
album_artist = "Unknown"
try:
title = audio["title"][0]
except KeyError:
try:
title = audio["TIT2"][0]
except:
title = full_path.split("/")[-1]
except:
title = full_path.split("/")[-1]
try:
album = audio["album"][0]
except KeyError:
try:
album = audio["TALB"][0]
except:
album = "Unknown"
except IndexError:
album = "Unknown"
try:
genre = audio["genre"][0]
except KeyError:
try:
genre = audio["TCON"][0]
except:
genre = "Unknown"
except IndexError:
genre = "Unknown"
try:
date = audio["date"][0]
except KeyError:
try:
date = audio["TDRC"][0]
except:
date = "Unknown"
except IndexError:
date = "Unknown"
img_path = extract_thumb(full_path)
length = str(datetime.timedelta(seconds=round(audio.info.length)))
if length[:2] == "0:":
length = length.replace("0:", "")
tags = { tags = {
"filepath": full_path.replace(helpers.home_dir, ""), "artists": parse_artist_tag(audio),
"folder": os.path.dirname(full_path).replace(helpers.home_dir, ""), "title": parse_title_tag(audio, full_path),
"title": title, "albumartist": parse_album_artist_tag(audio),
"artists": artists, "album": parse_album_tag(audio),
"album_artist": album_artist, "genre": parse_genre_tag(audio),
"album": album, "date": parse_date_tag(audio)[:4],
"genre": genre, "tracknumber": parse_track_number(audio),
"length": length, "discnumber": parse_disk_number(audio),
"length": audio.info.length,
"bitrate": round(int(audio.info.bitrate) / 1000), "bitrate": round(int(audio.info.bitrate) / 1000),
"date": str(date)[:4], "filepath": full_path.replace(helpers.home_dir, ""),
"image": img_path, "image": extract_thumb(full_path),
"folder": os.path.dirname(full_path).replace(helpers.home_dir, ""),
} }
instances.songs_instance.insert_song(tags) print(tags['filepath'])
return tags return tags
def getAlbumBio(title: str, album_artist: str): def get_album_bio(title: str, albumartist: str):
"""
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(
helpers.LAST_FM_API_KEY, album_artist, title helpers.LAST_FM_API_KEY, albumartist, title
) )
try: try:
@@ -262,11 +304,14 @@ def getAlbumBio(title: str, album_artist: str):
def create_track_class(tags): def create_track_class(tags):
"""
Creates a Track class from a dictionary of tags.
"""
return models.Track( return models.Track(
tags["_id"]["$oid"], tags["_id"]["$oid"],
tags["title"], tags["title"],
tags["artists"], tags["artists"],
tags["album_artist"], tags["albumartist"],
tags["album"], tags["album"],
tags["filepath"], tags["filepath"],
tags["folder"], tags["folder"],
@@ -275,4 +320,6 @@ def create_track_class(tags):
tags["genre"], tags["genre"],
tags["bitrate"], tags["bitrate"],
tags["image"], tags["image"],
tags['tracknumber'],
tags['discnumber'],
) )
+3 -2
View File
@@ -127,11 +127,11 @@ def create_config_dir() -> None:
os.chmod(path, 0o755) os.chmod(path, 0o755)
def getAllSongs() -> List: def get_all_songs() -> List:
""" """
Gets all songs under the ~/ directory. Gets all songs under the ~/ directory.
""" """
print("Getting all songs...")
tracks = [] tracks = []
for track in instances.songs_instance.get_all_songs(): for track in instances.songs_instance.get_all_songs():
@@ -140,6 +140,7 @@ def getAllSongs() -> List:
try: try:
os.chmod(os.path.join(home_dir, track.filepath), 0o755) os.chmod(os.path.join(home_dir, track.filepath), 0o755)
except FileNotFoundError: except FileNotFoundError:
print("")
instances.songs_instance.remove_song_by_filepath(track.filepath) instances.songs_instance.remove_song_by_filepath(track.filepath)
tracks.append(track) tracks.append(track)
+124 -51
View File
@@ -1,10 +1,13 @@
import json
from dataclasses import dataclass from dataclasses import dataclass
import pymongo import pymongo
import json
from bson import ObjectId, json_util from bson import ObjectId, json_util
def convert_one_to_json(song): def convert_one_to_json(song):
"""
Converts a single mongodb cursor to a json object.
"""
json_song = json.dumps(song, default=json_util.default) json_song = json.dumps(song, default=json_util.default)
loaded_song = json.loads(json_song) loaded_song = json.loads(json_song)
@@ -12,6 +15,10 @@ def convert_one_to_json(song):
def convert_to_json(array): def convert_to_json(array):
"""
Converts a list of mongodb cursors to a list of json objects.
"""
songs = [] songs = []
for song in array: for song in array:
@@ -24,99 +31,161 @@ def convert_to_json(array):
class Mongo: class Mongo:
"""
The base class for all mongodb classes.
"""
def __init__(self, database): def __init__(self, database):
mongo_uri = pymongo.MongoClient() mongo_uri = pymongo.MongoClient()
self.db = mongo_uri[database] self.db = mongo_uri[database]
class Artists(Mongo): class Artists(Mongo):
"""
The artist class for all artist related database operations.
"""
def __init__(self): def __init__(self):
super(Artists, self).__init__('ALL_ARTISTS') super(Artists, self).__init__("ALL_ARTISTS")
self.collection = self.db['THEM_ARTISTS'] self.collection = self.db["THEM_ARTISTS"]
def insert_artist(self, artist_obj): def insert_artist(self, artist_obj: dict) -> None:
self.collection.update_one( """
artist_obj, {'$set': artist_obj}, upsert=True) Inserts an artist into the database.
"""
self.collection.update_one(artist_obj, {"$set": artist_obj}, upsert=True)
def get_all_artists(self): def get_all_artists(self) -> list:
"""
Returns a list of all artists in the database.
"""
return self.collection.find() return self.collection.find()
def get_artist_by_id(self, artist_id): def get_artist_by_id(self, artist_id: str) -> dict:
return self.collection.find_one({'_id': ObjectId(artist_id)}) """
Returns an artist matching the mongo Id.
"""
return self.collection.find_one({"_id": ObjectId(artist_id)})
def get_artists_by_name(self, query): def get_artists_by_name(self, query: str):
return self.collection.find({'name': query}).limit(20) """
Returns all the artists matching the query.
"""
return self.collection.find({"name": query}).limit(20)
class AllSongs(Mongo): class AllSongs(Mongo):
"""
The class for all track-related database operations.
"""
def __init__(self): def __init__(self):
super(AllSongs, self).__init__('ALL_SONGS') super(AllSongs, self).__init__("ALL_SONGS")
self.collection = self.db['ALL_SONGS'] self.collection = self.db["ALL_SONGS"]
# def drop_db(self): # def drop_db(self):
# self.collection.drop() # self.collection.drop()
def insert_song(self, song_obj): def insert_song(self, song_obj: dict) -> None:
"""
Inserts a new track object into the database.
"""
self.collection.update_one( self.collection.update_one(
{'filepath': song_obj['filepath']}, {"$set": song_obj}, upsert=True) {"filepath": song_obj["filepath"]}, {"$set": song_obj}, upsert=True
)
def get_all_songs(self): def get_all_songs(self) -> list:
"""
Returns all tracks in the database.
"""
return convert_to_json(self.collection.find()) return convert_to_json(self.collection.find())
def get_song_by_id(self, file_id): def get_song_by_id(self, file_id: str) -> dict:
song = self.collection.find_one({'_id': ObjectId(file_id)}) """
Returns a track object by its mongodb id.
"""
song = self.collection.find_one({"_id": ObjectId(file_id)})
return convert_one_to_json(song) return convert_one_to_json(song)
def get_song_by_album(self, name, artist): def get_song_by_album(self, name: str, artist: str) -> dict:
song = self.collection.find_one( """
{'album': name, 'album_artist': artist}) Returns a single track matching the album in the query params.
"""
song = self.collection.find_one({"album": name, "albumartist": artist})
return convert_one_to_json(song) return convert_one_to_json(song)
def search_songs_by_album(self, query): def search_songs_by_album(self, query: str) -> list:
songs = self.collection.find( """
{'album': {'$regex': query, '$options': 'i'}}) Returns all the songs matching the albums in the query params (using regex).
"""
songs = self.collection.find({"album": {"$regex": query, "$options": "i"}})
return convert_to_json(songs) return convert_to_json(songs)
def search_songs_by_artist(self, query): def search_songs_by_artist(self, query: str) -> list:
songs = self.collection.find( """
{'artists': {'$regex': query, '$options': 'i'}}) Returns all the songs matching the artists in the query params.
"""
songs = self.collection.find({"artists": {"$regex": query, "$options": "i"}})
return convert_to_json(songs) return convert_to_json(songs)
def find_song_by_title(self, query): def find_song_by_title(self, query: str) -> list:
self.collection.create_index([('title', pymongo.TEXT)]) """
song = self.collection.find( Finds all the tracks matching the title in the query params.
{'title': {'$regex': query, '$options': 'i'}}) """
self.collection.create_index([("title", pymongo.TEXT)])
song = self.collection.find({"title": {"$regex": query, "$options": "i"}})
return convert_to_json(song) return convert_to_json(song)
def find_songs_by_album(self, name, artist): def find_songs_by_album(self, name: str, artist: str) -> list:
songs = self.collection.find({'album': name, 'album_artist': artist}) """
Returns all the tracks exactly matching the album in the query params.
"""
songs = self.collection.find({"album": name, "albumartist": artist})
return convert_to_json(songs) return convert_to_json(songs)
def find_songs_by_folder(self, query): def find_songs_by_folder(self, query: str) -> list:
songs = self.collection.find({'folder': query}).sort( """
'title', pymongo.ASCENDING) Returns a sorted list of all the tracks exactly matching the folder in the query params
"""
songs = self.collection.find({"folder": query}).sort("title", pymongo.ASCENDING)
return convert_to_json(songs) return convert_to_json(songs)
def find_songs_by_folder_og(self, query): def find_songs_by_folder_og(self, query: str) -> list:
songs = self.collection.find({'folder': query}) """
Returns an unsorted list of all the tracks exactly matching the folder in the query params
"""
songs = self.collection.find({"folder": query})
return convert_to_json(songs) return convert_to_json(songs)
def find_songs_by_artist(self, query): def find_songs_by_artist(self, query: str) -> list:
songs = self.collection.find({'artists': query}) """
Returns a list of all the tracks exactly matching the artists in the query params.
"""
songs = self.collection.find({"artists": query})
return convert_to_json(songs) return convert_to_json(songs)
def find_songs_by_album_artist(self, query): def find_songs_by_albumartist(self, query: str):
"""
Returns a list of all the tracks containing the albumartist in the query params.
"""
songs = self.collection.find( songs = self.collection.find(
{'album_artist': {'$regex': query, '$options': 'i'}}) {"albumartist": {"$regex": query, "$options": "i"}}
)
return convert_to_json(songs) return convert_to_json(songs)
def find_song_by_path(self, path): def find_song_by_path(self, path: str) -> dict:
song = self.collection.find_one({'filepath': path}) """
Returns a single track matching the filepath in the query params.
"""
song = self.collection.find_one({"filepath": path})
return convert_one_to_json(song) return convert_one_to_json(song)
def remove_song_by_filepath(self, filepath): def remove_song_by_filepath(self, filepath: str):
"""
Removes a single track from the database. Returns a boolean indicating success or failure of the operation.
"""
try: try:
self.collection.delete_one({'filepath': filepath}) self.collection.delete_one({"filepath": filepath})
return True return True
except: except:
return False return False
@@ -124,10 +193,14 @@ class AllSongs(Mongo):
@dataclass @dataclass
class Track: class Track:
id: str """
Track class
"""
track_id: str
title: str title: str
artists: str artists: str
album_artist: str albumartist: str
album: str album: str
filepath: str filepath: str
folder: str folder: str
@@ -136,9 +209,9 @@ class Track:
genre: str genre: str
bitrate: int bitrate: int
image: str image: str
tracknumber: int
discnumber: int
def __post_init__(self): def __post_init__(self):
self.artists = self.artists.split(', ') self.artists = self.artists.split(", ")
self.image = "http://127.0.0.1:8900/images/thumbnails/" + self.image self.image = "http://127.0.0.1:8900/images/thumbnails/" + self.image
+3 -1
View File
@@ -1,5 +1,5 @@
<template> <template>
<div class="r-home"> <div class="r-home rounded border">
<NowPlaying /> <NowPlaying />
<Recommendations /> <Recommendations />
</div> </div>
@@ -9,6 +9,8 @@
.r-home { .r-home {
height: 100%; height: 100%;
width: 31rem; width: 31rem;
background-color: $card-dark;
padding: $small;
} }
</style> </style>
+1 -2
View File
@@ -1,7 +1,7 @@
<template> <template>
<div class="r-sidebar"> <div class="r-sidebar">
<div class="grid"> <div class="grid">
<div class="r-content rounded"> <div class="r-content">
<div class="r-dash" v-show="current_tab == tabs.home"> <div class="r-dash" v-show="current_tab == tabs.home">
<DashBoard /> <DashBoard />
</div> </div>
@@ -63,7 +63,6 @@ function changeTab(tab) {
.r-content { .r-content {
grid-area: content; grid-area: content;
width: 31rem; width: 31rem;
overflow: hidden;
// @include tablet-landscape { // @include tablet-landscape {
// display: none; // display: none;
+2 -2
View File
@@ -108,13 +108,13 @@ export default {
#title { #title {
margin: 0; margin: 0;
width: 22rem; width: 20rem;
color: #fff; color: #fff;
} }
#artist { #artist {
font-size: small; font-size: small;
width: 22rem; width: 20rem;
color: $highlight-blue; color: $highlight-blue;
} }
+3 -4
View File
@@ -20,16 +20,16 @@
</div> </div>
</div> </div>
<div class="scrollable-r border rounded"> <div class="scrollable-r border rounded">
<TrackItem v-for="song in queue" :key="song.id" :track="song" /> <TrackItem v-for="song in queue" :key="song.track_id" :track="song" />
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { ref, toRefs } from "@vue/reactivity";
import perks from "@/composables/perks.js"; import perks from "@/composables/perks.js";
import audio from "@/composables/playAudio.js"; import audio from "@/composables/playAudio.js";
import { ref, toRefs } from "@vue/reactivity";
import { watch } from "@vue/runtime-core"; import { watch } from "@vue/runtime-core";
import TrackItem from "../shared/TrackItem.vue"; import TrackItem from "../shared/TrackItem.vue";
@@ -120,10 +120,9 @@ export default {
.r-grid { .r-grid {
position: relative; position: relative;
height: 100%; height: calc(100% - 2rem);
display: grid; display: grid;
grid-template-rows: min-content; grid-template-rows: min-content;
padding-bottom: 2.5rem;
.scrollable-r { .scrollable-r {
height: 100%; height: 100%;
+1 -1
View File
@@ -6,7 +6,7 @@
<tbody> <tbody>
<TrackItem <TrackItem
v-for="track in props.tracks" v-for="track in props.tracks"
:key="track.id" :key="track.track_id"
:track="track" :track="track"
/> />
</tbody> </tbody>
+2 -2
View File
@@ -1,5 +1,5 @@
<template> <template>
<tr class="songlist-item" :class="{ current: current.id == song.id }"> <tr class="songlist-item" :class="{ current: current.track_id == song.track_id }">
<td class="index">{{ index }}</td> <td class="index">{{ index }}</td>
<td class="flex" @click="emitUpdate(song)"> <td class="flex" @click="emitUpdate(song)">
<div <div
@@ -8,7 +8,7 @@
> >
<div <div
class="now-playing-track image" class="now-playing-track image"
v-if="current.id == song.id" v-if="current.track_id == song.track_id"
:class="{ active: is_playing, not_active: !is_playing }" :class="{ active: is_playing, not_active: !is_playing }"
></div> ></div>
</div> </div>
+2 -2
View File
@@ -3,7 +3,7 @@
class="track-item h-1" class="track-item h-1"
@click="playThis(props.track)" @click="playThis(props.track)"
:class="{ :class="{
currentInQueue: current.id == props.track.id, currentInQueue: current.track_id == props.track.track_id,
}" }"
> >
<div <div
@@ -14,7 +14,7 @@
> >
<div <div
class="now-playing-track image" class="now-playing-track image"
v-if="current.id == props.track.id" v-if="current.track_id == props.track.track_id"
:class="{ active: is_playing, not_active: !is_playing }" :class="{ active: is_playing, not_active: !is_playing }"
></div> ></div>
</div> </div>
+3 -3
View File
@@ -1,9 +1,9 @@
import { ref } from "@vue/reactivity"; import { ref } from "@vue/reactivity";
import { watch } from "@vue/runtime-core"; import { watch } from "@vue/runtime-core";
import media from "./mediaNotification.js"; import media from "./mediaNotification.js";
import state from "./state.js";
import playAudio from "./playAudio.js"; import playAudio from "./playAudio.js";
import state from "./state.js";
const current = ref(state.current); const current = ref(state.current);
@@ -50,7 +50,7 @@ function updateNext(song_) {
} }
function updatePrev(song) { function updatePrev(song) {
const index = state.queue.value.findIndex((item) => item.id === song.id); const index = state.queue.value.findIndex((item) => item.id === song.track_id);
if (index == 0) { if (index == 0) {
prev.value = queue.value[queue.value.length - 1]; prev.value = queue.value[queue.value.length - 1];
+1
View File
@@ -11,6 +11,7 @@ const playing = ref(state.is_playing);
const url = "http://0.0.0.0:8901/"; const url = "http://0.0.0.0:8901/";
const playAudio = (path) => { const playAudio = (path) => {
console.log(path)
const elem = document.getElementById('progress') const elem = document.getElementById('progress')
const full_path = url + encodeURIComponent(path); const full_path = url + encodeURIComponent(path);