avmc 0.1.0__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.
avmc-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,105 @@
1
+ Metadata-Version: 2.4
2
+ Name: avmc
3
+ Version: 0.1.0
4
+ Summary: Standalone AV metadata capture tool
5
+ Author: BossaMelon
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: requests>=2.31
9
+ Requires-Dist: beautifulsoup4>=4.12
10
+ Requires-Dist: lxml>=5.0
11
+ Requires-Dist: Pillow>=10.0
12
+
13
+ # AVMC
14
+
15
+ A standalone AV metadata capture tool (current source: `javbus`) with a clean pipeline.
16
+
17
+ ## Features
18
+ - Accepts a single video file or a directory path.
19
+ - If a directory is provided, recursively scans video files and processes them one by one.
20
+ - Detects subtitle-style filenames and appends `-C` to output names.
21
+ - Organizes output as `success_output_folder/Actor1,Actor2,Actor3/Number` (or `success_output_folder/Number` when no actor).
22
+ - Optional subtitle badge on poster image.
23
+ - Uses local `config.json` by default; no dependency on parent project config.
24
+
25
+ ## Project Structure
26
+ - `main.py`: CLI entry
27
+ - `pipeline.py`: scan + process pipeline
28
+ - `sources/javbus.py`: metadata scraper
29
+ - `io_ops.py`: image download/crop/badge, NFO writing, file move
30
+ - `config.json`: runtime config
31
+
32
+ ## Installation
33
+ ```bash
34
+ cd avmc
35
+ pip install -r requirements.txt
36
+ ```
37
+
38
+ ## Usage
39
+ Run as module:
40
+ ```bash
41
+ python -m avmc /path/to/video_or_dir
42
+ ```
43
+
44
+ Run as script:
45
+ ```bash
46
+ python avmc/main.py /path/to/video_or_dir
47
+ ```
48
+
49
+ Options:
50
+ - `-c, --config`: config file path (default: `avmc/config.json`)
51
+ - `-p, --proxy`: temporary proxy override (higher priority than config/env)
52
+ - `--debug`: dump raw HTML to `.adc_debug/`; keep source video in place and create a symlink in output
53
+
54
+ ## Config
55
+ Default config file: `avmc/config.json`
56
+
57
+ ```json
58
+ {
59
+ "success_output_folder": "output",
60
+ "failed": {
61
+ "move_enabled": false,
62
+ "output_folder": "failed"
63
+ },
64
+ "proxy": {
65
+ "proxy": "",
66
+ "timeout": 10,
67
+ "retry": 3
68
+ },
69
+ "javbus": {
70
+ "cookie": "existmag=all"
71
+ },
72
+ "scan": {
73
+ "escape_folders": ["output"]
74
+ },
75
+ "subtitle_badge": {
76
+ "enabled": true,
77
+ "backup_enabled": true
78
+ },
79
+ "image": {
80
+ "jpeg_quality": 85,
81
+ "optimize": true,
82
+ "progressive": true
83
+ }
84
+ }
85
+ ```
86
+
87
+ ## Subtitle Detection
88
+ Subtitle flag is inferred from filename patterns (case-insensitive), including compact forms like:
89
+ - `ABC123C`
90
+ - `ABC123CH`
91
+ - `ABC123CHS`
92
+ - `ABC123CHT`
93
+
94
+ When detected:
95
+ - output number becomes `NUMBER-C`
96
+ - NFO adds `中文字幕` tag/genre
97
+ - poster badge can be applied when enabled
98
+
99
+ ## Notes
100
+ - If scraping fails, source video is kept in place by default.
101
+ - Set `failed.move_enabled=true` to move failed files into `failed.output_folder`.
102
+ - Image host may return 403 depending on network/proxy/cookie status.
103
+
104
+ ## Development
105
+ - See `AGENTS.md` for coding-agent execution rules in this folder.
avmc-0.1.0/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # AVMC
2
+
3
+ A standalone AV metadata capture tool (current source: `javbus`) with a clean pipeline.
4
+
5
+ ## Features
6
+ - Accepts a single video file or a directory path.
7
+ - If a directory is provided, recursively scans video files and processes them one by one.
8
+ - Detects subtitle-style filenames and appends `-C` to output names.
9
+ - Organizes output as `success_output_folder/Actor1,Actor2,Actor3/Number` (or `success_output_folder/Number` when no actor).
10
+ - Optional subtitle badge on poster image.
11
+ - Uses local `config.json` by default; no dependency on parent project config.
12
+
13
+ ## Project Structure
14
+ - `main.py`: CLI entry
15
+ - `pipeline.py`: scan + process pipeline
16
+ - `sources/javbus.py`: metadata scraper
17
+ - `io_ops.py`: image download/crop/badge, NFO writing, file move
18
+ - `config.json`: runtime config
19
+
20
+ ## Installation
21
+ ```bash
22
+ cd avmc
23
+ pip install -r requirements.txt
24
+ ```
25
+
26
+ ## Usage
27
+ Run as module:
28
+ ```bash
29
+ python -m avmc /path/to/video_or_dir
30
+ ```
31
+
32
+ Run as script:
33
+ ```bash
34
+ python avmc/main.py /path/to/video_or_dir
35
+ ```
36
+
37
+ Options:
38
+ - `-c, --config`: config file path (default: `avmc/config.json`)
39
+ - `-p, --proxy`: temporary proxy override (higher priority than config/env)
40
+ - `--debug`: dump raw HTML to `.adc_debug/`; keep source video in place and create a symlink in output
41
+
42
+ ## Config
43
+ Default config file: `avmc/config.json`
44
+
45
+ ```json
46
+ {
47
+ "success_output_folder": "output",
48
+ "failed": {
49
+ "move_enabled": false,
50
+ "output_folder": "failed"
51
+ },
52
+ "proxy": {
53
+ "proxy": "",
54
+ "timeout": 10,
55
+ "retry": 3
56
+ },
57
+ "javbus": {
58
+ "cookie": "existmag=all"
59
+ },
60
+ "scan": {
61
+ "escape_folders": ["output"]
62
+ },
63
+ "subtitle_badge": {
64
+ "enabled": true,
65
+ "backup_enabled": true
66
+ },
67
+ "image": {
68
+ "jpeg_quality": 85,
69
+ "optimize": true,
70
+ "progressive": true
71
+ }
72
+ }
73
+ ```
74
+
75
+ ## Subtitle Detection
76
+ Subtitle flag is inferred from filename patterns (case-insensitive), including compact forms like:
77
+ - `ABC123C`
78
+ - `ABC123CH`
79
+ - `ABC123CHS`
80
+ - `ABC123CHT`
81
+
82
+ When detected:
83
+ - output number becomes `NUMBER-C`
84
+ - NFO adds `中文字幕` tag/genre
85
+ - poster badge can be applied when enabled
86
+
87
+ ## Notes
88
+ - If scraping fails, source video is kept in place by default.
89
+ - Set `failed.move_enabled=true` to move failed files into `failed.output_folder`.
90
+ - Image host may return 403 depending on network/proxy/cookie status.
91
+
92
+ ## Development
93
+ - See `AGENTS.md` for coding-agent execution rules in this folder.
avmc-0.1.0/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+ """Clean implementation for AV Data Capture."""
2
+
3
+ from .main import run
4
+
5
+ __all__ = ["run"]
avmc-0.1.0/__main__.py ADDED
@@ -0,0 +1,5 @@
1
+ from avmc.main import main
2
+
3
+
4
+ if __name__ == "__main__":
5
+ main()
@@ -0,0 +1,105 @@
1
+ Metadata-Version: 2.4
2
+ Name: avmc
3
+ Version: 0.1.0
4
+ Summary: Standalone AV metadata capture tool
5
+ Author: BossaMelon
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: requests>=2.31
9
+ Requires-Dist: beautifulsoup4>=4.12
10
+ Requires-Dist: lxml>=5.0
11
+ Requires-Dist: Pillow>=10.0
12
+
13
+ # AVMC
14
+
15
+ A standalone AV metadata capture tool (current source: `javbus`) with a clean pipeline.
16
+
17
+ ## Features
18
+ - Accepts a single video file or a directory path.
19
+ - If a directory is provided, recursively scans video files and processes them one by one.
20
+ - Detects subtitle-style filenames and appends `-C` to output names.
21
+ - Organizes output as `success_output_folder/Actor1,Actor2,Actor3/Number` (or `success_output_folder/Number` when no actor).
22
+ - Optional subtitle badge on poster image.
23
+ - Uses local `config.json` by default; no dependency on parent project config.
24
+
25
+ ## Project Structure
26
+ - `main.py`: CLI entry
27
+ - `pipeline.py`: scan + process pipeline
28
+ - `sources/javbus.py`: metadata scraper
29
+ - `io_ops.py`: image download/crop/badge, NFO writing, file move
30
+ - `config.json`: runtime config
31
+
32
+ ## Installation
33
+ ```bash
34
+ cd avmc
35
+ pip install -r requirements.txt
36
+ ```
37
+
38
+ ## Usage
39
+ Run as module:
40
+ ```bash
41
+ python -m avmc /path/to/video_or_dir
42
+ ```
43
+
44
+ Run as script:
45
+ ```bash
46
+ python avmc/main.py /path/to/video_or_dir
47
+ ```
48
+
49
+ Options:
50
+ - `-c, --config`: config file path (default: `avmc/config.json`)
51
+ - `-p, --proxy`: temporary proxy override (higher priority than config/env)
52
+ - `--debug`: dump raw HTML to `.adc_debug/`; keep source video in place and create a symlink in output
53
+
54
+ ## Config
55
+ Default config file: `avmc/config.json`
56
+
57
+ ```json
58
+ {
59
+ "success_output_folder": "output",
60
+ "failed": {
61
+ "move_enabled": false,
62
+ "output_folder": "failed"
63
+ },
64
+ "proxy": {
65
+ "proxy": "",
66
+ "timeout": 10,
67
+ "retry": 3
68
+ },
69
+ "javbus": {
70
+ "cookie": "existmag=all"
71
+ },
72
+ "scan": {
73
+ "escape_folders": ["output"]
74
+ },
75
+ "subtitle_badge": {
76
+ "enabled": true,
77
+ "backup_enabled": true
78
+ },
79
+ "image": {
80
+ "jpeg_quality": 85,
81
+ "optimize": true,
82
+ "progressive": true
83
+ }
84
+ }
85
+ ```
86
+
87
+ ## Subtitle Detection
88
+ Subtitle flag is inferred from filename patterns (case-insensitive), including compact forms like:
89
+ - `ABC123C`
90
+ - `ABC123CH`
91
+ - `ABC123CHS`
92
+ - `ABC123CHT`
93
+
94
+ When detected:
95
+ - output number becomes `NUMBER-C`
96
+ - NFO adds `中文字幕` tag/genre
97
+ - poster badge can be applied when enabled
98
+
99
+ ## Notes
100
+ - If scraping fails, source video is kept in place by default.
101
+ - Set `failed.move_enabled=true` to move failed files into `failed.output_folder`.
102
+ - Image host may return 403 depending on network/proxy/cookie status.
103
+
104
+ ## Development
105
+ - See `AGENTS.md` for coding-agent execution rules in this folder.
@@ -0,0 +1,38 @@
1
+ README.md
2
+ __init__.py
3
+ __main__.py
4
+ config.json
5
+ context.py
6
+ http_client.py
7
+ io_ops.py
8
+ main.py
9
+ models.py
10
+ numbering.py
11
+ pipeline.py
12
+ pyproject.toml
13
+ settings.py
14
+ ./__init__.py
15
+ ./__main__.py
16
+ ./config.json
17
+ ./context.py
18
+ ./http_client.py
19
+ ./io_ops.py
20
+ ./main.py
21
+ ./models.py
22
+ ./numbering.py
23
+ ./pipeline.py
24
+ ./settings.py
25
+ avmc.egg-info/PKG-INFO
26
+ avmc.egg-info/SOURCES.txt
27
+ avmc.egg-info/dependency_links.txt
28
+ avmc.egg-info/entry_points.txt
29
+ avmc.egg-info/requires.txt
30
+ avmc.egg-info/top_level.txt
31
+ sources/__init__.py
32
+ sources/base.py
33
+ sources/javbus.py
34
+ tests/test_io_ops.py
35
+ tests/test_javbus.py
36
+ tests/test_nfo.py
37
+ tests/test_numbering.py
38
+ tests/test_pipeline.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ avmc = avmc.main:main
@@ -0,0 +1,4 @@
1
+ requests>=2.31
2
+ beautifulsoup4>=4.12
3
+ lxml>=5.0
4
+ Pillow>=10.0
@@ -0,0 +1 @@
1
+ avmc
avmc-0.1.0/config.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "success_output_folder": "output",
3
+ "failed": {
4
+ "move_enabled": false,
5
+ "output_folder": "failed"
6
+ },
7
+ "proxy": {
8
+ "proxy": "",
9
+ "timeout": 10,
10
+ "retry": 3
11
+ },
12
+ "javbus": {
13
+ "cookie": "existmag=all"
14
+ },
15
+ "scan": {
16
+ "escape_folders": [
17
+ "output"
18
+ ]
19
+ },
20
+ "subtitle_badge": {
21
+ "enabled": true,
22
+ "backup_enabled": true
23
+ },
24
+ "image": {
25
+ "jpeg_quality": 85,
26
+ "optimize": true,
27
+ "progressive": true
28
+ }
29
+ }
avmc-0.1.0/context.py ADDED
@@ -0,0 +1,38 @@
1
+ from dataclasses import dataclass
2
+ import os
3
+ from pathlib import Path
4
+
5
+ from .http_client import HttpClient
6
+ from .settings import AppConfig
7
+
8
+
9
+ @dataclass
10
+ class AppContext:
11
+ config: AppConfig
12
+ http: HttpClient
13
+ debug: bool = False
14
+ debug_dir: Path = Path(".adc_debug")
15
+
16
+
17
+ def build_context(config_path: str, proxy_override: str | None = None, debug: bool = False) -> AppContext:
18
+ conf = AppConfig.from_path(config_path)
19
+ proxy_from_config, timeout, retry = conf.proxy()
20
+
21
+ if proxy_override is not None:
22
+ proxy = proxy_override.strip()
23
+ else:
24
+ proxy = _env_https_proxy() or proxy_from_config
25
+
26
+ http = HttpClient(proxy=proxy, timeout=timeout, retry=retry)
27
+ ctx = AppContext(config=conf, http=http, debug=debug)
28
+ if ctx.debug:
29
+ ctx.debug_dir.mkdir(parents=True, exist_ok=True)
30
+ return ctx
31
+
32
+
33
+ def _env_https_proxy() -> str | None:
34
+ value = os.getenv("https_proxy") or os.getenv("HTTPS_PROXY")
35
+ if value is None:
36
+ return None
37
+ value = value.strip()
38
+ return value if value else None
@@ -0,0 +1,60 @@
1
+ import requests
2
+
3
+
4
+ class HttpClient:
5
+ def __init__(self, proxy: str, timeout: int, retry: int):
6
+ self.proxy = proxy
7
+ self.timeout = timeout
8
+ self.retry = retry
9
+ self.proxies = _build_proxies(proxy)
10
+ self.session = requests.Session()
11
+
12
+ def get_text(self, url: str, headers: dict | None = None, cookies: dict | None = None) -> str:
13
+ resp = self.get_response(url, headers=headers, cookies=cookies)
14
+ resp.encoding = "utf-8"
15
+ return resp.text
16
+
17
+ def get_bytes(self, url: str, headers: dict | None = None, cookies: dict | None = None) -> bytes:
18
+ resp = self.get_response(url, headers=headers, cookies=cookies)
19
+ return resp.content
20
+
21
+ def get_response(self, url: str, headers: dict | None = None, cookies: dict | None = None) -> requests.Response:
22
+ return self._request("get", url, headers=headers, cookies=cookies)
23
+
24
+ def _request(
25
+ self,
26
+ method: str,
27
+ url: str,
28
+ headers: dict | None = None,
29
+ cookies: dict | None = None,
30
+ data: dict | None = None,
31
+ ) -> requests.Response:
32
+ last_error = None
33
+ for i in range(self.retry):
34
+ try:
35
+ resp = self.session.request(
36
+ method=method,
37
+ url=url,
38
+ timeout=self.timeout,
39
+ headers=headers,
40
+ cookies=cookies,
41
+ data=data,
42
+ proxies=self.proxies,
43
+ )
44
+ resp.raise_for_status()
45
+ return resp
46
+ except requests.RequestException as err:
47
+ last_error = err
48
+ print(f"[-] Connect retry {i + 1}/{self.retry}: {err}")
49
+ raise RuntimeError(f"Request failed: {method.upper()} {url}") from last_error
50
+
51
+
52
+ def _build_proxies(proxy: str | None) -> dict[str, str] | None:
53
+ if not proxy:
54
+ return None
55
+ proxy_value = proxy.strip()
56
+ if not proxy_value:
57
+ return None
58
+ if "://" not in proxy_value:
59
+ proxy_value = f"http://{proxy_value}"
60
+ return {"http": proxy_value, "https": proxy_value}