From 04b15a651d1fa0357d408fa46c1872a6ab939abc Mon Sep 17 00:00:00 2001 From: Connor Johnstone Date: Fri, 13 Mar 2026 12:25:58 -0400 Subject: [PATCH] Removed the old script --- scripts/search.py | 226 ---------------------------------------------- 1 file changed, 226 deletions(-) delete mode 100755 scripts/search.py diff --git a/scripts/search.py b/scripts/search.py deleted file mode 100755 index c6bc4c6..0000000 --- a/scripts/search.py +++ /dev/null @@ -1,226 +0,0 @@ -#!/usr/bin/env python3 -"""Fuzzy search artists in drift.db and show their similar artists.""" - -import curses -import os -import sqlite3 -import sys -from pathlib import Path - - -def find_db(): - """Find drift.db in XDG data dir.""" - data_home = os.environ.get("XDG_DATA_HOME", Path.home() / ".local" / "share") - p = Path(data_home) / "drift" / "drift.db" - if p.exists(): - return str(p) - print(f"Could not find {p}", file=sys.stderr) - sys.exit(1) - - -def load_artists(db_path): - conn = sqlite3.connect(db_path) - rows = conn.execute( - "SELECT a.mbid, COALESCE(a.name, a.mbid) FROM artists a " - "LEFT JOIN tracks t ON t.artist_mbid = a.mbid " - "GROUP BY a.mbid ORDER BY COUNT(t.path) DESC, a.name" - ).fetchall() - conn.close() - return rows # [(mbid, display_name), ...] - - -def get_similar(db_path, mbid): - conn = sqlite3.connect(db_path) - rows = conn.execute( - "SELECT similar_name, match_score FROM similar_artists " - "WHERE artist_mbid = ?1 ORDER BY match_score DESC", - (mbid,), - ).fetchall() - conn.close() - return rows - - -def get_top_tracks(db_path, mbid): - conn = sqlite3.connect(db_path) - rows = conn.execute( - "SELECT t.path, tt.playcount FROM tracks t " - "JOIN top_tracks tt ON tt.artist_mbid = t.artist_mbid " - " AND (LOWER(t.title) = tt.name_lower " - " OR t.recording_mbid = tt.recording_mbid) " - "WHERE t.artist_mbid = ?1 " - "ORDER BY tt.playcount DESC", - (mbid,), - ).fetchall() - conn.close() - return rows - - -def get_local_track_count(db_path, mbid): - conn = sqlite3.connect(db_path) - total = conn.execute( - "SELECT COUNT(*) FROM tracks WHERE artist_mbid = ?1", (mbid,) - ).fetchone()[0] - matched = conn.execute( - "SELECT COUNT(*) FROM tracks t " - "JOIN top_tracks tt ON tt.artist_mbid = t.artist_mbid " - " AND (LOWER(t.title) = tt.name_lower " - " OR t.recording_mbid = tt.recording_mbid) " - "WHERE t.artist_mbid = ?1", - (mbid,), - ).fetchone()[0] - conn.close() - return total, matched - - -def fuzzy_match(query, name): - """Simple fuzzy: all query chars appear in order in name.""" - name_lower = name.lower() - qi = 0 - for ch in name_lower: - if qi < len(query) and ch == query[qi]: - qi += 1 - return qi == len(query) - - -def run_tui(stdscr, db_path): - curses.curs_set(0) - curses.use_default_colors() - curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_CYAN) - curses.init_pair(2, curses.COLOR_CYAN, -1) - curses.init_pair(3, curses.COLOR_WHITE, -1) - - artists = load_artists(db_path) - query = "" - selected = 0 - scroll = 0 - - while True: - stdscr.erase() - h, w = stdscr.getmaxyx() - - # filter - q = query.lower() - if q: - filtered = [(m, n) for m, n in artists if fuzzy_match(q, n)] - else: - filtered = artists - - selected = max(0, min(selected, len(filtered) - 1)) - - # prompt - prompt = f" > {query}" - stdscr.addnstr(0, 0, prompt, w, curses.color_pair(2) | curses.A_BOLD) - count_str = f" {len(filtered)}/{len(artists)}" - if len(prompt) + len(count_str) < w: - stdscr.addstr(0, len(prompt), count_str, curses.color_pair(3)) - - # artist list - list_h = h - 1 - if list_h < 1: - stdscr.refresh() - continue - - if selected < scroll: - scroll = selected - if selected >= scroll + list_h: - scroll = selected - list_h + 1 - - for i in range(list_h): - idx = scroll + i - if idx >= len(filtered): - break - _, name = filtered[idx] - attr = curses.color_pair(1) if idx == selected else curses.A_NORMAL - stdscr.addnstr(i + 1, 0, f" {name}", w, attr) - - stdscr.refresh() - - key = stdscr.get_wch() - - if key == "\x1b": # Esc - return - elif key == curses.KEY_UP or key == "\x10": # Up / Ctrl-P - selected = max(0, selected - 1) - elif key == curses.KEY_DOWN or key == "\x0e": # Down / Ctrl-N - selected = min(len(filtered) - 1, selected + 1) - elif key == "\n" or key == curses.KEY_ENTER: - if filtered: - show_similar(stdscr, db_path, filtered[selected]) - elif key in (curses.KEY_BACKSPACE, "\x7f", "\x08"): - query = query[:-1] - selected = 0 - scroll = 0 - elif isinstance(key, str) and key.isprintable(): - query += key - selected = 0 - scroll = 0 - - -def show_similar(stdscr, db_path, artist): - mbid, name = artist - similar = get_similar(db_path, mbid) - top = get_top_tracks(db_path, mbid) - total_local, matched_local = get_local_track_count(db_path, mbid) - - curses.curs_set(0) - stdscr.erase() - h, w = stdscr.getmaxyx() - - mid = w // 2 - - title_l = f" Similar to {name}" - title_r = f" Top tracks ({matched_local}/{total_local} matched)" - stdscr.addnstr(0, 0, title_l, mid, curses.color_pair(2) | curses.A_BOLD) - stdscr.addnstr(0, mid, title_r, w - mid, curses.color_pair(2) | curses.A_BOLD) - stdscr.addnstr(h - 1, 0, " [q] back", w, curses.color_pair(3)) - - scroll_l = 0 - scroll_r = 0 - list_h = h - 2 - - while True: - # Left pane: similar artists - for i in range(list_h): - stdscr.move(i + 1, 0) - stdscr.clrtoeol() - idx = scroll_l + i - if idx < len(similar): - sname, score = similar[idx] - line = f" {score:5.2f} {sname}" - stdscr.addnstr(i + 1, 0, line, mid) - - # Right pane: top tracks - for i in range(list_h): - idx = scroll_r + i - if idx < len(top): - path, playcount = top[idx] - # Show just the filename without extension - fname = Path(path).stem - # Strip "Artist - " prefix if present - if " - " in fname: - fname = fname.split(" - ", 1)[1] - line = f" {playcount:>8} {fname}" - stdscr.addnstr(i + 1, mid, line, w - mid) - - stdscr.refresh() - key = stdscr.get_wch() - - if key in ("q", "Q", "\x1b"): - return - elif key == curses.KEY_UP or key == "\x10": - scroll_l = max(0, scroll_l - 1) - scroll_r = max(0, scroll_r - 1) - elif key == curses.KEY_DOWN or key == "\x0e": - if scroll_l + list_h < len(similar): - scroll_l += 1 - if scroll_r + list_h < len(top): - scroll_r += 1 - - -def main(): - db_path = find_db() - curses.wrapper(run_tui, db_path) - - -if __name__ == "__main__": - main()