
Jellyfin API实战指南从拿到一个令牌到接管整个媒体库【免费下载链接】jellyfinThe Free Software Media System - Server Backend API项目地址: https://gitcode.com/GitHub_Trending/je/jellyfin做自播 App 的开发者大多卡在同一处Jellyfin 的接口散落在几十个控制器里文档又多又碎。这篇教程只挑你最常用的那 5 个端点从认证、查库、播放同步到播放列表全部给出可直接复制的请求和响应。30 秒拿到第一个响应 不用先啃架构一条 curl 就能验证你的 Jellyfin 服务是否可达。用管理员账号换一个令牌POST http://localhost:8096/Users/AuthenticateByName Content-Type: application/json { Username: admin, Pw: changeme }预期响应里最关键的是AccessToken字段{ AccessToken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.demo-token-value, User: { Id: 3f2a8c1e-9b4d-4e7a-b1c2-5d6e7f8a9b0c, Name: admin } }令牌拿到手后任何接口都只需在请求头加一行X-Emby-Token。认证逻辑实现在 CustomAuthenticationHandler它校验令牌后把用户身份注入请求上下文后续控制器才能读到当前用户。核心模块怎么分工Jellyfin 的 HTTP 层全部收敛在Jellyfin.Api/Controllers目录按领域切分。你只需要记住下面这张表找接口时先定位领域再翻对应文件控制器负责什么源码ItemsController媒体项查询电影/剧集/音乐通用Jellyfin.Api/Controllers/ItemsController.csUserController登录、用户创建与资料管理Jellyfin.Api/Controllers/UserController.csPlaystateController播放状态上报与继续播放Jellyfin.Api/Controllers/PlaystateController.csPlaylistsController播放列表增删改查Jellyfin.Api/Controllers/PlaylistsController.csLibraryStructureController媒体库目录结构管理Jellyfin.Api/Controllers/LibraryStructureController.csLibraryController媒体库刷新、相似推荐Jellyfin.Api/Controllers/LibraryController.cs路由分发走标准 ASP.NET Core 管线请求进Program.cs启动的 WebHost经过 ExceptionMiddleware 等中间件后落到具体控制器响应统一用 DTO 序列化返回。令牌的获取与请求头携带方式上面演示过AuthenticateByName这里只补三个实用细节响应中的User.Id就是大多数查询接口必填的userId参数建议存下来复用。令牌是长效凭证客户端把它放本地安全存储即可每次请求通过X-Emby-Token头携带也支持旧式Authorization: MediaBrowser tokenxxx写法。想登出或吊销删用户会话即可令牌本身由服务端在每次请求时校验签名。场景实战场景一按类型查询媒体库做今天看什么这类功能时你需要的是带过滤的通用查询而不是按电影、剧集各写一套接口。GET /Items就是那个统一入口GET http://localhost:8096/Items?userId3f2a8c1e-9b4d-4e7a-b1c2-5d6e7f8a9b0cIncludeItemTypesMovieRecursivetrueLimit10StartIndex0 X-Emby-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.demo-token-value{ Items: [ { Id: b2c3d4e5-f6a7-5b6c-0d1e-8f9a0b1c2d3e, Name: 星际救援, Type: Movie, PremiereDate: 2023-01-01T00:00:00Z, RunTimeTicks: 72000000000, Path: /media/movies/星际救援.mkv } ], TotalRecordCount: 142, StartIndex: 0 }关键参数userId必填缺了直接 400。IncludeItemTypes逗号分隔多类型如Movie,Series。Recursive是否递归进入子文件夹默认 false 时容易查不到东西。Limit/StartIndex分页组合响应里的TotalRecordCount是总数。Fields只返回指定字段如FieldsName,PremiereDate能显著减小包体。实现入口在 ItemsController.GetItems查询条件的拼装逻辑在同文件的私有方法里参数不熟时可以翻这个文件对照。场景二同步播放进度到服务端客户端 App 上报进度后Web 端的继续播放才会准确。播放进度上报走 PlaystateController播放中每 10 秒左右发一次即可POST http://localhost:8096/Sessions/Playing/Progress Content-Type: application/json X-Emby-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.demo-token-value { ItemType: Movie, ItemId: b2c3d4e5-f6a7-5b6c-0d1e-8f9a0b1c2d3e, MediaSourceId: c9d8e7f6-a5b4-4c3d-8e2f-1a0b9c8d7e6f, Event: timeupdate, PositionTicks: 36000000000, IsPaused: false }{ PlaybackInfo: { CanResume: true, PositionTicks: 36000000000, MediaSource: { Id: c9d8e7f6-a5b4-4c3d-8e2f-1a0b9c8d7e6f, Name: 星际救援.mkv } } }关键参数ItemId媒体项 GUID来自场景一查询结果。PositionTicks100 纳秒为单位的播放位置秒 × 10_000_000 换算。IsPaused暂停/继续时务必携带服务端据此区分在播和挂着。MediaSourceId同一影片多版本如不同编码时用来区分。播放结束要记得补发一次Event: stoppedPOST /Sessions/Playing/Stopped否则继续播放列表会残留。场景三向播放列表批量加歌自建播单、给电视推歌单都绕不开播放列表接口。它挂在约定路由/playlists下追加条目是一个独立端点POST http://localhost:8096/playlists/7a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d/Items Content-Type: application/json X-Emby-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.demo-token-value [1f0e9d8c-7b6a-4f3e-9d2c-8b7a6e5f4d3c, 2a3b4c5d-6e7f-8a9b-0c1d-2e3f4a5b6c7d]{ Id: 7a1b2c3d-4e5f-6a7b-8c9d-0e1f2a3b4c5d, Name: 周末公路片, PlaylistType: Playlist, ItemCount: 12 }关键参数路径参数playlistId先调POST /playlists创建列表响应里带Id。请求体媒体项 GUID 数组顺序即追加顺序。同文件还有GET /playlists/{playlistId}/Items拉取列表内容、POST .../Items/{itemId}/Move/{newIndex}调整顺序。PlaylistsController 里每个端点都带[ProducesResponseType]标注了可能返回的状态码写异常分支时直接对着写。场景四管理员操作——建用户、挂媒体目录部署新服务器后通常要干两件事给家人开账号、把 NAS 路径挂进库。开账号走 UserControllerPOST http://localhost:8096/Users/New Content-Type: application/json X-Emby-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.demo-token-value { Name: alice }{ Id: 9c8d7e6f-5a4b-4c3d-8e2f-1b0a9c8d7e6f, Name: alice, Policy: { IsAdministrator: false, IsDisabled: false } }新建响应里的Id就是给 alice 用的userId初始密码首次登录时由系统强制修改。挂目录的端点在 LibraryStructureController注意它把基础参数放在 query、库级选项放在 body和前面几个接口的习惯不太一样POST http://localhost:8096/Library/VirtualFolders?nameFamilyPhotoscollectionTypephotosrefreshLibrarytrue Content-Type: application/json X-Emby-Token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.demo-token-value { LibraryOptions: { CollectionType: photos, Locations: [/media/photos/family], EnableRealtimeMonitor: true } }关键参数name媒体库显示名query 参数。collectionTypemovies、tvshows、music、photos等。refreshLibrary为 true 时立即触发扫描否则等定时任务。Locations服务端实际可访问的绝对路径路径写错是最常见翻车点。排错与高频问题状态码语义和常规 REST 一致速查如下状态码含义常见诱因200成功—400参数错误userId缺失、GUID 格式错401未认证X-Emby-Token缺失或令牌失效403权限不足非管理员调管理接口、用户无该库访问权404资源不存在itemId/playlistId写错或已被删除500服务器错误看服务端日志通常是插件或 FFmpeg 问题Q为什么查询结果总是空的九成是Recursivefalse默认值导致只查了顶层目录。影视库普遍有子文件夹加上Recursivetrue再试。Q401 但令牌明明没过期检查服务器时间——令牌是签名凭证服务端校签时若系统时钟偏移过大会直接拒绝。先date对一下时。QuserId和ItemId搞混了会怎样都是 GUIDHTTP 层不报错但查询会静默返回空。拿到 ID 时顺手看响应里的Type字段确认身份。进阶技巧分页拉全量大库别用大Limit一把梭。固定StartIndex步长循环如每次 100用TotalRecordCount判断终止压力最平稳。字段瘦身列表页只展示名称和时间时传FieldsName,PremiereDate详情页再单独GET /Items/{id}拉全量。带宽能省一半以上。实时监听轮询GET /Library/MediaFolders太浪费长连接走 WebSocket/websocket带同一令牌媒体变更由服务端主动推送。元数据插件查库之外/Library/RefreshLibraryController触发整库刷新刮削源可在插件管理界面切换比如内置的 OMDb 源OpenAPI 文档服务内置/api-docs/openapi.json第三方端点变更时先 diff 这份 spec 再改代码比翻源码快。延伸资源全部控制器源码Jellyfin.Api/Controllers每个端点的 XML 注释里都写了response code说明等价于活文档。服务端启动与路由装配Program.cs 和 Startup.cs想加自定义中间件从这里入手。接口行为测试tests/Jellyfin.Server.Integration.Tests里面有现成的请求构造样例照抄即可。动手建议先跑通30 秒一节拿令牌再用场景一的GET /Items把你现有库里真实的影片 ID 打印出来后面三个场景全部换成真实数据复跑一遍——半小时就能搭出一个最小可用的播放上报闭环。【免费下载链接】jellyfinThe Free Software Media System - Server Backend API项目地址: https://gitcode.com/GitHub_Trending/je/jellyfin创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考