243 lines
8.0 KiB
Julia
243 lines
8.0 KiB
Julia
import Dates
|
|
ms2string(m::Dates.DateTime) = Dates.format(m, Dates.dateformat"YYYY-mm-ddTHH:MM:SS")
|
|
|
|
import Base.push!
|
|
|
|
# Try to fix missing mime types
|
|
Mux.mimetypes["alac"] = "audio/x-m4a"
|
|
Mux.mimetypes["m4a"] = "audio/x-m4a"
|
|
|
|
function push!(root::XMLElement, p::Playlist)
|
|
playlistXML = new_child(root, "playlist")
|
|
set_attributes(playlistXML, [
|
|
("id", convert(String, p.uuid)),
|
|
("name", p.name),
|
|
("comment", p.comment),
|
|
("owner", p.owner),
|
|
("public", string(p.public)),
|
|
("songCount", string(length(p.songs))),
|
|
("duration", reduce(+,
|
|
Beets.songbyid.(p.songs),
|
|
init = 0.0) |> floor |> Int |> string),
|
|
("created", ms2string(p.created)),
|
|
("coverArt", p.cover),
|
|
])
|
|
playlistXML
|
|
end
|
|
|
|
# FIXME: save uuids in playlists and when importing them
|
|
# look for the correct song. metadata can change
|
|
function append!(root::XMLElement, p::Playlist)
|
|
playlistXML = push!(root, p)
|
|
# Allowed users
|
|
for al in p.allowed
|
|
set_content(new_child(playlistXML, "allowedUser"), al)
|
|
end
|
|
@info "OK"
|
|
for song in Beets.songbyid.(p.songs)
|
|
@show song
|
|
entry = new_child(playlistXML, "entry")
|
|
set_attributes(entry, props(song))
|
|
album = Beets.album(song)
|
|
set_attribute(entry, "coverArt", album.uuid)
|
|
try
|
|
artist = Beets.artist(song)
|
|
n = artist != nothing ? artist.name : ""
|
|
set_attribute(entry, "artist", n)
|
|
catch e
|
|
@warn e
|
|
@show song.uuid
|
|
end
|
|
end
|
|
playlistXML
|
|
end
|
|
|
|
# FIXME!!
|
|
function push!(root::XMLElement, s::Share)
|
|
shareXML = new_child(root, "share")
|
|
set_attributes(shareXML, [
|
|
("id", string(s.id)),
|
|
# FIXME: Don't hardcode
|
|
("url", string("https://music.", domain, "/share/", s.uuid)),
|
|
("description", s.description),
|
|
("username", s.username),
|
|
("created", ms2string(s.created)),
|
|
("lastVisited", ismissing(s.lastvisit) ? "" : ms2string(s.lastvisit)),
|
|
("expires", ms2string(s.expires)),
|
|
("visitCount", string(s.count))
|
|
])
|
|
if isa(s.item, Album)
|
|
push!.(Ref(shareXML), s.item.songs; element = "entry")
|
|
else
|
|
push!(shareXML, s.item; element = "entry")
|
|
end
|
|
shareXML
|
|
end
|
|
|
|
push!(p::Playlist, s::Song) = push!(p.songs, SongUUID(s.uuid))
|
|
push!(p::Playlist, s::SongUUID) = push!(p.songs, s)
|
|
|
|
function push!(root::XMLElement, album::Beets.Album; element = "album")
|
|
albumXML = new_child(root, element)
|
|
set_attributes(albumXML, [
|
|
("id", album.uuid),
|
|
("name", album.title),
|
|
("coverArt", album.uuid),
|
|
("songCount", string(length(album.songs))),
|
|
("created", ms2string(album.added)),
|
|
("duration", string(sum([t.length for t in album.songs]) |> floor |> Int)),
|
|
("artist", album.artist.name),
|
|
("artistId", album.artist.uuid)
|
|
])
|
|
albumXML
|
|
end
|
|
|
|
import Base.sort
|
|
sort(ss::Vector{Beets.Song}) = sort(ss, by = x -> x.track)
|
|
sort(a::Vector{Beets.Album}) = sort(a, by = a -> a.year)
|
|
|
|
function append!(root::XMLElement, a::Beets.Album)
|
|
albumXML = push!(root, a)
|
|
for song in sort(a.songs)
|
|
songXML = push!(albumXML, song)
|
|
set_attributes(songXML, [
|
|
("album", a.title),
|
|
("parent", a.artist.uuid), # Not clear
|
|
("artist", a.artist.name),
|
|
("coverArt", a.uuid),
|
|
("albumId", a.uuid),
|
|
("artistId", a.artist.uuid),
|
|
])
|
|
end
|
|
albumXML
|
|
end
|
|
|
|
function push!(root::XMLElement, artist::Beets.Artist)
|
|
artistXML = new_child(root, "artist")
|
|
set_attributes(artistXML, [
|
|
("id", artist.uuid),
|
|
("name", artist.name),
|
|
("coverArt", artist.uuid),
|
|
("albumCount", Beets.album(artist) |> length |> string)
|
|
])
|
|
artistXML
|
|
end
|
|
|
|
function push!(root::XMLElement, song::Beets.Song; element = "song")
|
|
songXML = new_child(root, element)
|
|
suffix = lowercase(song.format)
|
|
mime = suffix in keys(Mux.mimetypes) ? Mux.mimetypes[suffix] : suffix
|
|
set_attributes(songXML, [
|
|
("id", song.uuid),
|
|
("title", song.title),
|
|
("isDir", "false"),
|
|
("created", ms2string(song.added)),
|
|
("duration", string(floor(song.length) |> Int)),
|
|
("bitrate", string(song.bitrate)),
|
|
("size", string(filesize(song.path))),
|
|
("suffix", suffix),
|
|
("contentType", mime),
|
|
("isVideo", "false"),
|
|
("path", relpath(song.path, Beets.musicdir())),
|
|
("type", "music")
|
|
])
|
|
songXML
|
|
end
|
|
|
|
function push!(root::XMLElement, song_album::Tuple{Beets.Song,Beets.Album})
|
|
songXML = new_child(root, "song")
|
|
song, album = song_album
|
|
suffix = lowercase(song.format)
|
|
mime = suffix in keys(Mux.mimetypes) ? Mux.mimetypes[suffix] : suffix
|
|
set_attributes(songXML, [
|
|
("id", song.uuid),
|
|
("parent", album.artist.uuid), # Not clear
|
|
("title", song.title),
|
|
("album", album.title),
|
|
("artist", album.artist.name),
|
|
("isDir", "false"),
|
|
("coverArt", album.uuid),
|
|
("created", ms2string(album.added)),
|
|
("duration", string(floor(song.length) |> Int)),
|
|
("bitrate", string(song.bitrate)),
|
|
("size", string(filesize(song.path))),
|
|
("suffix", suffix),
|
|
("contentType", mime),
|
|
("isVideo", "false"),
|
|
("path", relpath(song.path, Beets.musicdir())),
|
|
("albumId", album.uuid),
|
|
("artistId", album.artist.uuid),
|
|
("type", "music")
|
|
])
|
|
root
|
|
end
|
|
|
|
function props(song::Song)
|
|
suffix = lowercase(song.format)
|
|
mime = suffix in keys(Mux.mimetypes) ? Mux.mimetypes[suffix] : suffix
|
|
[
|
|
("id", song.uuid),
|
|
# ("parent", album.artist.uuid), # Not clear
|
|
("title", song.title),
|
|
("album", song.title),
|
|
# ("artist", song.album.artist.name),
|
|
("isDir", "false"),
|
|
# ("coverArt", song.uuid),
|
|
("created", ms2string(song.added)),
|
|
("duration", string(floor(song.length) |> Int)),
|
|
("bitrate", string(song.bitrate)),
|
|
("size", string(filesize(song.path))),
|
|
("suffix", suffix),
|
|
("contentType", mime), # mpeg
|
|
("isVideo", "false"),
|
|
("path", relpath(song.path, Beets.musicdir())),
|
|
#("albumId", song.album.uuid),
|
|
#("artistId", song.album.artist.uuid),
|
|
("type", "music")
|
|
]
|
|
end
|
|
|
|
function push!(root::XMLElement, songs::Vector{Beets.Song})
|
|
for song in songs
|
|
album = Beets.album(song)
|
|
songXML = new_child(root, "song")
|
|
set_attributes(songXML, props(song))
|
|
set_attribute(songXML, "artistId", album.artist.uuid)
|
|
set_attribute(songXML, "albumId", album.uuid)
|
|
set_attribute(songXML, "artist", album.artist.name)
|
|
set_attribute(songXML, "album", album.title)
|
|
end
|
|
root
|
|
end
|
|
|
|
function push!(root::XMLElement, songs::Vector{Tuple{Beets.Song,Beets.Album}})
|
|
for (song, album) in songs
|
|
songXML = new_child(root, "song")
|
|
set_attributes(songXML, props(song))
|
|
set_attribute(songXML, "artistId", album.artist.uuid)
|
|
set_attribute(songXML, "albumId", album.uuid)
|
|
end
|
|
root
|
|
end
|
|
|
|
function push!(root::XMLElement, user::User)
|
|
userXML = new_child(root, "user")
|
|
set_attributes(userXML,
|
|
[
|
|
("username", user.name)
|
|
("email", user.email)
|
|
("adminRole", string(user.admin))
|
|
("scrobblingEnabled", "false")
|
|
("settingsRole", string(user.settings))
|
|
("downloadRole", string(user.download))
|
|
("uploadRole", string(user.upload))
|
|
("playlistRole", string(user.playlist))
|
|
("coverArtRole", string(user.cover))
|
|
("commentRole", string(user.comment))
|
|
("podcastRole", "false")
|
|
("streamRole", string(user.stream))
|
|
("jukeboxRole", "false")
|
|
("shareRole", string(user.share))
|
|
])
|
|
end
|