🔷 redesign playlist header
@@ -12,7 +12,6 @@ from app.lib import folderslib
|
|||||||
|
|
||||||
folder_bp = Blueprint("folder", __name__, url_prefix="/")
|
folder_bp = Blueprint("folder", __name__, url_prefix="/")
|
||||||
from app import helpers
|
from app import helpers
|
||||||
import time
|
|
||||||
|
|
||||||
|
|
||||||
@folder_bp.route("/folder", methods=["POST"])
|
@folder_bp.route("/folder", methods=["POST"])
|
||||||
|
|||||||
@@ -20,10 +20,11 @@ def send_track_file(trackid):
|
|||||||
for file in api.PRE_TRACKS
|
for file in api.PRE_TRACKS
|
||||||
if file["_id"]["$oid"] == trackid
|
if file["_id"]["$oid"] == trackid
|
||||||
][0]
|
][0]
|
||||||
return send_file(filepath, mimetype="audio/mp3")
|
except (FileNotFoundError, IndexError):
|
||||||
except FileNotFoundError:
|
|
||||||
return "File not found", 404
|
return "File not found", 404
|
||||||
|
|
||||||
|
return send_file(filepath, mimetype="audio/mp3")
|
||||||
|
|
||||||
|
|
||||||
@track_bp.route("/sample")
|
@track_bp.route("/sample")
|
||||||
def get_sample_track():
|
def get_sample_track():
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ from io import BytesIO
|
|||||||
import random
|
import random
|
||||||
import datetime
|
import datetime
|
||||||
from typing import List
|
from typing import List
|
||||||
from flask import request
|
|
||||||
import mutagen
|
import mutagen
|
||||||
import urllib
|
import urllib
|
||||||
|
|
||||||
@@ -24,10 +23,8 @@ from PIL import Image
|
|||||||
from app import helpers
|
from app import helpers
|
||||||
from app import instances
|
from app import instances
|
||||||
from app import settings, models
|
from app import settings, models
|
||||||
from app.lib import albumslib
|
|
||||||
from app import api
|
from app import api
|
||||||
from app.lib import watchdoge
|
from app.lib import watchdoge, folderslib, playlistlib, albumslib
|
||||||
from app.lib import folderslib
|
|
||||||
|
|
||||||
|
|
||||||
@helpers.background
|
@helpers.background
|
||||||
@@ -73,7 +70,7 @@ def populate():
|
|||||||
upsert_id = instances.songs_instance.insert_song(tags)
|
upsert_id = instances.songs_instance.insert_song(tags)
|
||||||
|
|
||||||
if upsert_id is not None:
|
if upsert_id is not None:
|
||||||
tags["_id"] = {"$oid": upsert_id}
|
tags["_id"] = {"$oid": str(upsert_id)}
|
||||||
api.PRE_TRACKS.append(tags)
|
api.PRE_TRACKS.append(tags)
|
||||||
|
|
||||||
_bar.next()
|
_bar.next()
|
||||||
@@ -81,6 +78,7 @@ def populate():
|
|||||||
|
|
||||||
albumslib.create_everything()
|
albumslib.create_everything()
|
||||||
folderslib.run_scandir()
|
folderslib.run_scandir()
|
||||||
|
playlistlib.create_all_playlists()
|
||||||
|
|
||||||
end = time.time()
|
end = time.time()
|
||||||
|
|
||||||
@@ -199,11 +197,10 @@ def save_t_colors():
|
|||||||
_bar.finish()
|
_bar.finish()
|
||||||
|
|
||||||
|
|
||||||
def extract_thumb(audio_file_path: str) -> str:
|
def extract_thumb(audio_file_path: str, webp_path: str) -> str:
|
||||||
"""
|
"""
|
||||||
Extracts the thumbnail from an audio file. Returns the path to the thumbnail.
|
Extracts the thumbnail from an audio file. Returns the path to the thumbnail.
|
||||||
"""
|
"""
|
||||||
webp_path = audio_file_path.split("/")[-1] + ".webp"
|
|
||||||
img_path = os.path.join(settings.THUMBS_PATH, webp_path)
|
img_path = os.path.join(settings.THUMBS_PATH, webp_path)
|
||||||
|
|
||||||
if os.path.exists(img_path):
|
if os.path.exists(img_path):
|
||||||
@@ -221,7 +218,7 @@ def extract_thumb(audio_file_path: str) -> str:
|
|||||||
try:
|
try:
|
||||||
png = img.convert("RGB")
|
png = img.convert("RGB")
|
||||||
small_img = png.resize((250, 250), Image.ANTIALIAS)
|
small_img = png.resize((250, 250), Image.ANTIALIAS)
|
||||||
small_img.save(img_path, format="webp")
|
small_img.save(webp_path, format="webp")
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -379,6 +376,7 @@ def get_all_albums() -> List[models.Album]:
|
|||||||
"""
|
"""
|
||||||
Returns a list of album objects for all albums in the database.
|
Returns a list of album objects for all albums in the database.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
albums: List[models.Album] = []
|
albums: List[models.Album] = []
|
||||||
|
|
||||||
_bar = Bar("Creating albums", max=len(api.PRE_TRACKS))
|
_bar = Bar("Creating albums", max=len(api.PRE_TRACKS))
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ This library contains all the functions related to albums.
|
|||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
import urllib
|
import urllib
|
||||||
from typing import List
|
from typing import List
|
||||||
from app import models, functions, helpers
|
from app import models, functions
|
||||||
from app.lib import trackslib
|
from app.lib import trackslib
|
||||||
from app import api
|
from app import api
|
||||||
|
|
||||||
@@ -19,7 +19,11 @@ def create_everything() -> List[models.Track]:
|
|||||||
|
|
||||||
api.ALBUMS.clear()
|
api.ALBUMS.clear()
|
||||||
api.ALBUMS.extend(albums)
|
api.ALBUMS.extend(albums)
|
||||||
trackslib.create_all_tracks()
|
|
||||||
|
tracks = trackslib.create_all_tracks()
|
||||||
|
|
||||||
|
api.TRACKS.clear()
|
||||||
|
api.TRACKS.extend(tracks)
|
||||||
|
|
||||||
|
|
||||||
def get_album_duration(album: list) -> int:
|
def get_album_duration(album: list) -> int:
|
||||||
@@ -41,7 +45,8 @@ def get_album_image(album: list) -> str:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
for track in album:
|
for track in album:
|
||||||
img = functions.extract_thumb(track["filepath"])
|
img_p = track["album"] + track["albumartist"] + ".webp"
|
||||||
|
img = functions.extract_thumb(track["filepath"], webp_path=img_p)
|
||||||
|
|
||||||
if img is not None:
|
if img is not None:
|
||||||
return img
|
return img
|
||||||
|
|||||||
@@ -18,12 +18,13 @@ def create_all_tracks() -> List[models.Track]:
|
|||||||
tracks: list[models.Track] = []
|
tracks: list[models.Track] = []
|
||||||
|
|
||||||
_bar = Bar("Creating tracks", max=len(api.PRE_TRACKS))
|
_bar = Bar("Creating tracks", max=len(api.PRE_TRACKS))
|
||||||
|
|
||||||
for track in api.PRE_TRACKS:
|
for track in api.PRE_TRACKS:
|
||||||
try:
|
try:
|
||||||
os.chmod(track["filepath"], 0o755)
|
os.chmod(track["filepath"], 0o755)
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
instances.songs_instance.remove_song_by_filepath(track["filepath"])
|
instances.songs_instance.remove_song_by_filepath(track["filepath"])
|
||||||
|
api.PRE_TRACKS.remove(track)
|
||||||
|
|
||||||
album = albumslib.find_album(track["album"], track["albumartist"])
|
album = albumslib.find_album(track["album"], track["albumartist"])
|
||||||
|
|
||||||
@@ -34,8 +35,7 @@ def create_all_tracks() -> List[models.Track]:
|
|||||||
|
|
||||||
_bar.finish()
|
_bar.finish()
|
||||||
|
|
||||||
api.TRACKS.clear()
|
return tracks
|
||||||
api.TRACKS.extend(tracks)
|
|
||||||
|
|
||||||
|
|
||||||
def get_album_tracks(albumname, artist):
|
def get_album_tracks(albumname, artist):
|
||||||
@@ -54,4 +54,3 @@ def get_track_by_id(trackid: str) -> models.Track:
|
|||||||
for track in api.TRACKS:
|
for track in api.TRACKS:
|
||||||
if track.trackid == trackid:
|
if track.trackid == trackid:
|
||||||
return track
|
return track
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,15 @@ def create_config_dir() -> None:
|
|||||||
path = os.path.join(config_folder, _dir)
|
path = os.path.join(config_folder, _dir)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
os.path.exists(path)
|
||||||
|
except FileNotFoundError:
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
except FileExistsError:
|
os.chmod(path, 0o755)
|
||||||
pass
|
|
||||||
|
|
||||||
os.chmod(path, 0o755)
|
if _dir == dirs[3]:
|
||||||
|
default_thumbnails_path = "../setup/default-images/thumbnails"
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.path.exists(os.path.join(path, "defaults"))
|
||||||
|
except FileNotFoundError:
|
||||||
|
pass
|
||||||
|
|||||||
@@ -19,3 +19,16 @@ IMG_THUMB_URI = IMG_BASE_URI + "thumbnails/"
|
|||||||
DEFAULT_ARTIST_IMG = IMG_ARTIST_URI + "0.webp"
|
DEFAULT_ARTIST_IMG = IMG_ARTIST_URI + "0.webp"
|
||||||
|
|
||||||
LAST_FM_API_KEY = "762db7a44a9e6fb5585661f5f2bdf23a"
|
LAST_FM_API_KEY = "762db7a44a9e6fb5585661f5f2bdf23a"
|
||||||
|
|
||||||
|
P_COLORS = [
|
||||||
|
"rgb(4, 40, 196)",
|
||||||
|
"rgb(196, 4, 68)",
|
||||||
|
"rgb(4, 99, 59)",
|
||||||
|
"rgb(161, 87, 1)",
|
||||||
|
"rgb(1, 161, 22)",
|
||||||
|
"rgb(116, 1, 161)",
|
||||||
|
"rgb(0, 0, 0)",
|
||||||
|
"rgb(95, 95, 95)",
|
||||||
|
"rgb(141, 132, 2)",
|
||||||
|
"rgb(141, 11, 2)",
|
||||||
|
]
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 984 B |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 7.2 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 25 KiB |
@@ -1,14 +1,21 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="p-header">
|
<div class="p-header">
|
||||||
<div class="carddd">
|
<div class="carddd">
|
||||||
<div class="type">❤ Playlist</div>
|
<div class="art image"></div>
|
||||||
<div class="title ellip">{{ props.info.name }}</div>
|
<div class="info">
|
||||||
<div class="desc">
|
<div class="btns">
|
||||||
{{ props.info.desc[0] }}
|
<PlayBtnRect :source="playSources.playlist" />
|
||||||
</div>
|
</div>
|
||||||
<div class="duration">4 Tracks • 3 Hours</div>
|
<div class="duration">4 Tracks • 3 Hours</div>
|
||||||
<div class="btns">
|
<div class="desc">
|
||||||
<PlayBtnRect />
|
{{ props.info.desc[0] }}
|
||||||
|
Juice is a drink made from the extraction or pressing of the natural
|
||||||
|
liquid contained in fruit and vegetables. It can also refer to liquids
|
||||||
|
that are flavored with concentrate or other biological food sources,
|
||||||
|
such as meat or seafood, such as clam juice
|
||||||
|
</div>
|
||||||
|
<div class="title ellip">{{ props.info.name }}</div>
|
||||||
|
<div class="type">❤ Playlist</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="last-updated">
|
<div class="last-updated">
|
||||||
@@ -21,6 +28,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { playSources } from "../../composables/enums";
|
||||||
|
|
||||||
import PlayBtnRect from "../shared/PlayBtnRect.vue";
|
import PlayBtnRect from "../shared/PlayBtnRect.vue";
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
info: {
|
info: {
|
||||||
@@ -38,7 +47,9 @@ const props = defineProps<{
|
|||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
height: 14rem;
|
height: 14rem;
|
||||||
background-image: url("../../assets/images/eggs.jpg");
|
// background-image: url("../../assets/images/eggs.jpg");
|
||||||
|
|
||||||
|
background-image: linear-gradient(23deg, $black 40%, rgb(141, 11, 2), $black);
|
||||||
position: relative;
|
position: relative;
|
||||||
margin-top: $small;
|
margin-top: $small;
|
||||||
border-radius: 0.75rem;
|
border-radius: 0.75rem;
|
||||||
@@ -46,8 +57,8 @@ const props = defineProps<{
|
|||||||
|
|
||||||
.last-updated {
|
.last-updated {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: $small;
|
bottom: 1rem;
|
||||||
right: $small;
|
right: 1rem;
|
||||||
padding: 0.5rem;
|
padding: 0.5rem;
|
||||||
background-color: $body;
|
background-color: $body;
|
||||||
color: rgb(255, 255, 255);
|
color: rgb(255, 255, 255);
|
||||||
@@ -71,13 +82,22 @@ const props = defineProps<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.carddd {
|
.carddd {
|
||||||
position: absolute;
|
width: 100%;
|
||||||
bottom: $small;
|
|
||||||
left: $small;
|
|
||||||
width: 25rem;
|
|
||||||
padding: 1rem;
|
padding: 1rem;
|
||||||
background-color: rgba(5, 4, 4, 0.829);
|
display: grid;
|
||||||
border-radius: .75rem;
|
grid-template-columns: 13rem 1fr;
|
||||||
|
|
||||||
|
.art {
|
||||||
|
width: 12rem;
|
||||||
|
height: 12rem;
|
||||||
|
background-color: red;
|
||||||
|
background-image: url("../../assets/images/eggs.jpg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column-reverse;
|
||||||
|
}
|
||||||
|
|
||||||
.type {
|
.type {
|
||||||
color: rgba(255, 255, 255, 0.692);
|
color: rgba(255, 255, 255, 0.692);
|
||||||
@@ -99,15 +119,11 @@ const props = defineProps<{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.duration {
|
.duration {
|
||||||
position: absolute;
|
|
||||||
right: 1rem;
|
|
||||||
bottom: 1rem;
|
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
color: $white;
|
color: $white;
|
||||||
padding: $smaller;
|
padding: $smaller;
|
||||||
border: solid 1px $gray1;
|
padding-left: 0;
|
||||||
user-select: none;
|
font-weight: 900;
|
||||||
border-radius: $smaller;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.btns {
|
.btns {
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
export enum playSources {
|
||||||
|
playlist,
|
||||||
|
album,
|
||||||
|
search,
|
||||||
|
folder,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum NotifType {
|
||||||
|
Success,
|
||||||
|
Info,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export enum NotifType {
|
|
||||||
Success,
|
|
||||||
Info,
|
|
||||||
Error
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ export default defineStore("FolderDirs&Tracks", {
|
|||||||
const { tracks, folders } = await fetchThem(path);
|
const { tracks, folders } = await fetchThem(path);
|
||||||
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
console.log(path)
|
|
||||||
this.dirs = folders;
|
this.dirs = folders;
|
||||||
this.tracks = tracks;
|
this.tracks = tracks;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { Notif } from "../interfaces";
|
import { Notif } from "../interfaces";
|
||||||
import { NotifType } from "./enums";
|
import { NotifType } from "../composables/enums";
|
||||||
|
|
||||||
const useNotifStore = defineStore("notification", {
|
const useNotifStore = defineStore("notification", {
|
||||||
state: () => ({
|
state: () => ({
|
||||||
|
|||||||