various fixes

master
nixo 2019-05-19 18:28:43 +02:00
parent 3d5510cedb
commit 0395955afc
3 changed files with 118 additions and 91 deletions

View File

@ -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

View File

@ -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),

View File

@ -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