flacfetch 0.15.3__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.
- flacfetch-0.15.3/ARCHITECTURE.md +97 -0
- flacfetch-0.15.3/LICENSE +22 -0
- flacfetch-0.15.3/MANIFEST.in +11 -0
- flacfetch-0.15.3/PKG-INFO +324 -0
- flacfetch-0.15.3/PLAN.md +118 -0
- flacfetch-0.15.3/README.md +252 -0
- flacfetch-0.15.3/flacfetch/__init__.py +30 -0
- flacfetch-0.15.3/flacfetch/api/__init__.py +17 -0
- flacfetch-0.15.3/flacfetch/api/auth.py +44 -0
- flacfetch-0.15.3/flacfetch/api/main.py +207 -0
- flacfetch-0.15.3/flacfetch/api/models.py +247 -0
- flacfetch-0.15.3/flacfetch/api/routes/__init__.py +19 -0
- flacfetch-0.15.3/flacfetch/api/routes/config.py +319 -0
- flacfetch-0.15.3/flacfetch/api/routes/credentials.py +66 -0
- flacfetch-0.15.3/flacfetch/api/routes/download.py +294 -0
- flacfetch-0.15.3/flacfetch/api/routes/health.py +288 -0
- flacfetch-0.15.3/flacfetch/api/routes/search.py +153 -0
- flacfetch-0.15.3/flacfetch/api/routes/torrents.py +227 -0
- flacfetch-0.15.3/flacfetch/api/services/__init__.py +36 -0
- flacfetch-0.15.3/flacfetch/api/services/credential_check.py +497 -0
- flacfetch-0.15.3/flacfetch/api/services/disk_manager.py +216 -0
- flacfetch-0.15.3/flacfetch/api/services/download_manager.py +562 -0
- flacfetch-0.15.3/flacfetch/api/services/search_cache.py +279 -0
- flacfetch-0.15.3/flacfetch/core/categorize.py +292 -0
- flacfetch-0.15.3/flacfetch/core/interfaces.py +68 -0
- flacfetch-0.15.3/flacfetch/core/log.py +17 -0
- flacfetch-0.15.3/flacfetch/core/manager.py +479 -0
- flacfetch-0.15.3/flacfetch/core/matching.py +53 -0
- flacfetch-0.15.3/flacfetch/core/models.py +319 -0
- flacfetch-0.15.3/flacfetch/downloaders/spotify.py +419 -0
- flacfetch-0.15.3/flacfetch/downloaders/torrent.py +356 -0
- flacfetch-0.15.3/flacfetch/downloaders/youtube.py +123 -0
- flacfetch-0.15.3/flacfetch/interface/cli.py +1680 -0
- flacfetch-0.15.3/flacfetch/interface/cli_remote.py +1585 -0
- flacfetch-0.15.3/flacfetch/providers/ops.py +484 -0
- flacfetch-0.15.3/flacfetch/providers/red.py +485 -0
- flacfetch-0.15.3/flacfetch/providers/spotify.py +251 -0
- flacfetch-0.15.3/flacfetch/providers/youtube.py +165 -0
- flacfetch-0.15.3/flacfetch.egg-info/PKG-INFO +324 -0
- flacfetch-0.15.3/flacfetch.egg-info/SOURCES.txt +68 -0
- flacfetch-0.15.3/flacfetch.egg-info/dependency_links.txt +1 -0
- flacfetch-0.15.3/flacfetch.egg-info/entry_points.txt +3 -0
- flacfetch-0.15.3/flacfetch.egg-info/requires.txt +48 -0
- flacfetch-0.15.3/flacfetch.egg-info/top_level.txt +1 -0
- flacfetch-0.15.3/pyproject.toml +161 -0
- flacfetch-0.15.3/requirements.txt +4 -0
- flacfetch-0.15.3/setup.cfg +4 -0
- flacfetch-0.15.3/setup.py +36 -0
- flacfetch-0.15.3/tests/test_api_auth.py +96 -0
- flacfetch-0.15.3/tests/test_api_config.py +315 -0
- flacfetch-0.15.3/tests/test_api_health_ytdlp.py +140 -0
- flacfetch-0.15.3/tests/test_api_integration.py +82 -0
- flacfetch-0.15.3/tests/test_api_models.py +267 -0
- flacfetch-0.15.3/tests/test_api_routes.py +152 -0
- flacfetch-0.15.3/tests/test_api_services.py +334 -0
- flacfetch-0.15.3/tests/test_cli_cookies.py +335 -0
- flacfetch-0.15.3/tests/test_cli_remote.py +159 -0
- flacfetch-0.15.3/tests/test_core.py +31 -0
- flacfetch-0.15.3/tests/test_logging.py +33 -0
- flacfetch-0.15.3/tests/test_manager.py +662 -0
- flacfetch-0.15.3/tests/test_matching.py +29 -0
- flacfetch-0.15.3/tests/test_models.py +186 -0
- flacfetch-0.15.3/tests/test_ops.py +207 -0
- flacfetch-0.15.3/tests/test_provider_errors.py +232 -0
- flacfetch-0.15.3/tests/test_red.py +226 -0
- flacfetch-0.15.3/tests/test_spotify.py +491 -0
- flacfetch-0.15.3/tests/test_torrent_downloader.py +152 -0
- flacfetch-0.15.3/tests/test_transcode_hf_noise.py +106 -0
- flacfetch-0.15.3/tests/test_youtube.py +214 -0
- flacfetch-0.15.3/tests/test_youtube_cookies.py +239 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# Architecture & Design
|
|
2
|
+
|
|
3
|
+
This document details the architectural decisions, component design, and key learnings from the development of **flacfetch**.
|
|
4
|
+
|
|
5
|
+
## 1. High-Level Architecture
|
|
6
|
+
|
|
7
|
+
The system follows **Clean Architecture** principles to decouple core logic from external providers and interfaces.
|
|
8
|
+
|
|
9
|
+
```mermaid
|
|
10
|
+
graph TD
|
|
11
|
+
CLI[CLI Adapter] --> Core
|
|
12
|
+
Lib[Library User] --> Core
|
|
13
|
+
|
|
14
|
+
subgraph Core
|
|
15
|
+
FM[FetchManager]
|
|
16
|
+
Models[Release, TrackQuery, Quality]
|
|
17
|
+
Interfaces[Provider, Downloader]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
FM --> Providers
|
|
21
|
+
FM --> Downloaders
|
|
22
|
+
|
|
23
|
+
subgraph Providers
|
|
24
|
+
RED[REDProvider]
|
|
25
|
+
YouTube[YoutubeProvider]
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
subgraph Downloaders
|
|
29
|
+
LibTorrent[TorrentDownloader]
|
|
30
|
+
YtDlp[YoutubeDownloader]
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Core Components
|
|
35
|
+
|
|
36
|
+
* **FetchManager**: The central orchestrator. It aggregates results from registered providers, applies sorting/prioritization logic, and delegates downloading.
|
|
37
|
+
* **Models**:
|
|
38
|
+
* `Release`: Unified representation of a search result. Abstracts away differences between a Torrent and a YouTube video. Contains metadata (Year, Label, Views) and download info.
|
|
39
|
+
* `Quality`: Value object representing format (FLAC/Opus/AAC), bitrate, and source media. Implements comparison logic (`__lt__`) for sorting.
|
|
40
|
+
* **Interfaces**:
|
|
41
|
+
* `Provider`: Abstract base class for search sources.
|
|
42
|
+
* `Downloader`: Abstract base class for download mechanisms.
|
|
43
|
+
|
|
44
|
+
## 2. Key Design Choices
|
|
45
|
+
|
|
46
|
+
### 2.1. Selective BitTorrent Downloading
|
|
47
|
+
**Challenge**: Private trackers usually organize content by **Album**, but users often want a single **Track**. Downloading a 500MB FLAC album for one 30MB song is inefficient.
|
|
48
|
+
**Solution**:
|
|
49
|
+
* **Search**: `REDProvider` uses the `filelist` API parameter to find torrents containing the specific track title.
|
|
50
|
+
* **Matching**: It parses the file list string (`filename{{{size}}}|||...`) to identify the exact target file index.
|
|
51
|
+
* **Download**: `TorrentDownloader` uses `libtorrent`'s `prioritize_files` API. It sets the target file priority to `7` (High) and all others to `0` (Skip), downloading only the necessary chunks.
|
|
52
|
+
|
|
53
|
+
### 2.2. Hybrid Prioritization Logic
|
|
54
|
+
**Challenge**: "Best" means different things for different sources.
|
|
55
|
+
* **RED**: "Best" = Original Release (Oldest), Lossless, Healthy (Seeders).
|
|
56
|
+
* **YouTube**: "Best" = Modern Codec (Newest), Official Source (Topic Channel), High Bitrate.
|
|
57
|
+
**Solution**:
|
|
58
|
+
The `FetchManager` implements a weighted sort key:
|
|
59
|
+
1. **Match Score**: Does the filename exactly match the query? (Crucial for filtering junk).
|
|
60
|
+
2. **Official Score**: (YouTube only) Is it a "Topic" channel or "Official Audio"? (Heavily boosted).
|
|
61
|
+
3. **Release Type**: (RED) Album > Single > EP.
|
|
62
|
+
4. **Health**: Seeders (RED) / Views (YouTube - implicitly handled via display).
|
|
63
|
+
5. **Quality**: Lossless > High Bitrate.
|
|
64
|
+
6. **Year (Contextual)**:
|
|
65
|
+
* *RED*: **Oldest First** (Prefer original pressings).
|
|
66
|
+
* *YouTube*: **Newest First** (Prefer modern Opus uploads over legacy 2011 AAC uploads).
|
|
67
|
+
|
|
68
|
+
### 2.3. YouTube Quality & Reliability
|
|
69
|
+
**Learnings**:
|
|
70
|
+
* **Metadata vs Reality**: YouTube metadata (via `yt-dlp`) can be misleading. Older videos might list "AAC" but provide very low bitrate (48kbps) streams even if `itag` suggests higher potential.
|
|
71
|
+
* **Bitrate Guessing**: Estimating bitrate from file size is dangerous for video containers. We switched to relying strictly on `abr` (Audio Bitrate) or known `itag` mapping (e.g., 251 -> Opus 130k).
|
|
72
|
+
* **Proxy for Quality**: Since accurate bitrate is hard to guarantee without downloading, we use **Upload Year** as a strong proxy. Videos uploaded post-2015 (and especially post-2020) almost always offer high-quality Opus streams. Pre-2015 uploads are often legacy AAC with lower fidelity.
|
|
73
|
+
* **Visuals**: The CLI color-codes the Year (Green > 2020, Red < 2015) instead of showing potentially inaccurate bitrate numbers, empowering the user to choose based on "Freshness".
|
|
74
|
+
|
|
75
|
+
### 2.4. Security: No Hardcoded URLs
|
|
76
|
+
**Design Decision**: Tracker API base URLs are **never** stored in the source code. Both `REDProvider` and `OPSProvider` require a `base_url` parameter that must be provided at runtime (typically via environment variables).
|
|
77
|
+
|
|
78
|
+
**Rationale**:
|
|
79
|
+
1. **Privacy**: Private trackers prefer their URLs not be publicly indexed.
|
|
80
|
+
2. **Safety**: Ensures test suites cannot accidentally hit real tracker APIs without proper mocking.
|
|
81
|
+
3. **Flexibility**: Allows easy switching between different tracker instances if needed.
|
|
82
|
+
|
|
83
|
+
## 3. Implementation Details
|
|
84
|
+
|
|
85
|
+
### RED Provider
|
|
86
|
+
* **Lazy Loading**: Fetching file lists for *every* search result is slow. We implemented a default search limit (20 groups) to prevent rate-limiting while still finding the best match.
|
|
87
|
+
* **Lossless Filter**: Hard-coded to only return `FLAC` results to ensure archival quality from trackers.
|
|
88
|
+
* **Base URL Required**: The `base_url` constructor parameter is mandatory; if not provided, an error is raised.
|
|
89
|
+
|
|
90
|
+
### YouTube Provider
|
|
91
|
+
* **Topic Search**: Appends "topic" to search queries to surface auto-generated "Art Tracks" (high quality, static image) which are preferred over user uploads.
|
|
92
|
+
* **URL Handling**: Constructs `youtu.be` short links for easy sharing/checking.
|
|
93
|
+
|
|
94
|
+
## 4. Future Improvements
|
|
95
|
+
* **Metadata Tagging**: Auto-tag downloaded files using MusicBrainz/Discogs.
|
|
96
|
+
* **Spectral Analysis**: Integrate `ffmpeg` or `sox` to verify frequency cutoffs post-download automatically.
|
|
97
|
+
|
flacfetch-0.15.3/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 FlacFetch Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flacfetch
|
|
3
|
+
Version: 0.15.3
|
|
4
|
+
Summary: Search and download high-quality audio from multiple sources
|
|
5
|
+
Home-page: https://github.com/yourusername/flacfetch
|
|
6
|
+
Author: Your Name
|
|
7
|
+
Author-email: Andrew Beveridge <andrew@beveridge.uk>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/nomadkaraoke/flacfetch
|
|
10
|
+
Project-URL: Repository, https://github.com/nomadkaraoke/flacfetch
|
|
11
|
+
Project-URL: Issues, https://github.com/nomadkaraoke/flacfetch/issues
|
|
12
|
+
Keywords: audio,music,flac,download,youtube,torrent
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
22
|
+
Classifier: Environment :: Console
|
|
23
|
+
Requires-Python: >=3.8
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: requests>=2.28.0
|
|
27
|
+
Requires-Dist: yt-dlp>=2023.0.0
|
|
28
|
+
Requires-Dist: transmission-rpc>=7.0.0
|
|
29
|
+
Provides-Extra: remote
|
|
30
|
+
Requires-Dist: httpx>=0.28.0; extra == "remote"
|
|
31
|
+
Requires-Dist: playwright>=1.40.0; extra == "remote"
|
|
32
|
+
Provides-Extra: api
|
|
33
|
+
Requires-Dist: fastapi>=0.115.0; extra == "api"
|
|
34
|
+
Requires-Dist: uvicorn[standard]>=0.24.0; extra == "api"
|
|
35
|
+
Requires-Dist: pydantic>=2.0.0; extra == "api"
|
|
36
|
+
Requires-Dist: httpx>=0.28.0; extra == "api"
|
|
37
|
+
Requires-Dist: google-cloud-storage>=2.13.0; extra == "api"
|
|
38
|
+
Requires-Dist: google-cloud-secret-manager>=2.16.0; extra == "api"
|
|
39
|
+
Provides-Extra: spotify
|
|
40
|
+
Requires-Dist: spotipy>=2.25.1; extra == "spotify"
|
|
41
|
+
Provides-Extra: ejs
|
|
42
|
+
Requires-Dist: yt-dlp-ejs>=0.3.0; extra == "ejs"
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "dev"
|
|
46
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
47
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
48
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
49
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
50
|
+
Requires-Dist: types-requests>=2.28.0; extra == "dev"
|
|
51
|
+
Provides-Extra: all
|
|
52
|
+
Requires-Dist: httpx>=0.28.0; extra == "all"
|
|
53
|
+
Requires-Dist: playwright>=1.40.0; extra == "all"
|
|
54
|
+
Requires-Dist: fastapi>=0.115.0; extra == "all"
|
|
55
|
+
Requires-Dist: uvicorn[standard]>=0.24.0; extra == "all"
|
|
56
|
+
Requires-Dist: pydantic>=2.0.0; extra == "all"
|
|
57
|
+
Requires-Dist: google-cloud-storage>=2.13.0; extra == "all"
|
|
58
|
+
Requires-Dist: google-cloud-secret-manager>=2.16.0; extra == "all"
|
|
59
|
+
Requires-Dist: spotipy>=2.25.1; extra == "all"
|
|
60
|
+
Requires-Dist: yt-dlp-ejs>=0.3.0; extra == "all"
|
|
61
|
+
Requires-Dist: pytest>=7.0.0; extra == "all"
|
|
62
|
+
Requires-Dist: pytest-mock>=3.10.0; extra == "all"
|
|
63
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "all"
|
|
64
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "all"
|
|
65
|
+
Requires-Dist: ruff>=0.1.0; extra == "all"
|
|
66
|
+
Requires-Dist: mypy>=1.0.0; extra == "all"
|
|
67
|
+
Requires-Dist: types-requests>=2.28.0; extra == "all"
|
|
68
|
+
Dynamic: author
|
|
69
|
+
Dynamic: home-page
|
|
70
|
+
Dynamic: license-file
|
|
71
|
+
Dynamic: requires-python
|
|
72
|
+
|
|
73
|
+
# flacfetch
|
|
74
|
+
|
|
75
|
+
[](https://pypi.org/project/flacfetch/)
|
|
76
|
+
[](https://pypi.org/project/flacfetch/)
|
|
77
|
+
[](https://github.com/nomadkaraoke/flacfetch/actions/workflows/test.yml)
|
|
78
|
+
[](https://codecov.io/gh/nomadkaraoke/flacfetch)
|
|
79
|
+
[](https://opensource.org/licenses/MIT)
|
|
80
|
+
|
|
81
|
+
**flacfetch** is a Python tool designed to search for and download high-quality audio files from various sources. It is optimized for finding specific tracks (songs) across both private music trackers and public sources, with intelligent prioritization of "Official" and "Original" releases.
|
|
82
|
+
|
|
83
|
+
## Features
|
|
84
|
+
|
|
85
|
+
- **Precise Track Search**:
|
|
86
|
+
- **Private Music Trackers**: RED and OPS (API integration). Uses advanced file list filtering to find specific songs within album torrents, downloading only the required track.
|
|
87
|
+
- **Streaming Services**: Spotify (via `librespot`, requires Premium account) - CD Quality FLAC (44.1kHz/16-bit).
|
|
88
|
+
- **Public Sources**: YouTube (via `yt-dlp`).
|
|
89
|
+
- **Smart Prioritization**:
|
|
90
|
+
- **Official Sources**: Automatically prioritizes "Topic" channels and "Official Audio" on YouTube. Spotify results are always from official sources.
|
|
91
|
+
- **Quality Heuristics**:
|
|
92
|
+
- **Trackers (RED/OPS)**: Prioritizes Lossless (FLAC) and healthy torrents (Seeders). Matches filename exactly to your query.
|
|
93
|
+
- **Spotify**: CD-quality FLAC (44.1kHz/16-bit) via librespot capture. Prioritizes by popularity.
|
|
94
|
+
- **YouTube**: Prioritizes newer uploads (Opus codec) over legacy uploads (AAC). Color-codes upload years to help you spot modern, high-quality streams (Green: 2020+, Yellow: 2015-2019, Red: <2015).
|
|
95
|
+
- **Flexible Interaction**:
|
|
96
|
+
- **Interactive Mode**: Present search results to the user for manual selection with rich, color-coded metadata (Seeders, Views, Duration).
|
|
97
|
+
- **Automatic Mode**: Automatically select the highest ranked release.
|
|
98
|
+
- **Smart Downloading**:
|
|
99
|
+
- **Selective BitTorrent**: Uses Transmission daemon to download *only* the specific file matching your search query from larger album torrents (saving bandwidth).
|
|
100
|
+
- **Direct Downloads**: Handles HTTP/Stream downloads for public sources.
|
|
101
|
+
|
|
102
|
+
## Requirements
|
|
103
|
+
|
|
104
|
+
- Python 3.10+
|
|
105
|
+
- `requests`
|
|
106
|
+
- `yt-dlp`
|
|
107
|
+
- `transmission-rpc`
|
|
108
|
+
- **Transmission** (daemon) - *Required for BitTorrent downloads* (Optional if only using YouTube)
|
|
109
|
+
|
|
110
|
+
### Installing Transmission
|
|
111
|
+
|
|
112
|
+
Transmission is a lightweight, cross-platform BitTorrent client with RPC support.
|
|
113
|
+
|
|
114
|
+
- **Ubuntu/Debian**: `sudo apt install transmission-daemon`
|
|
115
|
+
- **macOS**: `brew install transmission-cli`
|
|
116
|
+
- **Windows**: Download from [transmissionbt.com](https://transmissionbt.com)
|
|
117
|
+
|
|
118
|
+
flacfetch will automatically start the transmission daemon if it's not running.
|
|
119
|
+
|
|
120
|
+
## Installation
|
|
121
|
+
|
|
122
|
+
### From PyPI (Recommended)
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
pip install flacfetch
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### From Source
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
git clone https://github.com/nomadkaraoke/flacfetch.git
|
|
132
|
+
cd flacfetch
|
|
133
|
+
pip install .
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Development Installation
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
git clone https://github.com/nomadkaraoke/flacfetch.git
|
|
140
|
+
cd flacfetch
|
|
141
|
+
pip install -e ".[dev]"
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Usage
|
|
145
|
+
|
|
146
|
+
### CLI Usage
|
|
147
|
+
|
|
148
|
+
**Standard Search (Artist - Title)**
|
|
149
|
+
```bash
|
|
150
|
+
flacfetch "Seether" "Tonight"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Explicit Arguments (Recommended for precision)**
|
|
154
|
+
```bash
|
|
155
|
+
flacfetch --artist "Seether" --title "Tonight"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Auto-download Highest Quality**
|
|
159
|
+
```bash
|
|
160
|
+
flacfetch --auto --artist "Seether" --title "Tonight"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Output Options**
|
|
164
|
+
```bash
|
|
165
|
+
# Specify output directory
|
|
166
|
+
flacfetch --artist "Seether" --title "Tonight" -o ~/Music
|
|
167
|
+
|
|
168
|
+
# Auto-rename to "ARTIST - TITLE.ext"
|
|
169
|
+
flacfetch --artist "Seether" --title "Tonight" --rename
|
|
170
|
+
|
|
171
|
+
# Specify exact filename
|
|
172
|
+
flacfetch --artist "Seether" --title "Tonight" --filename "my_song"
|
|
173
|
+
|
|
174
|
+
# Combine options
|
|
175
|
+
flacfetch --artist "Seether" --title "Tonight" -o ~/Music --rename
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Verbose Logging**
|
|
179
|
+
```bash
|
|
180
|
+
flacfetch -v "Seether" "Tonight"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Configuration**
|
|
184
|
+
|
|
185
|
+
To use private music trackers, you must provide both an API Key and API URL:
|
|
186
|
+
```bash
|
|
187
|
+
# RED
|
|
188
|
+
export RED_API_KEY="your_api_key_here"
|
|
189
|
+
export RED_API_URL="your_tracker_url_here"
|
|
190
|
+
# OR
|
|
191
|
+
flacfetch "..." --red-key "your_key" --red-url "your_url"
|
|
192
|
+
|
|
193
|
+
# OPS
|
|
194
|
+
export OPS_API_KEY="your_api_key_here"
|
|
195
|
+
export OPS_API_URL="your_tracker_url_here"
|
|
196
|
+
# OR
|
|
197
|
+
flacfetch "..." --ops-key "your_key" --ops-url "your_url"
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**Spotify Configuration** (Optional - requires Premium account)
|
|
201
|
+
|
|
202
|
+
Spotify provides CD-quality audio (44.1kHz/16-bit) captured via librespot and converted to FLAC. This uses the official Spotify Web API for authentication (OAuth) and librespot for audio capture.
|
|
203
|
+
|
|
204
|
+
**Prerequisites:**
|
|
205
|
+
- Spotify Premium account
|
|
206
|
+
- `librespot` binary: `brew install librespot` or `cargo install librespot`
|
|
207
|
+
- `ffmpeg` for audio conversion
|
|
208
|
+
|
|
209
|
+
**Setup:**
|
|
210
|
+
```bash
|
|
211
|
+
# 1. Install Spotify extra dependencies
|
|
212
|
+
pip install flacfetch[spotify]
|
|
213
|
+
|
|
214
|
+
# 2. Create a Spotify Developer App
|
|
215
|
+
# Go to: https://developer.spotify.com/dashboard
|
|
216
|
+
# Click "Create App"
|
|
217
|
+
# Set redirect URI to: http://127.0.0.1:8888/callback
|
|
218
|
+
# Note your Client ID and Client Secret
|
|
219
|
+
|
|
220
|
+
# 3. Set environment variables
|
|
221
|
+
export SPOTIPY_CLIENT_ID='your-client-id'
|
|
222
|
+
export SPOTIPY_CLIENT_SECRET='your-client-secret'
|
|
223
|
+
export SPOTIPY_REDIRECT_URI='http://127.0.0.1:8888/callback'
|
|
224
|
+
|
|
225
|
+
# 4. First run will open browser for OAuth login (token cached automatically)
|
|
226
|
+
flacfetch "Artist" "Title"
|
|
227
|
+
|
|
228
|
+
# Disable Spotify if needed
|
|
229
|
+
flacfetch "Artist" "Title" --no-spotify
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**How it works:**
|
|
233
|
+
1. Uses Spotify Web API (via spotipy) for search and playback control
|
|
234
|
+
2. Starts librespot as a Spotify Connect device with OAuth token
|
|
235
|
+
3. Triggers playback via Web API, captures raw PCM via pipe backend
|
|
236
|
+
4. Converts PCM to FLAC using ffmpeg
|
|
237
|
+
|
|
238
|
+
**Note:** The redirect URI must use `127.0.0.1` (not `localhost`) as per Spotify's updated security requirements.
|
|
239
|
+
|
|
240
|
+
**Provider Priority**
|
|
241
|
+
|
|
242
|
+
When multiple providers are configured, flacfetch searches them in priority order. By default: **RED > OPS > Spotify > YouTube**
|
|
243
|
+
|
|
244
|
+
This means RED is searched first, and only if it returns no results will OPS be searched, then Spotify, then YouTube. This prioritizes lossless sources first, then high-quality streaming.
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
# Use default priority (RED > OPS > Spotify > YouTube)
|
|
248
|
+
export RED_API_KEY="..."
|
|
249
|
+
export RED_API_URL="..."
|
|
250
|
+
export OPS_API_KEY="..."
|
|
251
|
+
export OPS_API_URL="..."
|
|
252
|
+
flacfetch "Artist" "Title" --auto
|
|
253
|
+
|
|
254
|
+
# Custom priority (e.g., prefer Spotify over trackers)
|
|
255
|
+
flacfetch "Artist" "Title" --provider-priority "Spotify,RED,OPS,YouTube"
|
|
256
|
+
|
|
257
|
+
# Or via environment variable
|
|
258
|
+
export FLACFETCH_PROVIDER_PRIORITY="OPS,RED,Spotify,YouTube"
|
|
259
|
+
flacfetch "Artist" "Title" --auto
|
|
260
|
+
|
|
261
|
+
# Disable fallback (only search highest priority provider)
|
|
262
|
+
flacfetch "Artist" "Title" --auto --no-fallback
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
### Library Usage
|
|
266
|
+
|
|
267
|
+
**Quick Example:**
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
from flacfetch.core.manager import FetchManager
|
|
271
|
+
from flacfetch.core.models import TrackQuery
|
|
272
|
+
from flacfetch.providers.red import REDProvider
|
|
273
|
+
from flacfetch.providers.ops import OPSProvider
|
|
274
|
+
from flacfetch.providers.spotify import SpotifyProvider # Optional
|
|
275
|
+
from flacfetch.downloaders.spotify import SpotifyDownloader # Optional
|
|
276
|
+
|
|
277
|
+
manager = FetchManager()
|
|
278
|
+
manager.add_provider(REDProvider(api_key="...", base_url="..."))
|
|
279
|
+
manager.add_provider(OPSProvider(api_key="...", base_url="..."))
|
|
280
|
+
|
|
281
|
+
# Spotify (requires SPOTIPY_CLIENT_ID, SPOTIPY_CLIENT_SECRET, SPOTIPY_REDIRECT_URI env vars)
|
|
282
|
+
spotify_provider = SpotifyProvider()
|
|
283
|
+
manager.add_provider(spotify_provider)
|
|
284
|
+
manager.register_downloader("Spotify", SpotifyDownloader(provider=spotify_provider))
|
|
285
|
+
|
|
286
|
+
# Search for a specific track
|
|
287
|
+
results = manager.search(TrackQuery(artist="Seether", title="Tonight"))
|
|
288
|
+
best = manager.select_best(results)
|
|
289
|
+
|
|
290
|
+
if best:
|
|
291
|
+
# Download returns the path to the downloaded file
|
|
292
|
+
file_path = manager.download(
|
|
293
|
+
best,
|
|
294
|
+
output_path="./downloads",
|
|
295
|
+
output_filename="Seether - Tonight" # Optional: custom filename
|
|
296
|
+
)
|
|
297
|
+
print(f"Downloaded to: {file_path}")
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
**For comprehensive library documentation**, including:
|
|
301
|
+
- Complete API reference for all classes and methods
|
|
302
|
+
- Data models and type hints
|
|
303
|
+
- Provider configuration options
|
|
304
|
+
- Advanced usage patterns (filtering, custom sorting, batch processing)
|
|
305
|
+
- Error handling best practices
|
|
306
|
+
- 5+ detailed examples
|
|
307
|
+
|
|
308
|
+
See **[LIBRARY.md](LIBRARY.md)** for full library API documentation.
|
|
309
|
+
|
|
310
|
+
## Architecture & Design
|
|
311
|
+
|
|
312
|
+
See [ARCHITECTURE.md](ARCHITECTURE.md) for detailed architecture, design choices, and implementation learnings.
|
|
313
|
+
|
|
314
|
+
## Contributing
|
|
315
|
+
|
|
316
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
317
|
+
|
|
318
|
+
## Legal Disclaimer
|
|
319
|
+
|
|
320
|
+
This tool is intended for use with content to which you have legal access. Users are responsible for complying with all applicable laws and terms of service for the supported providers.
|
|
321
|
+
|
|
322
|
+
## License
|
|
323
|
+
|
|
324
|
+
MIT License - see [LICENSE](LICENSE) file for details.
|
flacfetch-0.15.3/PLAN.md
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# Architecture & Implementation Plan
|
|
2
|
+
|
|
3
|
+
## 1. High-Level Architecture
|
|
4
|
+
|
|
5
|
+
The system will be designed using **Clean Architecture** principles to separate concerns between the core logic, external interfaces (CLI/Library), and infrastructure (APIs/Downloaders).
|
|
6
|
+
|
|
7
|
+
### Core Components
|
|
8
|
+
|
|
9
|
+
1. **Orchestrator (`FetchManager`)**: The main entry point that coordinates searching, selection, and downloading.
|
|
10
|
+
2. **Domain Models**:
|
|
11
|
+
- `TrackQuery`: Input data (Artist, Title).
|
|
12
|
+
- `Release`: Represents a finding (Source, Quality, Metadata, Download Link/Magnet, **Target File**).
|
|
13
|
+
- `Quality`: Value object for audio quality (Format, Bitrate, Source Media) with comparison logic.
|
|
14
|
+
3. **Interfaces (Abstract Base Classes)**:
|
|
15
|
+
- `Provider`: Interface for searching (e.g., `REDProvider`, `OPSProvider`, `YoutubeProvider`).
|
|
16
|
+
- `Downloader`: Interface for retrieving content (e.g., `TorrentDownloader`, `HttpDownloader`).
|
|
17
|
+
- `UserInterface`: Interface for interaction (handling selection prompts).
|
|
18
|
+
|
|
19
|
+
### Component Diagram
|
|
20
|
+
|
|
21
|
+
```mermaid
|
|
22
|
+
graph TD
|
|
23
|
+
CLI[CLI Adapter] --> Core
|
|
24
|
+
Lib[Library User] --> Core
|
|
25
|
+
|
|
26
|
+
subgraph Core
|
|
27
|
+
FM[FetchManager]
|
|
28
|
+
QS[QualitySorter]
|
|
29
|
+
Handler[InteractionHandler]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
FM --> Providers
|
|
33
|
+
FM --> Downloaders
|
|
34
|
+
|
|
35
|
+
subgraph Providers
|
|
36
|
+
RED
|
|
37
|
+
OPS
|
|
38
|
+
YouTube
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
subgraph Downloaders
|
|
42
|
+
LibTorrent
|
|
43
|
+
YtDlp
|
|
44
|
+
DirectHttp
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 2. Detailed Design
|
|
49
|
+
|
|
50
|
+
### 2.1 Provider System
|
|
51
|
+
Each provider implements a `search(query: TrackQuery) -> List[Release]` method.
|
|
52
|
+
- **REDProvider / OPSProvider**:
|
|
53
|
+
- Uses `ajax.php?action=browse` with `artistname` and `filelist` parameters to find torrents containing the specific track.
|
|
54
|
+
- Requires `base_url` parameter (set via environment variable) in addition to API key.
|
|
55
|
+
- Parses the `fileList` field in the response to identify the specific file within the torrent that matches the requested song.
|
|
56
|
+
- Prioritizes "Album" releases (Type 1) and original release years when presenting options.
|
|
57
|
+
- **PublicProviders**: Wrappers around `yt-dlp` or scraping logic for YouTube.
|
|
58
|
+
|
|
59
|
+
### 2.2 Quality & Selection Logic
|
|
60
|
+
- **Quality Class**: Implements `__lt__`, `__eq__` to allow sorting.
|
|
61
|
+
- Hierarchy: `FLAC 24bit` > `FLAC 16bit` > `MP3 320` > `AAC` > `Other`.
|
|
62
|
+
- **Auto-Selection**: `FetchManager` sorts results by `Quality` and picks the top.
|
|
63
|
+
- **Interactive Selection**: `FetchManager` delegates to `InteractionHandler`.
|
|
64
|
+
- **CLI Implementation**: Prints list to stdout, reads index from stdin.
|
|
65
|
+
- **Library Implementation**: Accepts a callable/hook passed during initialization or method call.
|
|
66
|
+
|
|
67
|
+
### 2.3 Downloader System
|
|
68
|
+
- **TorrentDownloader**: Uses `libtorrent`.
|
|
69
|
+
- **Selective Downloading**: Uses the `target_file` information from the `Release` to set file priorities. All files are set to priority 0 (skip) except the target song file, which is set to priority 7 (high).
|
|
70
|
+
- Manages session, adds magnet/torrent file, monitors progress, alerts on completion.
|
|
71
|
+
- **HttpDownloader**: Standard HTTP GET or `yt-dlp` process.
|
|
72
|
+
|
|
73
|
+
## 3. Implementation Plan
|
|
74
|
+
|
|
75
|
+
### Phase 1: Core & Interfaces
|
|
76
|
+
- Define `TrackQuery`, `Release`, `Quality` data classes.
|
|
77
|
+
- Define `Provider` and `Downloader` abstract base classes (ABCs).
|
|
78
|
+
- Implement `Quality` comparison logic.
|
|
79
|
+
|
|
80
|
+
### Phase 2: Private Tracker Provider Integration
|
|
81
|
+
- Implement authentication (API Key + Base URL support via environment variables).
|
|
82
|
+
- Implement `REDProvider.search` and `OPSProvider.search` using specific `artistname` and `filelist` filtering.
|
|
83
|
+
- Parse `fileList` string (format: `filename{{{size}}}|||...`) to find target track.
|
|
84
|
+
- Parse results into `Release` objects, including `target_file` metadata.
|
|
85
|
+
|
|
86
|
+
### Phase 3: BitTorrent Integration
|
|
87
|
+
- Set up `libtorrent` session management.
|
|
88
|
+
- Implement `TorrentDownloader` with selective file downloading support.
|
|
89
|
+
- Ensure protocol compatibility.
|
|
90
|
+
|
|
91
|
+
### Phase 4: Public Providers
|
|
92
|
+
- Implement `YoutubeProvider` using `yt-dlp`.
|
|
93
|
+
- Implement `HttpDownloader`.
|
|
94
|
+
|
|
95
|
+
### Phase 5: CLI & Library API
|
|
96
|
+
- Build `FetchManager` to tie it all together.
|
|
97
|
+
- Implement CLI with separated `--artist` and `--title` arguments for precision.
|
|
98
|
+
- Implement `ConsoleInteractionHandler` (CLI) and `CallbackInteractionHandler` (Library).
|
|
99
|
+
|
|
100
|
+
## 4. Testing Strategy
|
|
101
|
+
|
|
102
|
+
### 4.1 Unit Testing (`pytest`)
|
|
103
|
+
- **Domain Logic**: Test `Quality` sorting and `FetchManager` flow (mocking providers).
|
|
104
|
+
- **Providers**: Test API response parsing using mocked JSON responses (recorded from actual API calls or synthesized based on docs).
|
|
105
|
+
- **Downloaders**: Mock `libtorrent` session and file system operations.
|
|
106
|
+
|
|
107
|
+
### 4.2 Integration Testing
|
|
108
|
+
- Test the "Search -> Select -> Download" pipeline with a "MockProvider" and "MockDownloader" to ensure the architecture holds together without hitting real external services.
|
|
109
|
+
|
|
110
|
+
### 4.3 End-to-End Testing (Manual/Staging)
|
|
111
|
+
- Run against real APIs (limited) to verify contract assumptions.
|
|
112
|
+
|
|
113
|
+
## 5. Technology Stack
|
|
114
|
+
- **Language**: Python 3.10+
|
|
115
|
+
- **HTTP Client**: `httpx` (async support) or `requests`.
|
|
116
|
+
- **Torrent**: `python-libtorrent` (via system package or pip).
|
|
117
|
+
- **CLI**: `argparse` (stdlib).
|
|
118
|
+
- **Testing**: `pytest`, `pytest-mock`.
|