Create listening experiences for collections of songs, based on their relationships as/to samples.
Setup TLDR;
git clone https://github.com/qzdl/samplify.git && cd samplify && venv samplify && source samplify/bin/activate && pip -r requirements.txt
git clone https://github.com/qzdl/samplify.git
cd
to the new directory, and create a new virtual environment with venv samplify
source samplify/bin/activate
to activate the new environment.pip install -r requirements.txt
requirements.txt
for a list of packagesIf you haven't used the spotify API before:
http://localhost:<SOME_FREE_PORT>
config.py
at the root of the repository, and populate it as follows:
(NOTE: these are not valid credentials )
# ClientID from registered application at:
# https://developers.spotify.com/dashboard/applications
client = '7bf224e8jn954215s3g11degh599e3an'
secret = '7bf224e8jn954215s3g11degh599e3an'
username = '1134745600'
redirect = 'http://localhost:8889'
## Documentation
### Command Line Interface `CLI`
Detail about the CLI can be found by reading the documentation provided by the `--help`
option flag. Documentation will but updated there as the project progresses.
```shell
(samplify) [samuel@qzdl spotify-samples]$ python samplify.py
usage: samplify.py [-h] (-l LINK | -s SEARCH)
(--album | --playlist | --song | --current-song)
[--direction DIRECTION] [--output-name OUTPUT_NAME]
[--output-type OUTPUT_TYPE] [--username USERNAME]
samplify.py: error: one of the arguments -l/--link -s/--search is required
(samplify) [samuel@qzdl spotify-samples]$ python samplify.py --help
usage: samplify.py [-h] (-l LINK | -s SEARCH)
(--album | --playlist | --song | --current-song)
[--direction DIRECTION] [--output-name OUTPUT_NAME]
[--output-type OUTPUT_TYPE] [--username USERNAME]
optional arguments:
-h, --help show this help message and exit
-l LINK, --link LINK Click "Share" > "Copy Link"
-s SEARCH, --search SEARCH
Search as you would in the app
--album
--playlist
--song
--current-song
--direction DIRECTION
--output-name OUTPUT_NAME
--output-type OUTPUT_TYPE
--username USERNAME
(samplify) [samuel@qzdl spotify-samples]$ python samplify.py --search 'uptown saturday night camp lo' --album
# SAMPLIFY: Uptown Saturday Night
This playlist was generated using Samplify.
GitHub: https://github.com/qzdl/samplify
The album, Uptown Saturday Night, has been broken down into:
"contains samples of "
Percentage Matched: 81.8%
Songs with no match:
Black Connection -> Love Is the Answer, by Van McCoy and The Soul City Symphony
Sparkle - Mr. Midnight Mix -> Leyte (Live at the Funky Quarters), by Cal Tjader
==> search terms:
Love Is the Answer van mccoy soul city symphony
Leyte (Live at the Funky Quarters) cal tjader
Sample Info:
Luchini AKA This Is It -> Adventures in the Land of Music, by Dynasty
Park Joint -> September 13, by Deodato
Sparkle -> Leyte, by Cal Tjader
Rockin' It AKA Spanish Harlem -> A Little Spice, by Loose Ends
Rockin' It AKA Spanish Harlem -> Rockin' It, by The Fearless Four
Rockin' It AKA Spanish Harlem -> The Bridge, by MC Shan
Black Nostaljack AKA Come On -> Tripping Out, by Curtis Mayfield
Coolie High -> Funny How Time Flies (When You're Having Fun), by Janet Jackson
Coolie High -> It's a New Day, by Skull Snaps
==> search terms:
Adventures in the Land of Music dynasty
September 13 deodato
Leyte cal tjader
A Little Spice loose ends
Rockin' It the fearless four
The Bridge mc shan
Tripping Out curtis mayfield
Funny How Time Flies (When You're Having Fun) janet jackson
It's a New Day skull snaps
Created playlist SAMPLIFY: Uptown Saturday Night
Aribrary playlists, albums, and songs, are read from Spotify via a fork of spotipy. Song names and artists are stored and then located on Whosampled.com
.
A request is sent to the site searching for the song name, selecting a result
with the matching artist name and storing the link to that song's page. A second
request is sent to that song page, and BeautifulSoup is used to scrape HTML for
sample details, while paging for >5 references to a category of a sample is recursively expanded in the scraper.
Next, the samples are located on Spotify, if they exist, by computing the Levenshtein distance between the a cleaned WhoSampled song title, and the top 10 search results - and choosing 'best match' - the highest ratio from this distance computation. Finally, a new playlist is created for the user, containing all the samples available on Spotify. These requests to add tracks are partioned to n requests, partitioned at 50, to side-skirt the rate-limiting imposed by Spotify's REST API for add-tracks-to-playlist.
Discovering how payloads differ to extend the functionality to albums, current song,
etc, is a process that requires some exploration. I'm sure there's examples of that
in the commit history.
album = None
with open('test_payload_f.json', 'r') as f:
import json
album = json.loads(f.read())
album_ttle = album['name']
artist = album['artists'][0]['name']
tracks = album['tracks']['items']
track_info = []
for track in tracks:
info = {}
info['title'] = track['name']
info['uri'] = track['uri']
track_info.append(info)
print(json.dumps(track_info, indent=2))
This project is based on the work of Christopher Pease (cpease00)'s sample collection tool Spotify-Samples. Without his medium article on the topic, it would have been much more painful to produce the project as it is now.
Options()
Samplify()
Scraper()