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

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

2026-09-09 22:05:31作者:董灵辛Dennis

本文以 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

参数说明:

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

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

四、源码级原理:请求如何从 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.jsonpublic/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 play MdSmartDisplay(实心显示器) 直接播放,无任何转码
均为 copy MdOutlineSmartDisplay(描边显示器) 容器/流复制(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.jssrc/widgets/tautulli/component.jsx 以及对应的 组件测试

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.15 K
2.78 K
kernelkernel
deepin linux kernel
C
34
18
docsdocs
暂无描述
Markdown
904
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
931
1.86 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
862
1.36 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.95 K
1.03 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.38 K
1.47 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
535
605
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
549
398
leetcodeleetcode
🔥LeetCode solutions in any programming language | 多种编程语言实现 LeetCode、《剑指 Offer(第 2 版)》、《程序员面试金典(第 6 版)》题解
Markdown
77
23