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