Playlists
A playlist is a JSON document of pages. playlist init prepares a full-screen document from ordered inputs. playlist create and playlist update read that document from a file; playlist patch, playlist rename and playlist page add|replace|remove change part of it. The shape is summarised under the commands.
playlist init#
Prepare an editable full-screen playlist from local media files, ready media IDs, application release IDs, HTTP or HTTPS URLs, or pasted iframe embed codes.
playlist init <inputs...> --name NAME --output FILE [--overwrite] [--screen-id ID]
[--target-width PX --target-height PX] [--duration-ms MS] [--fit contain|cover|fill] [--sound]
[--no-transcode] [--no-progress] [--poll-ms MS]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<inputs...> | files, med_ IDs, rel_ IDs, HTTP or HTTPS URLs, or pasted <iframe> embed codes | yes | none | Playback order. Local image, video and audio files upload and wait for readiness unless --no-transcode. Existing media must already be ready. An audio file or a ready audio med_ ID becomes the soundtrack, in input order, instead of a page; at least one input must be a page. HTTP and HTTPS URLs may include LAN hosts, embedded credentials and screen tokens such as {screen.field.kiosk_id}, kept as written, and are not fetched. A pasted embed code is read for its src. The Player web app requires HTTPS URLs without a username or password. |
--name NAME | string | yes | none | Playlist display name. |
--output FILE | path | yes | none | Write the editable playlist document. Parent directories are created. Exclusive by default: an existing non-empty file fails with usage_error (exit 2) and is left untouched. |
--overwrite | boolean | no | off | Replace an existing output file atomically with a document built from these inputs. |
--screen-id ID | string | no | none | Read the target screen's dimensions and revision. A screen with a video wall gives the wall's canvas and the matching format. |
--target-width PX / --target-height PX | integer | together | unset | Override canvas size. Both or neither. Required when no screen is supplied or the screen reports unknown or multiple surfaces. |
--duration-ms MS | integer | no | 8000 | Duration for non-video pages. An application page holds for 24 hours (86400000) unless this is given. |
--fit | string | no | contain | contain, cover, or fill for image and video pages. Applications and iframes use fill. |
--sound | boolean | no | off | Play the audio of video pages. Without it every video page is silent. A page with sound pauses the soundtrack while it shows. |
--no-transcode | boolean | no | off | Upload accepted file bytes unchanged. |
--no-progress | boolean | no | off | Suppress upload progress on stderr. |
--poll-ms MS | integer | no | 1000 | Upload polling interval. |
screenrig playlist init med_01EXAMPLEIMAGE0000000000 med_01EXAMPLEVIDEO0000000000 --name "Lobby loop" --screen-id scr_01EXAMPLESCREEN00000000 --output lobby.jsonPreparation writes the local document and may upload media; it neither creates a remote playlist nor assigns a screen. Inspect the document, then screen publish. See Prepare, publish, and edit playlists.
data reports output, width, height, page_count, soundtrack_tracks, release_ids, media_ids and uploads, and with --screen-id also screen_id, screen_revision and publish.argv; a screen with a video wall adds format. An application page set under 60 seconds earns an application_page_short warning.
playlist validate#
Validate a playlist document locally before create or update. No network.
playlist validate <file>| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<file> | path | yes | none | The playlist document, or - for stdin. |
screenrig playlist validate ./lobby-loop.jsonErrors name exact JSON paths. A pass means local shape and cross-field semantics are valid; authorization, media readiness, dynamic selector counts, durations, and remote availability still require server checks. playlist create, playlist update and screen publish run this check before their write. data reports valid, scope and server_checks, and carries geometry lint findings, each with page_id, code, id and message, that do not fail the check: motion_overuse, collision, safe_margin and adjacent_repeat. An application page that advances in under 60 seconds earns an application_page_short warning. To see how a page looks, publish it and run screen screenshot.
playlist create#
Create a playlist from a JSON document, from a template, or from the built-in Urgent notice template.
playlist create [file] [--from-template ID --name NAME [--set NAME=VALUE...] [--dry-run]] [--starter KEY [--name NAME]] [--format-region REGION --format-orientation ORIENTATION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
[file] | path | no | none | The playlist document, or - for stdin. Give it, or --from-template, or --starter. It holds name, pages and optionally audio, format and fields; any other member is a usage_error. |
--from-template ID | string | no | none | Make the playlist from this template (a pl_ id): its current pages with the --set values filled in, checked like any playlist. |
--name NAME | string | with --from-template | none | The new playlist's name. --dry-run does not need it, and --starter takes it optionally. |
--set NAME=VALUE | string | no | none | With --from-template: a field's value, the id of a ready image or video for a media field. Repeatable. NAME is a field name of 1 to 32 lower case letters, digits or underscores, given once. |
--dry-run | boolean | no | off | With --from-template: check the values and report the page count without creating anything. |
--starter KEY | string | no | none | Add a built-in template: urgent-notice, a headline and a message for quick announcements. |
--format-region REGION | string | no | none | header, footer or side: make the playlist a strip drawn over the page along that edge, replacing a format in the file. Give it with --format-orientation. See strips. |
--format-orientation ORIENTATION | string | with --format-region | none | landscape or portrait: the orientation of the display the strip is made for, as the viewer sees it. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig playlist create ./lobby-loop.jsonscreenrig playlist create --from-template pl_01EXAMPLETEMPLATE00000 --name "Monday notice" --set headline="Open late"The envelope's data.id is the pl_ id that screen assign takes. When the change waits for review, data is {status: pending_review, review, playlist, next}: the playlist exists with approved_revision: 0, and no screen can show it until a person approves (playlist_not_approved); next is screenrig reviews show ID. A template is a playlist that declares fields; it is never shown on a screen (playlist_is_template), and a playlist made from it is an ordinary one to assign, schedule and revise.
playlist update#
Replace a playlist document.
playlist update <id> <file> [--format-region REGION --format-orientation ORIENTATION] [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
<file> | path | yes | none | The replacement document, or - for stdin. It holds name, pages and optionally audio, format and fields; any other member is a usage_error. Omitting audio removes the soundtrack, omitting format makes the playlist an ordinary one, and omitted fields are kept. |
--format-region REGION | string | no | none | header, footer or side: make the playlist a strip drawn over the page along that edge, replacing a format in the file. Give it with --format-orientation. See strips. |
--format-orientation ORIENTATION | string | with --format-region | none | landscape or portrait: the orientation of the display the strip is made for, as the viewer sees it. |
--expect-rev REVISION | string | no | none | Optional revision precondition. Omit to write the current resource. A supplied stale value is revision_conflict: refetch, reapply, retry. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig playlist update pl_01EXAMPLEPLAYLIST000000 ./lobby-loop.jsonplaylist show ID --output FILE writes a file in this shape. To change only part of a playlist, use playlist patch, playlist rename or playlist page add|replace|remove.
When the change waits for review, the live playlist keeps playing unchanged until a person approves the proposal.
playlist patch#
Change only the supplied top-level members of a playlist and keep everything else.
playlist patch <id> [file] [--name NAME] [--clear-audio] [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
[file] | path | no | none | A partial JSON object with any of name, pages, audio, format and fields, or - for stdin. Supplied pages, audio and format replace the whole value; arrays are not merged. audio: null removes the soundtrack and format: null removes the format. |
--name NAME | string | no | unchanged | Set the name, 1 to 120 characters after trimming, without sending the content. Not together with name in the file. |
--clear-audio | boolean | no | off | Remove the soundtrack, as audio: null does. No page may keep an audio_cue. Not together with audio in the file. |
--expect-rev REVISION | string | no | none | Optional revision precondition. Omit to write the current resource. A supplied stale value is revision_conflict: refetch, reapply, retry. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig playlist patch pl_01EXAMPLEPLAYLIST000000 --name "Lobby loop" --expect-rev 7
screenrig playlist patch pl_01EXAMPLEPLAYLIST000000 changes.json --expect-rev 7Give a file, --name or --clear-audio. A name-only change does not check the existing content again. Supplied pages and audio are checked together by the server. A region format is {"region": "header", "orientation": "landscape"}; see strips. Under Propose access, or in a project that requires review for agent changes, the change waits as for playlist update and answers pending_review.
playlist rename#
Change a playlist's name without sending its content.
playlist rename <id> --name NAME [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
--name NAME | string | yes | none | The new name, 1 to 120 characters after trimming. |
--expect-rev REVISION | string | no | none | Optional revision precondition. Omit to write the current resource. A supplied stale value is revision_conflict: refetch, reapply, retry. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig playlist rename pl_01EXAMPLEPLAYLIST000000 --name "Lobby loop" --expect-rev 7The name-only form of playlist patch: pages, soundtrack and comments stay as they are, and the existing content is not checked again. A proposed rename waits for a person's approval like any other change.
playlist page add#
Add one page to a playlist without sending the others.
playlist page add <playlist-id> (--file PAGE.json | --media MED_ID) [--seconds N] [--fit contain|cover] [--sound]
[--from WHEN] [--until WHEN] [--before PAGE_ID] [--page-id ID]
[--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<playlist-id> | string | yes | none | The pl_ playlist id. |
--file PAGE.json | path | exactly one of --file, --media | none | A page object added as written, or - for stdin. --seconds and --fit do not apply to it. |
--media MED_ID | string | exactly one of --file, --media | none | A ready image or video. The page shows it full-canvas on the playlist's canvas (the wall's canvas for a video wall, else the first ordinary page's) with the first ordinary page's transition, and has no dates unless you give them. An image advances after --seconds; a video plays to its end, silent unless --sound. |
--seconds N | integer | no | 10 | How long an image shows, 1 to 86400. |
--fit | string | no | contain | contain or cover. |
--sound | boolean | no | off | Play the video's audio. A video only; the page pauses the soundtrack while it shows and cannot carry an audio_cue. Not with --file, whose page carries its own muted. |
--from WHEN | string | no | none | First time the page is shown: YYYY-MM-DDTHH:MM, or YYYY-MM-DD for 00:00, in each screen's timezone. |
--until WHEN | string | no | none | End of the page's showing, exclusive: YYYY-MM-DDTHH:MM, or YYYY-MM-DD for the end of that day. |
--before PAGE_ID | string | no | at the end | Put the page in front of this page. |
--page-id ID | string | no | up- and eight lower case letters or digits | The new page's id: a letter, then letters, digits, - or _, at most 64 characters. |
--expect-rev REVISION | string | no | none | Optional revision precondition. Omit to write the current resource. A supplied stale value is revision_conflict: refetch, reapply, retry. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig playlist page add pl_01EXAMPLEPLAYLIST000000 --media med_01EXAMPLEIMAGE0000000000 --from 2026-12-01 --until 2026-12-24
screenrig playlist page add pl_01EXAMPLEPLAYLIST000000 --media med_01EXAMPLEVIDEO0000000000 --before up-ab12cd34 --note "Winter menu"
screenrig playlist page add pl_01EXAMPLEPLAYLIST000000 --file page.json --page-id welcomeThe page is shown from --from up to, not including, --until. Ended pages stay until someone removes them. The answer is the updated playlist.
Under Propose access, in a project that requires review for agent changes, or as an uploader member whose changes are reviewed, the change answers pending_review (ok: true, exit 0). A later page change to the same playlist by the same proposer joins that review while it waits, so successive uploads do not replace each other. A playlist no person approved yet answers playlist_not_approved. An uploader adds only media pages of its own folders to its own playlists; anything else is outside_upload_scope, whose upload_scope lists what it may use. See Uploaders.
playlist page replace#
Replace one page of a playlist, keeping its place and id.
playlist page replace <playlist-id> <page-id> [--file PAGE.json | --media MED_ID] [--seconds N] [--fit contain|cover]
[--sound] [--from WHEN] [--until WHEN | --always] [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<playlist-id> | string | yes | none | The pl_ playlist id. |
<page-id> | string | yes | none | The page to replace. |
--file PAGE.json | path | no | none | The complete new page, or - for stdin. Its id must be <page-id> or absent. Not together with --media. |
--media MED_ID | string | no | none | Swap the page's media; everything else, dates included, stays as stored. An image for an image keeps the canvas, fit, seconds and dates, and so does a video for a video. An image for a video, or the other way, is rebuilt as a media page on the playlist's canvas that keeps the id, transition and dates. Needs a page with a single primitive. |
--seconds N | integer | no | unchanged | How long an image shows, 1 to 86400. Not with --file. |
--fit | string | no | unchanged | contain or cover. Not with --file. |
--sound | boolean | no | off | Play the audio of the page's video, on its own or with --media. A page with a single video primitive only; without it a swap keeps whether the page had sound. Not with --file. |
--from WHEN | string | no | unchanged | First time the page is shown: YYYY-MM-DDTHH:MM, or YYYY-MM-DD for 00:00, in each screen's timezone. Changes that bound alone. |
--until WHEN | string | no | unchanged | End of the page's showing, exclusive: YYYY-MM-DDTHH:MM, or YYYY-MM-DD for the end of that day. Changes that bound alone. |
--always | boolean | no | off | Remove the page's dates, from and until. A switch-off, weekly windows or data condition the project set stay. Not together with --from or --until. |
--expect-rev REVISION | string | no | none | Optional revision precondition. A page derived from the stored one is held to the revision it was read at unless you give one. A stale value is revision_conflict. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig playlist page replace pl_01EXAMPLEPLAYLIST000000 up-ab12cd34 --media med_01EXAMPLEIMAGE0000000000
screenrig playlist page replace pl_01EXAMPLEPLAYLIST000000 up-ab12cd34 --until 2026-12-31
screenrig playlist page replace pl_01EXAMPLEPLAYLIST000000 up-ab12cd34 --alwaysGive at least one of --file, --media, --sound, --from, --until or --always. Date flags also work on a page with several primitives; changing the media, fit or seconds needs a page with a single primitive, or the whole page in --file. An unknown page id is refused. Review and uploader rules are those of playlist page add; an uploader replaces only a media page of its own folders.
playlist page remove#
Remove one page from a playlist.
playlist page remove <playlist-id> <page-id> [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<playlist-id> | string | yes | none | The pl_ playlist id. |
<page-id> | string | yes | none | The page to remove. |
--expect-rev REVISION | string | no | none | Optional revision precondition. Omit to write the current resource. A supplied stale value is revision_conflict: refetch, reapply, retry. |
--note TEXT | string | no | none | A note for the person who reviews the change: plain text, at most 280 characters. Ignored when the change applies at once. |
screenrig playlist page remove pl_01EXAMPLEPLAYLIST000000 up-ab12cd34A playlist keeps 1 to 100 pages and one ordinary page with no visibility, so removing the last undated page is invalid_request. An unknown page is not_found. Review and uploader rules are those of playlist page add.
playlist show#
Read one playlist, including its current revision, or write it as an editable document.
playlist show <id> [--output FILE [--overwrite]] [--editable]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
--output FILE | path | no | none | Write the editable document to FILE and report its path, playlist_id and revision. The file is ready for playlist update as written. Parent directories are created. Exclusive by default. Takes precedence over --editable. |
--overwrite | boolean | no | off | Replace an existing --output file atomically. An empty file left by an interrupted run is replaced without it. |
--editable | boolean | no | off | Return the editable document and its revision in the envelope as data.document, data.playlist_id and data.revision. |
screenrig playlist show pl_01EXAMPLEPLAYLIST000000
screenrig playlist show pl_01EXAMPLEPLAYLIST000000 --output playlist.json
screenrig playlist show pl_01EXAMPLEPLAYLIST000000 --editablePlain show is an inspection response. It returns the live version. approved_revision is 0 for a playlist no person has approved yet, and approval names the open review while a change waits; reviews show ID returns the proposal. When open notes are about the playlist, the warning notes_about_resource counts them and names screenrig notes --about ID, and --human lists up to five.
playlist list#
List the project's playlists.
playlist list [--templates] [--library]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
--templates | boolean | no | off | Only templates: playlists that declare fields. |
--library | boolean | no | off | List the organization Library's playlists instead, read-only: assign them to screens, schedules and stacks, or copy one with playlist create --from-template; change them only in the Library project. |
screenrig playlist list --templates
screenrig playlist list --libraryplaylist fields#
Show a template's fields or a copy's values, or change the values and bring the copy up to date.
playlist fields <id> [--set NAME=VALUE...] [--clear NAME...] [--refresh] [--expect-rev REVISION] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ id of a template, or of a playlist made from one. |
--set NAME=VALUE | string | no | none | Set a field's value. Repeatable; NAME is a field name of 1 to 32 lower case letters, digits or underscores, given once. |
--clear NAME | string | no | none | Clear an optional field's value. Repeatable. |
--refresh | boolean | no | off | Build the pages again from the template's current revision, whatever the values. |
--expect-rev REVISION | string | no | none | Optionally require this resource revision. |
--note TEXT | string | no | none | A note for the person who reviews the change. |
screenrig playlist fields pl_01EXAMPLECOPY00000000 --set headline="Closed today"Plain, it shows a template's fields and how many playlists were made from it, or a copy's values, the template revision it was built from and whether the template has a newer one. data.kind is template or instance: a template reports fields and instances, a copy template_id, template_revision, template_current_revision, outdated and values. Every change, and --refresh alone, builds the copy's pages again from the template's current revision, which is how a brand change made to the template reaches existing copies; nothing pushes to them. Values are checked like a create checks them. Under Propose access a change becomes a review.
playlist instances#
List the playlists made from a template and the template revision each was built from.
playlist instances <id>| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ id of the template. |
screenrig playlist instances pl_01EXAMPLETEMPLATE00000outdated marks a playlist built from an older revision of the template; playlist fields ID --refresh brings it up to date.
playlist revisions#
List a playlist's revisions, newest first.
playlist revisions <id> [--after CURSOR]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
--after CURSOR | string | no | none | The data.next_cursor of the previous page. |
screenrig playlist revisions pl_01EXAMPLEPLAYLIST000000Each revision in data.items says what made it (created, edited, promoted with the revision it copied as restored_from, or baseline, the revision the playlist held when its history began), who made it, when, its name, how many pages it holds and whether it is current. A page holds at most 50 revisions; while data.next_cursor is a string, older revisions remain, and null marks the last page. Revisions are kept as long as the playlist is.
playlist revision show#
Read one revision and the playlist as it stood at it.
playlist revision show <id> --revision N| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
--revision N | integer | yes | none | The revision to read. |
screenrig playlist revision show pl_01EXAMPLEPLAYLIST000000 --revision 3data.revision holds the fields playlist revisions lists, and data.playlist the playlist as it stood: name, pages, soundtrack and format, with revision set to this one. A revision the playlist never had, or one from before its history began, is not_found.
playlist promote#
Make an earlier revision current again by copying it forward as a new revision.
playlist promote <id> --revision N --expect-rev CURRENT| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
--revision N | integer | yes | none | The revision to copy forward. |
--expect-rev CURRENT | string | yes | none | The playlist's current revision (playlist show). A stale value is revision_conflict: read the playlist again and retry. |
screenrig playlist promote pl_01EXAMPLEPLAYLIST000000 --revision 3 --expect-rev 9The revision's pages, soundtrack and format become the next revision. The name stays as it is, earlier revisions stay in the list, and every screen showing the playlist updates; the command returns once the playlist is written and does not wait for Players. Pages are resolved again as for any write: a selector matches today's media, and media or an application the revision used that is gone or not ready refuses the promote with the problem a write would get. Promoting needs a credential that publishes live; one whose changes wait for review gets forbidden, and a playlist no person approved yet is playlist_not_approved. A revision whose content is already current changes nothing. Promoting is a Premium feature: a plan without it answers feature_not_in_plan (exit 8), while playlist revisions and playlist revision show are in every plan.
playlist delete#
Delete one playlist.
playlist delete <id> [--expect-rev REVISION]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
--expect-rev REVISION | string | no | none | Optional revision precondition. Omit to write the current resource. A supplied stale value is revision_conflict: refetch, reapply, retry. |
screenrig playlist delete pl_01EXAMPLEPLAYLIST000000A playlist is not deleted while a screen, archived or still pairing, has it as its default, in its playlist schedule or as its takeover, while a screen folder has it as its default, or while a campaign plays it: the answer is resource_conflict (exit 5). Change those first.
playlist export#
Export image and video files, soundtrack audio and iframe URLs as a portable playlist bundle.
playlist export <id> --output DIRECTORY [--skip-applications]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
--output DIRECTORY | path | yes | none | Destination directory. It must not already exist; the bundle is written through a temporary sibling and renamed into place. |
--skip-applications | boolean | no | off | Drop application primitives and empty or application-controlled pages. At least one page must remain. The result lists the skipped primitive and page ids. |
screenrig playlist export pl_01EXAMPLEPLAYLIST000000 --output ./lobby-bundleThe bundle holds a manifest, the playlist document, and content-addressed image, video and soundtrack audio files. It carries name, audio and pages; a format and a template's fields stay behind. Dynamic all, tag and folder selectors are snapshotted to exact ids, iframe URLs are preserved, and comments are excluded.
Cards, streams and adslot pages stop export before media download. Applications also stop it by default; --skip-applications removes application primitives and empty or application-controlled pages, reporting the skipped primitive and page ids. At least one page must remain. Cards, streams and adslot pages still stop export with this flag.
For an editable document retaining card and application references, use screenrig playlist show pl_01EXAMPLEPLAYLIST000000 --output playlist.json. The document uses existing resources in the same project.
playlist import#
Create a playlist from a bundle directory, or update an existing one from it.
playlist import <directory> [--name NAME] [--update ID [--expect-rev REVISION]] [--poll-ms MS] [--note TEXT]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<directory> | path | yes | none | A bundle directory written by playlist export. |
--name NAME | string | no | the bundle's playlist name | 1 to 120 characters. Names the new playlist, or renames the one --update replaces. |
--update ID | string | no | a new playlist is created | Update this pl_ playlist instead of creating one. Affects every screen assigned to it. Accepts optional --expect-rev. |
--expect-rev REVISION | string | no | none | With --update: the destination playlist's current revision. |
--poll-ms MS | integer | no | 1000 | Interval for polling uploads while media becomes ready. |
--note TEXT | string | no | none | A note for the person who reviews the change when it waits for review, at most 280 characters. |
screenrig playlist import ./lobby-bundle
screenrig playlist import ./lobby-bundle --name "Lobby loop (copy)"
screenrig playlist import ./lobby-bundle --update pl_01EXAMPLEPLAYLIST000000Playlist display names may repeat. Import creates a separate playlist even when its name matches; use --update with an ID to replace an existing playlist.
Import validates the whole bundle locally before it touches the project: manifest, document, paths, media kinds, lengths, and hashes. Existing media are reused on an exact filename, media type, byte length, hash, and tag match; the rest are uploaded without conversion, and the playlist is written only after every object is ready. data reports mode (create or update), source_playlist_id, playlist, directory and media with total, reused and uploaded.
Under Propose access, or in a project that requires review for agent changes, the media still uploads and the playlist write becomes a review: data.status is pending_review, data.review names it and data.next is screenrig reviews show ID. Nothing changes on glass until a person approves.
Import never deletes or prunes remote media. If a later step fails after an upload has started, the error lists the objects confirmed ready and says whether the playlist write began. Retrying the same bundle reuses those objects.
playlist replace-release#
Preview or apply one application release replacement in a playlist, with the screens it reaches.
playlist replace-release <id> --page PAGE_ID --primitive PRIMITIVE_ID --release-id REL_ID
[--apply [--expect-rev REVISION] [--expect-impact TOKEN] [--note TEXT]]| Parameter | Type | Required | Default | Notes |
|---|---|---|---|---|
<id> | string | yes | none | The pl_ playlist id. |
--page PAGE_ID | string | yes | none | The exact id of the page that holds the application. |
--primitive PRIMITIVE_ID | string | yes | none | The exact id of the application primitive on that page. |
--release-id REL_ID | string | yes | none | The new immutable rel_ release, from data.application.release_id of app update. |
--apply | boolean | no | off | Write the replacement. Without it the command is a read-only preview. |
--expect-rev REVISION | string | no | none | With --apply: the playlist revision from the preview. A different current revision is revision_conflict, and the server checks it atomically. |
--expect-impact TOKEN | string | no | none | With --apply: data.impact from the preview. If the replacement or the affected screens changed since, the write is resource_conflict: preview again. |
--note TEXT | string | no | none | With --apply: a note for the person who reviews the change when it waits for review. |
screenrig playlist replace-release pl_01EXAMPLEPLAYLIST000000 --page board-page --primitive board --release-id rel_NEW
screenrig playlist replace-release pl_01EXAMPLEPLAYLIST000000 --page board-page --primitive board --release-id rel_NEW --applyThe preview lists the active, pairing-pending and archived screens whose default assignment, stored schedule entries (paused and future ones included), takeover or current effective playlist (campaign and inherited folder playback included) references the playlist. data carries previous_release_id, release_id, revision, affected_screens (each with id, label, state and revision), impact and applied. A direct --apply skips the screen survey, so affected_screens is omitted unless --expect-impact is given. An already pinned release succeeds without writing. Under review, --apply proposes the new pin. See Replace one application release.
The playlist document
A playlist is name (1 to 120 characters) plus pages (1 to 100), with an optional audio soundtrack and an optional format. Each page carries id, canvas, transition, advance, optional visibility, optional audio_cue, and primitives (1 to 24). Page, primitive and track ids are a letter followed by up to 63 letters, digits, _ or -; page ids are unique in the playlist and primitive ids on their page. A canvas takes width and height from 1 to 1,000,000, a background and an optional viewport_fit: see Page background and motion.
A format makes a playlist a video wall, {displays, arrangement, orientation} with columns for a grid, or a strip, {region, orientation}. A wall has 2 to 12 displays of 1920 x 1080 (1080 x 1920 in portrait), every ordinary page has the wall's canvas, and a primitive's displays names the tiles it covers in place of rect. See Video walls and Strips. An ad slot page, {id, type: "adslot", adslot_id} with optional visibility, holds no canvas or primitives; a playlist holds at most 16 of them and keeps one ordinary page with no visibility.
A template adds fields to the document, [{name, label, type, required, max_length?}] with type of text, media or url, and may mark any primitive locked: true. A page reads a field as {field.NAME} in a card's params (text and url fields), as an image or video selector.media_id (a media field) or as the whole src of an iframe (a url field). Every token must name a declared field of the right type, every field must be read, and a locked primitive reads none; playlist validate checks this offline. Only the owner or a member who can approve changes a locked primitive (primitive_locked). A template declares at most 16 fields: name is 1 to 32 lower case letters, digits or underscores, label up to 60 characters, and a text field's max_length (default 200) up to 2000. An optional media or url field left without a value leaves out the primitive that reads it. Declaring fields and locking a primitive are playlist templates, a Premium feature. A video wall format of 2 or 3 displays needs Plus and one of 4 to 12 displays Enterprise. A plan without the feature answers feature_not_in_plan with required_plan, while a write that keeps what the playlist already holds stays open. Making a copy from a template is in every plan.
The six primitives are image, uploaded video, live stream, web iframe and application, and card. Copy and chrome are not wire types: place a card for live text, or upload a finished still your agent made and place it as an image.
A stream takes one or two ordered sources with unique protocols and a ready image from the same project as fallback_media_id. Use at most one stream per page and duration-based advance. HLS uses a public HTTPS URL; Android and Qt Players connect directly to RTSP camera feeds, login included. See camera transport details for the URL forms each Player opens; optional direct UDP/MPEG-TS multicast on Android and Qt uses an IPv4 group in 239/8 and a port. A source can give only its url and let the scheme name the protocol. Other Players select the HLS alternative or display the fallback. Stream bytes are not cached for replay. Audio defaults to muted; muted set to false plays it, with the rules for a video's sound below. Playlist bundle import and export do not support streams.
{
"id": "live",
"primitive": "stream",
"sources": [
{
"protocol": "udp-mpegts",
"group": "239.10.0.1",
"port": 5000
},
{
"protocol": "hls",
"url": "https://example.com/live.m3u8"
}
],
"fallback_media_id": "med_fallback",
"muted": true,
"rect": {
"x": 0,
"y": 0,
"width": 1920,
"height": 1080
},
"layer": 0,
"content_fit": "contain"
}Use this primitive on a page with advance: {"mode":"duration","after_ms":30000}. Replace the example feed and fallback ID. Player requirements and transport setup.
Every primitive is flat: id, primitive, that primitive's own fields, then rect, layer, content_fit, and optional enter and motion. There is no nested content object. rect is x, y, width and height in canvas units and layer a whole number from 0 to 1024. A rect may extend past the canvas for bleed: Players fit content to the whole rect and then clip to the canvas, so use content_fit cover or fill to fill the visible canvas. A card is placed by layout and needs a rect only for free; on a wall playlist displays replaces rect.
Image and video primitives require a selector. selector.by is id with one ready media_id and one_at_a_time false, ids with 1 to 1,024 unique ready media_ids, all for every ready object of that primitive, tag matching ^[A-Za-z0-9]{1,32}$, or folder with the folder_id of an existing mfd_ media folder, which plays the ready files directly inside it and none of its subfolders. Do not put media_id on the primitive itself or send server-resolved items. An application primitive pins one release_id and an iframe primitive takes a src and a title of 1 to 200 characters, so neither of those takes a selector. src is any http or https page the screen can reach, a LAN page or a page behind a login included; a YouTube link is stored as its autoplaying embed. src, and an iframe's optional fallback_src, may carry screen tokens such as {screen.field.kiosk_id}, and an application primitive may carry params with the same tokens, so one playlist gives every screen its own page. Android, Amazon Signage Stick, Linux, Raspberry Pi and Windows Players open the page itself. The Player web app and the macOS, Samsung Tizen, LG webOS and BrightSign Players frame it, so a page that sends X-Frame-Options (DENY, SAMEORIGIN or the obsolete ALLOW-FROM), or a Content-Security-Policy frame-ancestors list without the Player's origin, shows a blocked frame on them, and the Player web app shows only https pages without a login in the address. When publishing detects a public HTTPS page that refuses framing, the write still succeeds and the CLI prints the server's warnings entry: code iframe_framing_refused, the page_id, primitive_id and src, the header that refused, and the next step (use a page that allows framing from the Player origin, or ask its owner to allow that origin). The server also appends a playlist.iframe_framing_refused warning to the event log, one per refusing page, which events list prints with primitive_id. A LAN page, an http page and a page the server cannot reach within a few seconds are not checked. A Player reports a playlist as playing once its manifest is on glass, so a verified publish does not prove that an iframe page rendered: act on the warning, or look at the screen. Both web primitives require content_fit of fill, because neither has an intrinsic size.
An iframe also takes reload_s (0, the default, never reloads; 60 to 86400 loads src again every reload_s seconds while the page is on glass), fallback_src (the page shown when src does not load, with the forms and rules of src; a recovered src replaces it at the next reload) and navigation_allowlist (1 to 64 host-sources of the form [scheme://]host[:port][path], such as example.com, *.example.com or https://example.com/docs/; with a list, the page's links, scripted navigations and redirects reach only src, fallback_src and matching addresses; omit it for no restriction, an empty list is refused). A pasted <iframe> embed code is read for its src. A Google Slides, Docs or Sheets share, Publish to web or embed link, or a Microsoft 365 Embed link, is stored rebuilt for the screen: Slides and PowerPoint decks loop, a Slides deck advances on the link's own delay held to the page duration (give the page the time of the whole deck), and Docs, Sheets, Word and Excel reload every 5 minutes. A file that asks viewers to sign in is refused with document_not_shared, whose detail names the sharing setting to change. See Show a web page, a video or a document.
advance.mode is duration with after_ms, which on a page holding exactly one YouTube video (not a playlist or live stream) may also carry until set to video_end so the page lasts until the video ends and after_ms is how long it shows when the screen cannot read the video's length, media_end on a page with exactly one image or video primitive, audio_end on a page whose audio_cue names a soundtrack track, or application with max_ms when the app ends its own turn by calling window.screenrig.nextPage(). An application page needs exactly one primitive marked controller; every other mode forbids it. after_ms, max_ms and dwell_ms are whole milliseconds from 1,000 to 86,400,000, and an image on a media_end page needs dwell_ms. A page holds at most one stream and at most two application or iframe primitives, and media_end forbids both of those.
transition.type is one of crossfade, swipe-left, swipe-right, swipe-up, swipe-down, dip, wipe-left, wipe-right, wipe-up, wipe-down, slide-left, slide-right, slide-up, slide-down, or stinger. duration_ms is required, 0 through 60000. playlist init writes a 200 ms crossfade. Swipe moves both pages together like a carousel. Slide moves the incoming page over the outgoing one, which drifts a quarter as far. Wipe uncovers the incoming page behind a moving hard edge. Dip fades the outgoing page to a solid colour and then in to the incoming page; color is an optional #RRGGBB, default #000000, and is valid only on dip. Direction names are the direction of motion: wipe-left is an edge moving left. ease is optional: linear, in, out or in-out; the default is linear for crossfade and swipe-* and in-out for dip, wipe-* and slide-*; it is not allowed on stinger. The incoming page owns its transition. The first page of a playlist plays no transition.
A stinger is a themed full-frame graphic that covers the outgoing page, swaps in the incoming page while the screen is covered, then uncovers it. Use it to name a section of a playlist: put it on the first page of the section. The stinger object is required for type: "stinger" and not allowed on other types. All its members are optional. theme is one of neomustard (the default), cyanotype, propaganda, signal, avant-garde, bloom or primetime, and matches the card themes. title is up to 40 characters and subtitle up to 60, set in the theme's display type. logo is media: plus the id of a ready image in the project, for example media:med_01EXAMPLE. accent is an optional #RRGGBB that replaces the theme accent. duration_ms for a stinger is 2000 through 6000 and covers the whole bumper; typical lengths are 2700 to 4000. The title stays fully displayed for hang_ms, 0 through 6000, default 1000 (one second), and hang_ms is at most 60 percent of duration_ms; a longer hang needs a longer duration_ms. A Player that cannot draw a stinger plays a crossfade of the same length. See the live Stinger card page to watch the transition play.
The following example shows a stinger page transition:
{ "type": "stinger", "duration_ms": 3500, "stinger": { "theme": "primetime", "title": "BREAKFAST", "subtitle": "Served until 11", "logo": "media:med_01EXAMPLE", "hang_ms": 1000 } }An optional enter object on a primitive adds one object animation: fade-up, fade-down, fade-left, fade-right, fade-in, zoom-in, or zoom-out, and an optional stagger from 0 to 8 delays its start by 120 ms a step. An optional motion keeps a primitive moving after it enters: spin and drift turn or slide an image or video, and path moves an image, video, application or iframe along waypoints. See Page background and motion.
An optional page visibility object limits when the page plays: a required enabled boolean, optional civil from and until bounds, and up to 16 recurring windows of days and civil times. from and until are YYYY-MM-DDTHH:MM in each screen's timezone, from inclusive and until exclusive and later than from; a window is days (mon to sun) with start and end as HH:MM, given together or both left out for the whole day, and an end at or before start crosses midnight. enabled: false hides the page; enabled: true needs at least one of from, until, windows or data. Every playlist keeps at least one page with no visibility field at all. A screen reads these times in its effective time zone: its override, else the zone its Player reports, else UTC.
A page visibility.data condition, {key, path?, equals?}, shows the page only while a card data document matches: key is a card data key or card ID, path an RFC 6901 pointer into the document, and equals a string, number, boolean or null (omit it to test that the value exists). The key {screen.weather} reads the weather at each screen's own location, which screen update ID --location LAT,LON sets: {"enabled":true,"data":{"key":"{screen.weather}","path":"/condition","equals":"rain"}} shows the page only while it rains where that screen is. The weather document has condition (clear, cloud, fog, rain, snow, storm or wind), band (freezing below 0 °C, cold 0 to 9, mild 10 to 17, warm 18 to 24, hot from 25), temperatureC in whole degrees and isDay. It is the current weather for the screen's 0.25 degree cell, refreshed about hourly, not a forecast. A screen without a location never shows the page, and publishing refuses a path or an equals the document cannot hold, such as cloudy for cloud. A Player that does not declare the page.conditions host capability gets such a page disabled. Data conditions are a Plus feature: without it, a write that adds a visibility.data condition a page does not already hold answers feature_not_in_plan, while keeping or removing a stored condition and time-window visibility stay open. Keep an ordinary page without visibility as the fallback.
A video or stream primitive plays silent unless it sets muted to false. Then it plays its sound at the screen's volume while its page is current, and that page pauses the playlist soundtrack, which resumes from the same point on the next page without sound. Several primitives on one page all play their sound. A page with sound cannot carry an audio_cue: a write that adds one answers invalid_request at pages[i].audio_cue, "a page with sound cannot cue the soundtrack", while a stored older page that has both keeps playing. Ads stay muted.
An optional top-level audio object adds a soundtrack that plays continuously while pages change and pauses on a page with sound. tracks lists 1 to 128 entries in playback order, each with a unique id (the page id pattern) and the media_id of a ready audio media object. loop defaults to true and restarts at the first track after the last; volume defaults to 1 and ranges from 0 to 1, multiplied by the Player volume; cued defaults to false, and true stops the soundtrack after each track so that a track plays only when a page audio_cue starts it. An ordinary page may carry audio_cue with a track id from that list and an optional restart boolean (default false): when the page appears, the Player switches to that track from its start, restarting it only when it is already playing and restart is true. Cues are hints, adslot pages cannot carry them, and a cue without a soundtrack is rejected. A page with advance {"mode":"audio_end"} ends when the track its audio_cue names ends, so it requires that cue and a soundtrack, takes no after_ms, and follows the duration rules for image and video primitives; a stream primitive still needs a duration page, and an application on the page is never its controller; max_ms is an optional hint that the server overrides. playlist update replaces the whole document, so omitting audio removes the soundtrack; playlist patch keeps it unless audio is supplied, and --clear-audio or audio: null removes it. A strip has no soundtrack. Soundtrack authoring.