Media file server
This commit is contained in:
@@ -1,114 +1,120 @@
|
||||
#lang scribble/manual
|
||||
|
||||
@(require (for-label racket/base
|
||||
racket/contract
|
||||
racket/list
|
||||
(file "../main.rkt")
|
||||
(file "../media-server.rkt")))
|
||||
@(require
|
||||
(for-label
|
||||
racket/base
|
||||
(file "../media-server.rkt")))
|
||||
|
||||
@title{Media Server Browser}
|
||||
@title{Media Servers}
|
||||
|
||||
@defmodule[@racketmodname[racket-upnp/media-server] #:module-paths ((file "../media-server.rkt"))]
|
||||
@defmodule[(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.
|
||||
This module provides a higher-level browser for UPnP and DLNA media servers.
|
||||
It converts ContentDirectory DIDL-Lite XML into containers, items, and media
|
||||
resources.
|
||||
|
||||
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.
|
||||
@defproc[(query-media-servers
|
||||
[#:interface interface (or/c #f string?) #f]
|
||||
[#:dns? dns? boolean? #f])
|
||||
(listof media-server?)]{
|
||||
|
||||
Discovers media servers.
|
||||
}
|
||||
|
||||
@defproc[(get-media-server [filter-name string?])
|
||||
(or/c #f media-server?)]{
|
||||
|
||||
Returns the first discovered media server whose name contains
|
||||
@racket[filter-name], ignoring case, or @racket[#f].
|
||||
}
|
||||
|
||||
@defproc[(media-server? [value any/c]) boolean?]
|
||||
@defproc[(media-server-name [server media-server?]) string?]
|
||||
@defproc[(media-server-address [server media-server?]) string?]
|
||||
@defproc[(media-server-manufacturer [server media-server?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-server-model [server media-server?])
|
||||
(or/c #f string?)]
|
||||
|
||||
@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])
|
||||
@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.
|
||||
|
||||
Browses object @tt{0}, the ContentDirectory root.
|
||||
}
|
||||
|
||||
@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])
|
||||
@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.
|
||||
|
||||
Browses one level below a container ID or a previously returned container.
|
||||
|
||||
In ContentDirectory, @racket[count] equal to zero asks the server to return all
|
||||
remaining entries. Use a positive count for large containers.
|
||||
}
|
||||
|
||||
@defproc[(media-container-children [server media-server?]
|
||||
[container media-container?]
|
||||
[#:start start exact-nonnegative-integer? 0]
|
||||
[#:count count exact-nonnegative-integer? 0])
|
||||
@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.
|
||||
|
||||
Equivalent to browsing the supplied container.
|
||||
}
|
||||
|
||||
@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-entry? [value any/c]) boolean?]
|
||||
@defproc[(media-entry-id [entry media-entry?]) (or/c #f string?)]
|
||||
@defproc[(media-entry-parent-id [entry media-entry?]) (or/c #f string?)]
|
||||
@defproc[(media-entry-title [entry media-entry?]) string?]
|
||||
@defproc[(media-entry-class [entry media-entry?]) (or/c #f string?)]
|
||||
@defproc[(media-entry-restricted? [entry media-entry?]) boolean?]
|
||||
|
||||
@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-container? [value any/c]) boolean?]
|
||||
@defproc[(media-container-child-count [container media-container?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-container-searchable? [container media-container?])
|
||||
boolean?]
|
||||
|
||||
@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.}
|
||||
@defproc[(media-item? [value any/c]) boolean?]
|
||||
@defproc[(media-item-creator [item media-item?]) (or/c #f string?)]
|
||||
@defproc[(media-item-artists [item media-item?]) (listof string?)]
|
||||
@defproc[(media-item-album [item media-item?]) (or/c #f string?)]
|
||||
@defproc[(media-item-genres [item media-item?]) (listof string?)]
|
||||
@defproc[(media-item-date [item media-item?]) (or/c #f string?)]
|
||||
@defproc[(media-item-album-art-uri [item media-item?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-item-resources [item media-item?])
|
||||
(listof media-resource?)]
|
||||
|
||||
@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)))
|
||||
]
|
||||
@defproc[(media-resource? [value any/c]) boolean?]
|
||||
@defproc[(media-resource-uri [resource media-resource?]) string?]
|
||||
@defproc[(media-resource-protocol-info [resource media-resource?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-resource-content-type [resource media-resource?])
|
||||
(or/c #f string?)]
|
||||
@defproc[(media-resource-size [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-duration [resource media-resource?])
|
||||
(or/c #f number?)]
|
||||
@defproc[(media-resource-bitrate [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-sample-frequency [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-bits-per-sample [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-channels [resource media-resource?])
|
||||
(or/c #f exact-nonnegative-integer?)]
|
||||
@defproc[(media-resource-resolution [resource media-resource?])
|
||||
(or/c #f string?)]
|
||||
|
||||
Reference in New Issue
Block a user