This is a wrapper to query and interact with the rekordbox 6 database
Motivation behind this tool is to enable better automation and integration with rekordbox. In previous versions it was possible to just use the rekordbox XML to query data, but since rekordbox 6 this is no longer possible
Note: This is a quickly hacked together project. Use at own risk, and make a backup of your database.
- Golang wrapper for rekordbox databases
This wrapper is mostly automatically generated by connecting to the rekordbox database and using it's schema to create a bunch of models including helper functions around SQL commands. You can find those in rekordbox/
, and the dumped schema in db/schema.sql
Docs are available at https://pkg.go.dev/github.com/dvcrn/go-rekordbox/rekordbox
go get github.com/dvcrn/go-rekordbox
Create a new rekordbox.Client
with rekordbox.NewClient
and use it to query
You'll need the following:
- path to
options.json
, on mac this is typically~/Library/Application Support/Pioneer/rekordboxAgent/storage/options.json
, on windows potentially inC:\Users\XXXX\AppData\Roaming\Pioneer\rekordboxAgent\storage
package main
import (
"context"
"fmt"
"github.com/dvcrn/go-rekordbox/rekordbox"
)
func main() {
ctx := context.Background()
homeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
optionsFilePath := filepath.Join(homeDir, "/Library/Application Support/Pioneer/rekordboxAgent/storage/", "options.json")
client, err := rekordbox.NewClient(optionsFilePath)
if err != nil {
panic(err)
}
defer client.Close()
// your amazing stuff here
package main
import (
"context"
"fmt"
"github.com/dvcrn/go-rekordbox/rekordbox"
)
func main() {
ctx := context.Background()
homeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
optionsFilePath := filepath.Join(homeDir, "/Library/Application Support/Pioneer/rekordboxAgent/storage/", "options.json")
client, err := rekordbox.NewClient(optionsFilePath)
if err != nil {
panic(err)
}
defer client.Close()
// query all playlists
playlists, err := client.AllDjmdPlaylist(ctx)
if err != nil {
panic(err)
}
for _, playlist := range playlists {
fmt.Printf("%s\n", playlist.Name.String)
// query all songs that are in the playlist
playlistSongs, err := client.DjmdSongPlaylistByPlaylistID(ctx, playlist.ID)
if err != nil {
panic(err)
}
// get all songs within the playlist
for _, playlistSong := range playlistSongs {
content, err := client.DjmdContentByID(ctx, playlistSong.ContentID)
if err != nil {
panic(err)
}
fmt.Printf("\t%s\n", content.Title.String)
}
}
}
Output:
Tech
8A - 125 - La Candela Viva (Extended Mix)
10A - 125 - Do It To It (Extended Mix)
8B - 125 - Milk Shake (Original Mix)
6A - 126 - You Give Me A Feeling (Original Mix)
12B - 129 - My Humps (Original Mix)
4A - 126 - Want To Love (Extended Mix)
12B - 126 - Technologic (Original Mix)
9B - 126 - Disconnected (Extended Mix)
(...and so on)
ctx := context.Background()
homeDir, err := os.UserHomeDir()
if err != nil {
panic(err)
}
optionsFilePath := filepath.Join(homeDir, "/Library/Application Support/Pioneer/rekordboxAgent/storage/", "options.json")
client, err := rekordbox.NewClient(optionsFilePath)
if err != nil {
panic(err)
}
defer client.Close()
songs, err := client.RecentDjmdSongHistory(ctx, 10)
if err != nil {
panic(err)
}
fmt.Println("Your recent songs")
for _, song := range songs {
content, err := client.DjmdContentByID(ctx, song.ContentID)
if err != nil {
panic(err)
}
fmt.Printf("\t%s (%s)\n", content.Title.String, song.ContentID.String)
}
Output:
Your recent songs
9A - 127 - Intense (Original Mix) (123557411)
7A - 127 - Gradual Disruption (Original Mix) (154120490)
7A - 126 - In Chicago (Extended Mix) (175359939)
7A - 126 - What I Need (Extended) (59136374)
10A - 127 - Romeo (Wh0 Extended Festival Remix) (59823290)
9A - 126 - Higher (Original Mix) (183964619)
9A - 125 - Gimme Some Keys (Original Mix) (247948942)
10A - 125 - Do It To It (Extended Mix) (150109009)
1B - 126 - Bad Habits (MEDUZA Extended Remix) (173015998)
12B - 130 - Last Step (A*S*Y*S Remix) (246529)
Smart playlists are not fully supported by this library yet, but work has started in djmdplaylist.go. The gist is - there is no built-in support for filtering smartlists. Those are not stored in the DB so you'll have to do the querying yourself.
If a playlist is a smartlist, the field SmartList
will be set with an XML of all conditions of the filter like so:
<NODE Id="1820824522" LogicalOperator="2" AutomaticUpdate="0"><CONDITION PropertyName="myTag" Operator="9" ValueUnit="" ValueLeft="-1758883739" ValueRight=""/><CONDITION PropertyName="artist" Operator="11" ValueUnit="" ValueLeft="hoge" ValueRight=""/></NODE>
Note here: Rekordbox stores value as 32bit integer, so if you see a negative value under ValueLeft
, this value likely overflowed by exceeding max int32, and you need to reverse the overflow process to get the original value back.
This library comes with helpers to parse the XML content and all sub-conditions. There are also helpers to parse the value and fix the overflow mentioned in the line above.
Here is an example that parses an intelligent playlist with 2 MyTag filters, one by MyTag "Genre" (this overflows and is stored as '-215641850' but the actual ID is '4079325446'), one by MyTag "Energy".
playlist, err := client.DjmdPlaylistByID(ctx, nulltype.NullStringOf("397309610"))
if err != nil {
panic(err)
}
if playlist.IsSmartlist() {
fmt.Println("playlist is a smartlist")
fmt.Println("title: ", playlist.Name)
node := playlist.SmartlistNode()
fmt.Println("conditions in this smartlist:")
for _, condition := range node.Conditions {
fmt.Println(condition.PropertyName)
fmt.Println(condition.ParseValueLeft())
}
}
Outputs:
playlist is a smartlist
title: Techno
conditions in this smartlist:
myTag
4079325446
myTag
22788202
You can also directly access the sqlx.DB object by calling client.GetDB()
, and use that to issue queries directly
There's a handy Makefile command that does all of this for you (works only on Mac):
make genmodels
You need to have xo (run make deps
and sqlcipher installed (through brew))
To add custom functions ontop of the existin generated code, just create a new file under rekordbox/
and name it accordingly, without xo
in the name.
For example, the recent song history implementation is done in djmdsonghistory.go
which extends djmdsonghistory.xo.go
(the auto-generated one)
Code generation is handled by xo. To extend the generated code, update the xo template in tpl/schema.xo.go.tpl
. Once you updated that, re-generate the models with make genmodels
to see your changes
- Initial database connection code taken from supbox