Skip to content

Commit

Permalink
add cli for ad hoc rule execution
Browse files Browse the repository at this point in the history
  • Loading branch information
azuline committed Nov 2, 2023
1 parent 2841cf8 commit a77d141
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 52 deletions.
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ $ nix profile install github:azuline/rose/release
```

> [!NOTE]
> The default branch tracks the unstable release, whose documentation may be
> The master branch tracks the unstable release, whose documentation may be
> more up-to-date than the latest release's documentation. You can view the
> latest release's documentation at https://github.com/azuline/rose/blob/release/README.md.
> latest release's documentation [here](https://github.com/azuline/rose/blob/release/README.md).
Most users should install the latest release version of Rosé. However, if you
wish to install the latest unstable version of Rosé, you can do so with the
Expand All @@ -212,19 +212,21 @@ $ rose

Usage: rose [OPTIONS] COMMAND [ARGS]...

A virtual filesystem for music and metadata improvement tooling.
A music manager with a virtual filesystem.

Options:
-v, --verbose Emit verbose logging.
-c, --config PATH Override the config file location.
--help Show this message and exit.

Commands:
cache Manage the read cache.
collages Manage collages.
fs Manage the virtual library.
releases Manage releases.
playlists Manage playlists.
cache Manage the read cache.
collages Manage collages.
completion Print a shell completion script.
fs Manage the virtual library.
metadata Run metadata improvement tools
playlists Manage playlists.
releases Manage releases.
```

> [!NOTE]
Expand Down Expand Up @@ -319,7 +321,6 @@ finally (3) play music!
Artist: LOOΠΔ ODD EYE CIRCLE
Album: Mix & Match
Album_Artist: LOOΠΔ ODD EYE CIRCLE
Comment: Cat #: WMED0709
Date: 2017
Genre: K-Pop
Title: Chaotic
Expand Down
14 changes: 7 additions & 7 deletions rose/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@
# captures logging output on its own, so by default, we do not attach our own.
if "pytest" not in sys.modules or LOG_EVEN_THOUGH_WERE_IN_TEST: # pragma: no cover
stream_template = "[%(asctime)s] %(levelname)s: %(message)s"
if LOG_EVEN_THOUGH_WERE_IN_TEST:
stream_template = "[ts=%(asctime)s] [pid=%(process)d] [src=%(name)s:%(lineno)s] %(levelname)s: %(message)s" # noqa: E501
stream_formatter = logging.Formatter(stream_template, datefmt="%H:%M:%S")
verbose_template = "[ts=%(asctime)s.%(msecs)d] [pid=%(process)d] [src=%(name)s:%(lineno)s] %(levelname)s: %(message)s" # noqa: E501

stream_formatter = logging.Formatter(
stream_template if not LOG_EVEN_THOUGH_WERE_IN_TEST else verbose_template,
datefmt="%H:%M:%S",
)
stream_handler = logging.StreamHandler(sys.stderr)
stream_handler.setFormatter(stream_formatter)
logger.addHandler(stream_handler)

file_formatter = logging.Formatter(
"[ts=%(asctime)s.%(msecs)d] [pid=%(process)d] [src=%(name)s:%(lineno)s] %(levelname)s: %(message)s", # noqa: E501
datefmt="%H:%M:%S",
)
file_formatter = logging.Formatter(verbose_template, datefmt="%H:%M:%S")
file_handler = logging.handlers.RotatingFileHandler(
LOGFILE,
maxBytes=20 * 1024 * 1024,
Expand Down
21 changes: 18 additions & 3 deletions rose/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@
set_release_cover_art,
toggle_release_new,
)
from rose.rules import execute_stored_metadata_rules
from rose.rule_parser import MetadataRule
from rose.rules import execute_metadata_rule, execute_stored_metadata_rules
from rose.virtualfs import VirtualPath, mount_virtualfs, unmount_virtualfs
from rose.watcher import start_watchdog

Expand All @@ -71,7 +72,7 @@ class Context:
@click.pass_context
# fmt: on
def cli(cc: click.Context, verbose: bool, config: Path | None = None) -> None:
"""A virtual filesystem for music and metadata improvement tooling."""
"""A music manager with a virtual filesystem."""
cc.obj = Context(
config=Config.parse(config_path_override=config),
)
Expand Down Expand Up @@ -398,11 +399,25 @@ def metadata() -> None:
"""Run metadata improvement tools"""


@metadata.command()
@click.argument("matcher", type=str, nargs=1)
@click.argument("actions", type=str, nargs=-1)
@click.option("--yes", "-y", is_flag=True, help="Bypass confirmation prompts.")
@click.pass_obj
def run_rule(ctx: Context, matcher: str, actions: list[str], yes: bool) -> None:
"""Run an ad hoc metadata rule"""
if not actions:
logger.info("No-Op: No actions passed")
return
rule = MetadataRule.parse(matcher, actions)
execute_metadata_rule(ctx.config, rule, confirm_yes=not yes)


@metadata.command()
@click.option("--yes", "-y", is_flag=True, help="Bypass confirmation prompts.")
@click.pass_obj
def run_stored_rules(ctx: Context, yes: bool) -> None:
"""Run the metadata rules stored in the config"""
"""Run the stored metadata rules defined in the config"""
execute_stored_metadata_rules(ctx.config, confirm_yes=not yes)


Expand Down
52 changes: 19 additions & 33 deletions rose/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ def execute_metadata_rule(
if fields_to_update == "matched":
fields_to_update = rule.matcher.tags
for field in fields_to_update:
# fmt: off
if field == "tracktitle":
tags.title = execute_single_action(act, tags.title)
potential_changes.append(("title", origtags.title, tags.title))
Expand All @@ -161,22 +162,16 @@ def execute_metadata_rule(
potential_changes.append(("year", origtags.year, tags.year))
elif field == "tracknumber":
tags.track_number = execute_single_action(act, tags.track_number)
potential_changes.append(
("track_number", origtags.track_number, tags.track_number)
) # noqa: E501
potential_changes.append(("track_number", origtags.track_number, tags.track_number)) # noqa: E501
elif field == "discnumber":
tags.disc_number = execute_single_action(act, tags.disc_number)
potential_changes.append(
("disc_number", origtags.disc_number, tags.disc_number)
) # noqa: E501
potential_changes.append(("disc_number", origtags.disc_number, tags.disc_number)) # noqa: E501
elif field == "albumtitle":
tags.album = execute_single_action(act, tags.album)
potential_changes.append(("album", origtags.album, tags.album))
elif field == "releasetype":
tags.release_type = execute_single_action(act, tags.release_type) or "unknown"
potential_changes.append(
("release_type", origtags.release_type, tags.release_type)
) # noqa: E501
potential_changes.append(("release_type", origtags.release_type, tags.release_type)) # noqa: E501
elif field == "genre":
tags.genre = execute_multi_value_action(act, tags.genre)
potential_changes.append(("genre", origtags.genre, tags.genre))
Expand All @@ -185,45 +180,36 @@ def execute_metadata_rule(
potential_changes.append(("label", origtags.label, tags.label))
elif field == "trackartist":
tags.artists.main = execute_multi_value_action(act, tags.artists.main)
potential_changes.append(("main", origtags.artists.main, tags.artists.main))
potential_changes.append(("trackartist[main]", origtags.artists.main, tags.artists.main)) # noqa: E501
tags.artists.guest = execute_multi_value_action(act, tags.artists.guest)
potential_changes.append(("guest", origtags.artists.guest, tags.artists.guest))
potential_changes.append(("trackartist[guest]", origtags.artists.guest, tags.artists.guest)) # noqa: E501
tags.artists.remixer = execute_multi_value_action(act, tags.artists.remixer)
potential_changes.append(
("remixer", origtags.artists.remixer, tags.artists.remixer)
) # noqa: E501
potential_changes.append(("trackartist[remixer]", origtags.artists.remixer, tags.artists.remixer)) # noqa: E501
tags.artists.producer = execute_multi_value_action(act, tags.artists.producer)
potential_changes.append(
("producer", origtags.artists.producer, tags.artists.producer)
) # noqa: E501
potential_changes.append(("trackartist[producer]", origtags.artists.producer, tags.artists.producer)) # noqa: E501
tags.artists.composer = execute_multi_value_action(act, tags.artists.composer)
potential_changes.append(
("composer", origtags.artists.composer, tags.artists.composer)
) # noqa: E501
potential_changes.append(("trackartist[composer]", origtags.artists.composer, tags.artists.composer)) # noqa: E501
tags.artists.djmixer = execute_multi_value_action(act, tags.artists.djmixer)
potential_changes.append(
("djmixer", origtags.artists.djmixer, tags.artists.djmixer)
) # noqa: E501
potential_changes.append(("trackartist[djmixer]", origtags.artists.djmixer, tags.artists.djmixer)) # noqa: E501
elif field == "albumartist":
# fmt: off
tags.album_artists.main = execute_multi_value_action(act, tags.album_artists.main) # noqa: E501
potential_changes.append(("main", origtags.album_artists.main, tags.album_artists.main)) # noqa: E501
potential_changes.append(("albumartist[main]", origtags.album_artists.main, tags.album_artists.main)) # noqa: E501
tags.album_artists.guest = execute_multi_value_action(act, tags.album_artists.guest) # noqa: E501
potential_changes.append(("guest", origtags.album_artists.guest, tags.album_artists.guest)) # noqa: E501
potential_changes.append(("albumartist[guest]", origtags.album_artists.guest, tags.album_artists.guest)) # noqa: E501
tags.album_artists.remixer = execute_multi_value_action(act, tags.album_artists.remixer) # noqa: E501
potential_changes.append(("remixer", origtags.album_artists.remixer, tags.album_artists.remixer)) # noqa: E501
potential_changes.append(("albumartist[remixer]", origtags.album_artists.remixer, tags.album_artists.remixer)) # noqa: E501
tags.album_artists.producer = execute_multi_value_action(act, tags.album_artists.producer) # noqa: E501
potential_changes.append(("producer", origtags.album_artists.producer, tags.album_artists.producer)) # noqa: E501
potential_changes.append(("albumartist[producer]", origtags.album_artists.producer, tags.album_artists.producer)) # noqa: E501
tags.album_artists.composer = execute_multi_value_action(act, tags.album_artists.composer) # noqa: E501
potential_changes.append(("composer", origtags.album_artists.composer, tags.album_artists.composer)) # noqa: E501
potential_changes.append(("albumartist[composer]", origtags.album_artists.composer, tags.album_artists.composer)) # noqa: E501
tags.album_artists.djmixer = execute_multi_value_action(act, tags.album_artists.djmixer) # noqa: E501
potential_changes.append(("djmixer", origtags.album_artists.djmixer, tags.album_artists.djmixer)) # noqa: E501
# fmt: on
potential_changes.append(("albumartist[djmixer]", origtags.album_artists.djmixer, tags.album_artists.djmixer)) # noqa: E501
# fmt: on

# Compute real changes by diffing the tags, and then store.
changes = [(x, y, z) for x, y, z in potential_changes if y != z]
if changes:
actionable_audiotags.append((tags, potential_changes))
actionable_audiotags.append((tags, changes))
else:
logger.debug(f"Skipping matched track {tags.path}: no changes calculated off tags")
if not actionable_audiotags:
Expand Down Expand Up @@ -288,8 +274,8 @@ def execute_metadata_rule(
f"{tags.path} changes: {' //// '.join([str(x)+' -> '+str(y) for _, x, y in changes])}"
)
tags.flush()
click.echo()

click.echo()
click.echo(f"Applied tag changes to {len(actionable_audiotags)} tracks!")


Expand Down

0 comments on commit a77d141

Please sign in to comment.