Compare commits

...

2 commits

Author SHA1 Message Date
8932231136 Change up this syntax a little 2026-06-06 09:26:48 -05:00
af43b2bacc Okay, this is an interface I am in love with 2026-06-06 09:26:38 -05:00
2 changed files with 68 additions and 24 deletions

View file

@ -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']

View file

@ -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,8 +242,7 @@ 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
@ -253,6 +260,7 @@ def edit_labels(lib, opts, args):
try:
new_labels[key] = int(val)
except ValueError:
if item:
print_(f"Warning: Invalid value for label '{key}' in item '{item.title}', skipping")
else:
new_labels[label_content.strip()] = 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
@ -321,19 +351,30 @@ class HasLabelQuery(FieldQuery):
super().__init__(LABELS_FIELD_NAME, pattern, False)
@classmethod
def value_match(self, pattern, labels):
if labels is not None:
label = pattern
value = None
if "." in pattern:
label, value = pattern.split(".")
if value is None:
return label in labels
else:
return label in labels and str(labels[label]) == value
def value_match(cls, pattern, labels):
if not labels:
return False
match = re.match(r'^([^.]+)(?:\.(gt|lt|eq)\.(\d+))?$', pattern)
if not match:
return False
label, op, val = match.group(1), match.group(2), match.group(3)
if label not in labels:
return False
if op is None:
return True
value = labels[label]
num = int(val)
if op == 'eq':
return value == num
elif op == 'gt':
return value > num
elif op == 'lt':
return value < num
class LabelValueSort(SlowFieldSort):
def __init__(self, field, ascending=True, case_insensitive=True):
super().__init__(field, ascending, case_insensitive)