#lang scribble/manual @(require (for-label racket/base racket/contract racket/list (file "../main.rkt") (file "../media-server.rkt"))) @title{Media Server Browser} @defmodule[@racketmodname[racket-upnp/media-server] #:module-paths ((file "../media-server.rkt"))] This module turns the DIDL-Lite returned by @racketmodname[racket-upnp/services/content-directory] into ordinary Racket values. Containers are browsed one level at a time; the module does not recursively load an entire media library. This is suitable for a browser that requests children when the user expands a container. The hierarchy is the logical hierarchy published by the media server. A server may offer views such as artist, album, genre, and physical folder, so a track can occur in more than one container. @section{Browsing} @defproc[(query-media-servers [#:interface interface (or/c #f string?) #f] [#:dns? dns? boolean? #f]) (listof media-server?)]{ Discovers UPnP MediaServer devices that provide a ContentDirectory service. } @defproc[(media-server? [value any/c]) boolean?]{ Recognises a MediaServer device with a ContentDirectory service. } @defproc[(media-server-root [server media-server?] [#:start start exact-nonnegative-integer? 0] [#:count count exact-nonnegative-integer? 0]) (listof media-entry?)]{ Returns the direct children of ContentDirectory object @tt{0}. The optional paging arguments are passed to ContentDirectory. A count of zero asks the server to return all available children, subject to the server's own limits. } @defproc[(media-server-browse [server media-server?] [container (or/c string? media-container?) "0"] [#:start start exact-nonnegative-integer? 0] [#:count count exact-nonnegative-integer? 0]) (listof media-entry?)]{ Returns the direct children of an object identifier or previously returned container. } @defproc[(media-container-children [server media-server?] [container media-container?] [#:start start exact-nonnegative-integer? 0] [#:count count exact-nonnegative-integer? 0]) (listof media-entry?)]{ Convenience form of @racket[media-server-browse] for a container value. } @section{Entries} @defproc[(media-entry? [value any/c]) boolean?]{Recognises a media container or media item.} @defproc[(media-entry-id [entry media-entry?]) (or/c #f string?)]{Returns the ContentDirectory object identifier.} @defproc[(media-entry-parent-id [entry media-entry?]) (or/c #f string?)]{Returns the parent object identifier.} @defproc[(media-entry-title [entry media-entry?]) string?]{Returns the displayed title.} @defproc[(media-entry-class [entry media-entry?]) (or/c #f string?)]{Returns the original UPnP class, such as @tt{object.item.audioItem.musicTrack}.} @defproc[(media-entry-restricted? [entry media-entry?]) boolean?]{Reports whether the server marks the object as restricted.} @defproc[(media-container? [value any/c]) boolean?]{Recognises a browsable container.} @defproc[(media-container-child-count [container media-container?]) (or/c #f exact-nonnegative-integer?)]{Returns the advertised number of children, when present.} @defproc[(media-container-searchable? [container media-container?]) boolean?]{Reports whether the container is advertised as searchable.} @defproc[(media-item? [value any/c]) boolean?]{Recognises a media item.} @defproc[(media-item-creator [item media-item?]) (or/c #f string?)]{Returns the Dublin Core creator.} @defproc[(media-item-artists [item media-item?]) (listof string?)]{Returns the advertised artists.} @defproc[(media-item-album [item media-item?]) (or/c #f string?)]{Returns the album title.} @defproc[(media-item-genres [item media-item?]) (listof string?)]{Returns the advertised genres.} @defproc[(media-item-date [item media-item?]) (or/c #f string?)]{Returns the advertised date without imposing a date format.} @defproc[(media-item-album-art-uri [item media-item?]) (or/c #f string?)]{Returns the album-art URI. Relative URIs are resolved against the device-description URL.} @defproc[(media-item-resources [item media-item?]) (listof media-resource?)]{Returns all playable or retrievable resources. One item may advertise several encodings.} @section{Resources} @defproc[(media-resource? [value any/c]) boolean?]{Recognises a DIDL-Lite resource.} @defproc[(media-resource-uri [resource media-resource?]) string?]{Returns the resource URI, resolved to an absolute URI where possible.} @defproc[(media-resource-protocol-info [resource media-resource?]) (or/c #f string?)]{Returns the complete UPnP @tt{protocolInfo} value.} @defproc[(media-resource-content-type [resource media-resource?]) (or/c #f string?)]{Returns the content-format portion of @tt{protocolInfo}, such as @tt{audio/flac}.} @defproc[(media-resource-size [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the size in bytes.} @defproc[(media-resource-duration [resource media-resource?]) (or/c #f nonnegative-real?)]{Returns the duration in seconds.} @defproc[(media-resource-bitrate [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the advertised bitrate in bytes per second, as defined by DIDL-Lite.} @defproc[(media-resource-sample-frequency [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the sample frequency in hertz.} @defproc[(media-resource-bits-per-sample [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the advertised bits per sample.} @defproc[(media-resource-channels [resource media-resource?]) (or/c #f exact-nonnegative-integer?)]{Returns the number of audio channels.} @defproc[(media-resource-resolution [resource media-resource?]) (or/c #f string?)]{Returns an advertised image or video resolution.} @section[#:tag "media-server-example"]{Example} @racketblock[ (define synology (car (query-media-servers #:interface "10.7.3.118"))) (define root (media-server-root synology)) (define music (findf (lambda (entry) (and (media-container? entry) (string=? (media-entry-title entry) "Muziek"))) root)) (for ([entry (in-list (media-container-children synology music))]) (printf "~a: ~a\n" (if (media-container? entry) 'container 'item) (media-entry-title entry))) ]