mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
Renamed all action occurrences with Action.
This commit is contained in:
parent
9147577b2b
commit
68acaa6470
16 changed files with 227 additions and 174 deletions
38
beets/importer/__init__.py
Normal file
38
beets/importer/__init__.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# This file is part of beets.
|
||||||
|
# Copyright 2016, Adrian Sampson.
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
# a copy of this software and associated documentation files (the
|
||||||
|
# "Software"), to deal in the Software without restriction, including
|
||||||
|
# without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
# permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
# the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be
|
||||||
|
# included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
"""Provides the basic, interface-agnostic workflow for importing and
|
||||||
|
autotagging music files.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from .session import ImportAbortError, ImportSession
|
||||||
|
from .tasks import (
|
||||||
|
Action,
|
||||||
|
ArchiveImportTask,
|
||||||
|
ImportTask,
|
||||||
|
SentinelImportTask,
|
||||||
|
SingletonImportTask,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Note: Stages are not exposed to the public API
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"ImportSession",
|
||||||
|
"ImportAbortError",
|
||||||
|
"Action",
|
||||||
|
"ImportTask",
|
||||||
|
"ArchiveImportTask",
|
||||||
|
"SentinelImportTask",
|
||||||
|
"SingletonImportTask",
|
||||||
|
]
|
||||||
|
|
@ -18,10 +18,10 @@ import time
|
||||||
from typing import TYPE_CHECKING, Sequence
|
from typing import TYPE_CHECKING, Sequence
|
||||||
|
|
||||||
from beets import config, dbcore, library, logging, plugins, util
|
from beets import config, dbcore, library, logging, plugins, util
|
||||||
from beets.importer.tasks import action
|
from beets.importer.tasks import Action
|
||||||
from beets.util import displayable_path, normpath, pipeline, syspath
|
from beets.util import displayable_path, normpath, pipeline, syspath
|
||||||
|
|
||||||
from .stages import *
|
from . import stages as stagefuncs
|
||||||
from .state import ImportState
|
from .state import ImportState
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
|
@ -162,15 +162,15 @@ class ImportSession:
|
||||||
# Duplicate: log all three choices (skip, keep both, and trump).
|
# Duplicate: log all three choices (skip, keep both, and trump).
|
||||||
if task.should_remove_duplicates:
|
if task.should_remove_duplicates:
|
||||||
self.tag_log("duplicate-replace", paths)
|
self.tag_log("duplicate-replace", paths)
|
||||||
elif task.choice_flag in (action.ASIS, action.APPLY):
|
elif task.choice_flag in (Action.ASIS, Action.APPLY):
|
||||||
self.tag_log("duplicate-keep", paths)
|
self.tag_log("duplicate-keep", paths)
|
||||||
elif task.choice_flag is action.SKIP:
|
elif task.choice_flag is Action.SKIP:
|
||||||
self.tag_log("duplicate-skip", paths)
|
self.tag_log("duplicate-skip", paths)
|
||||||
else:
|
else:
|
||||||
# Non-duplicate: log "skip" and "asis" choices.
|
# Non-duplicate: log "skip" and "asis" choices.
|
||||||
if task.choice_flag is action.ASIS:
|
if task.choice_flag is Action.ASIS:
|
||||||
self.tag_log("asis", paths)
|
self.tag_log("asis", paths)
|
||||||
elif task.choice_flag is action.SKIP:
|
elif task.choice_flag is Action.SKIP:
|
||||||
self.tag_log("skip", paths)
|
self.tag_log("skip", paths)
|
||||||
|
|
||||||
def should_resume(self, path: PathBytes):
|
def should_resume(self, path: PathBytes):
|
||||||
|
|
@ -192,17 +192,17 @@ class ImportSession:
|
||||||
|
|
||||||
# Set up the pipeline.
|
# Set up the pipeline.
|
||||||
if self.query is None:
|
if self.query is None:
|
||||||
stages = [read_tasks(self)]
|
stages = [stagefuncs.read_tasks(self)]
|
||||||
else:
|
else:
|
||||||
stages = [query_tasks(self)]
|
stages = [stagefuncs.query_tasks(self)]
|
||||||
|
|
||||||
# In pretend mode, just log what would otherwise be imported.
|
# In pretend mode, just log what would otherwise be imported.
|
||||||
if self.config["pretend"]:
|
if self.config["pretend"]:
|
||||||
stages += [log_files(self)]
|
stages += [stagefuncs.log_files(self)]
|
||||||
else:
|
else:
|
||||||
if self.config["group_albums"] and not self.config["singletons"]:
|
if self.config["group_albums"] and not self.config["singletons"]:
|
||||||
# Split directory tasks into one task for each album.
|
# Split directory tasks into one task for each album.
|
||||||
stages += [group_albums(self)]
|
stages += [stagefuncs.group_albums(self)]
|
||||||
|
|
||||||
# These stages either talk to the user to get a decision or,
|
# These stages either talk to the user to get a decision or,
|
||||||
# in the case of a non-autotagged import, just choose to
|
# in the case of a non-autotagged import, just choose to
|
||||||
|
|
@ -210,17 +210,20 @@ class ImportSession:
|
||||||
# also add the music to the library database, so later
|
# also add the music to the library database, so later
|
||||||
# stages need to read and write data from there.
|
# stages need to read and write data from there.
|
||||||
if self.config["autotag"]:
|
if self.config["autotag"]:
|
||||||
stages += [lookup_candidates(self), user_query(self)]
|
stages += [
|
||||||
|
stagefuncs.lookup_candidates(self),
|
||||||
|
stagefuncs.user_query(self),
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
stages += [import_asis(self)]
|
stages += [stagefuncs.import_asis(self)]
|
||||||
|
|
||||||
# Plugin stages.
|
# Plugin stages.
|
||||||
for stage_func in plugins.early_import_stages():
|
for stage_func in plugins.early_import_stages():
|
||||||
stages.append(plugin_stage(self, stage_func))
|
stages.append(stagefuncs.plugin_stage(self, stage_func))
|
||||||
for stage_func in plugins.import_stages():
|
for stage_func in plugins.import_stages():
|
||||||
stages.append(plugin_stage(self, stage_func))
|
stages.append(stagefuncs.plugin_stage(self, stage_func))
|
||||||
|
|
||||||
stages += [manipulate_files(self)]
|
stages += [stagefuncs.manipulate_files(self)]
|
||||||
|
|
||||||
pl = pipeline.Pipeline(stages)
|
pl = pipeline.Pipeline(stages)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ from beets import config, plugins
|
||||||
from beets.util import MoveOperation, displayable_path, pipeline
|
from beets.util import MoveOperation, displayable_path, pipeline
|
||||||
|
|
||||||
from .tasks import (
|
from .tasks import (
|
||||||
action,
|
Action,
|
||||||
ImportTask,
|
ImportTask,
|
||||||
ImportTaskFactory,
|
ImportTaskFactory,
|
||||||
SentinelImportTask,
|
SentinelImportTask,
|
||||||
|
|
@ -173,7 +173,7 @@ def user_query(session: ImportSession, task: ImportTask):
|
||||||
plugins.send("import_task_choice", session=session, task=task)
|
plugins.send("import_task_choice", session=session, task=task)
|
||||||
|
|
||||||
# As-tracks: transition to singleton workflow.
|
# As-tracks: transition to singleton workflow.
|
||||||
if task.choice_flag is action.TRACKS:
|
if task.choice_flag is Action.TRACKS:
|
||||||
# Set up a little pipeline for dealing with the singletons.
|
# Set up a little pipeline for dealing with the singletons.
|
||||||
def emitter(task):
|
def emitter(task):
|
||||||
for item in task.items:
|
for item in task.items:
|
||||||
|
|
@ -186,7 +186,7 @@ def user_query(session: ImportSession, task: ImportTask):
|
||||||
)
|
)
|
||||||
|
|
||||||
# As albums: group items by albums and create task for each album
|
# As albums: group items by albums and create task for each album
|
||||||
if task.choice_flag is action.ALBUMS:
|
if task.choice_flag is Action.ALBUMS:
|
||||||
return _extend_pipeline(
|
return _extend_pipeline(
|
||||||
[task],
|
[task],
|
||||||
group_albums(session),
|
group_albums(session),
|
||||||
|
|
@ -194,7 +194,7 @@ def user_query(session: ImportSession, task: ImportTask):
|
||||||
user_query(session),
|
user_query(session),
|
||||||
)
|
)
|
||||||
|
|
||||||
resolve_duplicates(session, task)
|
_resolve_duplicates(session, task)
|
||||||
|
|
||||||
if task.should_merge_duplicates:
|
if task.should_merge_duplicates:
|
||||||
# Create a new task for tagging the current items
|
# Create a new task for tagging the current items
|
||||||
|
|
@ -216,7 +216,7 @@ def user_query(session: ImportSession, task: ImportTask):
|
||||||
[merged_task], lookup_candidates(session), user_query(session)
|
[merged_task], lookup_candidates(session), user_query(session)
|
||||||
)
|
)
|
||||||
|
|
||||||
apply_choice(session, task)
|
_apply_choice(session, task)
|
||||||
return task
|
return task
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -231,8 +231,8 @@ def import_asis(session: ImportSession, task: ImportTask):
|
||||||
return
|
return
|
||||||
|
|
||||||
log.info("{}", displayable_path(task.paths))
|
log.info("{}", displayable_path(task.paths))
|
||||||
task.set_choice(action.ASIS)
|
task.set_choice(Action.ASIS)
|
||||||
apply_choice(session, task)
|
_apply_choice(session, task)
|
||||||
|
|
||||||
|
|
||||||
@pipeline.mutator_stage
|
@pipeline.mutator_stage
|
||||||
|
|
@ -312,7 +312,7 @@ def manipulate_files(session: ImportSession, task: ImportTask):
|
||||||
# Private functions only used in the stages above
|
# Private functions only used in the stages above
|
||||||
|
|
||||||
|
|
||||||
def apply_choice(session: ImportSession, task: ImportTask):
|
def _apply_choice(session: ImportSession, task: ImportTask):
|
||||||
"""Apply the task's choice to the Album or Item it contains and add
|
"""Apply the task's choice to the Album or Item it contains and add
|
||||||
it to the library.
|
it to the library.
|
||||||
"""
|
"""
|
||||||
|
|
@ -335,11 +335,11 @@ def apply_choice(session: ImportSession, task: ImportTask):
|
||||||
task.set_fields(session.lib)
|
task.set_fields(session.lib)
|
||||||
|
|
||||||
|
|
||||||
def resolve_duplicates(session: ImportSession, task: ImportTask):
|
def _resolve_duplicates(session: ImportSession, task: ImportTask):
|
||||||
"""Check if a task conflicts with items or albums already imported
|
"""Check if a task conflicts with items or albums already imported
|
||||||
and ask the session to resolve this.
|
and ask the session to resolve this.
|
||||||
"""
|
"""
|
||||||
if task.choice_flag in (action.ASIS, action.APPLY, action.RETAG):
|
if task.choice_flag in (Action.ASIS, Action.APPLY, Action.RETAG):
|
||||||
found_duplicates = task.find_duplicates(session.lib)
|
found_duplicates = task.find_duplicates(session.lib)
|
||||||
if found_duplicates:
|
if found_duplicates:
|
||||||
log.debug(
|
log.debug(
|
||||||
|
|
@ -360,7 +360,7 @@ def resolve_duplicates(session: ImportSession, task: ImportTask):
|
||||||
|
|
||||||
if duplicate_action == "s":
|
if duplicate_action == "s":
|
||||||
# Skip new.
|
# Skip new.
|
||||||
task.set_choice(action.SKIP)
|
task.set_choice(Action.SKIP)
|
||||||
elif duplicate_action == "k":
|
elif duplicate_action == "k":
|
||||||
# Keep both. Do nothing; leave the choice intact.
|
# Keep both. Do nothing; leave the choice intact.
|
||||||
pass
|
pass
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ from beets import autotag, config, dbcore, library, plugins, util
|
||||||
from .state import ImportState
|
from .state import ImportState
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .session import ImportSession
|
from .session import ImportSession, PathBytes
|
||||||
|
|
||||||
# Global logger.
|
# Global logger.
|
||||||
log = logging.getLogger("beets")
|
log = logging.getLogger("beets")
|
||||||
|
|
@ -62,18 +62,26 @@ REIMPORT_FRESH_FIELDS_ITEM = list(REIMPORT_FRESH_FIELDS_ALBUM)
|
||||||
log = logging.getLogger("beets")
|
log = logging.getLogger("beets")
|
||||||
|
|
||||||
|
|
||||||
action = Enum("action", ["SKIP", "ASIS", "TRACKS", "APPLY", "ALBUMS", "RETAG"])
|
|
||||||
# The RETAG action represents "don't apply any match, but do record
|
|
||||||
# new metadata". It's not reachable via the standard command prompt but
|
|
||||||
# can be used by plugins.
|
|
||||||
|
|
||||||
|
|
||||||
class ImportAbortError(Exception):
|
class ImportAbortError(Exception):
|
||||||
"""Raised when the user aborts the tagging operation."""
|
"""Raised when the user aborts the tagging operation."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Action(Enum):
|
||||||
|
"""Enumeration of possible actions for an import task."""
|
||||||
|
|
||||||
|
SKIP = "SKIP"
|
||||||
|
ASIS = "ASIS"
|
||||||
|
TRACKS = "TRACKS"
|
||||||
|
APPLY = "APPLY"
|
||||||
|
ALBUMS = "ALBUMS"
|
||||||
|
RETAG = "RETAG"
|
||||||
|
# The RETAG action represents "don't apply any match, but do record
|
||||||
|
# new metadata". It's not reachable via the standard command prompt but
|
||||||
|
# can be used by plugins.
|
||||||
|
|
||||||
|
|
||||||
class BaseImportTask:
|
class BaseImportTask:
|
||||||
"""An abstract base class for importer tasks.
|
"""An abstract base class for importer tasks.
|
||||||
|
|
||||||
|
|
@ -143,7 +151,7 @@ class ImportTask(BaseImportTask):
|
||||||
system.
|
system.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
choice_flag: action | None = None
|
choice_flag: Action | None = None
|
||||||
match: autotag.AlbumMatch | autotag.TrackMatch | None = None
|
match: autotag.AlbumMatch | autotag.TrackMatch | None = None
|
||||||
|
|
||||||
# Keep track of the current task item
|
# Keep track of the current task item
|
||||||
|
|
@ -165,7 +173,7 @@ class ImportTask(BaseImportTask):
|
||||||
self.search_ids = [] # user-supplied candidate IDs.
|
self.search_ids = [] # user-supplied candidate IDs.
|
||||||
|
|
||||||
def set_choice(
|
def set_choice(
|
||||||
self, choice: action | autotag.AlbumMatch | autotag.TrackMatch
|
self, choice: Action | autotag.AlbumMatch | autotag.TrackMatch
|
||||||
):
|
):
|
||||||
"""Given an AlbumMatch or TrackMatch object or an action constant,
|
"""Given an AlbumMatch or TrackMatch object or an action constant,
|
||||||
indicates that an action has been selected for this task.
|
indicates that an action has been selected for this task.
|
||||||
|
|
@ -174,20 +182,20 @@ class ImportTask(BaseImportTask):
|
||||||
use isinstance to check for them.
|
use isinstance to check for them.
|
||||||
"""
|
"""
|
||||||
# Not part of the task structure:
|
# Not part of the task structure:
|
||||||
assert choice != action.APPLY # Only used internally.
|
assert choice != Action.APPLY # Only used internally.
|
||||||
|
|
||||||
if choice in (
|
if choice in (
|
||||||
action.SKIP,
|
Action.SKIP,
|
||||||
action.ASIS,
|
Action.ASIS,
|
||||||
action.TRACKS,
|
Action.TRACKS,
|
||||||
action.ALBUMS,
|
Action.ALBUMS,
|
||||||
action.RETAG,
|
Action.RETAG,
|
||||||
):
|
):
|
||||||
# TODO: redesign to stricten the type
|
# TODO: redesign to stricten the type
|
||||||
self.choice_flag = choice # type: ignore[assignment]
|
self.choice_flag = choice # type: ignore[assignment]
|
||||||
self.match = None
|
self.match = None
|
||||||
else:
|
else:
|
||||||
self.choice_flag = action.APPLY # Implicit choice.
|
self.choice_flag = Action.APPLY # Implicit choice.
|
||||||
self.match = choice # type: ignore[assignment]
|
self.match = choice # type: ignore[assignment]
|
||||||
|
|
||||||
def save_progress(self):
|
def save_progress(self):
|
||||||
|
|
@ -205,11 +213,11 @@ class ImportTask(BaseImportTask):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def apply(self):
|
def apply(self):
|
||||||
return self.choice_flag == action.APPLY
|
return self.choice_flag == Action.APPLY
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def skip(self):
|
def skip(self):
|
||||||
return self.choice_flag == action.SKIP
|
return self.choice_flag == Action.SKIP
|
||||||
|
|
||||||
# Convenient data.
|
# Convenient data.
|
||||||
|
|
||||||
|
|
@ -219,10 +227,10 @@ class ImportTask(BaseImportTask):
|
||||||
(in which case the data comes from the files' current metadata)
|
(in which case the data comes from the files' current metadata)
|
||||||
or APPLY (in which case the data comes from the choice).
|
or APPLY (in which case the data comes from the choice).
|
||||||
"""
|
"""
|
||||||
if self.choice_flag in (action.ASIS, action.RETAG):
|
if self.choice_flag in (Action.ASIS, Action.RETAG):
|
||||||
likelies, consensus = autotag.current_metadata(self.items)
|
likelies, consensus = autotag.current_metadata(self.items)
|
||||||
return likelies
|
return likelies
|
||||||
elif self.choice_flag is action.APPLY and self.match:
|
elif self.choice_flag is Action.APPLY and self.match:
|
||||||
return self.match.info.copy()
|
return self.match.info.copy()
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
|
@ -232,9 +240,9 @@ class ImportTask(BaseImportTask):
|
||||||
If the tasks applies an album match the method only returns the
|
If the tasks applies an album match the method only returns the
|
||||||
matched items.
|
matched items.
|
||||||
"""
|
"""
|
||||||
if self.choice_flag in (action.ASIS, action.RETAG):
|
if self.choice_flag in (Action.ASIS, Action.RETAG):
|
||||||
return list(self.items)
|
return list(self.items)
|
||||||
elif self.choice_flag == action.APPLY and isinstance(
|
elif self.choice_flag == Action.APPLY and isinstance(
|
||||||
self.match, autotag.AlbumMatch
|
self.match, autotag.AlbumMatch
|
||||||
):
|
):
|
||||||
return list(self.match.mapping.keys())
|
return list(self.match.mapping.keys())
|
||||||
|
|
@ -401,7 +409,7 @@ class ImportTask(BaseImportTask):
|
||||||
"""
|
"""
|
||||||
changes = {}
|
changes = {}
|
||||||
|
|
||||||
if self.choice_flag == action.ASIS:
|
if self.choice_flag == Action.ASIS:
|
||||||
# Taking metadata "as-is". Guess whether this album is VA.
|
# Taking metadata "as-is". Guess whether this album is VA.
|
||||||
plur_albumartist, freq = util.plurality(
|
plur_albumartist, freq = util.plurality(
|
||||||
[i.albumartist or i.artist for i in self.items]
|
[i.albumartist or i.artist for i in self.items]
|
||||||
|
|
@ -418,7 +426,7 @@ class ImportTask(BaseImportTask):
|
||||||
changes["albumartist"] = config["va_name"].as_str()
|
changes["albumartist"] = config["va_name"].as_str()
|
||||||
changes["comp"] = True
|
changes["comp"] = True
|
||||||
|
|
||||||
elif self.choice_flag in (action.APPLY, action.RETAG):
|
elif self.choice_flag in (Action.APPLY, Action.RETAG):
|
||||||
# Applying autotagged metadata. Just get AA from the first
|
# Applying autotagged metadata. Just get AA from the first
|
||||||
# item.
|
# item.
|
||||||
if not self.items[0].albumartist:
|
if not self.items[0].albumartist:
|
||||||
|
|
@ -473,7 +481,7 @@ class ImportTask(BaseImportTask):
|
||||||
# old paths.
|
# old paths.
|
||||||
item.move(operation)
|
item.move(operation)
|
||||||
|
|
||||||
if write and (self.apply or self.choice_flag == action.RETAG):
|
if write and (self.apply or self.choice_flag == Action.RETAG):
|
||||||
item.try_write()
|
item.try_write()
|
||||||
|
|
||||||
with session.lib.transaction():
|
with session.lib.transaction():
|
||||||
|
|
@ -490,7 +498,7 @@ class ImportTask(BaseImportTask):
|
||||||
self.remove_replaced(lib)
|
self.remove_replaced(lib)
|
||||||
|
|
||||||
self.album = lib.add_album(self.imported_items())
|
self.album = lib.add_album(self.imported_items())
|
||||||
if self.choice_flag == action.APPLY and isinstance(
|
if self.choice_flag == Action.APPLY and isinstance(
|
||||||
self.match, autotag.AlbumMatch
|
self.match, autotag.AlbumMatch
|
||||||
):
|
):
|
||||||
# Copy album flexible fields to the DB
|
# Copy album flexible fields to the DB
|
||||||
|
|
@ -672,10 +680,10 @@ class SingletonImportTask(ImportTask):
|
||||||
(in which case the data comes from the files' current metadata)
|
(in which case the data comes from the files' current metadata)
|
||||||
or APPLY (in which case the data comes from the choice).
|
or APPLY (in which case the data comes from the choice).
|
||||||
"""
|
"""
|
||||||
assert self.choice_flag in (action.ASIS, action.RETAG, action.APPLY)
|
assert self.choice_flag in (Action.ASIS, Action.RETAG, Action.APPLY)
|
||||||
if self.choice_flag in (action.ASIS, action.RETAG):
|
if self.choice_flag in (Action.ASIS, Action.RETAG):
|
||||||
return dict(self.item)
|
return dict(self.item)
|
||||||
elif self.choice_flag is action.APPLY:
|
elif self.choice_flag is Action.APPLY:
|
||||||
return self.match.info.copy()
|
return self.match.info.copy()
|
||||||
|
|
||||||
def imported_items(self):
|
def imported_items(self):
|
||||||
|
|
|
||||||
|
|
@ -658,9 +658,9 @@ class ImportSessionFixture(ImportSession):
|
||||||
|
|
||||||
>>> lib = Library(':memory:')
|
>>> lib = Library(':memory:')
|
||||||
>>> importer = ImportSessionFixture(lib, paths=['/path/to/import'])
|
>>> importer = ImportSessionFixture(lib, paths=['/path/to/import'])
|
||||||
>>> importer.add_choice(importer.action.SKIP)
|
>>> importer.add_choice(importer.Action.SKIP)
|
||||||
>>> importer.add_choice(importer.action.ASIS)
|
>>> importer.add_choice(importer.Action.ASIS)
|
||||||
>>> importer.default_choice = importer.action.APPLY
|
>>> importer.default_choice = importer.Action.APPLY
|
||||||
>>> importer.run()
|
>>> importer.run()
|
||||||
|
|
||||||
This imports ``/path/to/import`` into `lib`. It skips the first
|
This imports ``/path/to/import`` into `lib`. It skips the first
|
||||||
|
|
@ -673,7 +673,7 @@ class ImportSessionFixture(ImportSession):
|
||||||
self._choices = []
|
self._choices = []
|
||||||
self._resolutions = []
|
self._resolutions = []
|
||||||
|
|
||||||
default_choice = importer.action.APPLY
|
default_choice = importer.Action.APPLY
|
||||||
|
|
||||||
def add_choice(self, choice):
|
def add_choice(self, choice):
|
||||||
self._choices.append(choice)
|
self._choices.append(choice)
|
||||||
|
|
@ -687,7 +687,7 @@ class ImportSessionFixture(ImportSession):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
choice = self.default_choice
|
choice = self.default_choice
|
||||||
|
|
||||||
if choice == importer.action.APPLY:
|
if choice == importer.Action.APPLY:
|
||||||
return task.candidates[0]
|
return task.candidates[0]
|
||||||
elif isinstance(choice, int):
|
elif isinstance(choice, int):
|
||||||
return task.candidates[choice - 1]
|
return task.candidates[choice - 1]
|
||||||
|
|
@ -707,7 +707,7 @@ class ImportSessionFixture(ImportSession):
|
||||||
res = self.default_resolution
|
res = self.default_resolution
|
||||||
|
|
||||||
if res == self.Resolution.SKIP:
|
if res == self.Resolution.SKIP:
|
||||||
task.set_choice(importer.action.SKIP)
|
task.set_choice(importer.Action.SKIP)
|
||||||
elif res == self.Resolution.REMOVE:
|
elif res == self.Resolution.REMOVE:
|
||||||
task.should_remove_duplicates = True
|
task.should_remove_duplicates = True
|
||||||
elif res == self.Resolution.MERGE:
|
elif res == self.Resolution.MERGE:
|
||||||
|
|
@ -720,7 +720,7 @@ class TerminalImportSessionFixture(TerminalImportSession):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self._choices = []
|
self._choices = []
|
||||||
|
|
||||||
default_choice = importer.action.APPLY
|
default_choice = importer.Action.APPLY
|
||||||
|
|
||||||
def add_choice(self, choice):
|
def add_choice(self, choice):
|
||||||
self._choices.append(choice)
|
self._choices.append(choice)
|
||||||
|
|
@ -742,15 +742,15 @@ class TerminalImportSessionFixture(TerminalImportSession):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
choice = self.default_choice
|
choice = self.default_choice
|
||||||
|
|
||||||
if choice == importer.action.APPLY:
|
if choice == importer.Action.APPLY:
|
||||||
self.io.addinput("A")
|
self.io.addinput("A")
|
||||||
elif choice == importer.action.ASIS:
|
elif choice == importer.Action.ASIS:
|
||||||
self.io.addinput("U")
|
self.io.addinput("U")
|
||||||
elif choice == importer.action.ALBUMS:
|
elif choice == importer.Action.ALBUMS:
|
||||||
self.io.addinput("G")
|
self.io.addinput("G")
|
||||||
elif choice == importer.action.TRACKS:
|
elif choice == importer.Action.TRACKS:
|
||||||
self.io.addinput("T")
|
self.io.addinput("T")
|
||||||
elif choice == importer.action.SKIP:
|
elif choice == importer.Action.SKIP:
|
||||||
self.io.addinput("S")
|
self.io.addinput("S")
|
||||||
else:
|
else:
|
||||||
self.io.addinput("M")
|
self.io.addinput("M")
|
||||||
|
|
|
||||||
|
|
@ -811,12 +811,12 @@ def _summary_judgment(rec):
|
||||||
|
|
||||||
if config["import"]["quiet"]:
|
if config["import"]["quiet"]:
|
||||||
if rec == Recommendation.strong:
|
if rec == Recommendation.strong:
|
||||||
return importer.action.APPLY
|
return importer.Action.APPLY
|
||||||
else:
|
else:
|
||||||
action = config["import"]["quiet_fallback"].as_choice(
|
action = config["import"]["quiet_fallback"].as_choice(
|
||||||
{
|
{
|
||||||
"skip": importer.action.SKIP,
|
"skip": importer.Action.SKIP,
|
||||||
"asis": importer.action.ASIS,
|
"asis": importer.Action.ASIS,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
elif config["import"]["timid"]:
|
elif config["import"]["timid"]:
|
||||||
|
|
@ -824,17 +824,17 @@ def _summary_judgment(rec):
|
||||||
elif rec == Recommendation.none:
|
elif rec == Recommendation.none:
|
||||||
action = config["import"]["none_rec_action"].as_choice(
|
action = config["import"]["none_rec_action"].as_choice(
|
||||||
{
|
{
|
||||||
"skip": importer.action.SKIP,
|
"skip": importer.Action.SKIP,
|
||||||
"asis": importer.action.ASIS,
|
"asis": importer.Action.ASIS,
|
||||||
"ask": None,
|
"ask": None,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if action == importer.action.SKIP:
|
if action == importer.Action.SKIP:
|
||||||
print_("Skipping.")
|
print_("Skipping.")
|
||||||
elif action == importer.action.ASIS:
|
elif action == importer.Action.ASIS:
|
||||||
print_("Importing as-is.")
|
print_("Importing as-is.")
|
||||||
return action
|
return action
|
||||||
|
|
||||||
|
|
@ -1064,7 +1064,7 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
|
|
||||||
# Take immediate action if appropriate.
|
# Take immediate action if appropriate.
|
||||||
action = _summary_judgment(task.rec)
|
action = _summary_judgment(task.rec)
|
||||||
if action == importer.action.APPLY:
|
if action == importer.Action.APPLY:
|
||||||
match = task.candidates[0]
|
match = task.candidates[0]
|
||||||
show_change(task.cur_artist, task.cur_album, match)
|
show_change(task.cur_artist, task.cur_album, match)
|
||||||
return match
|
return match
|
||||||
|
|
@ -1074,7 +1074,7 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
# Loop until we have a choice.
|
# Loop until we have a choice.
|
||||||
while True:
|
while True:
|
||||||
# Ask for a choice from the user. The result of
|
# Ask for a choice from the user. The result of
|
||||||
# `choose_candidate` may be an `importer.action`, an
|
# `choose_candidate` may be an `importer.Action`, an
|
||||||
# `AlbumMatch` object for a specific selection, or a
|
# `AlbumMatch` object for a specific selection, or a
|
||||||
# `PromptChoice`.
|
# `PromptChoice`.
|
||||||
choices = self._get_choices(task)
|
choices = self._get_choices(task)
|
||||||
|
|
@ -1089,7 +1089,7 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
)
|
)
|
||||||
|
|
||||||
# Basic choices that require no more action here.
|
# Basic choices that require no more action here.
|
||||||
if choice in (importer.action.SKIP, importer.action.ASIS):
|
if choice in (importer.Action.SKIP, importer.Action.ASIS):
|
||||||
# Pass selection to main control flow.
|
# Pass selection to main control flow.
|
||||||
return choice
|
return choice
|
||||||
|
|
||||||
|
|
@ -1097,7 +1097,7 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
# function.
|
# function.
|
||||||
elif choice in choices:
|
elif choice in choices:
|
||||||
post_choice = choice.callback(self, task)
|
post_choice = choice.callback(self, task)
|
||||||
if isinstance(post_choice, importer.action):
|
if isinstance(post_choice, importer.Action):
|
||||||
return post_choice
|
return post_choice
|
||||||
elif isinstance(post_choice, autotag.Proposal):
|
elif isinstance(post_choice, autotag.Proposal):
|
||||||
# Use the new candidates and continue around the loop.
|
# Use the new candidates and continue around the loop.
|
||||||
|
|
@ -1121,7 +1121,7 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
|
|
||||||
# Take immediate action if appropriate.
|
# Take immediate action if appropriate.
|
||||||
action = _summary_judgment(task.rec)
|
action = _summary_judgment(task.rec)
|
||||||
if action == importer.action.APPLY:
|
if action == importer.Action.APPLY:
|
||||||
match = candidates[0]
|
match = candidates[0]
|
||||||
show_item_change(task.item, match)
|
show_item_change(task.item, match)
|
||||||
return match
|
return match
|
||||||
|
|
@ -1135,12 +1135,12 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
candidates, True, rec, item=task.item, choices=choices
|
candidates, True, rec, item=task.item, choices=choices
|
||||||
)
|
)
|
||||||
|
|
||||||
if choice in (importer.action.SKIP, importer.action.ASIS):
|
if choice in (importer.Action.SKIP, importer.Action.ASIS):
|
||||||
return choice
|
return choice
|
||||||
|
|
||||||
elif choice in choices:
|
elif choice in choices:
|
||||||
post_choice = choice.callback(self, task)
|
post_choice = choice.callback(self, task)
|
||||||
if isinstance(post_choice, importer.action):
|
if isinstance(post_choice, importer.Action):
|
||||||
return post_choice
|
return post_choice
|
||||||
elif isinstance(post_choice, autotag.Proposal):
|
elif isinstance(post_choice, autotag.Proposal):
|
||||||
candidates = post_choice.candidates
|
candidates = post_choice.candidates
|
||||||
|
|
@ -1203,7 +1203,7 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
|
|
||||||
if sel == "s":
|
if sel == "s":
|
||||||
# Skip new.
|
# Skip new.
|
||||||
task.set_choice(importer.action.SKIP)
|
task.set_choice(importer.Action.SKIP)
|
||||||
elif sel == "k":
|
elif sel == "k":
|
||||||
# Keep both. Do nothing; leave the choice intact.
|
# Keep both. Do nothing; leave the choice intact.
|
||||||
pass
|
pass
|
||||||
|
|
@ -1239,16 +1239,16 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
"""
|
"""
|
||||||
# Standard, built-in choices.
|
# Standard, built-in choices.
|
||||||
choices = [
|
choices = [
|
||||||
PromptChoice("s", "Skip", lambda s, t: importer.action.SKIP),
|
PromptChoice("s", "Skip", lambda s, t: importer.Action.SKIP),
|
||||||
PromptChoice("u", "Use as-is", lambda s, t: importer.action.ASIS),
|
PromptChoice("u", "Use as-is", lambda s, t: importer.Action.ASIS),
|
||||||
]
|
]
|
||||||
if task.is_album:
|
if task.is_album:
|
||||||
choices += [
|
choices += [
|
||||||
PromptChoice(
|
PromptChoice(
|
||||||
"t", "as Tracks", lambda s, t: importer.action.TRACKS
|
"t", "as Tracks", lambda s, t: importer.Action.TRACKS
|
||||||
),
|
),
|
||||||
PromptChoice(
|
PromptChoice(
|
||||||
"g", "Group albums", lambda s, t: importer.action.ALBUMS
|
"g", "Group albums", lambda s, t: importer.Action.ALBUMS
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
choices += [
|
choices += [
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,10 @@ BytesOrStr = Union[str, bytes]
|
||||||
PathLike = Union[BytesOrStr, Path]
|
PathLike = Union[BytesOrStr, Path]
|
||||||
Replacements: TypeAlias = "Sequence[tuple[Pattern[str], str]]"
|
Replacements: TypeAlias = "Sequence[tuple[Pattern[str], str]]"
|
||||||
|
|
||||||
|
# Here for now to allow for a easy replace later on
|
||||||
|
# once we can move to a PathLike (mainly used in importer)
|
||||||
|
PathBytes = bytes
|
||||||
|
|
||||||
|
|
||||||
class HumanReadableError(Exception):
|
class HumanReadableError(Exception):
|
||||||
"""An Exception that can include a human-readable error message to
|
"""An Exception that can include a human-readable error message to
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ class BadFiles(BeetsPlugin):
|
||||||
sel = ui.input_options(["aBort", "skip", "continue"])
|
sel = ui.input_options(["aBort", "skip", "continue"])
|
||||||
|
|
||||||
if sel == "s":
|
if sel == "s":
|
||||||
return importer.action.SKIP
|
return importer.Action.SKIP
|
||||||
elif sel == "c":
|
elif sel == "c":
|
||||||
return None
|
return None
|
||||||
elif sel == "b":
|
elif sel == "b":
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ import yaml
|
||||||
|
|
||||||
from beets import plugins, ui, util
|
from beets import plugins, ui, util
|
||||||
from beets.dbcore import types
|
from beets.dbcore import types
|
||||||
from beets.importer import action
|
from beets.importer import Action
|
||||||
from beets.ui.commands import PromptChoice, _do_query
|
from beets.ui.commands import PromptChoice, _do_query
|
||||||
|
|
||||||
# These "safe" types can avoid the format/parse cycle that most fields go
|
# These "safe" types can avoid the format/parse cycle that most fields go
|
||||||
|
|
@ -380,9 +380,9 @@ class EditPlugin(plugins.BeetsPlugin):
|
||||||
|
|
||||||
# Save the new data.
|
# Save the new data.
|
||||||
if success:
|
if success:
|
||||||
# Return action.RETAG, which makes the importer write the tags
|
# Return Action.RETAG, which makes the importer write the tags
|
||||||
# to the files if needed without re-applying metadata.
|
# to the files if needed without re-applying metadata.
|
||||||
return action.RETAG
|
return Action.RETAG
|
||||||
else:
|
else:
|
||||||
# Edit cancelled / no edits made. Revert changes.
|
# Edit cancelled / no edits made. Revert changes.
|
||||||
for obj in task.items:
|
for obj in task.items:
|
||||||
|
|
|
||||||
|
|
@ -1306,12 +1306,12 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
|
||||||
):
|
):
|
||||||
# Album already has art (probably a re-import); skip it.
|
# Album already has art (probably a re-import); skip it.
|
||||||
return
|
return
|
||||||
if task.choice_flag == importer.action.ASIS:
|
if task.choice_flag == importer.Action.ASIS:
|
||||||
# For as-is imports, don't search Web sources for art.
|
# For as-is imports, don't search Web sources for art.
|
||||||
local = True
|
local = True
|
||||||
elif task.choice_flag in (
|
elif task.choice_flag in (
|
||||||
importer.action.APPLY,
|
importer.Action.APPLY,
|
||||||
importer.action.RETAG,
|
importer.Action.RETAG,
|
||||||
):
|
):
|
||||||
# Search everywhere for art.
|
# Search everywhere for art.
|
||||||
local = False
|
local = False
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
"""Warns you about things you hate (or even blocks import)."""
|
"""Warns you about things you hate (or even blocks import)."""
|
||||||
|
|
||||||
from beets.importer import action
|
from beets.importer import Action
|
||||||
from beets.library import Album, Item, parse_query_string
|
from beets.library import Album, Item, parse_query_string
|
||||||
from beets.plugins import BeetsPlugin
|
from beets.plugins import BeetsPlugin
|
||||||
|
|
||||||
|
|
@ -65,11 +65,11 @@ class IHatePlugin(BeetsPlugin):
|
||||||
skip_queries = self.config["skip"].as_str_seq()
|
skip_queries = self.config["skip"].as_str_seq()
|
||||||
warn_queries = self.config["warn"].as_str_seq()
|
warn_queries = self.config["warn"].as_str_seq()
|
||||||
|
|
||||||
if task.choice_flag == action.APPLY:
|
if task.choice_flag == Action.APPLY:
|
||||||
if skip_queries or warn_queries:
|
if skip_queries or warn_queries:
|
||||||
self._log.debug("processing your hate")
|
self._log.debug("processing your hate")
|
||||||
if self.do_i_hate_this(task, skip_queries):
|
if self.do_i_hate_this(task, skip_queries):
|
||||||
task.choice_flag = action.SKIP
|
task.choice_flag = Action.SKIP
|
||||||
self._log.info("skipped: {0}", summary(task))
|
self._log.info("skipped: {0}", summary(task))
|
||||||
return
|
return
|
||||||
if self.do_i_hate_this(task, warn_queries):
|
if self.do_i_hate_this(task, warn_queries):
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import re
|
||||||
import confuse
|
import confuse
|
||||||
from mediafile import MediaFile
|
from mediafile import MediaFile
|
||||||
|
|
||||||
from beets.importer import action
|
from beets.importer import Action
|
||||||
from beets.plugins import BeetsPlugin
|
from beets.plugins import BeetsPlugin
|
||||||
from beets.ui import Subcommand, decargs, input_yn
|
from beets.ui import Subcommand, decargs, input_yn
|
||||||
|
|
||||||
|
|
@ -105,7 +105,7 @@ class ZeroPlugin(BeetsPlugin):
|
||||||
self.fields_to_progs[field] = []
|
self.fields_to_progs[field] = []
|
||||||
|
|
||||||
def import_task_choice_event(self, session, task):
|
def import_task_choice_event(self, session, task):
|
||||||
if task.choice_flag == action.ASIS and not self.warned:
|
if task.choice_flag == Action.ASIS and not self.warned:
|
||||||
self._log.warning('cannot zero in "as-is" mode')
|
self._log.warning('cannot zero in "as-is" mode')
|
||||||
self.warned = True
|
self.warned = True
|
||||||
# TODO request write in as-is mode
|
# TODO request write in as-is mode
|
||||||
|
|
|
||||||
|
|
@ -648,6 +648,6 @@ by the choices on the core importer prompt, and hence should not be used:
|
||||||
``a``, ``s``, ``u``, ``t``, ``g``, ``e``, ``i``, ``b``.
|
``a``, ``s``, ``u``, ``t``, ``g``, ``e``, ``i``, ``b``.
|
||||||
|
|
||||||
Additionally, the callback function can optionally specify the next action to
|
Additionally, the callback function can optionally specify the next action to
|
||||||
be performed by returning a ``importer.action`` value. It may also return a
|
be performed by returning a ``importer.Action`` value. It may also return a
|
||||||
``autotag.Proposal`` value to update the set of current proposals to be
|
``autotag.Proposal`` value to update the set of current proposals to be
|
||||||
considered.
|
considered.
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class ImportAddedTest(PluginMixin, ImportTestCase):
|
||||||
self.matcher = AutotagStub().install()
|
self.matcher = AutotagStub().install()
|
||||||
self.matcher.matching = AutotagStub.IDENT
|
self.matcher.matching = AutotagStub.IDENT
|
||||||
self.importer = self.setup_importer()
|
self.importer = self.setup_importer()
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ from mediafile import MediaFile
|
||||||
|
|
||||||
from beets import config, importer, logging, util
|
from beets import config, importer, logging, util
|
||||||
from beets.autotag import AlbumInfo, AlbumMatch, TrackInfo
|
from beets.autotag import AlbumInfo, AlbumMatch, TrackInfo
|
||||||
from beets.importer import albums_in_dir
|
from beets.importer.tasks import albums_in_dir
|
||||||
from beets.test import _common
|
from beets.test import _common
|
||||||
from beets.test.helper import (
|
from beets.test.helper import (
|
||||||
NEEDS_REFLINK,
|
NEEDS_REFLINK,
|
||||||
|
|
@ -324,52 +324,52 @@ class ImportSingletonTest(ImportTestCase):
|
||||||
def test_apply_asis_adds_track(self):
|
def test_apply_asis_adds_track(self):
|
||||||
assert self.lib.items().get() is None
|
assert self.lib.items().get() is None
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().title == "Tag Track 1"
|
assert self.lib.items().get().title == "Tag Track 1"
|
||||||
|
|
||||||
def test_apply_asis_does_not_add_album(self):
|
def test_apply_asis_does_not_add_album(self):
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
|
|
||||||
def test_apply_asis_adds_singleton_path(self):
|
def test_apply_asis_adds_singleton_path(self):
|
||||||
self.assert_lib_dir_empty()
|
self.assert_lib_dir_empty()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.assert_file_in_lib(b"singletons", b"Tag Track 1.mp3")
|
self.assert_file_in_lib(b"singletons", b"Tag Track 1.mp3")
|
||||||
|
|
||||||
def test_apply_candidate_adds_track(self):
|
def test_apply_candidate_adds_track(self):
|
||||||
assert self.lib.items().get() is None
|
assert self.lib.items().get() is None
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().title == "Applied Track 1"
|
assert self.lib.items().get().title == "Applied Track 1"
|
||||||
|
|
||||||
def test_apply_candidate_does_not_add_album(self):
|
def test_apply_candidate_does_not_add_album(self):
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
|
|
||||||
def test_apply_candidate_adds_singleton_path(self):
|
def test_apply_candidate_adds_singleton_path(self):
|
||||||
self.assert_lib_dir_empty()
|
self.assert_lib_dir_empty()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.assert_file_in_lib(b"singletons", b"Applied Track 1.mp3")
|
self.assert_file_in_lib(b"singletons", b"Applied Track 1.mp3")
|
||||||
|
|
||||||
def test_skip_does_not_add_first_track(self):
|
def test_skip_does_not_add_first_track(self):
|
||||||
self.importer.add_choice(importer.action.SKIP)
|
self.importer.add_choice(importer.Action.SKIP)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get() is None
|
assert self.lib.items().get() is None
|
||||||
|
|
||||||
def test_skip_adds_other_tracks(self):
|
def test_skip_adds_other_tracks(self):
|
||||||
self.prepare_album_for_import(2)
|
self.prepare_album_for_import(2)
|
||||||
self.importer.add_choice(importer.action.SKIP)
|
self.importer.add_choice(importer.Action.SKIP)
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert len(self.lib.items()) == 1
|
assert len(self.lib.items()) == 1
|
||||||
|
|
||||||
|
|
@ -385,8 +385,8 @@ class ImportSingletonTest(ImportTestCase):
|
||||||
self.setup_importer()
|
self.setup_importer()
|
||||||
self.importer.paths = import_files
|
self.importer.paths = import_files
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
|
|
||||||
assert len(self.lib.items()) == 2
|
assert len(self.lib.items()) == 2
|
||||||
|
|
@ -406,7 +406,7 @@ class ImportSingletonTest(ImportTestCase):
|
||||||
|
|
||||||
# As-is item import.
|
# As-is item import.
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
|
|
||||||
for item in self.lib.items():
|
for item in self.lib.items():
|
||||||
|
|
@ -421,7 +421,7 @@ class ImportSingletonTest(ImportTestCase):
|
||||||
# Autotagged.
|
# Autotagged.
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
self.importer.clear_choices()
|
self.importer.clear_choices()
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
|
|
||||||
for item in self.lib.items():
|
for item in self.lib.items():
|
||||||
|
|
@ -449,41 +449,41 @@ class ImportTest(ImportTestCase):
|
||||||
def test_apply_asis_adds_album(self):
|
def test_apply_asis_adds_album(self):
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().album == "Tag Album"
|
assert self.lib.albums().get().album == "Tag Album"
|
||||||
|
|
||||||
def test_apply_asis_adds_tracks(self):
|
def test_apply_asis_adds_tracks(self):
|
||||||
assert self.lib.items().get() is None
|
assert self.lib.items().get() is None
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().title == "Tag Track 1"
|
assert self.lib.items().get().title == "Tag Track 1"
|
||||||
|
|
||||||
def test_apply_asis_adds_album_path(self):
|
def test_apply_asis_adds_album_path(self):
|
||||||
self.assert_lib_dir_empty()
|
self.assert_lib_dir_empty()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.assert_file_in_lib(b"Tag Artist", b"Tag Album", b"Tag Track 1.mp3")
|
self.assert_file_in_lib(b"Tag Artist", b"Tag Album", b"Tag Track 1.mp3")
|
||||||
|
|
||||||
def test_apply_candidate_adds_album(self):
|
def test_apply_candidate_adds_album(self):
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().album == "Applied Album"
|
assert self.lib.albums().get().album == "Applied Album"
|
||||||
|
|
||||||
def test_apply_candidate_adds_tracks(self):
|
def test_apply_candidate_adds_tracks(self):
|
||||||
assert self.lib.items().get() is None
|
assert self.lib.items().get() is None
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().title == "Applied Track 1"
|
assert self.lib.items().get().title == "Applied Track 1"
|
||||||
|
|
||||||
def test_apply_candidate_adds_album_path(self):
|
def test_apply_candidate_adds_album_path(self):
|
||||||
self.assert_lib_dir_empty()
|
self.assert_lib_dir_empty()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.assert_file_in_lib(
|
self.assert_file_in_lib(
|
||||||
b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3"
|
b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3"
|
||||||
|
|
@ -496,14 +496,14 @@ class ImportTest(ImportTestCase):
|
||||||
mediafile.genre = "Tag Genre"
|
mediafile.genre = "Tag Genre"
|
||||||
mediafile.save()
|
mediafile.save()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().genre == ""
|
assert self.lib.items().get().genre == ""
|
||||||
|
|
||||||
def test_apply_from_scratch_keeps_format(self):
|
def test_apply_from_scratch_keeps_format(self):
|
||||||
config["import"]["from_scratch"] = True
|
config["import"]["from_scratch"] = True
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().format == "MP3"
|
assert self.lib.items().get().format == "MP3"
|
||||||
|
|
||||||
|
|
@ -511,7 +511,7 @@ class ImportTest(ImportTestCase):
|
||||||
config["import"]["from_scratch"] = True
|
config["import"]["from_scratch"] = True
|
||||||
bitrate = 80000
|
bitrate = 80000
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().bitrate == bitrate
|
assert self.lib.items().get().bitrate == bitrate
|
||||||
|
|
||||||
|
|
@ -521,7 +521,7 @@ class ImportTest(ImportTestCase):
|
||||||
import_file = os.path.join(self.import_dir, b"album", b"track_1.mp3")
|
import_file = os.path.join(self.import_dir, b"album", b"track_1.mp3")
|
||||||
self.assertExists(import_file)
|
self.assertExists(import_file)
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.assertNotExists(import_file)
|
self.assertNotExists(import_file)
|
||||||
|
|
||||||
|
|
@ -531,26 +531,26 @@ class ImportTest(ImportTestCase):
|
||||||
import_file = os.path.join(self.import_dir, b"album", b"track_1.mp3")
|
import_file = os.path.join(self.import_dir, b"album", b"track_1.mp3")
|
||||||
self.assertExists(import_file)
|
self.assertExists(import_file)
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.assertNotExists(import_file)
|
self.assertNotExists(import_file)
|
||||||
|
|
||||||
def test_skip_does_not_add_track(self):
|
def test_skip_does_not_add_track(self):
|
||||||
self.importer.add_choice(importer.action.SKIP)
|
self.importer.add_choice(importer.Action.SKIP)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get() is None
|
assert self.lib.items().get() is None
|
||||||
|
|
||||||
def test_skip_non_album_dirs(self):
|
def test_skip_non_album_dirs(self):
|
||||||
self.assertIsDir(os.path.join(self.import_dir, b"album"))
|
self.assertIsDir(os.path.join(self.import_dir, b"album"))
|
||||||
self.touch(b"cruft", dir=self.import_dir)
|
self.touch(b"cruft", dir=self.import_dir)
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert len(self.lib.albums()) == 1
|
assert len(self.lib.albums()) == 1
|
||||||
|
|
||||||
def test_unmatched_tracks_not_added(self):
|
def test_unmatched_tracks_not_added(self):
|
||||||
self.prepare_album_for_import(2)
|
self.prepare_album_for_import(2)
|
||||||
self.matcher.matching = self.matcher.MISSING
|
self.matcher.matching = self.matcher.MISSING
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert len(self.lib.items()) == 1
|
assert len(self.lib.items()) == 1
|
||||||
|
|
||||||
|
|
@ -577,7 +577,7 @@ class ImportTest(ImportTestCase):
|
||||||
def test_asis_no_data_source(self):
|
def test_asis_no_data_source(self):
|
||||||
assert self.lib.items().get() is None
|
assert self.lib.items().get() is None
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
|
|
||||||
with pytest.raises(AttributeError):
|
with pytest.raises(AttributeError):
|
||||||
|
|
@ -599,7 +599,7 @@ class ImportTest(ImportTestCase):
|
||||||
|
|
||||||
# As-is album import.
|
# As-is album import.
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
|
|
||||||
for album in self.lib.albums():
|
for album in self.lib.albums():
|
||||||
|
|
@ -621,7 +621,7 @@ class ImportTest(ImportTestCase):
|
||||||
# Autotagged.
|
# Autotagged.
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
self.importer.clear_choices()
|
self.importer.clear_choices()
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
|
|
||||||
for album in self.lib.albums():
|
for album in self.lib.albums():
|
||||||
|
|
@ -656,9 +656,9 @@ class ImportTracksTest(ImportTestCase):
|
||||||
assert self.lib.items().get() is None
|
assert self.lib.items().get() is None
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.TRACKS)
|
self.importer.add_choice(importer.Action.TRACKS)
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().title == "Applied Track 1"
|
assert self.lib.items().get().title == "Applied Track 1"
|
||||||
assert self.lib.albums().get() is None
|
assert self.lib.albums().get() is None
|
||||||
|
|
@ -666,9 +666,9 @@ class ImportTracksTest(ImportTestCase):
|
||||||
def test_apply_tracks_adds_singleton_path(self):
|
def test_apply_tracks_adds_singleton_path(self):
|
||||||
self.assert_lib_dir_empty()
|
self.assert_lib_dir_empty()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.TRACKS)
|
self.importer.add_choice(importer.Action.TRACKS)
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.assert_file_in_lib(b"singletons", b"Applied Track 1.mp3")
|
self.assert_file_in_lib(b"singletons", b"Applied Track 1.mp3")
|
||||||
|
|
||||||
|
|
@ -687,7 +687,7 @@ class ImportCompilationTest(ImportTestCase):
|
||||||
self.matcher.restore()
|
self.matcher.restore()
|
||||||
|
|
||||||
def test_asis_homogenous_sets_albumartist(self):
|
def test_asis_homogenous_sets_albumartist(self):
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().albumartist == "Tag Artist"
|
assert self.lib.albums().get().albumartist == "Tag Artist"
|
||||||
for item in self.lib.items():
|
for item in self.lib.items():
|
||||||
|
|
@ -699,7 +699,7 @@ class ImportCompilationTest(ImportTestCase):
|
||||||
self.import_media[1].artist = "Another Artist"
|
self.import_media[1].artist = "Another Artist"
|
||||||
self.import_media[1].save()
|
self.import_media[1].save()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().albumartist == "Various Artists"
|
assert self.lib.albums().get().albumartist == "Various Artists"
|
||||||
for item in self.lib.items():
|
for item in self.lib.items():
|
||||||
|
|
@ -711,7 +711,7 @@ class ImportCompilationTest(ImportTestCase):
|
||||||
self.import_media[1].artist = "Another Artist"
|
self.import_media[1].artist = "Another Artist"
|
||||||
self.import_media[1].save()
|
self.import_media[1].save()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
for item in self.lib.items():
|
for item in self.lib.items():
|
||||||
assert item.comp
|
assert item.comp
|
||||||
|
|
@ -722,7 +722,7 @@ class ImportCompilationTest(ImportTestCase):
|
||||||
self.import_media[1].artist = "Other Artist"
|
self.import_media[1].artist = "Other Artist"
|
||||||
self.import_media[1].save()
|
self.import_media[1].save()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().albumartist == "Other Artist"
|
assert self.lib.albums().get().albumartist == "Other Artist"
|
||||||
for item in self.lib.items():
|
for item in self.lib.items():
|
||||||
|
|
@ -736,7 +736,7 @@ class ImportCompilationTest(ImportTestCase):
|
||||||
mediafile.mb_albumartistid = "Album Artist ID"
|
mediafile.mb_albumartistid = "Album Artist ID"
|
||||||
mediafile.save()
|
mediafile.save()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().albumartist == "Album Artist"
|
assert self.lib.albums().get().albumartist == "Album Artist"
|
||||||
assert self.lib.albums().get().mb_albumartistid == "Album Artist ID"
|
assert self.lib.albums().get().mb_albumartistid == "Album Artist ID"
|
||||||
|
|
@ -755,7 +755,7 @@ class ImportCompilationTest(ImportTestCase):
|
||||||
mediafile.mb_albumartistid = "Album Artist ID"
|
mediafile.mb_albumartistid = "Album Artist ID"
|
||||||
mediafile.save()
|
mediafile.save()
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().albumartist == "Album Artist"
|
assert self.lib.albums().get().albumartist == "Album Artist"
|
||||||
assert self.lib.albums().get().albumartists == [
|
assert self.lib.albums().get().albumartists == [
|
||||||
|
|
@ -802,7 +802,7 @@ class ImportExistingTest(ImportTestCase):
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert len(self.lib.items()) == 1
|
assert len(self.lib.items()) == 1
|
||||||
|
|
||||||
self.reimporter.add_choice(importer.action.APPLY)
|
self.reimporter.add_choice(importer.Action.APPLY)
|
||||||
self.reimporter.run()
|
self.reimporter.run()
|
||||||
assert len(self.lib.items()) == 1
|
assert len(self.lib.items()) == 1
|
||||||
|
|
||||||
|
|
@ -810,18 +810,18 @@ class ImportExistingTest(ImportTestCase):
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert len(self.lib.albums()) == 1
|
assert len(self.lib.albums()) == 1
|
||||||
|
|
||||||
self.reimporter.add_choice(importer.action.APPLY)
|
self.reimporter.add_choice(importer.Action.APPLY)
|
||||||
self.reimporter.run()
|
self.reimporter.run()
|
||||||
assert len(self.lib.albums()) == 1
|
assert len(self.lib.albums()) == 1
|
||||||
|
|
||||||
def test_does_not_duplicate_singleton_track(self):
|
def test_does_not_duplicate_singleton_track(self):
|
||||||
self.importer.add_choice(importer.action.TRACKS)
|
self.importer.add_choice(importer.Action.TRACKS)
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert len(self.lib.items()) == 1
|
assert len(self.lib.items()) == 1
|
||||||
|
|
||||||
self.reimporter.add_choice(importer.action.TRACKS)
|
self.reimporter.add_choice(importer.Action.TRACKS)
|
||||||
self.reimporter.add_choice(importer.action.APPLY)
|
self.reimporter.add_choice(importer.Action.APPLY)
|
||||||
self.reimporter.run()
|
self.reimporter.run()
|
||||||
assert len(self.lib.items()) == 1
|
assert len(self.lib.items()) == 1
|
||||||
|
|
||||||
|
|
@ -831,7 +831,7 @@ class ImportExistingTest(ImportTestCase):
|
||||||
medium.title = "New Title"
|
medium.title = "New Title"
|
||||||
medium.save()
|
medium.save()
|
||||||
|
|
||||||
self.reimporter.add_choice(importer.action.ASIS)
|
self.reimporter.add_choice(importer.Action.ASIS)
|
||||||
self.reimporter.run()
|
self.reimporter.run()
|
||||||
assert self.lib.items().get().title == "New Title"
|
assert self.lib.items().get().title == "New Title"
|
||||||
|
|
||||||
|
|
@ -846,7 +846,7 @@ class ImportExistingTest(ImportTestCase):
|
||||||
)
|
)
|
||||||
self.assert_file_in_lib(old_path)
|
self.assert_file_in_lib(old_path)
|
||||||
|
|
||||||
self.reimporter.add_choice(importer.action.ASIS)
|
self.reimporter.add_choice(importer.Action.ASIS)
|
||||||
self.reimporter.run()
|
self.reimporter.run()
|
||||||
self.assert_file_in_lib(
|
self.assert_file_in_lib(
|
||||||
b"Applied Artist", b"Applied Album", b"New Title.mp3"
|
b"Applied Artist", b"Applied Album", b"New Title.mp3"
|
||||||
|
|
@ -865,7 +865,7 @@ class ImportExistingTest(ImportTestCase):
|
||||||
self.assert_file_in_lib(old_path)
|
self.assert_file_in_lib(old_path)
|
||||||
|
|
||||||
config["import"]["copy"] = False
|
config["import"]["copy"] = False
|
||||||
self.reimporter.add_choice(importer.action.ASIS)
|
self.reimporter.add_choice(importer.Action.ASIS)
|
||||||
self.reimporter.run()
|
self.reimporter.run()
|
||||||
self.assert_file_not_in_lib(
|
self.assert_file_not_in_lib(
|
||||||
b"Applied Artist", b"Applied Album", b"New Title.mp3"
|
b"Applied Artist", b"Applied Album", b"New Title.mp3"
|
||||||
|
|
@ -880,7 +880,7 @@ class ImportExistingTest(ImportTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.reimporter = self.setup_importer()
|
self.reimporter = self.setup_importer()
|
||||||
self.reimporter.add_choice(importer.action.APPLY)
|
self.reimporter.add_choice(importer.Action.APPLY)
|
||||||
self.reimporter.run()
|
self.reimporter.run()
|
||||||
new_path = os.path.join(
|
new_path = os.path.join(
|
||||||
b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3"
|
b"Applied Artist", b"Applied Album", b"Applied Track 1.mp3"
|
||||||
|
|
@ -899,7 +899,7 @@ class ImportExistingTest(ImportTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.reimporter = self.setup_importer(move=True)
|
self.reimporter = self.setup_importer(move=True)
|
||||||
self.reimporter.add_choice(importer.action.APPLY)
|
self.reimporter.add_choice(importer.Action.APPLY)
|
||||||
self.reimporter.run()
|
self.reimporter.run()
|
||||||
self.assertNotExists(self.import_media[0].path)
|
self.assertNotExists(self.import_media[0].path)
|
||||||
|
|
||||||
|
|
@ -913,9 +913,9 @@ class GroupAlbumsImportTest(ImportTestCase):
|
||||||
self.setup_importer()
|
self.setup_importer()
|
||||||
|
|
||||||
# Split tracks into two albums and use both as-is
|
# Split tracks into two albums and use both as-is
|
||||||
self.importer.add_choice(importer.action.ALBUMS)
|
self.importer.add_choice(importer.Action.ALBUMS)
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
self.importer.add_choice(importer.action.ASIS)
|
self.importer.add_choice(importer.Action.ASIS)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
super().tearDown()
|
super().tearDown()
|
||||||
|
|
@ -972,7 +972,7 @@ class GlobalGroupAlbumsImportTest(GroupAlbumsImportTest):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.importer.clear_choices()
|
self.importer.clear_choices()
|
||||||
self.importer.default_choice = importer.action.ASIS
|
self.importer.default_choice = importer.Action.ASIS
|
||||||
config["import"]["group_albums"] = True
|
config["import"]["group_albums"] = True
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1019,7 +1019,7 @@ class InferAlbumDataTest(BeetsTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_asis_homogenous_single_artist(self):
|
def test_asis_homogenous_single_artist(self):
|
||||||
self.task.set_choice(importer.action.ASIS)
|
self.task.set_choice(importer.Action.ASIS)
|
||||||
self.task.align_album_level_fields()
|
self.task.align_album_level_fields()
|
||||||
assert not self.items[0].comp
|
assert not self.items[0].comp
|
||||||
assert self.items[0].albumartist == self.items[2].artist
|
assert self.items[0].albumartist == self.items[2].artist
|
||||||
|
|
@ -1027,7 +1027,7 @@ class InferAlbumDataTest(BeetsTestCase):
|
||||||
def test_asis_heterogenous_va(self):
|
def test_asis_heterogenous_va(self):
|
||||||
self.items[0].artist = "another artist"
|
self.items[0].artist = "another artist"
|
||||||
self.items[1].artist = "some other artist"
|
self.items[1].artist = "some other artist"
|
||||||
self.task.set_choice(importer.action.ASIS)
|
self.task.set_choice(importer.Action.ASIS)
|
||||||
|
|
||||||
self.task.align_album_level_fields()
|
self.task.align_album_level_fields()
|
||||||
|
|
||||||
|
|
@ -1037,7 +1037,7 @@ class InferAlbumDataTest(BeetsTestCase):
|
||||||
def test_asis_comp_applied_to_all_items(self):
|
def test_asis_comp_applied_to_all_items(self):
|
||||||
self.items[0].artist = "another artist"
|
self.items[0].artist = "another artist"
|
||||||
self.items[1].artist = "some other artist"
|
self.items[1].artist = "some other artist"
|
||||||
self.task.set_choice(importer.action.ASIS)
|
self.task.set_choice(importer.Action.ASIS)
|
||||||
|
|
||||||
self.task.align_album_level_fields()
|
self.task.align_album_level_fields()
|
||||||
|
|
||||||
|
|
@ -1047,7 +1047,7 @@ class InferAlbumDataTest(BeetsTestCase):
|
||||||
|
|
||||||
def test_asis_majority_artist_single_artist(self):
|
def test_asis_majority_artist_single_artist(self):
|
||||||
self.items[0].artist = "another artist"
|
self.items[0].artist = "another artist"
|
||||||
self.task.set_choice(importer.action.ASIS)
|
self.task.set_choice(importer.Action.ASIS)
|
||||||
|
|
||||||
self.task.align_album_level_fields()
|
self.task.align_album_level_fields()
|
||||||
|
|
||||||
|
|
@ -1060,7 +1060,7 @@ class InferAlbumDataTest(BeetsTestCase):
|
||||||
for item in self.items:
|
for item in self.items:
|
||||||
item.albumartist = "some album artist"
|
item.albumartist = "some album artist"
|
||||||
item.mb_albumartistid = "some album artist id"
|
item.mb_albumartistid = "some album artist id"
|
||||||
self.task.set_choice(importer.action.ASIS)
|
self.task.set_choice(importer.Action.ASIS)
|
||||||
|
|
||||||
self.task.align_album_level_fields()
|
self.task.align_album_level_fields()
|
||||||
|
|
||||||
|
|
@ -1089,7 +1089,7 @@ class InferAlbumDataTest(BeetsTestCase):
|
||||||
def test_small_single_artist_album(self):
|
def test_small_single_artist_album(self):
|
||||||
self.items = [self.items[0]]
|
self.items = [self.items[0]]
|
||||||
self.task.items = self.items
|
self.task.items = self.items
|
||||||
self.task.set_choice(importer.action.ASIS)
|
self.task.set_choice(importer.Action.ASIS)
|
||||||
self.task.align_album_level_fields()
|
self.task.align_album_level_fields()
|
||||||
assert not self.items[0].comp
|
assert not self.items[0].comp
|
||||||
|
|
||||||
|
|
@ -1599,7 +1599,7 @@ class ReimportTest(ImportTestCase):
|
||||||
|
|
||||||
def _setup_session(self, singletons=False):
|
def _setup_session(self, singletons=False):
|
||||||
self.setup_importer(import_dir=self.libdir, singletons=singletons)
|
self.setup_importer(import_dir=self.libdir, singletons=singletons)
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
|
|
||||||
def _album(self):
|
def _album(self):
|
||||||
return self.lib.albums().get()
|
return self.lib.albums().get()
|
||||||
|
|
@ -1845,7 +1845,7 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
||||||
search_ids=[self.MB_RELEASE_PREFIX + self.ID_RELEASE_0]
|
search_ids=[self.MB_RELEASE_PREFIX + self.ID_RELEASE_0]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().album == "VALID_RELEASE_0"
|
assert self.lib.albums().get().album == "VALID_RELEASE_0"
|
||||||
|
|
||||||
|
|
@ -1858,7 +1858,7 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.importer.add_choice(2) # Pick the 2nd best match (release 1).
|
self.importer.add_choice(2) # Pick the 2nd best match (release 1).
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.albums().get().album == "VALID_RELEASE_1"
|
assert self.lib.albums().get().album == "VALID_RELEASE_1"
|
||||||
|
|
||||||
|
|
@ -1867,7 +1867,7 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
||||||
search_ids=[self.MB_RECORDING_PREFIX + self.ID_RECORDING_0]
|
search_ids=[self.MB_RECORDING_PREFIX + self.ID_RECORDING_0]
|
||||||
)
|
)
|
||||||
|
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().title == "VALID_RECORDING_0"
|
assert self.lib.items().get().title == "VALID_RECORDING_0"
|
||||||
|
|
||||||
|
|
@ -1880,7 +1880,7 @@ class ImportMusicBrainzIdTest(ImportTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
self.importer.add_choice(2) # Pick the 2nd best match (recording 1).
|
self.importer.add_choice(2) # Pick the 2nd best match (recording 1).
|
||||||
self.importer.add_choice(importer.action.APPLY)
|
self.importer.add_choice(importer.Action.APPLY)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
assert self.lib.items().get().title == "VALID_RECORDING_1"
|
assert self.lib.items().get().title == "VALID_RECORDING_1"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,10 +24,10 @@ from mediafile import MediaFile
|
||||||
from beets import config, plugins, ui
|
from beets import config, plugins, ui
|
||||||
from beets.dbcore import types
|
from beets.dbcore import types
|
||||||
from beets.importer import (
|
from beets.importer import (
|
||||||
|
Action,
|
||||||
ArchiveImportTask,
|
ArchiveImportTask,
|
||||||
SentinelImportTask,
|
SentinelImportTask,
|
||||||
SingletonImportTask,
|
SingletonImportTask,
|
||||||
action,
|
|
||||||
)
|
)
|
||||||
from beets.library import Item
|
from beets.library import Item
|
||||||
from beets.plugins import MetadataSourcePlugin
|
from beets.plugins import MetadataSourcePlugin
|
||||||
|
|
@ -389,7 +389,7 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
||||||
"aBort",
|
"aBort",
|
||||||
) + ("Foo", "baR")
|
) + ("Foo", "baR")
|
||||||
|
|
||||||
self.importer.add_choice(action.SKIP)
|
self.importer.add_choice(Action.SKIP)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.mock_input_options.assert_called_once_with(
|
self.mock_input_options.assert_called_once_with(
|
||||||
opts, default="a", require=ANY
|
opts, default="a", require=ANY
|
||||||
|
|
@ -424,7 +424,7 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
||||||
) + ("Foo", "baR")
|
) + ("Foo", "baR")
|
||||||
|
|
||||||
config["import"]["singletons"] = True
|
config["import"]["singletons"] = True
|
||||||
self.importer.add_choice(action.SKIP)
|
self.importer.add_choice(Action.SKIP)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.mock_input_options.assert_called_with(
|
self.mock_input_options.assert_called_with(
|
||||||
opts, default="a", require=ANY
|
opts, default="a", require=ANY
|
||||||
|
|
@ -461,7 +461,7 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
||||||
"enter Id",
|
"enter Id",
|
||||||
"aBort",
|
"aBort",
|
||||||
) + ("baZ",)
|
) + ("baZ",)
|
||||||
self.importer.add_choice(action.SKIP)
|
self.importer.add_choice(Action.SKIP)
|
||||||
self.importer.run()
|
self.importer.run()
|
||||||
self.mock_input_options.assert_called_once_with(
|
self.mock_input_options.assert_called_once_with(
|
||||||
opts, default="a", require=ANY
|
opts, default="a", require=ANY
|
||||||
|
|
@ -523,7 +523,7 @@ class PromptChoicesTest(TerminalImportMixin, PluginImportTestCase):
|
||||||
return [ui.commands.PromptChoice("f", "Foo", self.foo)]
|
return [ui.commands.PromptChoice("f", "Foo", self.foo)]
|
||||||
|
|
||||||
def foo(self, session, task):
|
def foo(self, session, task):
|
||||||
return action.SKIP
|
return Action.SKIP
|
||||||
|
|
||||||
self.register_plugin(DummyPlugin)
|
self.register_plugin(DummyPlugin)
|
||||||
# Default options + extra choices by the plugin ('Foo', 'Bar')
|
# Default options + extra choices by the plugin ('Foo', 'Bar')
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue