#lang racket/base (require racket/cmdline racket/contract racket/format racket/string simple-log "private-player-agent/player-agent-config.rkt" "private-player-agent/player-agent-core.rkt") (provide run-player-agent-cli) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Supporting functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; goal : Produce a concise description of the current agent track. ; pre : track is #f or a server-supplied track hash. ; post : No state is changed. ; result : Artist and title when available, otherwise title or filename. ; internals: ; The CLI deliberately uses server metadata and does not reopen the ; downloaded media file solely for display purposes. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (track-description track) (cond ((not track) "geen track") (else (let ((title (hash-ref track 'title #f)) (artist (hash-ref track 'artist #f)) (filename (hash-ref track 'filename "onbekend"))) (cond ((and artist title (not (string=? artist ""))) (format "~a — ~a" artist title)) (title title) (else filename)))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Provided functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; goal : Run the headless polling playback agent. ; pre : Overrides are #f or valid strings/paths and the configured server ; is reachable for useful operation. ; post : Configuration is persisted; runtime resources are released after ; interruption or an exception. ; result : Void after the agent has shut down. ; internals: ; One monitor thread prints only changed playback summaries. The ; shared runtime owns polling, downloads, audio and prefetch state. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define/contract (run-player-agent-cli #:server-url [server-override #f] #:name [name-override #f] #:config-file [config-file #f]) (->* () (#:server-url (or/c string? #f) #:name (or/c string? #f) #:config-file (or/c path-string? #f)) void?) (sl-log-to-display) (let* ((loaded (if config-file (load-player-agent-config config-file) (load-player-agent-config))) (server-url (string-trim (or server-override (player-agent-config-server-url loaded)))) (name (string-trim (or name-override (player-agent-config-name loaded)))) (config (struct-copy player-agent-config loaded (server-url server-url) (name name))) (write-status (λ (message) (printf "[agent] ~a~n" message) (flush-output))) (runtime (make-player-agent-runtime server-url name (player-agent-config-app-id config) #:status-callback write-status #:denied-callback (λ (message) (eprintf "~a~n" message) (flush-output (current-error-port))))) (monitor #f)) (save-player-agent-config! config) (printf "RKT Web Player CLI Agent~n") (printf "Naam: ~a~n" name) (printf "Server: ~a~n" server-url) (printf "Applicatie-ID: ~a~n" (player-agent-config-app-id config)) (printf "Stoppen: Ctrl+C~n") (flush-output) (dynamic-wind (λ () ((player-agent-runtime-start! runtime)) (set! monitor (thread (λ () (let loop ((previous #f)) (let* ((snapshot ((player-agent-runtime-snapshot runtime))) (summary (cons (hash-ref snapshot 'state "stopped") (track-description ((player-agent-runtime-current-track runtime)))))) (unless (equal? summary previous) (printf "[playback] ~a — ~a~n" (car summary) (cdr summary)) (flush-output)) (sleep 1) (loop summary))))))) (λ () (with-handlers ((exn:break? void)) (sync never-evt))) (λ () (when (and monitor (not (thread-dead? monitor))) (kill-thread monitor)) ((player-agent-runtime-shutdown! runtime)))))) (module+ main (define server-url #f) (define name #f) (define config-file #f) (command-line #:program "rkt-web-player-agent-cli" #:once-each (("--server") value "RKT Web Player base URL" (set! server-url value)) (("--name") value "Name shown in the output selector" (set! name value)) (("--config") value "Agent INI file (defaults to the same file as the GUI agent)" (set! config-file value))) (run-player-agent-cli #:server-url server-url #:name name #:config-file config-file))