Merge remote-tracking branch 'warry-github/master' into feature/informations-window
# Conflicts: # CONTRIBUTING.md # README.md
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
docs/source
|
||||
vs_code/
|
||||
|
||||
# From https://raw.githubusercontent.com/github/gitignore/main/Python.gitignore
|
||||
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ Anything tagged with "enhancement" and "help wanted" is open to whoever wants to
|
||||
|
||||
## Write Documentation
|
||||
|
||||
Cookiecutter PyPackage could always use more documentation, whether as part of the official docs, in docstrings, or even on the web in blog posts, articles, and such.
|
||||
The TIDAL Downloader project could always use more documentation, whether as part of the official docs, in docstrings, or even on the web in blog posts, articles, and such.
|
||||
|
||||
## Submit Feedback
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
[](https://img.shields.io/github/commit-activity/m/exislow/tidal-dl-ng)
|
||||
[](https://img.shields.io/github/license/exislow/tidal-dl-ng)
|
||||
|
||||
This tool allows to download songs and videos from TIDAL. Multithreaded and multi-chunked downloads are supported.
|
||||
This tool allows you to download songs and videos from TIDAL. Multithreaded and multi-chunked downloads are supported.
|
||||
|
||||
⚠️ **Windows** Defender / **Anti Virus** software / web browser alerts, while you try to download the app binary: This
|
||||
is a **false positive**. Please
|
||||
@@ -39,7 +39,7 @@ $ tidal-dl-ng --help
|
||||
╰──────────────────────────────────────────────────────────────────────────────╯
|
||||
```
|
||||
|
||||
If you like this projects and want to support it, feel free to buy me a coffee 🙃✌️
|
||||
If you like this project and want to support it, feel free to buy me a coffee 🙃✌️
|
||||
|
||||
<a href="https://www.buymeacoffee.com/exislow" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/arial-orange.png" alt="Buy Me A Coffee" style="height: 51px !important;width: 217px !important;" ></a>
|
||||
<a href="https://ko-fi.com/exislow" target="_blank" rel="noopener noreferrer"><img src="https://help.ko-fi.com/hc/article_attachments/11833788361117" alt="61e11d430afb112ea33c3aa5_Button-1-p-500"></a>
|
||||
@@ -83,8 +83,8 @@ tdng
|
||||
tidal-dl-ng gui
|
||||
```
|
||||
|
||||
If you like to have the GUI version only as a binary, have a look at the
|
||||
[release page](https://github.com/exislow/tidal-dl-ng/releases) and download the correct version for your platform.
|
||||
If you would like to use the GUI version as a binary, have a look at the
|
||||
[release page](https://github.com/exislow/tidal-dl-ng/releases) and download the correct version for your OS.
|
||||
|
||||
## 🧁 Features
|
||||
|
||||
@@ -121,13 +121,13 @@ tidal_ng_dl/gui.py
|
||||
|
||||
### 📺 GUI Builder
|
||||
|
||||
The GUI is build with `PySide6` using the [Qt Designer](https://doc.qt.io/qt-6/qtdesigner-manual.html):
|
||||
The GUI is built with `PySide6` using the [Qt Designer](https://doc.qt.io/qt-6/qtdesigner-manual.html):
|
||||
|
||||
```bash
|
||||
PYSIDE_DESIGNER_PLUGINS=tidal_dl_ng/ui pyside6-designer
|
||||
```
|
||||
|
||||
After all changes are saved you need to translate the Qt Designer `*.ui` file into Python code, for instance:
|
||||
After all changes are saved, you need to translate the Qt Designer `*.ui` file into Python code, for instance:
|
||||
|
||||
```
|
||||
pyside6-uic tidal_dl_ng/ui/main.ui -o tidal_dl_ng/ui/main.py
|
||||
@@ -144,9 +144,9 @@ To build the project use this command:
|
||||
make install
|
||||
# Build macOS GUI
|
||||
make gui-macos-dmg
|
||||
# OR Build macOS GUI
|
||||
# OR Build Windows GUI
|
||||
make gui-windows
|
||||
# OR Build macOS GUI
|
||||
# OR Build Linux GUI
|
||||
make gui-linux
|
||||
# Check build output
|
||||
ls dist/
|
||||
@@ -206,7 +206,7 @@ sudo apt install libxcb-cursor0
|
||||
|
||||
### A terminal is flashing when I run this app on Windows
|
||||
|
||||
Please see this isse [#103](https://github.com/exislow/tidal-dl-ng/issues/103).
|
||||
Please see this issue [#103](https://github.com/exislow/tidal-dl-ng/issues/103).
|
||||
|
||||
This is due to the Python `ffmpeg` library which is used and only happens on windows if `extract_flac` is activated.
|
||||
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
name = "tidal-dl-ng"
|
||||
authors = [{ name = "Robert Honz", email = "<cen.sored@gmail.com>" }]
|
||||
version = "0.31.4"
|
||||
description = "TIDAL Medial Downloader Next Generation!"
|
||||
description = "TIDAL Media Downloader Next Generation!"
|
||||
readme = "README.md"
|
||||
license = "AGPL-3.0-only"
|
||||
license-files = ["LICENSE"]
|
||||
@@ -132,7 +132,7 @@ ignore = [
|
||||
# Do not use bare `except`
|
||||
"E722",
|
||||
# PEP 484 prohibits implicit `Optional`
|
||||
# Disabled only temporarely.
|
||||
# Disabled only temporarily.
|
||||
"RUF013",
|
||||
]
|
||||
|
||||
|
||||
+5
-5
@@ -171,7 +171,7 @@ def _process_url(
|
||||
return False
|
||||
|
||||
if "http" not in url:
|
||||
print(f"It seems like that you have supplied an invalid URL: {url}")
|
||||
print(f"It seems like you have supplied an invalid URL: {url}")
|
||||
return True
|
||||
|
||||
url_clean: str = url_ending_clean(url)
|
||||
@@ -286,7 +286,7 @@ def settings_management(
|
||||
|
||||
Args:
|
||||
names (list[str] | None, optional): None (list all options), one (list the value only for this option) or two arguments (set the value for the option). Defaults to None.
|
||||
editor (bool, optional): If set, your favorite system editor will be opened. Defaults to False.
|
||||
editor (bool, optional): If set, your default system editor will be opened. Defaults to False.
|
||||
"""
|
||||
if editor:
|
||||
config_path: Path = Path(path_file_settings())
|
||||
@@ -333,7 +333,7 @@ def login(ctx: typer.Context) -> bool:
|
||||
Returns:
|
||||
bool: True if login was successful, False otherwise.
|
||||
"""
|
||||
print("Let us check, if you are already logged in... ", end="")
|
||||
print("Let us check if you are already logged in... ", end="")
|
||||
|
||||
settings = Settings()
|
||||
tidal = Tidal(settings)
|
||||
@@ -375,7 +375,7 @@ def download(
|
||||
writable=False,
|
||||
readable=True,
|
||||
resolve_path=True,
|
||||
help="List with URLs to download. One per line",
|
||||
help="File with URLs to download. One URL per line.",
|
||||
),
|
||||
] = None,
|
||||
) -> bool:
|
||||
@@ -395,7 +395,7 @@ def download(
|
||||
text: str = file_urls.read_text()
|
||||
urls = text.splitlines()
|
||||
else:
|
||||
print("Provide either URLs, IDs or a file containing URLs (one per line).")
|
||||
print("Provide either URLs or a file containing URLs (one per line).")
|
||||
|
||||
raise typer.Abort()
|
||||
|
||||
|
||||
@@ -71,7 +71,6 @@ class BaseConfig:
|
||||
|
||||
# Move the invalid config file to the backup location.
|
||||
shutil.move(path, path_bak)
|
||||
# TODO: Implement better global logger.
|
||||
print(
|
||||
"Something is wrong with your config. Maybe it is not compatible anymore due to a new app version."
|
||||
f" You can find a backup of your old config here: '{path_bak}'. A new default config was created."
|
||||
|
||||
@@ -203,7 +203,7 @@ class DialogPreferences(QtWidgets.QDialog):
|
||||
):
|
||||
# If a path is set, use it otherwise the users home directory.
|
||||
path_settings: str = os.path.expanduser(obj_line_edit.text()) if obj_line_edit.text() else ""
|
||||
# Check if obj_line_edit is empty but path_default can be usd instead
|
||||
# Check if obj_line_edit is empty but path_default can be used instead
|
||||
path_settings = (
|
||||
path_settings if path_settings else os.path.expanduser(path_default) if path_default else path_settings
|
||||
)
|
||||
@@ -223,7 +223,7 @@ class DialogPreferences(QtWidgets.QDialog):
|
||||
|
||||
dialog.setDirectory(dir_current)
|
||||
|
||||
# Execute dialog and set path is something is choosen.
|
||||
# Execute dialog and set path if something is chosen.
|
||||
if dialog.exec():
|
||||
dir_name: str = dialog.selectedFiles()[0]
|
||||
path: Path = Path(dir_name)
|
||||
|
||||
+17
-3
@@ -411,7 +411,7 @@ class Download:
|
||||
with path_file.open("wb") as f_target:
|
||||
for dl_segment_result in dl_segment_results:
|
||||
with dl_segment_result.path_segment.open("rb") as f_segment:
|
||||
# Read and write junks, which gives better HDD write performance
|
||||
# Read and write chunks, which gives better HDD write performance
|
||||
while segment := f_segment.read(CHUNK_SIZE):
|
||||
f_target.write(segment)
|
||||
|
||||
@@ -1249,7 +1249,7 @@ class Download:
|
||||
response: requests.Response = requests.get(url, timeout=REQUESTS_TIMEOUT_SEC)
|
||||
result = response.content
|
||||
except Exception as e:
|
||||
# TODO: Implement propper logging.
|
||||
# TODO: Implement proper logging.
|
||||
print(e)
|
||||
finally:
|
||||
response.close()
|
||||
@@ -1258,7 +1258,7 @@ class Download:
|
||||
with open(path_file, "rb") as f:
|
||||
result = f.read()
|
||||
except OSError as e:
|
||||
# TODO: Implement propper logging.
|
||||
# TODO: Implement proper logging.
|
||||
print(e)
|
||||
|
||||
return result
|
||||
@@ -1750,15 +1750,22 @@ class Download:
|
||||
pathlib.Path: Path to the converted MP4 file.
|
||||
"""
|
||||
path_file_out: pathlib.Path = path_file.with_suffix(AudioExtensions.MP4)
|
||||
|
||||
self.fn_logger.debug(f"Converting video: {path_file.name} -> {path_file_out.name}")
|
||||
|
||||
ffmpeg = (
|
||||
FFmpeg(executable=self.settings.data.path_binary_ffmpeg)
|
||||
.option("y")
|
||||
.option("hide_banner")
|
||||
.option("nostdin")
|
||||
.input(url=path_file)
|
||||
.output(url=path_file_out, codec="copy", map=0, loglevel="quiet")
|
||||
)
|
||||
|
||||
ffmpeg.execute()
|
||||
|
||||
self.fn_logger.debug(f"Video conversion complete: {path_file_out.name}")
|
||||
|
||||
return path_file_out
|
||||
|
||||
def _extract_flac(self, path_media_src: pathlib.Path) -> pathlib.Path:
|
||||
@@ -1771,8 +1778,13 @@ class Download:
|
||||
pathlib.Path: Path to the extracted FLAC file.
|
||||
"""
|
||||
path_media_out = path_media_src.with_suffix(AudioExtensions.FLAC)
|
||||
|
||||
self.fn_logger.debug(f"Extracting FLAC: {path_media_src.name} -> {path_media_out.name}")
|
||||
|
||||
ffmpeg = (
|
||||
FFmpeg(executable=self.settings.data.path_binary_ffmpeg)
|
||||
.option("hide_banner")
|
||||
.option("nostdin")
|
||||
.input(url=path_media_src)
|
||||
.output(
|
||||
url=path_media_out,
|
||||
@@ -1786,6 +1798,8 @@ class Download:
|
||||
|
||||
ffmpeg.execute()
|
||||
|
||||
self.fn_logger.debug(f"FLAC extraction complete: {path_media_out.name}")
|
||||
|
||||
return path_media_out
|
||||
|
||||
def _extract_video_stream(self, m3u8_variant: m3u8.M3U8, quality: int) -> tuple[m3u8.M3U8 | bool, str]:
|
||||
|
||||
@@ -69,7 +69,7 @@ class Settings:
|
||||
@dataclass
|
||||
class HelpSettings:
|
||||
skip_existing: str = "Skip download if file already exists."
|
||||
album_cover_save: str = "Safe cover to album folder."
|
||||
album_cover_save: str = "Save cover to album folder."
|
||||
lyrics_embed: str = "Embed lyrics in audio file, if lyrics are available."
|
||||
use_primary_album_artist: str = "Use only the primary album artist for folder paths instead of track artists."
|
||||
lyrics_file: str = "Save lyrics to separate *.lrc file, if lyrics are available."
|
||||
@@ -97,11 +97,11 @@ class HelpSettings:
|
||||
"will be converted to MP4. FFmpeg must be installed."
|
||||
)
|
||||
path_binary_ffmpeg: str = (
|
||||
"Path to FFmpeg binary file (executable). Only necessary if FFmpeg not set in $PATH. Mandatory for Windows: "
|
||||
"The directory of `ffmpeg.exe`must be set in %PATH%."
|
||||
"Path to FFmpeg binary file (executable). Only necessary if FFmpeg is not set in $PATH. Mandatory for Windows: "
|
||||
"The directory of `ffmpeg.exe` must be set in %PATH%."
|
||||
)
|
||||
metadata_cover_dimension: str = (
|
||||
"The dimensions of the cover image embedded into the track. Possible values: 320x320, 640x640x 1280x1280."
|
||||
"The dimensions of the cover image embedded into the track. Possible values: 320x320, 640x640, 1280x1280."
|
||||
)
|
||||
metadata_cover_embed: str = "Embed album cover into file."
|
||||
mark_explicit: str = "Mark explicit tracks with '🅴' in track title (only applies to metadata)."
|
||||
|
||||
Reference in New Issue
Block a user