Skip to content

A custom scripting language to create semi-randomised playlists that are different based on configurable rulesets.

Notifications You must be signed in to change notification settings

AK1089/spotify-scripting

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Spotify Scripting

This documentation serves as a brief introduction to my Spotify Scripting language, which can construct custom playlists for you based on a complex set of rules.

Want a playlist to open with a random song from a list of good opening tracks, then be followed by a random Taylor Swift song, and then two Lady Gaga songs from different albums? This is easy to do with Spotify Scripting!


Authors


Setup

The main directory should contain interpreter.py, as well as the files:
config.txt filled in with your Spotify API details
playlists.txt which contains specified playlist details (the API's playlist search is notoriously bad.)
tracks.json which can be left empty to start (the program will build out a track cache as you use it.)

Each playlist you create should be contained in its own text file (.txt) in the Playlists subfolder, named after its intended title.
To use the program, run python3 interpreter.py playlist (with playlist being the name of your desired playlist) in the directory. The first time you run the program, you'll have to log in with Spotify to grant access to your details.

Documentation

The syntax of the scripting language is detailed in the rest of this document. Each line should begin with a keyword from the following table.


Keyword Function
# a comment (line does nothing)
var declares / alters a variable
if branching logic
elseif branching logic
else branching logic
fi closes a branch of if/elseif/else
pass no operation (does nothing)
jumpto jumps to a line number or the specified coda
coda trigger for jumpto
quit halts execution


Declaring Variables

Variables are declared and set using the var keyword. For example,
var a = 3
initialises the variable a to the value of 3. As in Python, there is no syntactic difference between declaring new variables and changing the value of existing ones. Variables can only take floating point values. Boolean values are represented by 1 and 0 for True and False.


Operators

The basic operators are:

+ addition
- subtraction
* multiplication
/ division
^ exponentiation

The comparative operators are:

== equal to
!= not equal to
> greater than
>= strictly greater than
< less than
<= strictly less than

The logical operators are:

! NOT
| OR
& AND

Parentheses are used as normal to bracket the order of expressions. Comparative and logical operators return either 0 or 1.

Some random features are available in variables too.
rand() -> a random float uniformly distributed across [0, 1]
randint(a, b) -> a random integer uniformly distributed across [a, b] (where a<b)
choose(a, b, c, ...) -> returns one of a, b, c, etc. with equal chance



Branching Logic

a = rand()
if a < 4

  # this code runs if a is less than 4
  var b = 10

elseif a < 5

  # this code runs if a is less than 5, but was not less than 4
  var b = 8

else

  # this code runs if a is neither less than 4 nor less than 5
  var b = 12

fi

This works like nearly all other languages.

Jumping Logic

The jumpto keyword can take two types of arguments: integers (line numbers), and keywords. These two uses are demonstrated below: line number jumps skip to the beginning of that line, and keyword jumps skip to the next line containing coda <keyword>.

 1 |  var a = 10
 2 |  jumpto trigger
 3 |  
 4 |  # the following line is not run, as we are jumping to trigger
 5 |  var a = 20
 6 |  
 7 |  coda trigger
 8 |  var a = 30
 9 |  jumpto 14
10 |
11 |  # the following line is also not run, as we are jumping to line 14
12 |  var a = 40
13 |
14 |  var a = 50

This sets the variable a to 10 on line 1, then 30 on line 8, then 50 on line 14. All other lines are skipped by the two types of jumpto.

The "pass" and "quit" keywords

The pass and quit keywords are very simple. A line which starts with pass does nothing, and a line starting with quit halts the entire program.

Actually Playing Music

Finally, the good bit! To play music, use the play keyword. For example:

play 2 from playlist("my favourite songs")

The first number can be literal, a variable you've defined, or the word "all". The line above will play 2 (different, randomly selected) songs from the selected playlist.

play 1 from album("future nostalgia")

will play a random song from the album Future Nostalgia by Dua Lipa.

play 1 from album(choose("1989 deluxe", "reputation", "lover"))

will select a random album from 1989 (Deluxe), reputation, or Lover by Taylor Swift, then play a random song from there.

play all from choose(artist("lady gaga").albums)

will select a random album from all of Lady Gaga's discography, then play it through.

More complicated expressions are also available, including using the "filtered by" keyword! For example,

var a = randint(2, 3)
play a from playlist(choose("party playlist", "best sad songs")) filtered by (year=span(None, 2018))

will pick either the "party playlist" or "best sad songs" playlist, filter that playlist down to songs which were released during or before 2018, and then play either 2 or 3 songs from the resulting shortlist.

Note that you can filter by year, duration, popularity, or track_number (position within its album). Use span(lower, upper) to denote an inclusive range, with None being an acceptable endpoint (eg. span(None, 2018) denotes "during or before 2018").

Accepted Music Sources (functions)

The functions you can use to find music in script code include:
artist("name") finds an artist by the given name. You can access the .albums attribute.
album("name") finds an album by the given name. You can access the .tracks attribute, as well as the .artist, .year, and .length attributes.
playlist("name") finds a playlist by the given name, either through the playlists.txt file or through Spotify search.
track("name") finds a track by the given name.

A Full Example (also found in example.txt)

# plays 1 from a random album out of the ones listed
play 1 from album(choose("reputation", "lover", "1989 deluxe"))

# plays two 2018-2020 song from the pres playlist
play 2 from playlist("pres") filtered by (year=span(2018,2020))

# plays a song from the first four from my current obsessions playlist
play 1 from playlist("songs i'm currently obsessed with")[:4]

# plays a song from the top thirteen taylor playlist
play 1 from playlist("top thirteen taylor")

# sets a to a random value out of 1 / 2 and plays that many songs from one of these albums (that's 2-4 minutes long)
var a = randint(1, 2)
play a from album(choose("future nostalgia", "mercurial world")) filtered by (duration=span(120, 240))

# if a was set to 2, play a random carly rae jepsen song
if a == 2
  play 1 from choose(artist("carly rae jepsen").albums)

# otherwise if a was 1, play a fairly popular 3-3.5 minute song from the NYE party playlist
else
  play 1 from playlist("nye party playlist") filtered by (duration=span(180, 210), popularity=span(70, 90))
fi

# 99% chance we end here
if rand() < 0.99
  quit
fi

play 1 from track("never gonna give you up")

About

A custom scripting language to create semi-randomised playlists that are different based on configurable rulesets.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages