#lang scribble/manual @(require (for-label racket/base (file "../didl-lite.rkt") (file "../media-file-server.rkt"))) @title{Publishing Media Files} @defmodule[racket-upnp/media-file-server] This module publishes local files through a small Racket web server. The underlying Racket file dispatcher streams files and supports both @tt{HEAD} requests and HTTP byte ranges. Byte ranges are important for media-renderer probing and seeking. At info log level, each published transfer reports its start and completion or interruption, including client address, HTTP method, requested range and elapsed time. No publication lock is held while the response is being streamed. @defproc[(media-file-server? [value any/c]) boolean?]{ Returns @racket[#t] when @racket[value] is a media file server. } @defproc[(start-media-file-server [url string?] [#:listen-ip listen-ip (or/c #f string?) #f]) media-file-server?]{ Starts a server for the HTTP origin and path prefix in @racket[url]. The URL must be an absolute @tt{http://} URL. A trailing slash is added when needed. When @racket[listen-ip] is @racket[#f], the server listens on all local interfaces. Supply a local address, such as @tt{10.7.3.118}, to restrict the listener to that interface. } @defproc[(media-file-server-url [server media-file-server?]) string?]{ Returns the normalized base URL of @racket[server]. } @defproc[(media-file-server-publish! [server media-file-server?] [file path-string?] [url string?] [#:mime-type mime-type (or/c #f bytes? string?) #f]) string?]{ Publishes @racket[file] at @racket[url] and returns the absolute URL. The URL may be relative to the server URL: @racketblock[ (define uri (media-file-server-publish! files "C:/muziek/test.flac" "test.flac")) ] It may also be the complete URL, provided that its origin and path prefix match the server: @racketblock[ (media-file-server-publish! files "C:/muziek/test.flac" "http://10.7.3.118:8080/media/test.flac") ] The MIME type is inferred for common audio, video, and image extensions. Use @racket[#:mime-type] to override it. } @defproc[(media-file-server-unpublish! [server media-file-server?] [url string?]) void?]{ Removes the URL mapping. Requests that are already in progress may still finish. } @defproc[(media-file-server-didl-lite [server media-file-server?] [url string?] [#:title title (or/c #f string?) #f] [#:artist artist (or/c #f string?) #f] [#:album album (or/c #f string?) #f] [#:genre genre (or/c #f string?) #f] [#:year year (or/c #f exact-nonnegative-integer?) #f] [#:track track (or/c #f exact-nonnegative-integer?) #f] [#:duration duration (or/c #f nonnegative-real?) #f] [#:id id string? "0"] [#:parent-id parent-id string? "0"]) string?]{ Returns DIDL-Lite metadata for a URL previously installed with @racket[media-file-server-publish!]. The MIME type, file size, and @tt{DLNA.ORG_OP=01} byte-range capability are taken from the actual publication. The file name is used as the title when @racket[title] is @racket[#f]. Pass the result as @racket[#:metadata] or @racket[#:next-metadata] to the media-renderer functions. Supplying the duration is recommended because some renderers use it when deciding whether time seeking is available. } @defproc[(media-file-server-stop! [server media-file-server?]) void?]{ Stops the web server. Repeated calls have no effect. } @section{Playing local files} @racketblock[ (define files (start-media-file-server "http://10.7.3.118:8080/media/" #:listen-ip "10.7.3.118")) (define first-uri (media-file-server-publish! files "C:/muziek/first.flac" "first.flac")) (define second-uri (media-file-server-publish! files "C:/muziek/second.flac" "second.flac")) (define first-metadata (media-file-server-didl-lite files first-uri #:title "First track" #:duration 639)) (define second-metadata (media-file-server-didl-lite files second-uri #:title "Second track" #:duration 242)) (media-renderer-play-uri! renderer first-uri #:metadata first-metadata #:next-uri second-uri #:next-metadata second-metadata) ] Keep the URLs published until the renderer has finished reading them.