Skip to content

Commit 28fdcda

Browse files
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.
1 parent 5f8b859 commit 28fdcda

File tree

2 files changed

+33
-6
lines changed

2 files changed

+33
-6
lines changed

soundscrape/soundscrape.py

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#! /usr/bin/env python
22
from __future__ import unicode_literals
33

4+
import unicodedata
45
import argparse
56
import demjson
67
import os
@@ -10,6 +11,7 @@
1011
import sys
1112
import urllib
1213

14+
from glob import glob
1315
from clint.textui import colored, puts, progress
1416
from datetime import datetime
1517
from mutagen.mp3 import MP3, EasyMP3
@@ -77,6 +79,8 @@ def main():
7779
help='Open downloaded files after downloading.')
7880
parser.add_argument('-k', '--keep', action='store_true',
7981
help='Keep 30-second preview tracks')
82+
parser.add_argument('-s', '--plays', action='store_true',
83+
help='Add number of plays to the file name (SoundCloud playlists only)')
8084
parser.add_argument('-v', '--version', action='store_true', default=False,
8185
help='Display the current version of SoundScrape')
8286

@@ -133,6 +137,7 @@ def process_soundcloud(vargs):
133137
track_permalink = vargs['track']
134138
keep_previews = vargs['keep']
135139
folders = vargs['folders']
140+
add_play_count = vargs['plays']
136141

137142
id3_extras = {}
138143
one_track = False
@@ -289,7 +294,8 @@ def process_soundcloud(vargs):
289294

290295
if not aggressive:
291296
filenames = download_tracks(client, tracks, num_tracks, vargs['downloadable'], vargs['folders'], vargs['path'],
292-
id3_extras=id3_extras)
297+
id3_extras=id3_extras,
298+
add_play_count=add_play_count)
293299

294300
if vargs['open']:
295301
open_files(filenames)
@@ -363,7 +369,17 @@ def download_track(track, album_name=u'', keep_previews=False, folders=False, fi
363369

364370
return filename
365371

366-
def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False, folders=False, custom_path='', id3_extras={}):
372+
def escape_glob(path):
373+
transdict = {
374+
'[': '[[]',
375+
']': '[]]',
376+
'*': '[*]',
377+
'?': '[?]',
378+
}
379+
rc = re.compile('|'.join(map(re.escape, transdict)))
380+
return rc.sub(lambda m: transdict[m.group(0)], path)
381+
382+
def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False, folders=False, custom_path='', id3_extras={}, add_play_count=False):
367383
"""
368384
Given a list of tracks, iteratively download all of them.
369385
@@ -372,6 +388,10 @@ def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False,
372388
filenames = []
373389

374390
for i, track in enumerate(tracks):
391+
plays = ""
392+
393+
if add_play_count and track.has_key('playback_count'):
394+
plays = str(track['playback_count']) + " - "
375395

376396
# "Track" and "Resource" objects are actually different,
377397
# even though they're the same.
@@ -416,7 +436,8 @@ def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False,
416436
else:
417437
track_artist = sanitize_filename(track['user']['username'])
418438
track_title = sanitize_filename(track['title'])
419-
track_filename = track_artist + ' - ' + track_title + '.mp3'
439+
actual_track_filename = unicodedata.normalize('NFD', track_artist + ' - ' + track_title + '.mp3')
440+
track_filename = plays + actual_track_filename
420441

421442
if folders:
422443
track_artist_path = join(custom_path, track_artist)
@@ -426,7 +447,13 @@ def download_tracks(client, tracks, num_tracks=sys.maxsize, downloadable=False,
426447
else:
427448
track_filename = join(custom_path, track_filename)
428449

429-
if exists(track_filename):
450+
if add_play_count:
451+
glob_pattern = "*" + escape_glob(actual_track_filename)
452+
file_exists = len(glob(glob_pattern)) > 0
453+
else:
454+
file_exists = exists(actual_track_filename)
455+
456+
if file_exists:
430457
puts_safe(colored.yellow("Track already downloaded: ") + colored.white(track_title))
431458
continue
432459

tests/test.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def test_soundcloud(self):
3535
os.unlink(f)
3636

3737
mp3_count = len(glob.glob1('', "*.mp3"))
38-
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}
38+
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}
3939
process_soundcloud(vargs)
4040
new_mp3_count = len(glob.glob1('', "*.mp3"))
4141
self.assertTrue(new_mp3_count > mp3_count)
@@ -48,7 +48,7 @@ def test_soundcloud_hard(self):
4848
os.unlink(f)
4949

5050
mp3_count = len(glob.glob1('', "*.mp3"))
51-
vargs = {'path':'', 'folders': False, 'group': False, 'track': '', 'num_tracks': 1, 'bandcamp': False, 'downloadable': False, 'likes': False, 'open': False, 'artist_url': 'puptheband', 'keep': False}
51+
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}
5252
process_soundcloud(vargs)
5353
new_mp3_count = len(glob.glob1('', "*.mp3"))
5454
self.assertTrue(new_mp3_count > mp3_count)

0 commit comments

Comments
 (0)