added download-archive feature (#232)
parent
ebf66a278c
commit
d95a99cc5e
|
@ -45,6 +45,9 @@ scdl -l https://soundcloud.com/jumpstreetpsy/low-extender
|
|||
# Download one playlist
|
||||
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
|
||||
|
||||
# Download your likes (with authentification token)
|
||||
scdl me -f
|
||||
```
|
||||
|
@ -75,6 +78,7 @@ scdl me -f
|
|||
--debug Set log level to DEBUG
|
||||
--hide-progress Hide the wget progress bar
|
||||
--no-playlist-folder Download playlist tracks into directory, instead of making a playlist subfolder (the default)
|
||||
--download-archive [file] Keep track of track IDs in an archive file and skip already-downloaded files
|
||||
```
|
||||
|
||||
|
||||
|
@ -85,6 +89,7 @@ scdl me -f
|
|||
* Download all songs from one playlist
|
||||
* 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.)
|
||||
* Set the tags with mutagen (Title / Artist / Album / Artwork)
|
||||
* Create playlist files when downloading a playlist
|
||||
|
||||
|
|
100
scdl/scdl.py
100
scdl/scdl.py
|
@ -6,10 +6,10 @@
|
|||
Usage:
|
||||
scdl -l <track_url> [-a | -f | -C | -t | -p][-c][-o <offset>]\
|
||||
[--hidewarnings][--debug | --error][--path <path>][--addtofile][--addtimestamp][--onlymp3]
|
||||
[--hide-progress][--min-size <size>][--max-size <size>][--remove][--no-playlist-folder]
|
||||
[--hide-progress][--min-size <size>][--max-size <size>][--remove][--no-playlist-folder][--download-archive <file>]
|
||||
scdl me (-s | -a | -f | -t | -p | -m)[-c][-o <offset>]\
|
||||
[--hidewarnings][--debug | --error][--path <path>][--addtofile][--addtimestamp][--onlymp3]
|
||||
[--hide-progress][--min-size <size>][--max-size <size>][--remove][--no-playlist-folder]
|
||||
[--hide-progress][--min-size <size>][--max-size <size>][--remove][--no-playlist-folder][--download-archive <file>]
|
||||
scdl -h | --help
|
||||
scdl --version
|
||||
|
||||
|
@ -40,6 +40,7 @@ Options:
|
|||
--debug Set log level to DEBUG
|
||||
--hide-progress Hide the wget progress bar
|
||||
--no-playlist-folder Download playlist tracks into directory, instead of making a playlist subfolder (the default)
|
||||
--download-archive [file] Keep track of track IDs in an archive file and skip already-downloaded files
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
@ -393,9 +394,11 @@ def try_utime(path, filetime):
|
|||
def get_filename(track, title, is_original = False):
|
||||
invalid_chars = '\/:*?|<>"'
|
||||
username = track['user']['username']
|
||||
|
||||
if arguments['--addtofile']:
|
||||
if username not in title and '-' not in title:
|
||||
title = '{0} - {1}'.format(username, title)
|
||||
logger.debug('Adding "{0}" to filename'.format(username))
|
||||
|
||||
if arguments['--addtimestamp']:
|
||||
# created_at sample: 2017/03/03 09:29:33 +0000
|
||||
|
@ -421,15 +424,15 @@ def download_track(track, playlist_name=None, playlist_file=None):
|
|||
|
||||
title = track['title']
|
||||
title = title.encode('utf-8', 'ignore').decode('utf8')
|
||||
if track['streamable']:
|
||||
url = track['stream_url']
|
||||
else:
|
||||
logger.error('{0} is not streamable...'.format(title))
|
||||
return
|
||||
logger.info('Downloading {0}'.format(title))
|
||||
|
||||
# Not streamable
|
||||
if not track['streamable']:
|
||||
logger.error('{0} is not streamable...'.format(title))
|
||||
return
|
||||
|
||||
r = None
|
||||
# filename
|
||||
# Downloadable track
|
||||
if track['downloadable'] and not arguments['--onlymp3']:
|
||||
logger.info('Downloading the original file.')
|
||||
original_url = track['download_url']
|
||||
|
@ -446,9 +449,11 @@ def download_track(track, playlist_name=None, playlist_file=None):
|
|||
filename = get_filename(track, title)
|
||||
else:
|
||||
filename = get_filename(track, title)
|
||||
|
||||
|
||||
logger.debug("filename : {0}".format(filename))
|
||||
|
||||
# Skip if file ID or filename already exists
|
||||
if already_downloaded(track, title, filename): return
|
||||
|
||||
# Add the track to the generated m3u playlist file
|
||||
if playlist_file:
|
||||
duration = math.floor(track['duration'] / 1000)
|
||||
|
@ -461,9 +466,9 @@ def download_track(track, playlist_name=None, playlist_file=None):
|
|||
if arguments['--remove']:
|
||||
fileToKeep.append(filename)
|
||||
|
||||
# Download
|
||||
if not os.path.isfile(filename):
|
||||
# Streamable track download
|
||||
if r is None or r.status_code == 401:
|
||||
url = track['stream_url']
|
||||
r = requests.get(url, params={'client_id': CLIENT_ID}, stream=True)
|
||||
logger.debug(r.url)
|
||||
if r.status_code == 401 or r.status_code == 429:
|
||||
|
@ -510,15 +515,70 @@ def download_track(track, playlist_name=None, playlist_file=None):
|
|||
filetime = int(time.mktime(datetime.strptime(created_at, '%Y/%m/%d %H:%M:%S %z').timetuple()))
|
||||
try_utime(filename,filetime)
|
||||
|
||||
else:
|
||||
if arguments['-c'] or arguments['--remove']:
|
||||
logger.info('{0} already Downloaded'.format(title))
|
||||
return
|
||||
else:
|
||||
logger.error('Music already exists ! (use -c to continue)')
|
||||
sys.exit(0)
|
||||
|
||||
logger.info('{0} Downloaded.\n'.format(filename))
|
||||
record_download_archive(track)
|
||||
|
||||
|
||||
def already_downloaded(track, title, filename=None):
|
||||
"""
|
||||
Returns True if the file has already been downloaded
|
||||
"""
|
||||
global arguments
|
||||
already_downloaded = False
|
||||
|
||||
if filename and os.path.isfile(filename):
|
||||
already_downloaded = True
|
||||
if arguments['--download-archive'] and in_download_archive(track):
|
||||
already_downloaded = True
|
||||
|
||||
if already_downloaded:
|
||||
if arguments['-c'] or arguments['--remove']:
|
||||
logger.info('Track "{0}" already downloaded.'.format(title))
|
||||
return True
|
||||
else:
|
||||
logger.error('Track "{0}" already exists! Exiting... (run again with -c to continue)'.format(title))
|
||||
sys.exit(0)
|
||||
return False
|
||||
|
||||
|
||||
def in_download_archive(track):
|
||||
"""
|
||||
Returns True if a track_id exists in the download archive
|
||||
"""
|
||||
global arguments
|
||||
if not arguments['--download-archive']: return
|
||||
|
||||
archive_filename = arguments.get('--download-archive')
|
||||
try:
|
||||
with open(archive_filename, 'a+', encoding='utf-8') as file:
|
||||
logger.debug('Contents of {0}:'.format(archive_filename))
|
||||
file.seek(0)
|
||||
track_id = '{0}'.format(track['id'])
|
||||
for line in file:
|
||||
logger.debug('"'+line.strip()+'"')
|
||||
if line.strip() == track_id:
|
||||
return True
|
||||
except IOError as ioe:
|
||||
logger.error('Error trying to read download archive...')
|
||||
logger.debug(ioe)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def record_download_archive(track):
|
||||
"""
|
||||
Write the track_id in the download archive
|
||||
"""
|
||||
global arguments
|
||||
if not arguments['--download-archive']: return
|
||||
|
||||
archive_filename = arguments.get('--download-archive')
|
||||
try:
|
||||
with open(archive_filename, 'a', encoding='utf-8') as file:
|
||||
file.write('{0}'.format(track['id'])+'\n')
|
||||
except IOError as ioe:
|
||||
logger.error('Error trying to write to download archive...')
|
||||
logger.debug(ioe)
|
||||
|
||||
|
||||
def set_metadata(track, filename, album=None):
|
||||
|
|
Loading…
Reference in New Issue