Example #1
0
def test_directory__episode():
    episode_path = Path("/some/episode/path").absolute()
    target = Target(
        Path(),
        Settings(media=MediaType.EPISODE, episode_directory=episode_path),
    )
    assert target.directory == episode_path
Example #2
0
 def __init__(self, file_path: Union[str, Path], settings: Settings):
     self._settings = settings
     self._has_moved: False
     self._has_renamed: False
     self.source = Path(file_path).resolve()
     self.metadata = parse_metadata(file_path=file_path,
                                    media_hint=settings.media)
     self.provider_type = settings.api_for(self.metadata.media)
     self._override_metadata_ids(settings)
     self._register_provider()
Example #3
0
def run(load_configuration=True, load_arguments=True):
    """The main program loop."""
    # setup arguments and load runtime configuration
    try:
        settings = Settings(
            load_configuration=load_configuration, load_arguments=load_arguments
        )
    except MnamerException as e:
        tty.msg(str(e), MessageType.ERROR)
        raise SystemExit(1)
    targets = Target.populate_paths(settings)
    tty.configure(settings)

    # handle directives and configuration
    if settings.version:
        tty.msg(f"mnamer version {VERSION}")
        raise SystemExit(0)

    if settings.config_dump:
        print(settings.as_json)
        raise SystemExit(0)

    tty.msg("Starting mnamer", MessageType.HEADING)
    if settings.no_cache:
        clear_cache()
        tty.msg("cache cleared", MessageType.ALERT)
    if settings.test:
        tty.msg("testing mode", MessageType.ALERT)
    if settings.configuration_path:
        tty.msg(
            f"loaded config from '{settings.configuration_path}'",
            MessageType.ALERT,
        )

    # print configuration details
    tty.msg("\nsystem", debug=True)
    tty.msg(SYSTEM, debug=True)
    tty.msg("\nsettings", debug=True)
    tty.msg(settings.as_dict, debug=True)
    tty.msg("\ntargets", debug=True)
    tty.msg(targets or [None], debug=True)

    # exit early if no media files are found
    total_count = len(targets)
    if total_count == 0:
        tty.msg("", debug=True)
        tty.msg("no media files found", MessageType.ALERT)
        raise SystemExit(0)

    # main program loop
    success_count = 0
    for target in targets:

        # announce file
        media_label = target.metadata.media.value.title()
        filename_label = target.source.name
        filesize_label = get_filesize(target.source)
        tty.msg(
            f'\nProcessing {media_label} "{filename_label}" ({filesize_label})',
            MessageType.HEADING,
        )
        tty.msg(target.source, debug=True)

        # list details
        tty.msg(
            f"using {target.provider_type.value}", MessageType.ALERT, debug=True
        )
        tty.msg("\nsearch parameters", debug=True)
        tty.msg(target.metadata.as_dict, debug=True)
        tty.msg("", debug=True)

        # find match for target
        matches = []
        try:
            matches = target.query()
        except MnamerNotFoundException:
            tty.msg("no matches found", MessageType.ALERT)
        except MnamerNetworkException:
            tty.msg("network error", MessageType.ALERT)
        if not matches and settings.no_guess:
            tty.msg("skipping (--no-guess)", MessageType.ALERT)
            continue
        try:
            if settings.batch:
                match = matches[0] if matches else target.metadata
            elif not matches:
                match = tty.confirm_guess(target.metadata)
            else:
                tty.msg("results")
                match = tty.prompt(matches)
        except MnamerSkipException:
            tty.msg("skipping (user request)", MessageType.ALERT)
            continue
        except MnamerAbortException:
            tty.msg("aborting (user request)", MessageType.ERROR)
            break
        target.metadata.update(match)

        # sanity check move
        if target.destination == target.source:
            tty.msg(
                f"skipping (source and destination paths are the same)",
                MessageType.ALERT,
            )
            continue
        if settings.no_overwrite and target.destination.exists():
            tty.msg(
                f"skipping (--no-overwrite)", MessageType.ALERT,
            )
            continue

        tty.msg(
            f"moving to {target.destination.absolute()}", MessageType.SUCCESS,
        )

        # rename and move file
        if settings.test:
            success_count += 1
            continue
        try:
            target.relocate()
        except MnamerException:
            tty.msg("FAILED!", MessageType.ERROR)
        else:
            tty.msg("OK!", MessageType.SUCCESS)
            success_count += 1

    # report results
    if success_count == 0:
        message_type = MessageType.ERROR
    elif success_count == total_count:
        message_type = MessageType.SUCCESS
    else:
        message_type = MessageType.ALERT
    tty.msg(
        f"\n{success_count} out of {total_count} files processed successfully",
        message_type,
    )
Example #4
0
def test_version(flag: str, e2e_run: Callable):
    result = e2e_run(flag)
    assert result.code == 0
    assert result.out == f"mnamer version {VERSION}"


@patch("mnamer.__main__.clear_cache")
def test_directives__cache_clear(mock_clear_cache: MagicMock,
                                 e2e_run: Callable):
    result = e2e_run("--no_cache")
    assert result.code == 0
    assert "cache cleared" in result.out
    mock_clear_cache.assert_called_once()


@pytest.mark.parametrize("key", Settings._serializable_fields())
@patch("mnamer.utils.crawl_out")
def test_directives__config_dump(mock_crawl_out: MagicMock, key: str,
                                 e2e_run: Callable):
    mock_crawl_out.return_value = None
    result = e2e_run("--config_dump")
    assert result.code == 0
    if key.startswith("api_key"):
        return
    json_out = json.loads(result.out)
    value = DEFAULT_SETTINGS[key]
    expected = getattr(value, "value", value)
    actual = json_out[key]
    assert actual == expected

Example #5
0
def test_directory__movie():
    movie_path = Path("/some/movie/path").absolute()
    target = Target(
        Path(), Settings(media=MediaType.MOVIE, movie_directory=movie_path))
    assert target.directory == movie_path
Example #6
0
def test_media__override(media: MediaType):
    target = Target(Path(), Settings(media=media))
    assert target.media is media
Example #7
0
def test_media__episode():
    target = Target(Path("ninja turtles s01e01.mkv"), Settings())
    assert target.media is MediaType.EPISODE
Example #8
0
def test_media__movie():
    target = Target(Path("ninja turtles (1990).mkv"), Settings())
    assert target.media is MediaType.MOVIE