server: add get album bio from last fm function

- co-written by Github Copilot
This commit is contained in:
geoffrey45
2022-01-17 12:32:27 +03:00
parent a720891c20
commit 2ee8d27bf0
20 changed files with 370 additions and 446 deletions
+14 -15
View File
@@ -5,18 +5,19 @@ from app import functions, instances, helpers, cache
bp = Blueprint('api', __name__, url_prefix='')
all_the_f_music = []
home_dir = helpers.home_dir
all_the_f_music = helpers.getAllSongs()
def initialize() -> None:
helpers.create_config_dir()
helpers.check_for_new_songs()
initialize()
@bp.route('/')
def adutsfsd():
return "^ _ ^"
@@ -79,7 +80,7 @@ def x():
def get_album_artists(album, artist):
album = album.replace('|', '/')
artist = artist.replace('|', '/')
tracks = []
for track in all_the_f_music:
@@ -161,7 +162,7 @@ def getArtistData(artist: str):
@bp.route("/f/<folder>")
@cache.cached()
def getFolderTree(folder: str = None):
def getFolderTree(folder: str):
req_dir = folder.replace('|', '/')
if folder == "home":
@@ -180,21 +181,11 @@ def getFolderTree(folder: str = None):
dir = {
"name": entry.name,
"count": len(files_in_dir),
"path": entry.path.replace(home_dir, "")
"path": entry.path.replace(home_dir, ""),
}
folders.append(dir)
# if entry.is_file():
# if isValidFile(entry.name) == True:
# file = instances.songs_instance.find_song_by_path(entry.path)
# if not file:
# getTags(entry.path)
# songs_array = instances.songs_instance.find_songs_by_folder(
# req_dir)
songs = []
for x in all_the_f_music:
@@ -203,6 +194,7 @@ def getFolderTree(folder: str = None):
return {"files": helpers.remove_duplicates(songs), "folders": sorted(folders, key=lambda i: i['name'])}
@bp.route('/qwerty')
def populateArtists():
all_songs = instances.songs_instance.get_all_songs()
@@ -222,6 +214,7 @@ def populateArtists():
return {'songs': artists}
@bp.route('/albums')
def getAlbums():
s = instances.songs_instance.get_all_songs()
@@ -239,6 +232,7 @@ def getAlbums():
return {'albums': albums}
@bp.route('/albums/<query>')
@cache.cached()
def getAlbumSongs(query: str):
@@ -260,3 +254,8 @@ def getAlbumSongs(query: str):
}
return {'songs': helpers.remove_duplicates(songs), 'info': album_obj}
@bp.route('/album/<title>/<artist>/bio')
def drop_db(title, artist):
return functions.getAlbumBio(title, artist)
+172 -16
View File
@@ -3,14 +3,23 @@ This module contains larger functions for the server
"""
import time
from progress.bar import Bar
import requests
import os
import requests
import random
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
from app import api
def populate():
'''
Populate the database with all songs in the music directory
@@ -23,21 +32,8 @@ def populate():
files = helpers.run_fast_scandir(helpers.home_dir, [".flac", ".mp3"])[1]
for file in files:
file_in_db_obj = instances.songs_instance.find_song_by_path(file)
getTags(file)
try:
image = file_in_db_obj['image']
if not os.path.exists(os.path.join(helpers.app_dir, 'images', 'thumbnails', image)):
helpers.extract_thumb(file)
except:
image = None
if image is None:
try:
helpers.getTags(file)
except MutagenError:
pass
api.all_the_f_music = helpers.getAllSongs()
print('\ncheck done')
@@ -82,3 +78,163 @@ def populate_images():
bar.next()
bar.finish()
def extract_thumb(path: str) -> str:
"""
Extracts the thumbnail from an audio file. Returns the path to the thumbnail.
"""
def use_defaults() -> str:
"""
Returns a path to a random image in the defaults directory.
"""
path = "http://127.0.0.1:8900/images/defaults/" + \
str(random.randint(0, 10)) + '.webp'
return path
webp_path = path.split('/')[-1] + '.webp'
img_path = os.path.join(helpers.app_dir, "images", "thumbnails", webp_path)
if os.path.exists(img_path):
return "http://127.0.0.1:8900/images/thumbnails/" + webp_path
if path.endswith('.flac'):
try:
audio = FLAC(path)
album_art = audio.pictures[0].data
except:
album_art = None
elif path.endswith('.mp3'):
try:
audio = ID3(path)
album_art = audio.getall('APIC')[0].data
except:
album_art = None
if album_art is None:
return use_defaults()
else:
img = Image.open(BytesIO(album_art))
try:
small_img = img.resize((150, 150), Image.ANTIALIAS)
small_img.save(img_path, format="webp")
except OSError:
try:
png = img.convert('RGB')
small_img = png.resize((150, 150), Image.ANTIALIAS)
small_img.save(img_path, format="webp")
except:
return use_defaults()
final_path = "http://127.0.0.1:8900/images/thumbnails/" + webp_path
return final_path
def getTags(full_path: str) -> dict:
"""
Returns a dictionary of tags for a given file.
"""
if full_path.endswith('.flac'):
try:
audio = FLAC(full_path)
except:
return
elif full_path.endswith('.mp3'):
try:
audio = MP3(full_path)
except:
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"
img_path = extract_thumb(full_path)
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": round(audio.info.length),
"bitrate": audio.info.bitrate,
"image": img_path,
"type": {
"name": None,
"id": None
}
}
instances.songs_instance.insert_song(tags)
return tags
def getAlbumBio(title: str, album_artist: str) -> dict:
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)
response = requests.get(last_fm_url)
data = response.json()
try:
bio = data['album']['wiki']['content']
except KeyError:
bio = None
if bio is None:
return "None"
return {'data': data}
+19 -158
View File
@@ -7,28 +7,25 @@ import threading
import time
import requests
from mutagen.mp3 import MP3
from mutagen.id3 import ID3
from mutagen.flac import FLAC
from io import BytesIO
from PIL import Image
from app import instances
from app import functions
home_dir = os.path.expanduser('~') + "/"
app_dir = home_dir + '/.musicx'
home_dir = os.path.expanduser('~') + '/'
app_dir = os.path.join(home_dir, '.musicx')
last_fm_api_key = "762db7a44a9e6fb5585661f5f2bdf23a"
def background(f):
'''
a threading decorator
use @background above the function you want to run in the background
'''
def backgrnd_func(*a, **kw):
def background_func(*a, **kw):
threading.Thread(target=f, args=a, kwargs=kw).start()
return backgrnd_func
return background_func
@background
def check_for_new_songs():
@@ -62,142 +59,6 @@ def run_fast_scandir(dir: str, ext: str) -> list:
return subfolders, files
def extract_thumb(path: str) -> str:
"""
Extracts the thumbnail from an audio file. Returns the path to the thumbnail.
"""
webp_path = path.split('/')[-1] + '.webp'
img_path = app_dir + "/images/thumbnails/" + webp_path
if os.path.exists(img_path):
return webp_path
if path.endswith('.flac'):
try:
audio = FLAC(path)
album_art = audio.pictures[0].data
except:
album_art = None
elif path.endswith('.mp3'):
try:
audio = ID3(path)
album_art = audio.getall('APIC')[0].data
except:
album_art = None
if album_art is None:
return "null.webp"
else:
img = Image.open(BytesIO(album_art))
try:
small_img = img.resize((150, 150), Image.ANTIALIAS)
small_img.save(img_path, format="webp")
except OSError:
try:
png = img.convert('RGB')
small_img = png.resize((150, 150), Image.ANTIALIAS)
small_img.save(img_path, format="webp")
print('{} :: was png'.format(
img_path
))
except:
img_path = None
return webp_path
def getTags(full_path: str) -> dict:
"""
Returns a dictionary of tags for a given file.
"""
if full_path.endswith('.flac'):
try:
audio = FLAC(full_path)
except:
return
elif full_path.endswith('.mp3'):
try:
audio = MP3(full_path)
except:
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"
img_path = extract_thumb(full_path)
tags = {
"filepath": full_path.replace(home_dir, ''),
"folder": os.path.dirname(full_path).replace(home_dir, ""),
"title": title,
"artists": artists,
"album_artist": album_artist,
"album": album,
"genre": genre,
"length": round(audio.info.length),
"bitrate": audio.info.bitrate,
"image": img_path,
"type": {
"name": None,
"id": None
}
}
instances.songs_instance.insert_song(tags)
return tags
def remove_duplicates(array: list) -> list:
"""
Removes duplicates from a list. Returns a list without duplicates.
@@ -245,33 +106,33 @@ def create_config_dir() -> None:
"""
home_dir = os.path.expanduser('~')
config_folder = home_dir + app_dir
config_folder = os.path.join(home_dir, app_dir)
dirs = ["", "/images", "/images/artists", "/images/thumbnails"]
dirs = ["", "images", "images/defaults",
"images/artists", "images/thumbnails"]
for dir in dirs:
if not os.path.exists(config_folder + dir):
os.makedirs(config_folder + dir)
path = os.path.join(config_folder, dir)
os.chmod(path, 0o755)
try:
os.makedirs(path)
except FileExistsError:
pass
def getAllSongs() -> None:
"""
Gets all songs under the ~/ directory.
"""
tracks = []
tracks.extend(instances.songs_instance.get_all_songs())
tracks = instances.songs_instance.get_all_songs()
for track in tracks:
try:
os.chmod(os.path.join(home_dir, track['filepath']), 0o755)
except FileNotFoundError:
instances.songs_instance.remove_song_by_filepath(
os.path.join(home_dir, track['filepath']))
if track['image'] is not None:
track['image'] = "http://127.0.0.1:8900/images/thumbnails/" + \
track['image']
instances.songs_instance.remove_song_by_filepath(track['filepath'])
if track['artists'] is not None:
track['artists'] = track['artists'].split(', ')
+1 -1
View File
@@ -115,7 +115,7 @@ class AllSongs(Mongo):
def remove_song_by_filepath(self, filepath):
try:
self.collection.remove({'filepath': filepath})
self.collection.delete_one({'filepath': filepath})
return True
except:
return False