观看它的构建过程
影片 / 使用 SDK 构建自助服务终端应用
3:07

有些屏幕是应用程序,而非静态图像。Claude Code 编写了一个自助服务终端应用程序,将其作为不可变版本上传(带有 app upload),并将其固定在一个播放列表中,用于自助服务终端和欢迎墙。章节和文字记录 →
在 开始 会话设置后使用 screenrig。
选择内容路径
| 页面 | 工具 |
|---|---|
| 完成的图像或视频 | media upload |
| 完成的海报、菜单或公告 | media generate,包含提示中的所有文本 |
| 提供的图稿,上面叠加文字 | media upload 图稿,再在同一页面放置内置卡片 |
| 保持可编辑的文本、表格、菜单或公告板 | 内置卡片:card create,放置在播放列表中 |
| 直播视频、流、iframe 或应用 | 播放列表原语 |
| 需要登录的仪表板 | 放在 iframe 元素中的 BI Web 连接和视图 |
| 随文件添加或标记而变化的媒体 | 动态选择器(tag、folder 或 all),用 media selector-preview 检查 |
| 整个播放列表的背景音乐 | media upload 一个 MP3,然后播放列表 audio 配乐 |
生成会将图稿和文字一并排版,因此请把所有文案放入提示中。卡片在播放器中绘制文本,因此更改一个词或数字无需新的静态图像。提供的成品素材无需生成。仅有动画并不需要二者。
生成完成静态图像
代理发送提示加上 aspect_ratio 和 quality。screenRIG 返回账户媒体库中的 med_… 媒体对象。调用方不重新上传字节。仅为检查而获取原始字节;否则在播放列表中保留 med_… 引用。
自有 media upload 依然有效。已有文件时请勿重复生成。实时视频、流、iframe 和 Web 应用页面属于播放列表原语,不是生成的静态图像。
质量为 low、medium 或 high(默认 medium)。宽高比为 1:1、16:9、9:16、4:3、3:4、3:2 或 2:3(默认 16:9)。--quality 决定静态图像的细节程度及其使用的令牌数量:
| 质量 | 何时 |
|---|---|
low |
不重要的生成静态图像 |
medium |
默认;推荐大多数情况使用 |
high |
密集文本 / 复杂海报 |
media generate --prompt TEXT [--aspect-ratio RATIO] [--quality QUALITY] [--tag TAG]
screenrig media generate --prompt "A 16:9 restaurant menu poster for North Lobby Cafe. Dark walnut, gold type. Title NORTH LOBBY CAFE. Items: Espresso $4, Cortado $4.50, House Blend $3. Footer Open 7am to 7pm. Typeset every line of copy in the image." --aspect-ratio 16:9 --quality high --tag LobbyMenu
信封报告一个 med_… ID。它从不打印图像字节。
{
"ok": true,
"data": {
"id": "med_01EXAMPLEGENERATED0000000",
"media_id": "med_01EXAMPLEGENERATED0000000"
}
}
添加配乐
播放列表可携带一个原声带:一个有序的 MP3 曲目列表,页面切换时持续播放。页面转换不会停止、重启或淡出音乐。原声带为播放列表设置,不是第七种原始元素,因此画布上无矩形或图层。
使用 media upload 上传每个曲目。MP3 文件按原样上传;WAV、AAC、M4A、OGG 和 FLAC 文件先转码为 MP3。每个曲目变成一个 audio 媒体对象,带有 med_… ID 和时长。
screenrig media upload ./intro.mp3 --tag LobbyMusic
screenrig media upload ./bed.wav --tag LobbyMusic
为播放列表 audio 成员命名曲目;它包含 1 到 128 首曲目。曲目按顺序连续播放。loop(默认 true)在最后一首后重新从第一首开始;volume(默认 1,范围 0 到 1)调整播放器自身音量。
{
"name": "Lobby",
"audio": {
"tracks": [
{ "id": "intro", "media_id": "med_01EXAMPLEINTRO000000000" },
{ "id": "bed", "media_id": "med_01EXAMPLEBED00000000000" }
],
"loop": true,
"volume": 0.8
},
"pages": [
{ "id": "welcome", "audio_cue": { "track": "intro", "restart": true } },
{ "id": "menu" }
]
}
页面可携带可选的 audio_cue。当该页面出现时,播放器从指定轨道的起始位置切换播放;若该轨道已在播放,仅当 restart 为 true 时才重新开始。随后序列从指定轨道继续。提示为建议:播放器以短淡入淡出应用提示,或当轨道未准备好时跳过。无提示的页面不影响音乐。示例中省略了除 id 和 audio_cue 之外的页面字段。
替换播放列表时也替换其配乐;省略audio可移除配乐。画布上的视频保持静音,因此屏幕仅播放配乐声音。
将页面绑定到轨道
针对专辑或每轨一页的书籍,或任何持续时间恰好等于轨道长度的页面,将页面绑定到其轨道。
将页面 advance 设置为 { "mode": "audio_end" }。页面出现时应用其 audio_cue,如任何提示一样,且在该曲目结束时结束,类似于带视频的 media_end 页面结束。页面必须携带 audio_cue,播放列表必须有 audio 原声带。图像和视频原语遵循 duration 规则:无 dwell_ms,且每个动态选择器(all、tag、folder 或带多个 ID 的 ids)均有 one_at_a_time: true,即使今天只匹配一个对象。stream 原语仍需 duration 页面,页面上的应用永远不是其控制器。max_ms 是可选安全提示;服务器根据曲目长度设置截止时间,故可省略。如果播放器无法播放曲目,页面仍持续曲目长度。
在 audio 成员中将 cued 设置为 true,以在每首曲目后停止原声带。提示曲目仅在页面 audio_cue 启动时播放。它会在其页面之后的任何普通页面中继续播放,直到结束,然后原声带静音,直到下一次提示,因此页面与其曲目绑定,中间可有任意数量的普通页面。loop 对提示原声带无效,cued 默认为 false。
{
"name": "Album",
"audio": {
"tracks": [
{ "id": "song1", "media_id": "med_01EXAMPLESONG1000000000" },
{ "id": "song2", "media_id": "med_01EXAMPLESONG2000000000" }
],
"cued": true
},
"pages": [
{ "id": "song1-cover", "advance": { "mode": "audio_end" }, "audio_cue": { "track": "song1", "restart": true } },
{ "id": "interlude", "advance": { "mode": "duration", "after_ms": 8000 } },
{ "id": "song2-cover", "advance": { "mode": "audio_end" }, "audio_cue": { "track": "song2", "restart": true } }
]
}
示例中省略了除 id、advance 和 audio_cue 之外的页面字段。
为实时文本放置卡片
内置卡片在播放器本身中绘制文本、菜单、表格、时钟或仪表,因此文本保持可编辑,新值无需新的静态图像即可到达每块屏幕。cards list 显示类型,card create 创建实例,播放列表将其作为 card 原语放置。card data put 写入其实时值。卡片列出每种类型和布局。
screenrig cards list
screenrig card create --type gauge --file gauge-params.json
screenrig card data put crd_EXAMPLE --file gauge-data.json
显示需要登录的仪表板
Web 连接像人一样用服务账号登录网站,Web 视图则显示该网站的一个页面。它适用于 Salesforce、Looker Studio、Datadog、HubSpot 以及其他没有公开链接的网站的仪表板。screenRIG 边缘的浏览器会以已登录状态打开页面,播放器显示它的图片,每 refresh_s 秒重新绘制一次(60 到 86,400,默认 300)。同样尺寸的所有屏幕共享一张图片,因此增加屏幕不会增加登录次数,而且只有在屏幕的播放列表显示该视图时才会绘制图片。Grafana、Power BI 和 Tableau 的连接和视图以同样方式工作,见 API 参考。
- 在网站上创建一个服务账号,只能读取您的屏幕要显示的仪表板。每次截图都以它登录。
- 创建连接,使用
kindweb和下面的设置。密码是secret。 - 创建一个视图,对应一个页面:把它的
https地址作为url,并把一个只有在页面已登录且就绪时才出现的元素的 CSS 选择器作为wait_for,这样登录页面会超时,而不会被绘制出来。clip只绘制选择器指定的页面部分,wait_ms(最多 10,000)会等待延迟出现的图表。 - 把视图的
embed_url放在带content_fitfill的iframe元素中。
{
"kind": "web",
"name": "Sales dashboard",
"config": {
"login_mode": "auto",
"login_url": "https://login.example.com/sign-in",
"username": "screens@example.com"
},
"secret": "ACCOUNT_PASSWORD",
"totp_secret": "AUTHENTICATOR_KEY"
}
{
"connection_id": "bic_01EXAMPLECONNECTION0000",
"name": "Sales this week",
"url": "https://app.example.com/dashboards/sales",
"refresh_s": 300,
"wait_for": "#sales-total"
}
| 设置 | 含义 |
|---|---|
login_mode | auto 用 username 和密码填写 login_url 处的表单。steps 运行您自己的脚本。none 不在任何地方登录:连接显示带有其 Cookie 的页面,或不带 Cookie 的页面 |
login_url | 网站登录页面的 https 地址,位于公共主机上。auto 和 steps 必填 |
username | 服务账号的用户名,用于 auto 和 steps |
steps | 最多 30 个步骤:goto(url)、fill(selector、value)、click 和 wait_for(selector)、press(value 是 Enter 之类的按键,可选的 selector 用于先获取焦点)以及 wait_ms(ms)。值可以包含 {{username}}、{{password}} 和 {{otp}}:请写占位符,绝不要写密码或验证码 |
secret | 密码。auto 必填 |
totp_secret | 适用于使用身份验证器应用的账号:网站显示的 base32 密钥(16 到 128 个字符,可含空格),或其 otpauth://totp/... 地址,后者可设置 SHA256 或 SHA512、6 到 8 位数字以及 10 到 120 秒的周期。screenRIG 在其服务器上计算验证码,并且只发送验证码 |
cookies | 从已登录浏览器导出的 Cookie 集,最多 100 个 Cookie:name、value、domain(所有子域用 .example.com)、path、expires(Unix 秒,0 表示会话 Cookie)、httpOnly、secure 和 sameSite |
密码、TOTP 密钥和 Cookie 与 config 并列提供,加密封存且不会再次显示:读取时会说明每一项是否已设置。清空 secret 或 totp_secret,或设为 cookies: [],即可将其删除。
- Cookie 优先。 连接保留一份加密封存的 Cookie 集:先是您粘贴的,然后是每次截图返回的 Cookie。截图会发送 Cookie 集而不发送任何凭据,只有在没有 Cookie 集或上次截图到达了登录页面时才会登录。把会话保存在 Cookie 之外的网站每次截图都会登录,因此请给它的视图设置较长的
refresh_s。 - 密码只会送到登录页面。 它只会在
login_url和goto步骤中输入,绝不会输入到视图的地址中。向其中任何一个添加地址都需要在同一个请求中提供密码,因此无法读取密码的成员不能把它指向自己的页面。 - 账号受到保护。 被拒绝的登录(
bi_web_login_failed或bi_web_otp_required)会等待 5 分钟,然后是 15、60 和 120 分钟,连续第五次会停止连接,直到您更改其凭据或登录设置,因此第一个小时内最多尝试 3 次。以其他方式结束的登录(超时、被拦截、页面打不开)会等待 15 分钟。请使用只读的服务账号。 - 有些网站无法用脚本登录。 在手机上批准登录、检查设备或显示 CAPTCHA 的网站,需要 Cookie 集(
login_modenone)或网站豁免的服务账号。
截图失败期间,播放器会保留最后一张正常的图片,视图的状态会带有下列代码之一:
| 代码 | 含义 |
|---|---|
bi_web_login_failed | 网站拒绝了登录:请修正用户名、密码、TOTP 密钥、login_url 或步骤 |
bi_web_otp_required | 网站要求输入验证码,但连接无法提供 |
bi_web_session_expired | 出现了登录页面。使用 auto 或 steps 时,下一次截图会登录;只有 Cookie 时,请粘贴新的 Cookie 集 |
bi_web_login_paused | 登录正在等待速率限制结束、连接已停止,或另一次截图正在登录 |
bi_web_timeout | 页面没有加载:请设置 wait_for 或 wait_ms |
bi_web_navigation_failed | 页面打不开 |
bi_web_blocked | 网站用机器人检查或 CAPTCHA 拦截了渲染器 |
bi_upstream_unavailable | 渲染器没有响应 |
screenrig bi connection test ID 会登录并报告结果。连接的 session 说明其 Cookie 和登录的状态:idle、active、login_needed、paused、stopped 或 expired。
标记筛选器和播放批次
媒体最多携带 32 个唯一标签,每个标签由 1 到 32 个字母或数字组成。用 screenrig media update med_ID --tags Summer,Drinks 替换整个集合。--tag Summer 用一个标签替换;--clear-tag 清除所有标签。media list --tag Summer 匹配集合中任何位置的成员。标签区分大小写,且绝不用于授权。
动态选择器可使用一个 tag 或一个 tags 过滤对象:
{
"by": "tag",
"tags": { "all": ["Summer", "Drinks"], "any": ["Lobby", "Patio"], "none": ["Expired"] },
"order": "random",
"one_at_a_time": false,
"batch_size": 3
}
all 需要所有列出的标签,any 至少需要一个,none 排除任何列出的标签。存在的组用 AND 连接;省略的组不施加条件。至少提供一个非空组。每组最多接受 32 个唯一标签。tag 和 tags 互斥。仅 none 过滤器选择该原语的所有就绪媒体,除排除标签外。图像选择器选择图像,视频选择器选择视频。
候选池每个选择器最多包含 1,024 个准备好的媒体,整个循环快照中有 1,024 个媒体引用。匹配数量过大将返回错误;请缩小筛选条件。batch_size 是每次页面访问 1–1,024 项的单独限制。在 media_end 页面上,one_at_a_time: false 按顺序播放下一批;省略 batch_size 则播放剩余批次。one_at_a_time: true 每次出现播放一项,仅允许省略批量大小或 batch_size: 1。持续时间、应用和 audio_end 页面需要 one_at_a_time: true。media_end 上的图像也需要 dwell_ms;该页面上的视频不能循环。
播放器在播放列表启动和每个循环边界时,一次请求解析所有动态媒体原语。循环期间成员冻结。上传、移除、标签变更和可用时段边界不重新生成清单。下次刷新时,移除或新排除项离开待处理队列;新匹配项在当前轮次结束时加入。最终批次可能少于请求数;不会从下一轮补充。文件名排序按文件名再媒体 ID。随机排序每轮完整播放洗牌一次,保持循环刷新间剩余顺序。加权排序遵循其权重,见下文。光标本地于屏幕、播放列表、页面和原语,重启持续,过滤、排序或批次策略变更时重置。离线播放使用最后成功快照。空匹配跳过原语及任何空页面。
将上面的选择器对象保存为 selector.json,然后在发布前检查其当前候选目录:
screenrig media selector-preview selector.json --primitive video
预览返回 matched_count,按文件名排序的 candidates(包含媒体 ID 和标签),以及规范化的 selector 策略。随机顺序显示池和洗牌策略;不选择播放器的洗牌,不推进光标,不创建播放授权,也不更改清单。加权顺序下,它会返回每个候选项的 weight 和 share_percent,以及 cycle。--rect WxH(API 为 rect: {width, height})是版位的尺寸,与 fit: "aspect" 一起使用时必填;被排除的匹配项列在 excluded 中,原因为 aspect_mismatch。图像选择器传入 --primitive image。API 与 POST /api/selectors/preview 结合 { "primitive": "video", "selector": ... } 使用。它使用经过身份验证的项目和与播放相同的匹配规则。预览后的目录更改将在播放的下一个循环边界解决。
静态包导出将动态匹配冻结为精确 ID。它保留一次或完整播放;使用带有 batch_size 和 one_at_a_time: false 的有界运行时序列时,需要在导出前移除该字段或选择明确的 ID。这防止在静态包中静默丢失运行时批次游标。
加权轮换和宽高比适配
order: "weighted" 按权重轮换一个版位的素材,使每个赞助商保持其播放占比。weights 将媒体 ID(med_...)或 tag:NAME 映射为 1 到 1,000 的整数,最多 64 个键。它适用于 by 为 all、tag 或 folder 时:
{
"by": "all",
"order": "weighted",
"one_at_a_time": true,
"weights": { "tag:Acme": 50, "tag:Globex": 30, "tag:Initech": 20 },
"fit": "aspect"
}
权重 50、30 和 20 在每个周期中恰好交付每 10 次播放中的 5、3 和 2 次,重启后从周期中途继续。条目的权重是其媒体 ID 键(若存在);否则取它所带标签中按字母顺序第一个 tag:NAME 键,在所选条目中带有该键的条目之间平均分配,因此无论赞助商有多少素材,其占比都保持不变;否则该条目自成一组,权重为 1。一个周期最多 4,096 次播放;仅当精确比例需要更长周期时,占比才会按其取整。
加权顺序每次访问播放一个条目,因此请设置 one_at_a_time: true 或 batch_size: 1。加权顺序必须提供 weights,且仅允许与其一起使用;否则写入返回 invalid_request。Web、Android、Apple、Windows 和 Linux 播放器自声明 selector.weighted 主机能力的版本起实现加权顺序。较旧的播放器将该选择器按随机顺序播放,清单诊断中带有 selector_order_downgraded。
动态选择器上的 fit: "aspect" 只保留宽高比与版位矩形(包括视频墙或显示器边框)的宽高比相差在 5% 以内的文件,在选择器解析时读取。竖屏版位不会播放横屏文件。无需更改播放器。
screenrig media selector-preview 会输出每个加权或按宽高比筛选的选择器的预期占比,控制台的页面编辑器也在检查器中显示同一张表。静态包导出将加权选择器冻结为按文件名排序的精确 ID,不保留权重。
标签选择器中的屏幕令牌
标签选择器的 tag,以及其 tags 过滤器的每个条目,可以是 {screen.field.NAME} 或 {screen.id}(不带 scr_ 前缀的屏幕标识符,它本身就是标签)。服务器在构建每块屏幕的清单和选择器快照时为其填充令牌,因此一个播放列表即可播放每块屏幕各自的媒体。为媒体打上 Lobby 或 Garage 标签,用 screenrig screen update scr_ID --field zone=Lobby 设置每块屏幕的字段,然后为版位指定这个选择器:
{ "by": "tag", "tag": "{screen.field.zone}", "one_at_a_time": true }
填充后的值遵循标签规则:1 到 32 个字母或数字。没有该字段、或字段值不是标签的屏幕不选择任何内容:它不会播放该版位中的任何文件,清单诊断中带有 screen_fact_missing 或 screen_fact_invalid。更改字段会为该屏幕重新生成清单。带令牌的选择器无法预览(media selector-preview 需要具体标签),也无法被 playlist export 冻结。
iframe 地址和应用参数中的屏幕令牌
iframe 的 src 和 fallback_src 可在 http 或 https 地址的路径、查询或片段中携带屏幕令牌,application 原语的可选 params 也可以:最多 16 个名称,每个由 1 到 32 个小写字母、数字或下划线组成(ticket 和 policy 为保留名称),值最多 512 个字符。服务器会为每个屏幕填入:
| 令牌 | 值 |
|---|---|
{screen.id} | 屏幕的标识符,不含其 scr_ 前缀。 |
{screen.name} | 屏幕的名称。 |
{screen.timezone} | 屏幕已存储的 IANA 时区。 |
{screen.field.NAME} | 屏幕的字段 NAME,由 1 到 32 个小写字母、数字或下划线组成。 |
{screen.location.lat}, {screen.location.lon} | 其位置,以十进制度数表示。 |
{screen.location.name}, {screen.location.address} | 其地名和街道地址。 |
{
"primitive": "iframe",
"src": "https://maps.example.com/directory?kiosk={screen.field.kiosk_id}&level={screen.field.level}",
"title": "Directory"
}
写入时按原样存储模板,包括花括号。每个屏幕的清单携带其自己的地址,每个值都按其在 URL 中的位置进行百分号编码:kiosk_id 为 B 2&3 会变成 B%202%263。位于协议、凭据、主机或端口,或 YouTube 链接、Google 或 Microsoft 文档链接或 BI 视图地址中的令牌,在 src(或 fallback_src)处为 invalid_request。含模板的 src 在发布时跳过嵌入检查,预览则按原样显示模板。
缺少某个值(未设置的字段、无位置),或其值填入后得到超过 2048 个字符的地址,或路径段为 . 或 .. 的屏幕,不会获得此类 iframe 或应用,其清单诊断携带 screen_fact_missing 或 screen_fact_invalid;留空的页面会被丢弃。每个作用于此类屏幕的写入(播放列表写入、screen assign、screen update、机群分配、已批准的审核)都会返回 screen_fact_missing 警告,其中列出令牌、前 20 个屏幕 id 及总数。更改字段或位置会重新生成其所影响屏幕的清单。
对于应用,每个填入的参数会在 ticket 之后以百分号编码追加到启动地址,合计最多 4096 个字符,因此应用从 location.search 读取它们(SDK)。启动参数会到达 Player 网页应用及运行它的播放器(Samsung Tizen、BrightSign、LG webOS 和 Vega);Qt、Android、Apple 和 Windows 播放器从本地包加载应用,不发送任何参数。模板的 url 字段可以是整个 iframe src,其值本身也可携带屏幕令牌,在构建清单时填入。标签选择器以同样方式使用 {screen.id} 和 {screen.field.NAME}(见上文)。卡片保留自己的 {screen.…} 令牌。
媒体可用性
screenrig media availability med_ID --file rule.json 设置动态选择器(all、tag 和 folder)何时可以选取某个文件。--clear 移除规则,--expect-rev N 保护媒体修订版本。API 为 PATCH /api/media/{id}/availability,使用 If-Match 和 { "availability": {...} | null }。设置规则需要 Manage 访问权限;Propose 凭据会收到 insufficient_access。
规则采用排程的时钟语法,按每块屏幕的时区解读,至少包含一个成员:from 和 until(民用时间 YYYY-MM-DDTHH:MM,until 不含),windows(每周 {days, start, end}),monthly({day} 或 {nth, weekday},各自带可选的 start 和 end),dates({date, start, end})以及 except(移除某次出现的日期,包括跨午夜的尾段)。它没有 data 或 interaction。赞助商在长周末的素材,仅在时段内的工作日晚间可用:
{
"from": "2026-11-27T00:00",
"until": "2026-11-30T23:59",
"windows": [{ "days": ["mon", "tue", "wed", "thu", "fri"], "start": "17:00", "end": "22:00" }]
}
只有选择器会读取该规则:显式的 id 或 ids 选择器会忽略它,卡片的媒体引用、配乐音频和广告素材同样不受影响。文件会在每块屏幕的下一个播放列表循环离开或重新进入选择,在边界后约一分钟内生效。播放列表和清单的修订版本都不会变化,离线的播放器会保留其上一次的选择,直到重新连接。screenrig media selector-preview --timezone ZONE(默认 UTC)会在 excluded 中列出此刻处于规则之外的文件,原因为 outside_window。
返回 screenRIG CLI 参考。