ini file support and cover art
This commit is contained in:
+81
-15
@@ -19,6 +19,8 @@
|
||||
player-agent-register!
|
||||
player-agent-poll!
|
||||
player-agent-media
|
||||
player-track-artwork
|
||||
exn:fail:agent-denied?
|
||||
player-close!)
|
||||
|
||||
(sl-def-log web-player)
|
||||
@@ -38,12 +40,16 @@
|
||||
[ended-counter #:mutable])
|
||||
#:transparent)
|
||||
|
||||
(struct exn:fail:agent-denied exn:fail ()
|
||||
#:transparent)
|
||||
|
||||
(struct playlist-tab
|
||||
(id [name #:mutable] [tracks #:mutable])
|
||||
#:transparent)
|
||||
|
||||
(struct player
|
||||
(libraries
|
||||
allowed-agent-ids
|
||||
[agents #:mutable]
|
||||
[current-library-id #:mutable]
|
||||
[browser-path #:mutable]
|
||||
@@ -103,6 +109,25 @@
|
||||
(and (string? value)
|
||||
(regexp-match? #px"^[0-9a-fA-F]{64}$" value)))
|
||||
|
||||
(define (normal-agent-id value)
|
||||
(and (valid-agent-id? value)
|
||||
(string-downcase value)))
|
||||
|
||||
(define (authorized-agent-id? value app-id)
|
||||
(and (normal-agent-id app-id)
|
||||
(member (normal-agent-id app-id)
|
||||
(player-allowed-agent-ids value))
|
||||
#t))
|
||||
|
||||
(define (require-authorized-agent! value app-id)
|
||||
(unless (authorized-agent-id? value app-id)
|
||||
(raise
|
||||
(exn:fail:agent-denied
|
||||
(format
|
||||
"Playback agent ~a is niet toegestaan; voeg het applicatie-ID eerst toe aan [playback-agents] in de server-INI"
|
||||
(or app-id "(ontbreekt)"))
|
||||
(current-continuation-marks)))))
|
||||
|
||||
(define (fresh-media-token)
|
||||
(bytes->hex-string (crypto-random-bytes 32)))
|
||||
|
||||
@@ -736,6 +761,7 @@
|
||||
'album (track-album item)
|
||||
'duration (or (track-duration item) 'null)
|
||||
'mimeType (track-mime-type item)
|
||||
'artworkId (track-cache-key item)
|
||||
'source (path->string
|
||||
(or (file-name-from-path (track-file item))
|
||||
(track-file item)))))
|
||||
@@ -1011,11 +1037,21 @@
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : Create a player for lazily browsed music libraries.
|
||||
; pre : Libraries is a list of music-library values; DLNA port is positive.
|
||||
; pre : Libraries are valid; allowed agent IDs are 256-bit hex strings.
|
||||
; post : Only the selected root directory has been listed; no backend exists.
|
||||
; result : A player that initially selects local playback.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (make-player libraries #:dlna-port [dlna-port 8734])
|
||||
(define (make-player libraries
|
||||
#:allowed-agent-ids [allowed-agent-ids '()]
|
||||
#:dlna-port [dlna-port 8734])
|
||||
(define normalized-agent-ids
|
||||
(for/list ((app-id (in-list allowed-agent-ids)))
|
||||
(unless (valid-agent-id? app-id)
|
||||
(raise-argument-error
|
||||
'make-player
|
||||
"64-character hexadecimal playback agent id"
|
||||
app-id))
|
||||
(string-downcase app-id)))
|
||||
(let* ((library (and (pair? libraries) (car libraries)))
|
||||
(browser-entries
|
||||
(if library
|
||||
@@ -1023,6 +1059,7 @@
|
||||
'()))
|
||||
(tab (playlist-tab "default" "Default" '())))
|
||||
(player libraries
|
||||
(remove-duplicates normalized-agent-ids string=?)
|
||||
'()
|
||||
(and library (music-library-id library))
|
||||
'()
|
||||
@@ -1184,12 +1221,13 @@
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : Register or refresh one polling playback agent.
|
||||
; pre : Data contains a 256-bit hexadecimal application id.
|
||||
; pre : Data contains an allowlisted 256-bit hexadecimal application id.
|
||||
; post : The agent is available as a renderer under its advertised name.
|
||||
; result : Agent configuration for the polling client.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (player-agent-register! value data)
|
||||
(let* ((app-id (json-string data 'appId #f))
|
||||
(let* ((supplied-app-id (json-string data 'appId #f))
|
||||
(app-id (normal-agent-id supplied-app-id))
|
||||
(suggested-name
|
||||
(string-trim
|
||||
(or (json-string data 'name #f)
|
||||
@@ -1198,11 +1236,12 @@
|
||||
(if (string=? suggested-name "")
|
||||
"RKT playback agent"
|
||||
suggested-name)))
|
||||
(unless (valid-agent-id? app-id)
|
||||
(unless app-id
|
||||
(raise-arguments-error
|
||||
'player-agent-register!
|
||||
"appId must contain exactly 64 hexadecimal characters"
|
||||
"appId" app-id))
|
||||
"appId" supplied-app-id))
|
||||
(require-authorized-agent! value app-id)
|
||||
(with-state-lock
|
||||
value
|
||||
(λ ()
|
||||
@@ -1247,13 +1286,15 @@
|
||||
; result : Poll response containing the current agent name and optional command.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (player-agent-poll! value data)
|
||||
(let ((app-id (json-string data 'appId #f))
|
||||
(let* ((supplied-app-id (json-string data 'appId #f))
|
||||
(app-id (normal-agent-id supplied-app-id))
|
||||
(name (json-string data 'name #f)))
|
||||
(unless (valid-agent-id? app-id)
|
||||
(unless app-id
|
||||
(raise-arguments-error
|
||||
'player-agent-poll!
|
||||
"appId must contain exactly 64 hexadecimal characters"
|
||||
"appId" app-id))
|
||||
"appId" supplied-app-id))
|
||||
(require-authorized-agent! value app-id)
|
||||
(call-with-semaphore
|
||||
(player-command-lock value)
|
||||
(λ ()
|
||||
@@ -1324,12 +1365,30 @@
|
||||
(with-state-lock
|
||||
value
|
||||
(λ ()
|
||||
(let ((agent (and (valid-agent-id? app-id)
|
||||
(agent-by-id value app-id))))
|
||||
(let* ((normalized (normal-agent-id app-id))
|
||||
(agent (and normalized
|
||||
(authorized-agent-id? value normalized)
|
||||
(agent-by-id value normalized))))
|
||||
(and agent
|
||||
(string? token)
|
||||
(hash-ref (playback-agent-media agent) token #f))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : Resolve an opaque playlist artwork id.
|
||||
; pre : Artwork id came from player-state->jsexpr.
|
||||
; post : Player state remains unchanged.
|
||||
; result : Artwork bytes and MIME type, or #f when unavailable.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (player-track-artwork value artwork-id)
|
||||
(let ((item
|
||||
(with-state-lock
|
||||
value
|
||||
(λ ()
|
||||
(findf (λ (candidate)
|
||||
(string=? (track-cache-key candidate) artwork-id))
|
||||
(player-tracks value))))))
|
||||
(and item (track-artwork item))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : Stop playback and release all player resources.
|
||||
; pre : Value was created with make-player.
|
||||
@@ -1358,7 +1417,10 @@
|
||||
(λ ()
|
||||
(make-directory (build-path root "Album"))
|
||||
(let* ((libraries (make-music-libraries (list root)))
|
||||
(example-player (make-player libraries))
|
||||
(test-agent-id (make-string 64 #\a))
|
||||
(example-player
|
||||
(make-player libraries
|
||||
#:allowed-agent-ids (list test-agent-id)))
|
||||
(initial-state
|
||||
(player-state->jsexpr example-player)))
|
||||
(check-equal? (hash-ref initial-state 'state) "stopped")
|
||||
@@ -1423,9 +1485,6 @@
|
||||
|
||||
(check-equal? (length (hash-ref deleted-state 'tabs)) 1)
|
||||
|
||||
(define test-agent-id
|
||||
(make-string 64 #\a))
|
||||
|
||||
(define registration
|
||||
(player-agent-register!
|
||||
example-player
|
||||
@@ -1433,6 +1492,13 @@
|
||||
'name "Test laptop")))
|
||||
|
||||
(check-equal? (hash-ref registration 'name) "Test laptop")
|
||||
(check-exn
|
||||
exn:fail:agent-denied?
|
||||
(λ ()
|
||||
(player-agent-register!
|
||||
example-player
|
||||
(hasheq 'appId (make-string 64 #\b)
|
||||
'name "Unknown laptop"))))
|
||||
|
||||
(define agent-renderer-state
|
||||
(player-command!
|
||||
|
||||
Reference in New Issue
Block a user