mnamer 2.5.6.dev3__tar.gz → 2.5.6.dev8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mnamer-2.5.6.dev8/.github/actions/init/action.yml +19 -0
- mnamer-2.5.6.dev8/.github/actions/lint/action.yml +31 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/.github/actions/test/action.yml +4 -4
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/.github/dependabot.yml +4 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/.github/workflows/publish.yml +4 -8
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/.github/workflows/pull_request.yml +3 -5
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/.github/workflows/push.yml +4 -2
- mnamer-2.5.6.dev8/.python-version +1 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/PKG-INFO +15 -7
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/README.md +3 -3
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/__main__.py +2 -2
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/__version__.py +1 -1
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/endpoints.py +1 -1
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/language.py +3 -3
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/metadata.py +2 -1
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/providers.py +2 -3
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/setting_store.py +4 -3
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/target.py +6 -6
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/tty.py +8 -7
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/types.py +2 -2
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/utils.py +13 -13
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer.egg-info/PKG-INFO +15 -7
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer.egg-info/SOURCES.txt +1 -2
- mnamer-2.5.6.dev8/mnamer.egg-info/requires.txt +8 -0
- mnamer-2.5.6.dev8/pyproject.toml +101 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/test_utils.py +1 -1
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/test_endpoints__omdb.py +2 -2
- mnamer-2.5.6.dev8/uv.lock +937 -0
- mnamer-2.5.6.dev3/.github/actions/init/action.yml +0 -19
- mnamer-2.5.6.dev3/.github/actions/lint/action.yml +0 -46
- mnamer-2.5.6.dev3/.python-version +0 -1
- mnamer-2.5.6.dev3/mnamer.egg-info/requires.txt +0 -24
- mnamer-2.5.6.dev3/pyproject.toml +0 -64
- mnamer-2.5.6.dev3/requirements-dev.txt +0 -14
- mnamer-2.5.6.dev3/requirements.txt +0 -8
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/.gitignore +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/.vscode/settings.json +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/Dockerfile +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/LICENSE.txt +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/MANIFEST.in +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/assets/design.eps +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/assets/logo-2.png +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/assets/logo-3.png +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/assets/logo.png +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/assets/recording.mov +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/assets/screenshot.eps +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/assets/screenshot.png +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/makefile +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/__init__.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/argument.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/const.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/exceptions.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/frontends.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/py.typed +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer/setting_spec.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer.egg-info/dependency_links.txt +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer.egg-info/entry_points.txt +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/mnamer.egg-info/top_level.txt +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/pytest.ini +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/setup.cfg +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/__init__.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/conftest.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/e2e/__init__.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/e2e/conftest.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/e2e/test_directives.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/e2e/test_errors.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/e2e/test_moving.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/__init__.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/test_argument.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/test_language.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/test_metadata.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/test_setting_spec.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/test_setting_store.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/test_target.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/local/test_tty.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/__init__.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/test_endpoints__tmdb.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/test_endpoints__tvdb.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/test_endpoints__tvmaze.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/test_providers__omdb.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/test_providers__tmdb.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/test_providers__tvdb.py +0 -0
- {mnamer-2.5.6.dev3 → mnamer-2.5.6.dev8}/tests/network/test_providers__tvmaze.py +0 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
name: Init
|
|
2
|
+
description: Sets up the environment for build, lint, and test jobs
|
|
3
|
+
|
|
4
|
+
runs:
|
|
5
|
+
using: composite
|
|
6
|
+
steps:
|
|
7
|
+
- uses: actions/setup-python@v5
|
|
8
|
+
with:
|
|
9
|
+
python-version: '3.12'
|
|
10
|
+
|
|
11
|
+
- name: Install uv
|
|
12
|
+
uses: astral-sh/setup-uv@v4
|
|
13
|
+
with:
|
|
14
|
+
enable-cache: true
|
|
15
|
+
cache-dependency-glob: "**/pyproject.toml"
|
|
16
|
+
|
|
17
|
+
- name: Install dependencies
|
|
18
|
+
shell: sh
|
|
19
|
+
run: uv sync --dev
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
name: Lint
|
|
2
|
+
description: Lints the codebase with ruff and mypy
|
|
3
|
+
|
|
4
|
+
inputs:
|
|
5
|
+
ruff:
|
|
6
|
+
description: Whether to run ruff
|
|
7
|
+
required: false
|
|
8
|
+
default: "true"
|
|
9
|
+
|
|
10
|
+
mypy:
|
|
11
|
+
description: Whether to run mypy
|
|
12
|
+
required: false
|
|
13
|
+
default: "true"
|
|
14
|
+
|
|
15
|
+
runs:
|
|
16
|
+
using: composite
|
|
17
|
+
steps:
|
|
18
|
+
- name: Linting with ruff
|
|
19
|
+
if: inputs.ruff == 'true'
|
|
20
|
+
run: uv run ruff check mnamer tests
|
|
21
|
+
shell: sh
|
|
22
|
+
|
|
23
|
+
- name: Formatting with ruff
|
|
24
|
+
if: inputs.ruff == 'true'
|
|
25
|
+
run: uv run ruff format --check mnamer tests
|
|
26
|
+
shell: sh
|
|
27
|
+
|
|
28
|
+
- name: Type checking with mypy
|
|
29
|
+
if: inputs.mypy == 'true'
|
|
30
|
+
run: uv run mypy mnamer tests
|
|
31
|
+
shell: sh
|
|
@@ -28,7 +28,7 @@ runs:
|
|
|
28
28
|
- name: Running Local Unit Tests
|
|
29
29
|
if: inputs.local == 'true'
|
|
30
30
|
run: >-
|
|
31
|
-
|
|
31
|
+
uv run pytest
|
|
32
32
|
-m local
|
|
33
33
|
--durations=10
|
|
34
34
|
--cov=./
|
|
@@ -40,7 +40,7 @@ runs:
|
|
|
40
40
|
- name: Running Network Unit Tests
|
|
41
41
|
if: inputs.network == 'true'
|
|
42
42
|
run: >-
|
|
43
|
-
|
|
43
|
+
uv run pytest
|
|
44
44
|
-m network
|
|
45
45
|
--reruns 3
|
|
46
46
|
--durations=10
|
|
@@ -53,7 +53,7 @@ runs:
|
|
|
53
53
|
- name: Running End to End Tests
|
|
54
54
|
if: inputs.e2e == 'true'
|
|
55
55
|
run: >-
|
|
56
|
-
|
|
56
|
+
uv run pytest
|
|
57
57
|
-m e2e
|
|
58
58
|
--reruns 3
|
|
59
59
|
--durations=10
|
|
@@ -71,7 +71,7 @@ runs:
|
|
|
71
71
|
&& failure()
|
|
72
72
|
|
|
73
73
|
- name: Reporting Coverage Statistics
|
|
74
|
-
uses: codecov/codecov-action@
|
|
74
|
+
uses: codecov/codecov-action@v5
|
|
75
75
|
if: >-
|
|
76
76
|
success()
|
|
77
77
|
&& inputs.coverage == 'true'
|
|
@@ -9,19 +9,15 @@ jobs:
|
|
|
9
9
|
runs-on: ubuntu-latest
|
|
10
10
|
|
|
11
11
|
steps:
|
|
12
|
-
- uses: actions/checkout@
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
13
|
with: { fetch-depth: 0 } # required for setuptools_scm to detect git tags
|
|
14
14
|
- uses: ./.github/actions/init
|
|
15
15
|
|
|
16
16
|
- name: Building
|
|
17
|
-
run:
|
|
17
|
+
run: uv build
|
|
18
18
|
|
|
19
19
|
- name: Reporting Version
|
|
20
|
-
run:
|
|
20
|
+
run: uv run python -m mnamer --version
|
|
21
21
|
|
|
22
22
|
- name: Uploading to PyPI
|
|
23
|
-
run:
|
|
24
|
-
twine upload
|
|
25
|
-
--username __token__
|
|
26
|
-
--password ${{secrets.pypi_password}}
|
|
27
|
-
dist/*
|
|
23
|
+
run: uv publish --token ${{secrets.pypi_password}}
|
|
@@ -7,22 +7,20 @@ jobs:
|
|
|
7
7
|
runs-on: ubuntu-latest
|
|
8
8
|
|
|
9
9
|
steps:
|
|
10
|
-
- uses: actions/checkout@
|
|
10
|
+
- uses: actions/checkout@v4
|
|
11
11
|
- uses: ./.github/actions/init
|
|
12
12
|
|
|
13
13
|
- name: Linting
|
|
14
14
|
uses: ./.github/actions/lint
|
|
15
15
|
with:
|
|
16
|
-
|
|
17
|
-
isort: true
|
|
18
|
-
pyflakes: true
|
|
16
|
+
ruff: true
|
|
19
17
|
mypy: true
|
|
20
18
|
|
|
21
19
|
test:
|
|
22
20
|
runs-on: ubuntu-latest
|
|
23
21
|
|
|
24
22
|
steps:
|
|
25
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v4
|
|
26
24
|
- uses: ./.github/actions/init
|
|
27
25
|
|
|
28
26
|
- name: Testing (contributor)
|
|
@@ -2,6 +2,8 @@ name: push
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
5
7
|
schedule:
|
|
6
8
|
- cron: "0 8 * * 1" # mondays at 8am
|
|
7
9
|
release:
|
|
@@ -14,7 +16,7 @@ jobs:
|
|
|
14
16
|
runs-on: ubuntu-latest
|
|
15
17
|
|
|
16
18
|
steps:
|
|
17
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@v4
|
|
18
20
|
- uses: ./.github/actions/init
|
|
19
21
|
- uses: ./.github/actions/lint
|
|
20
22
|
|
|
@@ -22,7 +24,7 @@ jobs:
|
|
|
22
24
|
runs-on: ubuntu-latest
|
|
23
25
|
|
|
24
26
|
steps:
|
|
25
|
-
- uses: actions/checkout@
|
|
27
|
+
- uses: actions/checkout@v4
|
|
26
28
|
- uses: ./.github/actions/init
|
|
27
29
|
- uses: ./.github/actions/test
|
|
28
30
|
with:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mnamer
|
|
3
|
-
Version: 2.5.6.
|
|
3
|
+
Version: 2.5.6.dev8
|
|
4
4
|
Summary: A command-line utility for organizing media files.
|
|
5
5
|
Author-email: Jessy Williams <jessy@jessywilliams.com>
|
|
6
6
|
Maintainer-email: Jessy Williams <jessy@jessywilliams.com>
|
|
@@ -27,16 +27,24 @@ License: MIT License
|
|
|
27
27
|
SOFTWARE.
|
|
28
28
|
|
|
29
29
|
Project-URL: repository, https://github.com/jkwill87/mnamer
|
|
30
|
-
Requires-Python: >=3.
|
|
30
|
+
Requires-Python: >=3.12
|
|
31
31
|
Description-Content-Type: text/markdown
|
|
32
|
-
Provides-Extra: dev
|
|
33
32
|
License-File: LICENSE.txt
|
|
33
|
+
Requires-Dist: appdirs>=1.4.4
|
|
34
|
+
Requires-Dist: babelfish>=0.6.0
|
|
35
|
+
Requires-Dist: guessit>=3.8.0
|
|
36
|
+
Requires-Dist: requests>=2.32.0
|
|
37
|
+
Requires-Dist: requests-cache~=0.9.8
|
|
38
|
+
Requires-Dist: setuptools-scm>=8.0.0
|
|
39
|
+
Requires-Dist: teletype>=1.3.4
|
|
40
|
+
Requires-Dist: typing-extensions>=4.7.0
|
|
41
|
+
Dynamic: license-file
|
|
34
42
|
|
|
35
43
|
[](https://pypi.python.org/pypi/mnamer)
|
|
36
44
|
[](https://github.com/jkwill87/mnamer/actions/workflows/push.yml?query=branch:main)
|
|
37
45
|
[](https://codecov.io/gh/jkwill87/mnamer)
|
|
38
46
|
[](https://en.wikipedia.org/wiki/MIT_License)
|
|
39
|
-
[](https://github.com/astral-sh/ruff)
|
|
40
48
|
|
|
41
49
|
<img src="https://github.com/jkwill87/mnamer/raw/main/assets/logo.png" width="450"/>
|
|
42
50
|
|
|
@@ -54,7 +62,7 @@ Check out the [wiki page](https://github.com/jkwill87/mnamer/wiki) for more deta
|
|
|
54
62
|
|
|
55
63
|
💾 [**Installation**](https://github.com/jkwill87/mnamer/wiki/Installation)
|
|
56
64
|
|
|
57
|
-
`$ pip3 install --user mnamer`
|
|
65
|
+
`$ uv tool install mnamer` or `$ pip3 install --user mnamer`
|
|
58
66
|
|
|
59
67
|
🤖 [**Automation**](https://github.com/jkwill87/mnamer/wiki/Automation)
|
|
60
68
|
|
|
@@ -124,6 +132,6 @@ Parameters can either by entered as command line arguments or from a config file
|
|
|
124
132
|
|
|
125
133
|
## Contributions
|
|
126
134
|
|
|
127
|
-
Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [
|
|
135
|
+
Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [ruff](https://docs.astral.sh/ruff/) for consistency with the rest of the project and pass the continuous integration tests run against each PR. Before introducing any major features or changes to the configuration api please consider opening [an issue](https://github.com/jkwill87/mnamer/issues) to outline your proposal.
|
|
128
136
|
|
|
129
137
|
Bug reports are also welcome on the [issue page](https://github.com/jkwill87/mnamer/issues). Please include any generated crash reports if applicable. Feature requests are welcome but consider checking out [if it is in the works](https://github.com/jkwill87/mnamer/issues?q=label%3Arequest) first to avoid duplication.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
[](https://github.com/jkwill87/mnamer/actions/workflows/push.yml?query=branch:main)
|
|
3
3
|
[](https://codecov.io/gh/jkwill87/mnamer)
|
|
4
4
|
[](https://en.wikipedia.org/wiki/MIT_License)
|
|
5
|
-
[](https://github.com/astral-sh/ruff)
|
|
6
6
|
|
|
7
7
|
<img src="https://github.com/jkwill87/mnamer/raw/main/assets/logo.png" width="450"/>
|
|
8
8
|
|
|
@@ -20,7 +20,7 @@ Check out the [wiki page](https://github.com/jkwill87/mnamer/wiki) for more deta
|
|
|
20
20
|
|
|
21
21
|
💾 [**Installation**](https://github.com/jkwill87/mnamer/wiki/Installation)
|
|
22
22
|
|
|
23
|
-
`$ pip3 install --user mnamer`
|
|
23
|
+
`$ uv tool install mnamer` or `$ pip3 install --user mnamer`
|
|
24
24
|
|
|
25
25
|
🤖 [**Automation**](https://github.com/jkwill87/mnamer/wiki/Automation)
|
|
26
26
|
|
|
@@ -90,6 +90,6 @@ Parameters can either by entered as command line arguments or from a config file
|
|
|
90
90
|
|
|
91
91
|
## Contributions
|
|
92
92
|
|
|
93
|
-
Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [
|
|
93
|
+
Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [ruff](https://docs.astral.sh/ruff/) for consistency with the rest of the project and pass the continuous integration tests run against each PR. Before introducing any major features or changes to the configuration api please consider opening [an issue](https://github.com/jkwill87/mnamer/issues) to outline your proposal.
|
|
94
94
|
|
|
95
95
|
Bug reports are also welcome on the [issue page](https://github.com/jkwill87/mnamer/issues). Please include any generated crash reports if applicable. Feature requests are welcome but consider checking out [if it is in the works](https://github.com/jkwill87/mnamer/issues?q=label%3Arequest) first to avoid duplication.
|
|
@@ -17,13 +17,13 @@ def main(): # pragma: no cover
|
|
|
17
17
|
settings.load()
|
|
18
18
|
except MnamerException as e:
|
|
19
19
|
tty.error(e)
|
|
20
|
-
raise SystemExit(2)
|
|
20
|
+
raise SystemExit(2) from None
|
|
21
21
|
try:
|
|
22
22
|
frontend = Cli(settings)
|
|
23
23
|
frontend.launch()
|
|
24
24
|
except SystemExit:
|
|
25
25
|
raise
|
|
26
|
-
except:
|
|
26
|
+
except Exception:
|
|
27
27
|
if IS_DEBUG:
|
|
28
28
|
# allow exceptions to raised when debugging
|
|
29
29
|
raise
|
|
@@ -35,7 +35,7 @@ def omdb_title(
|
|
|
35
35
|
if (not title and not id_imdb) or (title and id_imdb):
|
|
36
36
|
raise MnamerException("either id_imdb or title must be specified")
|
|
37
37
|
elif plot and plot not in OMDB_PLOT_TYPES:
|
|
38
|
-
raise MnamerException("plot must be one of
|
|
38
|
+
raise MnamerException(f"plot must be one of {','.join(OMDB_PLOT_TYPES)}")
|
|
39
39
|
url = "http://www.omdbapi.com"
|
|
40
40
|
parameters = {
|
|
41
41
|
"apikey": api_key,
|
|
@@ -53,8 +53,8 @@ class Language:
|
|
|
53
53
|
try:
|
|
54
54
|
if getattr(value, "alpha3", None):
|
|
55
55
|
return cls(value.name, value.alpha2, value.alpha3)
|
|
56
|
-
except:
|
|
57
|
-
raise MnamerException("Could not determine language")
|
|
56
|
+
except Exception:
|
|
57
|
+
raise MnamerException("Could not determine language") from None
|
|
58
58
|
value = value.lower()
|
|
59
59
|
for row in KNOWN_LANGUAGES:
|
|
60
60
|
for item in row:
|
|
@@ -99,4 +99,4 @@ class Language:
|
|
|
99
99
|
"zh",
|
|
100
100
|
}
|
|
101
101
|
if language is not None and language.a2 not in valid:
|
|
102
|
-
raise MnamerException("'lang' must be one of
|
|
102
|
+
raise MnamerException(f"'lang' must be one of {','.join(valid)}")
|
|
@@ -3,8 +3,9 @@ from __future__ import annotations
|
|
|
3
3
|
import dataclasses
|
|
4
4
|
import datetime as dt
|
|
5
5
|
import re
|
|
6
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
6
7
|
from string import Formatter
|
|
7
|
-
from typing import Any
|
|
8
|
+
from typing import Any
|
|
8
9
|
|
|
9
10
|
from mnamer.language import Language
|
|
10
11
|
from mnamer.types import MediaType
|
|
@@ -4,8 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import datetime as dt
|
|
6
6
|
from abc import ABC, abstractmethod
|
|
7
|
+
from collections.abc import Iterator
|
|
7
8
|
from os import environ
|
|
8
|
-
from typing import Iterator
|
|
9
9
|
|
|
10
10
|
from mnamer.endpoints import (
|
|
11
11
|
omdb_search,
|
|
@@ -242,8 +242,7 @@ class Tvdb(Provider):
|
|
|
242
242
|
)
|
|
243
243
|
else:
|
|
244
244
|
raise MnamerNotFoundException
|
|
245
|
-
|
|
246
|
-
yield result
|
|
245
|
+
yield from results
|
|
247
246
|
|
|
248
247
|
def _search_id(
|
|
249
248
|
self,
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import dataclasses
|
|
2
2
|
import json
|
|
3
|
+
from collections.abc import Callable
|
|
3
4
|
from pathlib import Path
|
|
4
|
-
from typing import Any
|
|
5
|
+
from typing import Any
|
|
5
6
|
|
|
6
7
|
from mnamer.argument import ArgLoader
|
|
7
8
|
from mnamer.const import SUBTITLE_CONTAINERS
|
|
@@ -424,7 +425,7 @@ class SettingStore:
|
|
|
424
425
|
try:
|
|
425
426
|
arguments = arg_loader.load()
|
|
426
427
|
except RuntimeError as e:
|
|
427
|
-
raise MnamerException(e)
|
|
428
|
+
raise MnamerException(e) from e
|
|
428
429
|
config_path = arguments.get("config_path", crawl_out(".mnamer-v2.json"))
|
|
429
430
|
config = json_loads(str(config_path)) if config_path else {}
|
|
430
431
|
if not self.config_ignore and not arguments.get("config_ignore"):
|
|
@@ -447,4 +448,4 @@ class SettingStore:
|
|
|
447
448
|
|
|
448
449
|
def formatting_for(self, media: MediaType | Metadata) -> str:
|
|
449
450
|
"""Returns the formatting string for a given media type or metadata."""
|
|
450
|
-
return getattr(self, f"{
|
|
451
|
+
return getattr(self, f"{media.to_media_type().value}_format")
|
|
@@ -4,7 +4,7 @@ import datetime as dt
|
|
|
4
4
|
from os import path
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
from shutil import move
|
|
7
|
-
from typing import Any, ClassVar
|
|
7
|
+
from typing import Any, ClassVar
|
|
8
8
|
|
|
9
9
|
from guessit import guessit # type: ignore
|
|
10
10
|
|
|
@@ -58,7 +58,7 @@ class Target:
|
|
|
58
58
|
return str(self.source)
|
|
59
59
|
|
|
60
60
|
@classmethod
|
|
61
|
-
def populate_paths(cls:
|
|
61
|
+
def populate_paths(cls: type[Target], settings: SettingStore) -> list[Target]:
|
|
62
62
|
"""Creates a list of Target objects for media files found in paths."""
|
|
63
63
|
file_paths = crawl_in(settings.targets, settings.recurse)
|
|
64
64
|
file_paths = filter_blacklist(file_paths, settings.ignore)
|
|
@@ -132,9 +132,9 @@ class Target:
|
|
|
132
132
|
path_data[k] = Language.parse(v)
|
|
133
133
|
except MnamerException:
|
|
134
134
|
continue
|
|
135
|
-
elif isinstance(v,
|
|
135
|
+
elif isinstance(v, int | str | dt.date):
|
|
136
136
|
path_data[k] = v
|
|
137
|
-
elif isinstance(v, list) and all(
|
|
137
|
+
elif isinstance(v, list) and all(isinstance(_, int | str) for _ in v):
|
|
138
138
|
path_data[k] = v[0]
|
|
139
139
|
if self._settings.media:
|
|
140
140
|
media_type = self._settings.media
|
|
@@ -244,5 +244,5 @@ class Target:
|
|
|
244
244
|
destination_path.parent.mkdir(parents=True, exist_ok=True)
|
|
245
245
|
try:
|
|
246
246
|
move(str(self.source), destination_path)
|
|
247
|
-
except OSError: # pragma: no cover
|
|
248
|
-
raise MnamerException
|
|
247
|
+
except OSError as e: # pragma: no cover
|
|
248
|
+
raise MnamerException from e
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"""Provides an interface for handling user input and printing output."""
|
|
2
2
|
|
|
3
3
|
import traceback
|
|
4
|
-
from
|
|
4
|
+
from collections.abc import Callable
|
|
5
|
+
from typing import Any
|
|
5
6
|
|
|
6
7
|
from teletype import codes
|
|
7
8
|
from teletype.components import ChoiceHelper, SelectOne
|
|
@@ -28,9 +29,9 @@ def _chars() -> dict[str, str]:
|
|
|
28
29
|
return chars
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
def _abort_helpers() ->
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
def _abort_helpers() -> tuple[
|
|
33
|
+
ChoiceHelper[MnamerSkipException], ChoiceHelper[MnamerAbortException]
|
|
34
|
+
]:
|
|
34
35
|
if no_style:
|
|
35
36
|
style = None
|
|
36
37
|
skip_mnemonic = "[s]"
|
|
@@ -90,7 +91,7 @@ def metadata_prompt(matches: list[Metadata]) -> Metadata: # pragma: no cover
|
|
|
90
91
|
msg("select match")
|
|
91
92
|
selector = SelectOne([*matches, *_abort_helpers()], **_chars())
|
|
92
93
|
choice = selector.prompt()
|
|
93
|
-
if isinstance(choice,
|
|
94
|
+
if isinstance(choice, MnamerAbortException | MnamerSkipException):
|
|
94
95
|
raise choice
|
|
95
96
|
return choice
|
|
96
97
|
|
|
@@ -105,7 +106,7 @@ def metadata_guess(metadata: Metadata) -> Metadata: # pragma: no cover
|
|
|
105
106
|
option = ChoiceHelper(metadata, label)
|
|
106
107
|
selector = SelectOne([option, *_abort_helpers()], **_chars())
|
|
107
108
|
choice = selector.prompt()
|
|
108
|
-
if isinstance(choice,
|
|
109
|
+
if isinstance(choice, MnamerAbortException | MnamerSkipException):
|
|
109
110
|
raise choice
|
|
110
111
|
else:
|
|
111
112
|
return choice
|
|
@@ -116,7 +117,7 @@ def subtitle_prompt() -> Language:
|
|
|
116
117
|
choices = [ChoiceHelper(language, language.name) for language in Language.all()]
|
|
117
118
|
selector = SelectOne([*choices, *_abort_helpers()], **_chars())
|
|
118
119
|
choice = selector.prompt()
|
|
119
|
-
if isinstance(choice,
|
|
120
|
+
if isinstance(choice, MnamerAbortException | MnamerSkipException):
|
|
120
121
|
raise choice
|
|
121
122
|
else:
|
|
122
123
|
return choice
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"""Enum type definitions."""
|
|
2
|
+
|
|
2
3
|
from __future__ import annotations
|
|
3
4
|
|
|
4
5
|
from enum import Enum
|
|
5
|
-
from typing import Type
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class MediaType(Enum):
|
|
@@ -10,7 +10,7 @@ class MediaType(Enum):
|
|
|
10
10
|
MOVIE = "movie"
|
|
11
11
|
|
|
12
12
|
@classmethod
|
|
13
|
-
def to_media_type(cls) ->
|
|
13
|
+
def to_media_type(cls) -> type[MediaType]:
|
|
14
14
|
return cls
|
|
15
15
|
|
|
16
16
|
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
import datetime as dt
|
|
4
4
|
import json
|
|
5
5
|
import re
|
|
6
|
+
from collections.abc import Callable, Iterator
|
|
6
7
|
from os import walk
|
|
7
8
|
from os.path import exists, expanduser, expandvars, getsize, splitdrive, splitext
|
|
8
9
|
from pathlib import Path, PurePath
|
|
9
|
-
from typing import Any
|
|
10
|
+
from typing import Any
|
|
10
11
|
from unicodedata import normalize
|
|
11
12
|
|
|
12
13
|
import requests_cache
|
|
@@ -43,7 +44,7 @@ def crawl_in(file_paths: list[Path], recurse: bool = False) -> list[Path]:
|
|
|
43
44
|
found_files.add(Path(root, file).absolute())
|
|
44
45
|
if not recurse:
|
|
45
46
|
break
|
|
46
|
-
return sorted(
|
|
47
|
+
return sorted(found_files)
|
|
47
48
|
|
|
48
49
|
|
|
49
50
|
def crawl_out(filename: str | Path | PurePath) -> Path | None:
|
|
@@ -157,23 +158,22 @@ def get_session() -> requests_cache.CachedSession:
|
|
|
157
158
|
return session
|
|
158
159
|
|
|
159
160
|
if hasattr(get_session, "session"):
|
|
160
|
-
session: requests_cache.CachedSession =
|
|
161
|
+
session: requests_cache.CachedSession = get_session.session # type: ignore[attr-defined]
|
|
161
162
|
return session
|
|
162
163
|
session = make_session()
|
|
163
|
-
|
|
164
|
+
get_session.session = session # type: ignore[attr-defined]
|
|
164
165
|
return session
|
|
165
166
|
|
|
166
167
|
|
|
167
168
|
def get_filesize(path: Path) -> str:
|
|
168
169
|
"""Returns the human-readable filesize for a given path."""
|
|
169
170
|
size = float(getsize(path))
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
171
|
+
units = ["B", "KB", "MB", "GB", "TB"]
|
|
172
|
+
for i, unit in enumerate(units):
|
|
173
|
+
if size < 1024.0 or i == len(units) - 1:
|
|
174
|
+
return f"{size:.{2}f}{unit}"
|
|
173
175
|
size /= 1024.0
|
|
174
|
-
|
|
175
|
-
return "undetermined size"
|
|
176
|
-
return f"{size:.{2}f}{unit}"
|
|
176
|
+
return "undetermined size"
|
|
177
177
|
|
|
178
178
|
|
|
179
179
|
def json_dumps(d: dict[str, Any]) -> str:
|
|
@@ -194,7 +194,7 @@ def json_loads(path: str) -> dict[str, Any]:
|
|
|
194
194
|
path = expanduser(path)
|
|
195
195
|
path = expandvars(path)
|
|
196
196
|
if exists(path):
|
|
197
|
-
with open(path
|
|
197
|
+
with open(path) as fp:
|
|
198
198
|
json_data = fp.read()
|
|
199
199
|
return json.loads(json_data) if json_data else {}
|
|
200
200
|
|
|
@@ -242,7 +242,7 @@ def request_json(
|
|
|
242
242
|
if isinstance(headers, dict):
|
|
243
243
|
headers = clean_dict(headers)
|
|
244
244
|
else:
|
|
245
|
-
headers =
|
|
245
|
+
headers = {}
|
|
246
246
|
if isinstance(parameters, dict):
|
|
247
247
|
parameters = [(k, v) for k, v in clean_dict(parameters).items()]
|
|
248
248
|
if body:
|
|
@@ -269,7 +269,7 @@ def request_json(
|
|
|
269
269
|
)
|
|
270
270
|
status = response.status_code
|
|
271
271
|
content = response.json() if status // 100 == 2 else None
|
|
272
|
-
except:
|
|
272
|
+
except Exception:
|
|
273
273
|
content = None
|
|
274
274
|
status = 500
|
|
275
275
|
finally:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: mnamer
|
|
3
|
-
Version: 2.5.6.
|
|
3
|
+
Version: 2.5.6.dev8
|
|
4
4
|
Summary: A command-line utility for organizing media files.
|
|
5
5
|
Author-email: Jessy Williams <jessy@jessywilliams.com>
|
|
6
6
|
Maintainer-email: Jessy Williams <jessy@jessywilliams.com>
|
|
@@ -27,16 +27,24 @@ License: MIT License
|
|
|
27
27
|
SOFTWARE.
|
|
28
28
|
|
|
29
29
|
Project-URL: repository, https://github.com/jkwill87/mnamer
|
|
30
|
-
Requires-Python: >=3.
|
|
30
|
+
Requires-Python: >=3.12
|
|
31
31
|
Description-Content-Type: text/markdown
|
|
32
|
-
Provides-Extra: dev
|
|
33
32
|
License-File: LICENSE.txt
|
|
33
|
+
Requires-Dist: appdirs>=1.4.4
|
|
34
|
+
Requires-Dist: babelfish>=0.6.0
|
|
35
|
+
Requires-Dist: guessit>=3.8.0
|
|
36
|
+
Requires-Dist: requests>=2.32.0
|
|
37
|
+
Requires-Dist: requests-cache~=0.9.8
|
|
38
|
+
Requires-Dist: setuptools-scm>=8.0.0
|
|
39
|
+
Requires-Dist: teletype>=1.3.4
|
|
40
|
+
Requires-Dist: typing-extensions>=4.7.0
|
|
41
|
+
Dynamic: license-file
|
|
34
42
|
|
|
35
43
|
[](https://pypi.python.org/pypi/mnamer)
|
|
36
44
|
[](https://github.com/jkwill87/mnamer/actions/workflows/push.yml?query=branch:main)
|
|
37
45
|
[](https://codecov.io/gh/jkwill87/mnamer)
|
|
38
46
|
[](https://en.wikipedia.org/wiki/MIT_License)
|
|
39
|
-
[](https://github.com/astral-sh/ruff)
|
|
40
48
|
|
|
41
49
|
<img src="https://github.com/jkwill87/mnamer/raw/main/assets/logo.png" width="450"/>
|
|
42
50
|
|
|
@@ -54,7 +62,7 @@ Check out the [wiki page](https://github.com/jkwill87/mnamer/wiki) for more deta
|
|
|
54
62
|
|
|
55
63
|
💾 [**Installation**](https://github.com/jkwill87/mnamer/wiki/Installation)
|
|
56
64
|
|
|
57
|
-
`$ pip3 install --user mnamer`
|
|
65
|
+
`$ uv tool install mnamer` or `$ pip3 install --user mnamer`
|
|
58
66
|
|
|
59
67
|
🤖 [**Automation**](https://github.com/jkwill87/mnamer/wiki/Automation)
|
|
60
68
|
|
|
@@ -124,6 +132,6 @@ Parameters can either by entered as command line arguments or from a config file
|
|
|
124
132
|
|
|
125
133
|
## Contributions
|
|
126
134
|
|
|
127
|
-
Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [
|
|
135
|
+
Community contributions are a welcome addition to the project. In order to be merged upsteam any additions will need to be formatted with [ruff](https://docs.astral.sh/ruff/) for consistency with the rest of the project and pass the continuous integration tests run against each PR. Before introducing any major features or changes to the configuration api please consider opening [an issue](https://github.com/jkwill87/mnamer/issues) to outline your proposal.
|
|
128
136
|
|
|
129
137
|
Bug reports are also welcome on the [issue page](https://github.com/jkwill87/mnamer/issues). Please include any generated crash reports if applicable. Feature requests are welcome but consider checking out [if it is in the works](https://github.com/jkwill87/mnamer/issues?q=label%3Arequest) first to avoid duplication.
|