Use filelocks on unix systems
This commit is contained in:
18
README.md
18
README.md
@@ -55,14 +55,15 @@ scdl me -f
|
||||
-r Download all reposts of user
|
||||
-c Continue if a downloaded file already exists
|
||||
--force-metadata This will set metadata on already downloaded track
|
||||
-o [offset] Begin with a custom offset
|
||||
-o [offset] Start downloading a playlist from the [offset]th track (starting with 1)
|
||||
--addtimestamp Add track creation timestamp to filename,
|
||||
which allows for chronological sorting
|
||||
(Deprecated. Use --name-format instead.)
|
||||
--addtofile Add artist to filename if missing
|
||||
--debug Set log level to DEBUG
|
||||
--error Set log level to ERROR
|
||||
--download-archive [file] Keep track of track IDs in an archive file,
|
||||
and skip already-downloaded files
|
||||
--error Set log level to ERROR
|
||||
--extract-artist Set artist tag from title instead of username
|
||||
--hide-progress Hide the wget progress bar
|
||||
--hidewarnings Hide Warnings. (use with precaution)
|
||||
@@ -70,16 +71,16 @@ scdl me -f
|
||||
--min-size [min-size] Skip tracks smaller than size (k/m/g)
|
||||
--no-playlist-folder Download playlist tracks into main directory,
|
||||
instead of making a playlist subfolder
|
||||
--onlymp3 Download only the streamable mp3 file,
|
||||
even if track has a Downloadable file
|
||||
--onlymp3 Download only mp3 files
|
||||
--path [path] Use a custom path for downloaded files
|
||||
--remove Remove any files not downloaded from execution
|
||||
--sync [file] Compare an archive file to a playlist and downloads/removes any changed tracks
|
||||
--flac Convert original files to .flac
|
||||
--sync [file] Compares an archive file to a playlist and downloads/removes any changed tracks
|
||||
--flac Convert original files to .flac. Only works if the original file is lossless quality
|
||||
--no-album-tag On some player track get the same cover art if from the same album, this prevent it
|
||||
--original-art Download original cover art
|
||||
--original-art Download original cover art, not just 500x500 JPEG
|
||||
--original-name Do not change name of original file downloads
|
||||
--no-original Do not download original file; only mp3 or m4a
|
||||
--original-metadata Do not change metadata of original file downloads
|
||||
--no-original Do not download original file; only mp3, m4a, or opus
|
||||
--only-original Only download songs with original file available
|
||||
--name-format [format] Specify the downloaded file name format
|
||||
--playlist-name-format [format] Specify the downloaded file name format, if it is being downloaded as part of a playlist
|
||||
@@ -88,6 +89,7 @@ scdl me -f
|
||||
--overwrite Overwrite file if it already exists
|
||||
--strict-playlist Abort playlist downloading if one track fails to download
|
||||
--no-playlist Skip downloading playlists
|
||||
--opus Prefer downloading opus streams over mp3 streams
|
||||
```
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
"""Python Soundcloud Music Downloader."""
|
||||
__version__ = "v2.9.2"
|
||||
__version__ = "v2.9.3"
|
||||
|
||||
51
scdl/scdl.py
51
scdl/scdl.py
@@ -68,15 +68,15 @@ Options:
|
||||
--opus Prefer downloading opus streams over mp3 streams
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import base64
|
||||
import cgi
|
||||
import configparser
|
||||
import contextlib
|
||||
import itertools
|
||||
import logging
|
||||
import math
|
||||
import mimetypes
|
||||
from typing import Optional, TypedDict
|
||||
from typing import List, Optional, TypedDict
|
||||
|
||||
mimetypes.init()
|
||||
|
||||
@@ -92,16 +92,7 @@ import urllib.parse
|
||||
import warnings
|
||||
from dataclasses import asdict
|
||||
|
||||
if os.name == "nt":
|
||||
import filelock
|
||||
|
||||
FileLockTimeout = filelock.Timeout
|
||||
else:
|
||||
|
||||
class FileLockTimeout(Exception):
|
||||
pass
|
||||
|
||||
|
||||
import filelock
|
||||
import mutagen
|
||||
import mutagen.flac
|
||||
import mutagen.id3
|
||||
@@ -148,12 +139,26 @@ class PlaylistInfo(TypedDict):
|
||||
id: int
|
||||
title: str
|
||||
|
||||
file_lock_dirs: List[pathlib.Path] = []
|
||||
|
||||
|
||||
def clean_up_locks():
|
||||
for dir in file_lock_dirs:
|
||||
for lock in dir.glob("*.scdl.lock"):
|
||||
try:
|
||||
lock.unlink(True)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
atexit.register(clean_up_locks)
|
||||
|
||||
|
||||
def get_filelock(path: pathlib.Path, timeout: int = 10):
|
||||
if os.name == "nt":
|
||||
return filelock.FileLock(str(path) + ".scdl.lock", timeout=timeout)
|
||||
else:
|
||||
return contextlib.nullcontext()
|
||||
path = path.resolve()
|
||||
file_lock_dirs.append(path.parent)
|
||||
lock_path = str(path) + ".scdl.lock"
|
||||
return filelock.FileLock(lock_path, timeout=timeout)
|
||||
|
||||
|
||||
def main():
|
||||
@@ -712,7 +717,7 @@ def download_original_file(
|
||||
shutil.move(temp.name, os.path.join(os.getcwd(), filename))
|
||||
if kwargs.get("flac") and can_convert(filename):
|
||||
logger.info("Converting to .flac...")
|
||||
newfilename = limit_filename_length(filename[:-4], ".flac")
|
||||
newfilename = sanitize_str(filename[:-4], ".flac")
|
||||
|
||||
commands = ["ffmpeg", "-i", filename, newfilename, "-loglevel", "error"]
|
||||
logger.debug(f"Commands: {commands}")
|
||||
@@ -760,7 +765,6 @@ def download_hls(
|
||||
|
||||
transcoding = None
|
||||
ext = None
|
||||
|
||||
# ordered in terms of preference best -> worst
|
||||
valid_presets = [("mp3", ".mp3")]
|
||||
|
||||
@@ -836,7 +840,7 @@ def download_track(
|
||||
# Get user_id from the client
|
||||
client_user_id = client.get_me().id if client.auth_token else None
|
||||
|
||||
lock = get_filelock(f"{track.id}", 0)
|
||||
lock = get_filelock(pathlib.Path(f"./{track.id}"), 0)
|
||||
|
||||
# Downloadable track
|
||||
downloaded_original = False
|
||||
@@ -854,7 +858,7 @@ def download_track(
|
||||
client, track, title, playlist_info, **kwargs
|
||||
)
|
||||
downloaded_original = True
|
||||
except FileLockTimeout:
|
||||
except filelock.Timeout:
|
||||
logger.debug(f"Could not acquire lock: {lock}. Skipping")
|
||||
return
|
||||
|
||||
@@ -866,7 +870,7 @@ def download_track(
|
||||
filename, is_already_downloaded = download_hls(
|
||||
client, track, title, playlist_info, **kwargs
|
||||
)
|
||||
except FileLockTimeout:
|
||||
except filelock.Timeout:
|
||||
logger.debug(f"Could not acquire lock: {lock}. Skipping")
|
||||
return
|
||||
|
||||
@@ -1118,11 +1122,6 @@ def set_metadata(
|
||||
audio.save()
|
||||
|
||||
|
||||
def limit_filename_length(name: str, ext: str, max_bytes=255):
|
||||
while len(name.encode("utf-8")) + len(ext.encode("utf-8")) > max_bytes:
|
||||
name = name[:-1]
|
||||
return name + ext
|
||||
|
||||
def is_ffmpeg_available():
|
||||
"""
|
||||
Returns true if ffmpeg is available in the operating system
|
||||
|
||||
Reference in New Issue
Block a user