JlSonic/JlSonic/beet2xml.jl

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