Homepage 集成 Tautulli(Plex)Widget:实时监控播放流的完整配置指南
2026/9/10 21:53:25 网站建设 项目流程

Homepage 集成 Tautulli(Plex)Widget:实时监控播放流的完整配置指南

【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage

本文以 Homepage 开源项目中的 Tautulli 服务 Widget 文档 为主体,介绍如何在 Homepage 中接入 Tautulli(Plex 媒体服务器监控工具),在个人主页/应用仪表板上实时展示当前活跃的 Plex 播放流。读完本文,你将掌握 API Key 获取、YAML 配置的每个参数含义与默认值,并能结合源码理解该 Widget 的底层请求链路、渲染逻辑与排错方法。

一、功能概述:为什么在 Homepage 中集成 Tautulli

Tautulli(原名 PlexPy)是 Plex 生态中流行的第三方监控与统计工具,能够记录播放历史、追踪活跃会话、统计带宽与转码情况。Homepage 的 Tautulli Widget 定位十分聚焦:实时展示当前正在进行的 Plex 播放流(active streams),包括正在播放的媒体标题、观看进度、播放/暂停状态、视频与音频的决策(Direct Play / Copy / Transcode)等信息,让你在打开个人主页时即可一眼掌握媒体服务器的实时负载。

从官方文档的定位描述看(docs/widgets/services/plex-tautulli.md):

Provides detailed information about currently active streams.

即该 Widget 只围绕"当前活跃播放流"这一核心场景,不承担历史统计等 Tautulli 的其他能力,配置上也因此非常简单——没有可配置的显示字段(Allowed fields: no configurable fields for this widget),只通过少量布尔选项调整展示细节。

二、前置条件:获取 Tautulli API Key

Homepage 通过 Tautulli 的 HTTP API 拉取实时数据,因此需要 API Key 才能访问。获取方式如下:

  1. 登录 Tautulli 的 Web 界面;
  2. 进入Settings > Web Interface > API
  3. 在该页面中复制 API Key(一串较长的字符串)。

该 Key 将作为配置项key填入 Homepage 的 Widget 配置中。值得注意的是,Tautulli 的 API 默认要求请求携带apikey参数(详见下文源码分析),Homepage 正是以该参数形式透传认证信息的。

三、Widget 配置指南

3.1 最小可运行配置

在 Homepage 的services.yaml(或对应的分组配置)中新增一个服务条目,将widget.type设为tautulli,并填入 Tautulli 服务的 URL 与 API Key:

- Tautulli: icon: tautulli.png href: http://tautulli.host.or.ip:port description: Plex 监控 widget: type: tautulli url: http://tautulli.host.or.ip:port key: apikeyapikeyapikeyapikeyapikey
  • url:Tautulli 服务地址,格式为http://tautulli.host.or.ip:port,需与 Tautulli 实际监听端口(默认 8181)一致;
  • key:上一节获取的 API Key。

3.2 完整参数与默认值

根据 docs/widgets/services/plex-tautulli.md 中的官方示例,该 Widget 的全部可用参数如下:

widget: type: tautulli url: http://tautulli.host.or.ip:port key: apikeyapikeyapikeyapikeyapikey enableUser: true # optional, defaults to false showEpisodeNumber: true # optional, defaults to false expandOneStreamToTwoRows: false # optional, defaults to true

参数说明:

参数类型默认值作用
typestring必填固定为tautulli,用于加载对应 Widget 实现
urlstring必填Tautulli 服务地址(含端口)
keystring必填Tautulli API Key
enableUserbooleanfalse是否在流标题后显示播放用户(friendly_name
showEpisodeNumberbooleanfalse对剧集类媒体是否显示 Sxx · Exx 集数信息
expandOneStreamToTwoRowsbooleantrue当只有一个活跃播放流时,是否展开为两行显示(标题行 + 进度行)

这三个布尔参数的默认值均有对应源码实现支撑,详见下文第四、五节。

四、源码级原理:请求如何从 Widget 到达 Tautulli

4.1 API 模板与 Endpoint 映射

Tautulli Widget 的核心定义位于 src/widgets/tautulli/widget.js,代码非常精简:

import genericProxyHandler from "utils/proxy/handlers/generic"; const widget = { api: "{url}/api/v2?apikey={key}&cmd={endpoint}", proxyHandler: genericProxyHandler, mappings: { get_activity: { endpoint: "get_activity", }, }, }; export default widget;

可以提炼出几个关键事实:

  • Widget 通过 Tautulli 的API v2接口获取数据,最终请求 URL 形如{url}/api/v2?apikey={key}&cmd=get_activity
  • cmd=get_activity是 Tautulli API 中用于查询当前活跃会话的命令,与本文档"active streams"的定位完全对应;
  • 该 Widget 使用通用的genericProxyHandler作为代理处理器,没有自定义的响应映射(mappings仅声明 endpoint)。

4.2 通用代理链路:服务端如何透传请求

Homepage 的所有 Widget 请求都先打到项目自身的 API 路由,再由服务端代理转发到目标服务,避免在浏览器端暴露 API Key。Tautulli Widget 走的是通用链路,核心实现在 src/utils/proxy/handlers/generic.js:

  1. 从请求 query 中解析groupserviceendpointindex
  2. 通过getServiceWidget读取当前服务的 Widget 配置;
  3. 使用formatApiCall(widgets[widget.type].api, { endpoint, ...widget }){url}{key}{endpoint}等占位符替换为实际值,拼出最终 URL;
  4. 通过httpProxy发起 HTTP 请求,并做响应校验(validateWidgetData)与错误信息脱敏(sanitizeErrorURL)。

前端侧,组件通过 src/utils/proxy/use-widget-api.js 中封装的useSWR拉取数据,并为get_activity设置了5000ms(5 秒)的刷新间隔(见 src/widgets/tautulli/component.jsx):

const { data: activityData, error: activityError } = useWidgetAPI(widget, "get_activity", { refreshInterval: 5000, });

也就是说,只要页面处于打开状态,Tautulli Widget 每 5 秒会自动重新请求一次活跃会话数据,保证仪表板上的播放状态接近实时。

五、渲染行为详解:三种展示形态与判断逻辑

Tautulli Widget 的渲染组件在 src/widgets/tautulli/component.jsx 中实现,其展示逻辑可以根据活跃流数量分为三种形态。

5.1 加载态与空态

  • 加载中:数据尚未返回时,渲染 1~2 行占位符(-);
  • 无活跃流sessions为空数组时,显示国际化文案tautulli.no_active(英文为 "No Active Streams",简体中文为"暂无播放",见 public/locales/en/common.json 与 public/locales/zh-Hans/common.json);
  • 连接错误:请求失败或返回空数据时,显示tautulli.plex_connection_error(英文 "Check Plex Connection",简体中文"检查Plex连接"),提示检查 Plex/Tautulli 连通性。

5.2 单流双行展开(expandOneStreamToTwoRows)

expandOneStreamToTwoRowstrue(默认值)且当前恰好只有一个活跃播放流时,Widget 使用SingleSessionEntry渲染两行:

  • 第一行(标题行):展示流标题,并在右侧显示播放决策图标;
  • 第二行(进度行):带进度的进度条背景,左侧显示播放/暂停图标,右侧显示当前观看位置 / 总时长(格式为HH:MM:SSMM:SS)。

多流时(2 个及以上),则退化为紧凑的单行模式SessionEntry:每行显示状态图标、标题、播放决策图标和当前观看位置,不再展示完整进度条与总时长。

这个开关的默认值在源码中是这样生效的:

const expandOneStreamToTwoRows = service.widget?.expandOneStreamToTwoRows !== false; // default is true

即只有当显式配置为false时才会关闭双行展开,不配置即为true

5.3 标题与集数显示(enableUser / showEpisodeNumber)

标题的生成逻辑由generateStreamTitle完成:

function generateStreamTitle(session, enableUser, showEpisodeNumber) { let stream_title = ""; const { media_type, parent_media_index, media_index, title, grandparent_title, full_title, friendly_name } = session; if (media_type === "episode" && showEpisodeNumber) { const season_str = `S${parent_media_index.toString().padStart(2, "0")}`; const episode_str = `E${media_index.toString().padStart(2, "0")}`; stream_title = `${grandparent_title}: ${season_str} · ${episode_str} - ${title}`; } else { stream_title = full_title; } return enableUser ? `${stream_title} (${friendly_name})` : stream_title; }
  • showEpisodeNumber: true:当媒体类型为剧集(episode)时,标题显示为剧名: S01 · E05 - 单集标题的格式,方便快速定位季/集;
  • enableUser: true:在标题末尾追加(用户名),其中用户名取自 Tautulli 会话中的friendly_name字段,便于在多用户家庭环境中区分谁在观看。

5.4 播放决策图标:Direct Play / Copy / Transcode

每行右侧的图标用于表达 Tautulli 返回的video_decisionaudio_decision组合:

视频/音频决策图标含义
均为direct playMdSmartDisplay(实心显示器)直接播放,无任何转码
均为copyMdOutlineSmartDisplay(描边显示器)容器/流复制(remux),接近无损
其他组合BsFillCpuFill/BsCpu涉及转码,CPU 参与处理

图标语义结合国际化文案tautulli.playing(播放中)、tautulli.transcoding(转码)、tautulli.bitrate(比特率)使用,可直观判断当前播放流的资源占用情况。

5.5 排序规则

获取到会话列表后,组件会对sessionsview_offset(当前观看位置,毫秒)进行升序排序后再渲染,即观看进度靠前的播放流显示在上面

const playing = activityData.response.data.sessions.sort((a, b) => { if (a.view_offset > b.view_offset) return 1; if (a.view_offset < b.view_offset) return -1; return 0; });

六、测试与验证:Widget 行为的自动化保障

仓库为 Tautulli Widget 提供了完整的测试,可作为理解其行为与验证配置合法性的参考:

  • src/widgets/tautulli/widget.test.js:通过expectWidgetConfigShape校验 Widget 配置对象(apiproxyHandlermappings等)符合项目约定的结构,任何字段缺失都会导致测试失败;
  • src/widgets/tautulli/component.test.jsx:使用vi.mock模拟useWidgetAPI,覆盖三类关键场景:
    • 加载中显示占位行(-);
    • 无活跃会话时显示tautulli.no_active文案;
    • 单个会话播放时渲染双行展开,且时间格式正确(如view_offset: 1000毫秒渲染为00:01duration: 2000渲染为00:02)。

这些测试一方面验证了渲染逻辑的正确性,另一方面也侧面印证了本文第五节描述的展示规则。

七、常见问题与排错

1. Widget 显示"检查Plex连接"(Check Plex Connection)

该错误对应tautulli.plex_connection_error,出现时说明请求 Tautulli 失败或返回数据为空。请依次检查:

  • url是否可从运行 Homepage 的主机访问(注意不要写成 Plex 的地址,而是 Tautulli 的地址);
  • key是否复制完整,API Key 在Settings > Web Interface > API中查看;
  • Tautulli 服务是否运行正常、端口是否正确。

2. 显示"暂无播放"(No Active Streams)但 Plex 明明在播放

确认 Plex 用户确实在当前活跃播放(而非暂停很久或已退出),Tautulli 的get_activity接口只返回当前处于活动状态的会话。另外注意 Widget 每 5 秒刷新一次,数据可能存在数秒延迟。

3. 不想看到用户名 / 不想显示集数

分别将enableUsershowEpisodeNumber配置为false(或不配置,因为默认即false)。

4. 希望单流时也保持一行

expandOneStreamToTwoRows显式设置为false,此时无论活跃流数量多少,都使用紧凑单行渲染。

八、小结

Homepage 的 Tautulli Widget 以"实时活跃播放流监控"为单一职责,配置只需url+key两个必填项,配合enableUsershowEpisodeNumberexpandOneStreamToTwoRows三个可选开关即可适配不同展示偏好。底层通过服务端通用代理调用 Tautulli API v2 的get_activity命令,前端每 5 秒刷新,并针对 Direct Play / Copy / Transcode 提供直观的图标反馈。若需深入理解实现细节,可继续阅读 src/widgets/tautulli/widget.js、src/widgets/tautulli/component.jsx 以及对应的 组件测试。

【免费下载链接】homepageA highly customizable homepage (or startpage / application dashboard) with Docker and service API integrations.项目地址: https://gitcode.com/GitHub_Trending/ho/homepage

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询