New sync option (#374)

master
hunkyburrito 2022-04-06 00:25:15 -05:00 committed by GitHub
parent 3ecc7196b3
commit 24988f740d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 85 additions and 17 deletions

View File

@ -13,6 +13,9 @@ Compatible with Windows, OS X, Linux.
## Installation Instructions
https://github.com/flyingrub/scdl/wiki/Installation-Instruction
## Configuration
There is a configuration file left in `~/.config/scdl/scdl.cfg`
## Examples:
```
# Download track & repost of the user QUANTA
@ -30,6 +33,9 @@ scdl -l https://soundcloud.com/pandadub/sets/the-lost-ship
# Download only new tracks from a playlist
scdl -l https://soundcloud.com/pandadub/sets/the-lost-ship --download-archive archive.txt -c
# Sync playlist
scdl -l https://soundcloud.com/pandadub/sets/the-lost-ship --sync archive.txt
# Download your likes (with authentification token)
scdl me -f
```
@ -68,6 +74,7 @@ scdl me -f
even if track has a Downloadable file
--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
--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
@ -91,6 +98,7 @@ scdl me -f
* Download all songs from all playlists from a user
* Download all songs from a user's favorites
* Download only new tracks from a list (playlist, favorites, etc.)
* Sync Playlist
* Set the tags with mutagen (Title / Artist / Album / Artwork)
* Create playlist files when downloading a playlist

View File

@ -1,5 +1,3 @@
# -*- encoding: utf-8 -*-
"""Python Soundcloud Music Downloader."""
__version__ = "v2.6.2"

View File

@ -3,7 +3,7 @@ client_id = a3e059563d7fd3372b49b37f00a00bcf
auth_token =
path = .
name_format = {title}
playlist_name_format = {playlist[title]}_{playlist[tracknumber]}_{title}
playlist_name_format = {playlist[title]}_{title}
# example name_format values:
# {timestamp}_{user[username]}_{title}
@ -13,5 +13,4 @@ playlist_name_format = {playlist[title]}_{playlist[tracknumber]}_{title}
# playlist_name_format playlist attributes:
# playlist[author] - username of playlist author
# playlist[title] - name of playlist
# playlist[tracknumber] - tracknumber of track in playlist (zero-padded)
# playlist[title] - name of playlist

View File

@ -4,12 +4,15 @@
"""scdl allows you to download music from Soundcloud
Usage:
scdl (-l <track_url> | me) [-a | -f | -C | -t | -p | -r][-c | --force-metadata][-n <maxtracks>]
[-o <offset>][--hidewarnings][--debug | --error][--path <path>][--addtofile][--addtimestamp]
[--onlymp3][--hide-progress][--min-size <size>][--max-size <size>][--remove][--no-album-tag]
[--no-playlist-folder][--download-archive <file>][--extract-artist][--flac][--original-art]
[--original-name][--no-original][--only-original][--name-format <format>][--strict-playlist]
[--playlist-name-format <format>][--client-id <id>][--auth-token <token>][--overwrite][--no-playlist]
scdl (-l <track_url> | me) [-a | -f | -C | -t | -p | -r][-c | --force-metadata]
[-n <maxtracks>][-o <offset>][--hidewarnings][--debug | --error][--path <path>]
[--addtofile][--addtimestamp][--onlymp3][--hide-progress][--min-size <size>]
[--max-size <size>][--remove][--no-album-tag][--no-playlist-folder]
[--download-archive <file>][--sync <file>][--extract-artist][--flac][--original-art]
[--original-name][--no-original][--only-original][--name-format <format>]
[--strict-playlist][--playlist-name-format <format>][--client-id <id>]
[--auth-token <token>][--overwrite][--no-playlist]
scdl -h | --help
scdl --version
@ -47,6 +50,7 @@ Options:
even if track has a Downloadable file
--path [path] Use a custom path for downloaded files
--remove Remove any files not downloaded from execution
--sync [file] Compares an archive file to a playlist and downloads/removes any changed tracks
--flac Convert original files to .flac
--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
@ -210,6 +214,9 @@ def main():
arguments["-l"] = client.get_me().permalink_url
arguments["-l"] = validate_url(client, arguments["-l"])
if arguments["--sync"]:
arguments["--download-archive"] = arguments["--sync"]
# convert arguments dict to python_args (kwargs-friendly args)
python_args = {}
@ -234,6 +241,7 @@ def main():
if arguments["--remove"]:
remove_files()
def validate_url(client: SoundCloud, url: str):
"""
If url is a valid soundcloud.com url, return it.
@ -387,6 +395,53 @@ def remove_files():
if f not in fileToKeep:
os.remove(f)
def sync(client: SoundCloud, playlist: BasicAlbumPlaylist, playlist_info, **kwargs):
"""
Downloads/Removes tracks that have been changed on playlist since last archive file
"""
logger.info("Comparing tracks...")
archive = kwargs.get("sync")
with open(archive) as f:
try:
old = [int(i) for i in ''.join(f.readlines()).strip().split('\n')]
except IOError as ioe:
logger.error(f'Error trying to read download archive {archive}')
logger.debug(ioe)
sys.exit(1)
except ValueError as verr:
logger.error(f'Error trying to convert track ids. Verify archive file is not empty.')
logger.debug(verr)
sys.exit(1)
new = [track.id for track in playlist.tracks]
add = set(new).difference(old) # find tracks to download
rem = set(old).difference(new) # find tracks to remove
if not (add or rem):
logger.info("No changes found. Exiting...")
sys.exit(0)
if rem:
for track_id in rem:
filename = get_filename(client.get_track(track_id),playlist_info=playlist_info,**kwargs)
if filename in os.listdir('.'):
os.remove(filename)
logger.info(f'Removed {filename}')
else:
logger.info(f'Could not find {filename} to remove')
with open(archive,'w') as f:
for track_id in old:
if track_id not in rem:
f.write(str(track_id)+'\n')
else:
logger.info('No tracks to remove.')
if add:
return [track for track in playlist.tracks if track.id in add]
else:
logger.info('No tracks to download. Exiting...')
sys.exit(0)
def download_playlist(client: SoundCloud, playlist: BasicAlbumPlaylist, **kwargs):
"""
Downloads a playlist
@ -397,6 +452,11 @@ def download_playlist(client: SoundCloud, playlist: BasicAlbumPlaylist, **kwargs
playlist_name = playlist.title.encode("utf-8", "ignore")
playlist_name = playlist_name.decode("utf-8")
playlist_name = sanitize_filename(playlist_name)
playlist_info = {
"author": playlist.user.username,
"id": playlist.id,
"title": playlist.title
}
if not kwargs.get("no_playlist_folder"):
if not os.path.exists(playlist_name):
@ -410,21 +470,24 @@ def download_playlist(client: SoundCloud, playlist: BasicAlbumPlaylist, **kwargs
)
playlist.tracks = playlist.tracks[: int(kwargs.get("n"))]
kwargs["playlist_offset"] = 0
if kwargs.get("sync"):
if os.path.isfile(kwargs.get("sync")):
playlist.tracks = sync(client, playlist, playlist_info, **kwargs)
else:
logger.error(f'Invalid sync archive file {kwargs.get("sync")}')
sys.exit(1)
tracknumber_digits = len(str(len(playlist.tracks)))
for counter, track in itertools.islice(enumerate(playlist.tracks, 1), kwargs.get("playlist_offset", 0), None):
logger.debug(track)
logger.info(f"Track n°{counter}")
playlist_info = {
"author": playlist.user.username,
"id": playlist.id,
"title": playlist.title,
"tracknumber": str(counter).zfill(tracknumber_digits),
}
playlist_info["tracknumber"] = str(counter).zfill(tracknumber_digits)
if isinstance(track, MiniTrack):
if playlist.secret_token:
track = client.get_tracks([track.id], playlist.id, playlist.secret_token)[0]
else:
track = client.get_track(track.id)
download_track(client, track, playlist_info, kwargs.get("strict_playlist"), **kwargs)
finally:
if not kwargs.get("no_playlist_folder"):