From af43b2baccc778d2fae9e0bca26a76d8d0e863c9 Mon Sep 17 00:00:00 2001 From: Benson Chu Date: Sat, 6 Jun 2026 09:26:38 -0500 Subject: [PATCH] Okay, this is an interface I am in love with --- config.yaml | 13 ++++++++----- plugins/labels.py | 46 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/config.yaml b/config.yaml index 536ebc1..52ece86 100644 --- a/config.yaml +++ b/config.yaml @@ -64,6 +64,9 @@ beetslabels: # in the future? concat: ["label:a", "label:b"] query: "label:effortless" sort: "effortless + exercise" + - name: everyday + query: "label:everyday" + sort: "everyday" smartplaylist: relative_to: ~/Music/0beets_playlists @@ -71,23 +74,23 @@ smartplaylist: forward_slash: no playlists: - name: "favorites.m3u" - query: ['plfavorites:1'] + query: ['label:favorites'] + - name: "everyday.m3u" + query: ['sorted_playlist:everyday'] + - name: "exercise.m3u" + query: ['sorted_playlist:exercise'] # ['^plexercise::^$ plexercise-'] - name: "focus.m3u" query: ['plfocus:1'] - name: "warmth.m3u" query: ['plwarmth:1'] - name: "relax.m3u" query: ['plrelax:1'] - - name: "everyday.m3u" - query: ['^pleveryday::^$ pleveryday-'] - name: "word.m3u" query: ['plword:1'] - name: "control.m3u" query: ['plcontrol:1'] - name: "precision.m3u" query: ['plprecision:1'] - - name: "exercise.m3u" - query: ['sorted_playlist:exercise'] # ['^plexercise::^$ plexercise-'] - name: "chiptune.m3u" query: ['genre:chiptune', 'genre:8-bit', 'plchiptune:1'] diff --git a/plugins/labels.py b/plugins/labels.py index 9748428..97f2dcd 100644 --- a/plugins/labels.py +++ b/plugins/labels.py @@ -4,6 +4,7 @@ from beets.ui.commands.modify import print_and_modify from beets.dbcore import FieldQuery from beets.dbcore.query import SlowFieldSort +import re import json import os import subprocess @@ -218,13 +219,20 @@ def edit_labels(lib, opts, args): finally: os.remove(temp_file.name) + # Build a lookup from header string to item + def item_header(item): + if item.artist: + return f"{item.artist} - {item.title}:" + return f"{item.title}:" + + item_by_header = {item_header(item): item for item in items_list} + # Parse the edited labels and apply changes # Format: "Artist - Title:\n - key: value\n - key2: value2\n\n" changes = [] i = 0 - item_idx = 0 - while i < len(lines) and item_idx < len(items_list): + while i < len(lines): line = lines[i].strip() # Skip blank lines @@ -234,18 +242,17 @@ def edit_labels(lib, opts, args): # Check if this is an item header (ends with :) if line.endswith(':'): - item = items_list[item_idx] - item_idx += 1 + item = item_by_header.get(line) i += 1 # Now read all label lines for this item new_labels = {} while i < len(lines): label_line = lines[i] - # Check if this is a label line (starts with " - ") + # Check if this is a label line (starts with "- ") if label_line.startswith('- '): - # Parse: " - key: value" - label_content = label_line.strip()[2:].strip() # Remove " - " + # Parse: "- key: value" + label_content = label_line.strip()[2:].strip() # Remove "- " if ':' in label_content: key, val = label_content.split(':', 1) key = key.strip() @@ -253,7 +260,8 @@ def edit_labels(lib, opts, args): try: new_labels[key] = int(val) except ValueError: - print_(f"Warning: Invalid value for label '{key}' in item '{item.title}', skipping") + if item: + print_(f"Warning: Invalid value for label '{key}' in item '{item.title}', skipping") else: new_labels[label_content.strip()] = 1 i += 1 @@ -261,6 +269,10 @@ def edit_labels(lib, opts, args): # Not a label line, done with this item break + if item is None: + print_(f"Warning: Header '{line}' not found in query results, skipping") + continue + # Compare with old labels old_labels = {} if LABELS_FIELD_NAME in item and item[LABELS_FIELD_NAME]: @@ -272,6 +284,24 @@ def edit_labels(lib, opts, args): # Unexpected format, skip i += 1 + # Items removed from the file get their labels cleared + headers_in_file = set() + i = 0 + while i < len(lines): + line = lines[i].strip() + if line.endswith(':') and line in item_by_header: + headers_in_file.add(line) + i += 1 + + for item in items_list: + header = item_header(item) + if header not in headers_in_file: + old_labels = {} + if LABELS_FIELD_NAME in item and item[LABELS_FIELD_NAME]: + old_labels = item[LABELS_FIELD_NAME] + if old_labels: + changes.append((item, {})) + if not changes: print_("No changes to make.") return