From 062b3ddbf3a57360b47d7fc0ccf05277c5ff97f1 Mon Sep 17 00:00:00 2001 From: Alex Gorbatchev Date: Mon, 10 Jul 2017 14:01:59 -0700 Subject: [PATCH 1/2] Adds `--plays` option to add play count in front of file names when downloading from SoundCloud playlists. Why? Because sometimes when you want to archive a very long play list (eg https://soundcloud.com/muloka/sets/burning-man-2016) it could be handy to be able to sort files by "popularity". To achieve that, `--plays` option adds play count at the moment of the download as the first thing in the file name. If you want to resync the playlist, files that were downloaded already won't be redownloaded with new play count. At the same time, existing file's play count won't be updated either. --- soundscrape/soundscrape.py | 35 +++++++++++++++++++++++++++++++---- tests/test.py | 4 ++-- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/soundscrape/soundscrape.py b/soundscrape/soundscrape.py index 4132423..e1e5827 100755 --- a/soundscrape/soundscrape.py +++ b/soundscrape/soundscrape.py @@ -1,6 +1,7 @@ #! /usr/bin/env python from __future__ import unicode_literals +import unicodedata import argparse import demjson import os @@ -10,6 +11,7 @@ import sys import urllib +from glob import glob from clint.textui import colored, puts, progress from datetime import datetime from mutagen.mp3 import MP3, EasyMP3 @@ -77,6 +79,8 @@ def main(): help='Open downloaded files after downloading.') parser.add_argument('-k', '--keep', action='store_true', help='Keep 30-second preview tracks') + parser.add_argument('-s', '--plays', action='store_true', + help='Add number of plays to the file name (SoundCloud playlists only)') parser.add_argument('-v', '--version', action='store_true', default=False, help='Display the current version of SoundScrape') @@ -133,6 +137,7 @@ def process_soundcloud(vargs): track_permalink = vargs['track'] keep_previews = vargs['keep'] folders = vargs['folders'] + add_play_count = vargs['plays'] id3_extras = {} one_track = False @@ -289,7 +294,8 @@ def process_soundcloud(vargs): if not aggressive: filenames = download_tracks(client, tracks, num_tracks, vargs['downloadable'], vargs['folders'], vargs['path'], - id3_extras=id3_extras) + id3_extras=id3_extras, + add_play_count=add_play_count) if vargs['open']: open_files(filenames) @@ -363,7 +369,17 @@ def download_track(track, album_name=u'', keep_previews=False, folders=False, fi return filename -def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False, folders=False, custom_path='', id3_extras={}): +def escape_glob(path): + transdict = { + '[': '[[]', + ']': '[]]', + '*': '[*]', + '?': '[?]', + } + rc = re.compile('|'.join(map(re.escape, transdict))) + return rc.sub(lambda m: transdict[m.group(0)], path) + +def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False, folders=False, custom_path='', id3_extras={}, add_play_count=False): """ Given a list of tracks, iteratively download all of them. @@ -372,6 +388,10 @@ def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False, filenames = [] for i, track in enumerate(tracks): + plays = "" + + if add_play_count and track.has_key('playback_count'): + plays = str(track['playback_count']) + " - " # "Track" and "Resource" objects are actually different, # even though they're the same. @@ -416,7 +436,8 @@ def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False, else: track_artist = sanitize_filename(track['user']['username']) track_title = sanitize_filename(track['title']) - track_filename = track_artist + ' - ' + track_title + '.mp3' + actual_track_filename = unicodedata.normalize('NFD', track_artist + ' - ' + track_title + '.mp3') + track_filename = plays + actual_track_filename if folders: track_artist_path = join(custom_path, track_artist) @@ -426,7 +447,13 @@ def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False, else: track_filename = join(custom_path, track_filename) - if exists(track_filename): + if add_play_count: + glob_pattern = "*" + escape_glob(actual_track_filename) + file_exists = len(glob(glob_pattern)) > 0 + else: + file_exists = exists(actual_track_filename) + + if file_exists: puts_safe(colored.yellow("Track already downloaded: ") + colored.white(track_title)) continue diff --git a/tests/test.py b/tests/test.py index 626bf4b..05db627 100644 --- a/tests/test.py +++ b/tests/test.py @@ -35,7 +35,7 @@ def test_soundcloud(self): os.unlink(f) mp3_count = len(glob.glob1('', "*.mp3")) - vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 9223372036854775807, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'https://soundcloud.com/fzpz/revised', 'keep': True} + vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 9223372036854775807, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'https://soundcloud.com/fzpz/revised', 'keep': True, 'plays': False} process_soundcloud(vargs) new_mp3_count = len(glob.glob1('', "*.mp3")) self.assertTrue(new_mp3_count > mp3_count) @@ -48,7 +48,7 @@ def test_soundcloud_hard(self): os.unlink(f) mp3_count = len(glob.glob1('', "*.mp3")) - vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 1, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'puptheband', 'keep': False} + vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 1, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'puptheband', 'keep': False, 'plays': False} process_soundcloud(vargs) new_mp3_count = len(glob.glob1('', "*.mp3")) self.assertTrue(new_mp3_count > mp3_count) From 35532509af53b8b150aa6b9fb20c3e4a9b15719e Mon Sep 17 00:00:00 2001 From: Alex Gorbatchev Date: Tue, 16 Jan 2018 16:43:53 -0800 Subject: [PATCH 2/2] Fixes `--plays` related failures --- tests/test.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/test.py b/tests/test.py index 05db627..62f8721 100644 --- a/tests/test.py +++ b/tests/test.py @@ -62,7 +62,7 @@ def test_soundcloud_hard_2(self): os.unlink(f) mp3_count = len(glob.glob1('', "*.mp3")) - vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 1, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'https://soundcloud.com/lostdogz/snuggles-chapstick', 'keep': False} + vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 1, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'https://soundcloud.com/lostdogz/snuggles-chapstick', 'keep': False, 'plays': False} process_soundcloud(vargs) new_mp3_count = len(glob.glob1('', "*.mp3")) self.assertTrue(new_mp3_count > mp3_count) @@ -92,7 +92,7 @@ def test_bandcamp(self): os.unlink(f) mp3_count = len(glob.glob1('', "*.mp3")) - vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 9223372036854775807, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'https://atenrays.bandcamp.com/track/who-u-think'} + vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 9223372036854775807, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'https://atenrays.bandcamp.com/track/who-u-think', 'plays': False} process_bandcamp(vargs) new_mp3_count = len(glob.glob1('', "*.mp3")) self.assertTrue(new_mp3_count > mp3_count) @@ -105,7 +105,7 @@ def test_bandcamp_slashes(self): os.unlink(f) mp3_count = len(glob.glob1('', "*.mp3")) - vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 9223372036854775807, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'https://defill.bandcamp.com/track/amnesia-chamber-harvest-skit'} + vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 9223372036854775807, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'https://defill.bandcamp.com/track/amnesia-chamber-harvest-skit', 'plays': False} process_bandcamp(vargs) new_mp3_count = len(glob.glob1('', "*.mp3")) self.assertTrue(new_mp3_count > mp3_count)