various fixes
This commit is contained in:
parent
3d5510cedb
commit
0395955afc
138
JlSonic/api.jl
138
JlSonic/api.jl
|
@ -61,54 +61,48 @@ function getMusicFolders()
|
|||
end
|
||||
end
|
||||
|
||||
# Implement:
|
||||
# getIndexes
|
||||
# getMusicDirectory
|
||||
|
||||
"Returns all genres."
|
||||
function getGenres()
|
||||
@subsonic begin
|
||||
songs = allsongs();
|
||||
res = Dict{String,Int}()
|
||||
for genre in filter!(!isempty, getfield.(songs, :genre))
|
||||
t = get(res, genre, 0)
|
||||
res[genre] = t+1
|
||||
end
|
||||
genres = new_child(xroot, "genres")
|
||||
for k in keys(res)
|
||||
genre = new_child(genres, "genre")
|
||||
set_attributes(genre, [
|
||||
("songCount", string(res[k])),
|
||||
# FIXME
|
||||
("albumCount", "0"),
|
||||
])
|
||||
add_text(genre, k)
|
||||
end
|
||||
(xdoc, xroot) = subsonic()
|
||||
songs = Beets.songs();
|
||||
res = Dict{String,Int}()
|
||||
genrelist = strip.(sort(filter!(!isempty, Beets.genre.(Beets.albums))))
|
||||
for genre in genrelist
|
||||
t = get(res, genre, 0)
|
||||
res[genre] = t+1
|
||||
end
|
||||
genres = new_child(xroot, "genres")
|
||||
for k in keys(res)
|
||||
genre = new_child(genres, "genre")
|
||||
set_attributes(genre, [
|
||||
("songCount", string(res[k])),
|
||||
# FIXME
|
||||
("albumCount", string(count(genrelist .== k))),
|
||||
])
|
||||
add_text(genre, k)
|
||||
end
|
||||
return subsonic_return(xdoc)
|
||||
end
|
||||
|
||||
"Similar to getIndexes, but organizes music according to ID3 tags."
|
||||
function getArtists()
|
||||
# TODO
|
||||
(xdoc, xroot) = subsonic(version = "1.12.0")
|
||||
(xdoc, xroot) = subsonic()
|
||||
indexes = new_child(xroot, "artists")
|
||||
set_attribute(indexes, "ignoredArticles", "")
|
||||
beetsdb = Beets.getartists()
|
||||
artists = unique(beetsdb)
|
||||
# albums = group_albums_as_artists()
|
||||
# .|> does not work in a macro. What to do?
|
||||
for index in unique(first.(filter(!isempty,
|
||||
getfield.(artists, Ref(:name)))) .|> uppercase)
|
||||
artists = Beets.artists()
|
||||
firstletters = unique(first.(filter(!isempty, Beets.name.(artists))) .|> uppercase)
|
||||
for index in string.(firstletters)
|
||||
indexXML = new_child(indexes, "index")
|
||||
set_attribute(indexXML, "name", string(index))
|
||||
for artist in filter(x -> startswith(x.name, string(index)), artists)
|
||||
artistXML = new_child(indexXML, "artist")
|
||||
set_attributes(artistXML,
|
||||
[("name", artist.name),
|
||||
("id", artist.uuid),
|
||||
("coverArt", ""),
|
||||
("albumCount", "")])
|
||||
set_attribute(indexXML, "name", index)
|
||||
for artist in unique(filter(x -> startswith(x.name, index), artists))
|
||||
artistXML = push!(indexXML, artist)
|
||||
end
|
||||
end
|
||||
doc_str = string(xdoc)
|
||||
free(xdoc)
|
||||
return doc_str
|
||||
return subsonic_return(xdoc)
|
||||
end
|
||||
|
||||
"""Returns details for an artist, including a list of albums.
|
||||
|
@ -116,22 +110,14 @@ end
|
|||
This method organizes music according to ID3 tags."""
|
||||
function getArtist(id::String)
|
||||
artists = Beets.getartists()
|
||||
matching = artists[getfield.(artists, :uuid) .== id]
|
||||
name = length(matching) > 0 ? first(matching).name : ""
|
||||
isempty(name) && return not_found()
|
||||
matching = findfirst(a -> a.uuid == id, artists)
|
||||
matching === nothing && return not_found("id")
|
||||
artist = artists[matching]
|
||||
# Create the response
|
||||
(xdoc, xroot) = subsonic()
|
||||
artistXML = new_child(xroot, "artist")
|
||||
artist = first(matching)
|
||||
artist_albums = [i for i in Beets.getalbums() if i.artist == artist]
|
||||
set_attributes(artistXML, [
|
||||
("id", artist.uuid),
|
||||
("albumCount", string(length(artist_albums))),
|
||||
("name", artist.name),
|
||||
("coverArt", "false")
|
||||
])
|
||||
for album in artist_albums
|
||||
push!(xroot, album)
|
||||
artistXML = push!(xroot, artist)
|
||||
for album in Beets.albums(artist)
|
||||
push!(artistXML, album)
|
||||
end
|
||||
return subsonic_return(xdoc)
|
||||
end
|
||||
|
@ -150,9 +136,17 @@ function getAlbum(req::Dict)
|
|||
return getAlbum(albumid)
|
||||
end
|
||||
|
||||
function getAlbum(albumid)
|
||||
album = Beets.album(string(albumid))
|
||||
album === nothing && return not_found("album")
|
||||
(xdoc, xroot) = subsonic()
|
||||
# push!(albumXML, [(s, album) for s in album.songs])
|
||||
append!(xroot, album)
|
||||
return subsonic_return(xdoc)
|
||||
end
|
||||
|
||||
function getAlbumList(req::Dict)
|
||||
query = HTTP.URIs.queryparams(req[:query])
|
||||
@show query
|
||||
albumtype = get(query, "type", "")
|
||||
isempty(albumtype) && return missing_parameter("type")
|
||||
@subsonic begin
|
||||
|
@ -161,18 +155,6 @@ function getAlbumList(req::Dict)
|
|||
end
|
||||
end
|
||||
|
||||
function getAlbum(albumid)
|
||||
matching = [album for album in Beets.getalbums() if album.uuid == albumid]
|
||||
if length(matching) < 1
|
||||
return not_found("album")
|
||||
end
|
||||
album = first(matching)
|
||||
(xdoc, xroot) = subsonic()
|
||||
albumXML = push!(xroot, album)
|
||||
push!(albumXML, [(s, album) for s in album.songs])
|
||||
return subsonic_return(xdoc)
|
||||
end
|
||||
|
||||
function getSong(req)
|
||||
query = HTTP.URIs.queryparams(req[:query])
|
||||
id = get(query, "id", "")
|
||||
|
@ -192,7 +174,7 @@ function getRandomSongs(; size = 10,
|
|||
fromYear::Union{Missing,Int} = missing,
|
||||
toYear::Union{Missing,Int} = missing,
|
||||
musicFolderId::Union{Missing,String} = missing)
|
||||
songs = allsongs();
|
||||
songs = Beets.songs();
|
||||
# Randomize
|
||||
songs = songs[Random.randperm(length(songs))];
|
||||
# Filter
|
||||
|
@ -299,7 +281,7 @@ function createPlaylist(req)
|
|||
songId = get(query, "songId", "")
|
||||
# Check required params
|
||||
isempty(songId) && return missing_parameter("songId")
|
||||
songs = allsongs();
|
||||
songs = Beets.songs();
|
||||
songn = findfirst(s -> s.uuid == songId, songs)
|
||||
songn === nothing && return not_found("songId")
|
||||
song = songs[songn]
|
||||
|
@ -355,7 +337,6 @@ end
|
|||
function updatePlaylist(req)
|
||||
global user_playlists
|
||||
query = HTTP.URIs.queryparams(req[:query])
|
||||
@show query
|
||||
playlistId = get(query, "playlistId", "")
|
||||
isempty(playlistId) && return missing_parameter("playlistId")
|
||||
# FIXME: check ownership
|
||||
|
@ -374,7 +355,7 @@ function updatePlaylist(req)
|
|||
|
||||
# TODO: Support multiple (repeated) parameter
|
||||
if !isempty(songIdAdd)
|
||||
songs = allsongs();
|
||||
songs = Beets.songs();
|
||||
songn = findfirst(s -> s.uuid == songIdAdd, songs)
|
||||
songn === nothing && return not_found("songIdToAdd")
|
||||
song = songs[songn]
|
||||
|
@ -405,17 +386,15 @@ function getUser(req)
|
|||
end
|
||||
|
||||
# Media retriveal
|
||||
|
||||
"Returns a cover art image."
|
||||
function getCoverArt(req::Dict)
|
||||
query = HTTP.URIs.queryparams(req[:query])
|
||||
id = get(query, "id", "")
|
||||
isempty(id) && return missing_parameter("id")
|
||||
albums = Beets.getalbums()
|
||||
n = findfirst(a -> album.uuid == id, albums)
|
||||
n = findfirst(a -> a.uuid == id, Beets.albums)
|
||||
n === nothing && return not_found("id")
|
||||
# @show matching.cover
|
||||
return Dict(:body => read(albums))
|
||||
headers = Dict{String,String}()
|
||||
return sendfile(Beets.albums[n].cover)
|
||||
end
|
||||
|
||||
"Streams a given media file."
|
||||
|
@ -423,8 +402,19 @@ function stream(req::Dict)
|
|||
query = HTTP.URIs.queryparams(req[:query])
|
||||
id = get(query, "id", "")
|
||||
isempty(id) && return missing_parameter("id")
|
||||
songs = allsongs()
|
||||
songs = Beets.songs()
|
||||
m = findfirst(x -> (x.uuid == id), songs)
|
||||
m === nothing && return not_found("id")
|
||||
return Dict(:body => read(songs[m].path))
|
||||
|
||||
return sendfile(songs[m].path)
|
||||
end
|
||||
|
||||
function sendfile(path; suffix = nothing)
|
||||
isfile(path) || return Dict{String,String}(:body => "Not Found")
|
||||
suffix = suffix == nothing ? lowercase(split(path, '.')[end]) : suffix
|
||||
headers = Dict{String,String}()
|
||||
headers["Content-Type"] = Mux.mimetypes[suffix]
|
||||
headers["Content-Length"] = string(filesize(path))
|
||||
return Dict(:body => read(path),
|
||||
:headers => headers)
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ function push!(root::XMLElement, p::Playlist)
|
|||
("owner", p.owner),
|
||||
("public", string(p.public)),
|
||||
("songCount", string(length(p.songs))),
|
||||
("duration", reduce(+, p.songs, init = 0.0) |> floor |> string),
|
||||
("duration", reduce(+, p.songs, init = 0.0) |> floor |> Int |> string),
|
||||
("created", "FIXME"),
|
||||
("coverArt", p.cover),
|
||||
])
|
||||
|
@ -35,38 +35,72 @@ push!(p::Playlist, s::Song) = push!(p.songs, s)
|
|||
function push!(root::XMLElement, album::Beets.Album)
|
||||
albumXML = new_child(root, "album")
|
||||
set_attributes(albumXML, [
|
||||
("name", album.title),
|
||||
("id", album.uuid),
|
||||
("name", album.artist.name),
|
||||
("artistId", album.artist.uuid),
|
||||
("artist", album.artist.name),
|
||||
# FIXME
|
||||
("created", "0"),
|
||||
("name", album.title),
|
||||
("coverArt", album.uuid),
|
||||
("songs", "FIXME"),
|
||||
("songCount", string(length(album.songs))),
|
||||
("duration", string(sum([t.length for t in album.songs])))
|
||||
("created", "0"), # FIXME
|
||||
("duration", string(sum([t.length for t in album.songs]) |> floor |> Int)),
|
||||
("artist", album.artist.name),
|
||||
("artistId", album.artist.uuid)
|
||||
])
|
||||
albumXML
|
||||
end
|
||||
|
||||
function append!(root::XMLElement, a::Beets.Album)
|
||||
albumXML = push!(root, a)
|
||||
for song in 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", "0")
|
||||
("albumCount", Beets.albums(artist) |> length |> string)
|
||||
])
|
||||
artistXML
|
||||
end
|
||||
|
||||
function push!(root::XMLElement, song::Beets.Song)
|
||||
songXML = new_child(root, "song")
|
||||
suffix = lowercase(song.format)
|
||||
set_attributes(songXML, [
|
||||
("id", song.uuid),
|
||||
("title", song.title),
|
||||
("isDir", "false"),
|
||||
("created", "FIXME"),
|
||||
("duration", string(floor(song.length) |> Int)),
|
||||
("bitrate", string(song.bitrate)),
|
||||
("size", string(filesize(song.path))),
|
||||
("suffix", suffix),
|
||||
("contentType", Mux.mimetypes[suffix]),
|
||||
("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)
|
||||
set_attributes(songXML, [
|
||||
("id", song.uuid),
|
||||
# ("parent", album.artist.uuid), # Not clear
|
||||
("parent", album.artist.uuid), # Not clear
|
||||
("title", song.title),
|
||||
("album", album.title),
|
||||
("artist", album.artist.name),
|
||||
|
@ -76,9 +110,8 @@ function push!(root::XMLElement, song_album::Tuple{Beets.Song,Beets.Album})
|
|||
("duration", string(floor(song.length) |> Int)),
|
||||
("bitrate", string(song.bitrate)),
|
||||
("size", string(filesize(song.path))),
|
||||
("suffix", lowercase(song.format)),
|
||||
## FIXME
|
||||
("contentType", "audio/flac"), # mpeg
|
||||
("suffix", suffix),
|
||||
("contentType", Mux.mimetypes[suffix]), # mpeg
|
||||
("isVideo", "false"),
|
||||
("path", relpath(song.path, Beets.musicdir())),
|
||||
("albumId", album.uuid),
|
||||
|
@ -89,6 +122,7 @@ function push!(root::XMLElement, song_album::Tuple{Beets.Song,Beets.Album})
|
|||
end
|
||||
|
||||
function props(song::Song)
|
||||
suffix = lowercase(song.format)
|
||||
[
|
||||
("id", song.uuid),
|
||||
# ("parent", album.artist.uuid), # Not clear
|
||||
|
@ -101,9 +135,8 @@ function props(song::Song)
|
|||
("duration", string(floor(song.length) |> Int)),
|
||||
("bitrate", string(song.bitrate)),
|
||||
("size", string(filesize(song.path))),
|
||||
("suffix", lowercase(song.format)),
|
||||
## FIXME
|
||||
("contentType", "audio/flac"), # mpeg
|
||||
("suffix", suffix),
|
||||
("contentType", Mux.mimetypes[suffix]), # mpeg
|
||||
("isVideo", "false"),
|
||||
("path", relpath(song.path, Beets.musicdir())),
|
||||
# ("albumId", song.album.uuid),
|
||||
|
|
|
@ -2,10 +2,13 @@ using Mux
|
|||
using HTTP
|
||||
using Revise
|
||||
|
||||
push!(LOAD_PATH, "/home/nixo/memories/projects/2018-2019/musicjl")
|
||||
import Beets
|
||||
Beets.update_albums();
|
||||
push!(LOAD_PATH, realpath("JlSonic"))
|
||||
using JlSonic
|
||||
|
||||
|
||||
include("router.jl")
|
||||
include("login.jl")
|
||||
@app sonic = (
|
||||
|
@ -21,3 +24,4 @@ if !isdefined(Main, :started)
|
|||
serve(sonic)
|
||||
started = true
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue