From 2b33fb87a2260e5576ca2f19cb395f19f95ef83c Mon Sep 17 00:00:00 2001 From: "restyled-io[bot]" <32688539+restyled-io[bot]@users.noreply.github.com> Date: Thu, 26 May 2022 19:12:04 +0300 Subject: [PATCH] Restyle Implement Fuzzy search using rapidfuzz (#60) --- server/app/api/search.py | 28 ++++++++++------ server/app/helpers.py | 23 +++++++------ server/app/lib/albumslib.py | 2 +- server/app/lib/populate.py | 33 +++++++++---------- server/app/lib/searchlib.py | 16 ++++++--- server/app/lib/watchdoge.py | 9 ++--- server/app/models.py | 10 +++--- server/start.sh | 16 ++++----- src/assets/css/BottomBar/BottomBar.scss | 2 +- src/components/AlbumView/Header.vue | 2 +- src/components/LeftSidebar/Navigation.vue | 2 +- .../RightSideBar/Search/TracksGrid.vue | 2 +- src/composables/keyboard.ts | 2 +- src/composables/normalizeContextMenu.js | 3 +- src/main.js | 14 ++++---- 15 files changed, 90 insertions(+), 74 deletions(-) diff --git a/server/app/api/search.py b/server/app/api/search.py index 719f4b0..9c550ce 100644 --- a/server/app/api/search.py +++ b/server/app/api/search.py @@ -1,11 +1,10 @@ """ Contains all the search routes. """ - -from flask import Blueprint, request - -from app.lib import searchlib from app import helpers +from app.lib import searchlib +from flask import Blueprint +from flask import request search_bp = Blueprint("search", __name__, url_prefix="/") @@ -96,9 +95,18 @@ def search(): return { "data": [ - {"tracks": tracks[:5], "more": len(tracks) > 5}, - {"albums": albums[:6], "more": len(albums) > 6}, - {"artists": artists_dicts[:6], "more": len(artists_dicts) > 6}, + { + "tracks": tracks[:5], + "more": len(tracks) > 5 + }, + { + "albums": albums[:6], + "more": len(albums) > 6 + }, + { + "artists": artists_dicts[:6], + "more": len(artists_dicts) > 6 + }, ] } @@ -116,18 +124,18 @@ def search_load_more(): if type == "tracks": return { - "tracks": SEARCH_RESULTS["tracks"][index : index + 5], + "tracks": SEARCH_RESULTS["tracks"][index:index + 5], "more": len(SEARCH_RESULTS["tracks"]) > index + 5, } elif type == "albums": return { - "albums": SEARCH_RESULTS["albums"][index : index + 6], + "albums": SEARCH_RESULTS["albums"][index:index + 6], "more": len(SEARCH_RESULTS["albums"]) > index + 6, } elif type == "artists": return { - "artists": SEARCH_RESULTS["artists"][index : index + 6], + "artists": SEARCH_RESULTS["artists"][index:index + 6], "more": len(SEARCH_RESULTS["artists"]) > index + 6, } diff --git a/server/app/helpers.py b/server/app/helpers.py index 0d8bd63..3cf4932 100644 --- a/server/app/helpers.py +++ b/server/app/helpers.py @@ -6,9 +6,11 @@ import random import threading import time from datetime import datetime -from typing import Dict, List +from typing import Dict +from typing import List -from app import models, settings +from app import models +from app import settings app_dir = settings.APP_DIR @@ -25,7 +27,9 @@ def background(func): return background_func -def run_fast_scandir(__dir: str, ext: list, full=False) -> Dict[List[str], List[str]]: +def run_fast_scandir(__dir: str, + ext: list, + full=False) -> Dict[List[str], List[str]]: """ Scans a directory for files with a specific extension. Returns a list of files and folders in the directory. """ @@ -58,12 +62,10 @@ def remove_duplicates(tracklist: List[models.Track]) -> List[models.Track]: while song_num < len(tracklist) - 1: for index, song in enumerate(tracklist): - if ( - tracklist[song_num].title == song.title - and tracklist[song_num].album == song.album - and tracklist[song_num].artists == song.artists - and index != song_num - ): + if (tracklist[song_num].title == song.title + and tracklist[song_num].album == song.album + and tracklist[song_num].artists == song.artists + and index != song_num): tracklist.remove(song) song_num += 1 @@ -106,7 +108,8 @@ def check_artist_image(image: str) -> str: """ img_name = image.replace("/", "::") + ".webp" - if not os.path.exists(os.path.join(app_dir, "images", "artists", img_name)): + if not os.path.exists(os.path.join(app_dir, "images", "artists", + img_name)): return use_memoji() else: return img_name diff --git a/server/app/lib/albumslib.py b/server/app/lib/albumslib.py index aa59a86..58c8466 100644 --- a/server/app/lib/albumslib.py +++ b/server/app/lib/albumslib.py @@ -6,13 +6,13 @@ import urllib from typing import List from app import api +from app import helpers from app import instances from app import models from app.lib import taglib from app.lib import trackslib from progress.bar import Bar from tqdm import tqdm -from app import helpers def get_all_albums() -> List[models.Album]: diff --git a/server/app/lib/populate.py b/server/app/lib/populate.py index 364f391..c579225 100644 --- a/server/app/lib/populate.py +++ b/server/app/lib/populate.py @@ -1,26 +1,26 @@ -from concurrent.futures import ThreadPoolExecutor -from multiprocessing import Pool -from copy import deepcopy import os -from os import path import time +from concurrent.futures import ThreadPoolExecutor +from copy import deepcopy +from multiprocessing import Pool +from os import path from typing import List -from tqdm import tqdm - from app import api from app import settings -from app.helpers import create_album_hash, run_fast_scandir +from app.helpers import create_album_hash +from app.helpers import run_fast_scandir from app.instances import album_instance from app.instances import tracks_instance from app.lib import folderslib from app.lib.albumslib import create_album from app.lib.albumslib import find_album from app.lib.taglib import get_tags -from app.logger import Log -from app.models import Album, Track - from app.lib.trackslib import find_track +from app.logger import Log +from app.models import Album +from app.models import Track +from tqdm import tqdm class Populate: @@ -95,7 +95,8 @@ class Populate: folder = tags["folder"] self.folders.add(folder) - tags["albumhash"] = create_album_hash(tags["album"], tags["albumartist"]) + tags["albumhash"] = create_album_hash(tags["album"], + tags["albumartist"]) self.tagged_tracks.append(tags) api.DB_TRACKS.append(tags) @@ -168,9 +169,8 @@ class Populate: for album in tqdm(self.pre_albums, desc="Building albums"): self.create_album(album) - Log( - f"{self.exist_count} of {len(self.pre_albums)} albums were already in the database" - ) + Log(f"{self.exist_count} of {len(self.pre_albums)} albums were already in the database" + ) def create_track(self, track: dict): """ @@ -205,9 +205,8 @@ class Populate: with ThreadPoolExecutor() as executor: executor.map(self.create_track, self.tagged_tracks) - Log( - f"Added {len(self.tagged_tracks)} new tracks and {len(self.albums)} new albums" - ) + Log(f"Added {len(self.tagged_tracks)} new tracks and {len(self.albums)} new albums" + ) def save_albums(self): """ diff --git a/server/app/lib/searchlib.py b/server/app/lib/searchlib.py index f5851c3..6b8ff22 100644 --- a/server/app/lib/searchlib.py +++ b/server/app/lib/searchlib.py @@ -1,13 +1,14 @@ """ This library contains all the functions related to the search functionality. """ - from typing import List -from app import api, helpers, models +from app import api +from app import helpers +from app import models from app.lib import albumslib -from rapidfuzz import fuzz, process - +from rapidfuzz import fuzz +from rapidfuzz import process ratio = fuzz.ratio wratio = fuzz.WRatio @@ -34,6 +35,7 @@ class Limit: class SearchTracks: + def __init__(self, query) -> None: self.query = query @@ -55,6 +57,7 @@ class SearchTracks: class SearchArtists: + def __init__(self, query) -> None: self.query = query @@ -100,6 +103,7 @@ class SearchArtists: class SearchAlbums: + def __init__(self, query) -> None: self.query = query @@ -137,6 +141,7 @@ class SearchAlbums: class GetTopArtistTracks: + def __init__(self, artist: str) -> None: self.artist = artist @@ -160,5 +165,6 @@ def get_artists(artist: str) -> List[models.Track]: Gets all songs with a given artist. """ return [ - track for track in api.TRACKS if artist.lower() in str(track.artists).lower() + track for track in api.TRACKS + if artist.lower() in str(track.artists).lower() ] diff --git a/server/app/lib/watchdoge.py b/server/app/lib/watchdoge.py index 2b98bd2..91b3419 100644 --- a/server/app/lib/watchdoge.py +++ b/server/app/lib/watchdoge.py @@ -7,14 +7,14 @@ import time from app import api from app import instances from app import models +from app.helpers import create_album_hash from app.lib import folderslib -from app.lib.albumslib import create_album, find_album +from app.lib.albumslib import create_album +from app.lib.albumslib import find_album from app.lib.taglib import get_tags from watchdog.events import PatternMatchingEventHandler from watchdog.observers import Observer -from app.helpers import create_album_hash - class OnMyWatch: """ @@ -87,7 +87,8 @@ def remove_track(filepath: str) -> None: fpath = filepath.replace(fname, "") try: - trackid = instances.tracks_instance.get_song_by_path(filepath)["_id"]["$oid"] + trackid = instances.tracks_instance.get_song_by_path( + filepath)["_id"]["$oid"] except TypeError: print(f"💙 Watchdog Error: Error removing track {filepath} TypeError") return diff --git a/server/app/models.py b/server/app/models.py index c4ac3be..27453ff 100644 --- a/server/app/models.py +++ b/server/app/models.py @@ -6,8 +6,8 @@ from dataclasses import field from typing import List from app import api -from app.exceptions import TrackExistsInPlaylist from app import helpers +from app.exceptions import TrackExistsInPlaylist @dataclass(slots=True) @@ -97,11 +97,9 @@ class Album: def get_p_track(ptrack): for track in api.TRACKS: - if ( - track.title == ptrack["title"] - and track.artists == ptrack["artists"] - and ptrack["album"] == track.album - ): + if (track.title == ptrack["title"] + and track.artists == ptrack["artists"] + and ptrack["album"] == track.album): return track diff --git a/server/start.sh b/server/start.sh index f1ce5d0..2bac5a6 100755 --- a/server/start.sh +++ b/server/start.sh @@ -8,17 +8,15 @@ gpath=$(poetry run which gunicorn) while getopts ':s' opt; do case $opt in s) - echo "🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴" - cd "./app" - "$gpath" -b 0.0.0.0:9877 -w 4 --threads=2 "imgserver:app" & - cd ../ - ;; + echo "🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴" + cd "./app" + "$gpath" -b 0.0.0.0:9877 -w 4 --threads=2 "imgserver:app" & + cd ../ + ;; \?) - echo "Invalid option: -$OPTARG" >&2 - ;; + echo "Invalid option: -$OPTARG" >&2 + ;; esac done "$gpath" -b 0.0.0.0:9876 -w 1 --threads=4 "manage:create_app()" - - diff --git a/src/assets/css/BottomBar/BottomBar.scss b/src/assets/css/BottomBar/BottomBar.scss index 2cd8cf7..775e7c9 100644 --- a/src/assets/css/BottomBar/BottomBar.scss +++ b/src/assets/css/BottomBar/BottomBar.scss @@ -7,7 +7,7 @@ display: grid; height: 100%; padding-right: $small; - + @include phone-only { grid-template-columns: 1fr 9.2rem; } diff --git a/src/components/AlbumView/Header.vue b/src/components/AlbumView/Header.vue index 91bf89d..3dfd56e 100644 --- a/src/components/AlbumView/Header.vue +++ b/src/components/AlbumView/Header.vue @@ -15,7 +15,7 @@
Compilation
diff --git a/src/components/LeftSidebar/Navigation.vue b/src/components/LeftSidebar/Navigation.vue index 210167c..e2ced37 100644 --- a/src/components/LeftSidebar/Navigation.vue +++ b/src/components/LeftSidebar/Navigation.vue @@ -9,7 +9,7 @@ class="nav-button" id="home-button" v-motion-slide-from-left-100 - + >
diff --git a/src/components/RightSideBar/Search/TracksGrid.vue b/src/components/RightSideBar/Search/TracksGrid.vue index f6d6e47..7c1e71c 100644 --- a/src/components/RightSideBar/Search/TracksGrid.vue +++ b/src/components/RightSideBar/Search/TracksGrid.vue @@ -43,7 +43,7 @@ function updateQueue(track: Track) { padding: $small; height: 100% !important; overflow: hidden; - + .list-enter-active, .list-leave-active { transition: all 0.5s ease; diff --git a/src/composables/keyboard.ts b/src/composables/keyboard.ts index f2774b9..157e1ba 100644 --- a/src/composables/keyboard.ts +++ b/src/composables/keyboard.ts @@ -64,7 +64,7 @@ export default function (queue: any) { if (!key_down_fired) { if (!ctrlKey) return; e.preventDefault(); - + key_down_fired = true; } diff --git a/src/composables/normalizeContextMenu.js b/src/composables/normalizeContextMenu.js index 5761670..ed5f67b 100644 --- a/src/composables/normalizeContextMenu.js +++ b/src/composables/normalizeContextMenu.js @@ -3,7 +3,8 @@ import { getElem } from "./perks"; export default (mouseX, mouseY) => { const scope = getElem("app", "id"); const contextMenu = getElem("context-menu", "class"); - // ? compute what is the mouse position relative to the container element (scope) + // ? compute what is the mouse position relative to the container element + // (scope) let { left: scopeOffsetX, top: scopeOffsetY } = scope.getBoundingClientRect(); scopeOffsetX = scopeOffsetX < 0 ? 0 : scopeOffsetX; diff --git a/src/main.js b/src/main.js index d1a44e3..84490d4 100644 --- a/src/main.js +++ b/src/main.js @@ -1,12 +1,14 @@ -import { createApp } from "vue"; -import App from "./App.vue"; import "./registerServiceWorker"; -import router from "./router"; -import { createPinia } from "pinia"; -import { MotionPlugin } from "@vueuse/motion"; -import useCustomTransitions from "./transitions"; import "../src/assets/css/global.scss"; +import { MotionPlugin } from "@vueuse/motion"; +import { createPinia } from "pinia"; +import { createApp } from "vue"; + +import App from "./App.vue"; +import router from "./router"; +import useCustomTransitions from "./transitions"; + const app = createApp(App); app.use(createPinia());