Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions tests/recorded/jellyfin-10.11.11/RECORDED.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# One response set from a Jellyfin 10.11.11 server

Recorded on 2026-09-18 against a server I run for this purpose, the Docker image jellyfin/jellyfin at tag
10.11.11 in a container on this machine, reached over loopback, with the same library as the 12.0.0
set beside this one and nothing in it a person made: three two-second black videos, one
film under `Filme` and two episodes of one series under `Serien`, mounted read-only from the
files the 12.0.0 server generated. The server reported itself as:

```
GET /System/Info/Public ProductName "Jellyfin Server" Version "10.11.11"
```

10.11 is the oldest line the core claims to support, which is what #88 asks a recording
from: a dependency on something the newer line offers and this one does not is what the
comparison against these files exists to redden.

## What each file holds

The same sixteen calls as the 12.0.0 set beside this directory, made by the same recorder in the same order
with the same request bodies, one file per capability of
`docs/decisions/0272-the-route-next-up-is-read-from.md`, in the same envelope: `capability`,
`method`, `path`, `status`, the three response headers kept (`content-type`,
`content-length`, `server`), the request body where the call had one, and `body` as the
parsed JSON, or `body_bytes` with `body_content_type` where the answer was not JSON or
empty. What each file shows is the table in `tests/recorded/jellyfin-12.0.0/RECORDED.md`, and it is not
copied here so that the two cannot drift.

Read call for call against the 12.0.0 set, every status agrees and so does every top-level
key of every JSON body. What differs below the top level is what the comparison in #88 and
#104 reads, and this file does not pre-empt it.

## What was scrubbed, in the order `tests/recorded/README.md` gives

The token was removed from every envelope rather than rewritten, and no password was ever
in a response. The server address became `https://server.invalid`. The device identity was
synthetic from the first request. The account name appears in no response of this set.
Titles and paths were generated for this recording and name nobody.

Every server-supplied identifier, in keys as well as in values, became one of the sixteen
synthetic identifiers, by the rule the 12.0.0 set states: the recording holds twenty
distinct ones, twelve of which name a thing, the server, the three views, a view's parent,
the film, its parent, the play session, the first episode, the second episode, the series
behind its user-data key and its season, and each of those got its own value in order of
first appearance. The other eight are digests, five entity tags, two image tags and the
display-preferences id, and they took the remaining four values, the last five of them
sharing the sixteenth. A reader of an image tag or an entity tag should not take equality
of two of them as a fact about the server. A user-data `Key` is the server's own
hyphenated identifier with the episode's season and index appended, and the scrub keeps
that shape.

The check that judges all of this is `.github/fixture-scrub/fixture-scrub.sh check`, and
it was run on these files before they were committed.
13 changes: 13 additions & 0 deletions tests/recorded/jellyfin-10.11.11/after-sign-out.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"capability": "after-sign-out",
"method": "GET",
"path": "/UserViews",
"status": 401,
"headers": {
"Content-Length": "0",
"Server": "Kestrel"
},
"request_body": null,
"body_bytes": 0,
"body_content_type": ""
}
14 changes: 14 additions & 0 deletions tests/recorded/jellyfin-10.11.11/artwork-head.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"capability": "artwork-head",
"method": "HEAD",
"path": "/Items/00000000000040008000000000000005/Images/Primary",
"status": 200,
"headers": {
"Content-Length": "581",
"Content-Type": "image/jpeg",
"Server": "Kestrel"
},
"request_body": null,
"body_bytes": 0,
"body_content_type": "image/jpeg"
}
14 changes: 14 additions & 0 deletions tests/recorded/jellyfin-10.11.11/artwork.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"capability": "artwork",
"method": "GET",
"path": "/Items/00000000000040008000000000000005/Images/Primary",
"status": 200,
"headers": {
"Content-Length": "581",
"Content-Type": "image/jpeg",
"Server": "Kestrel"
},
"request_body": null,
"body_bytes": 581,
"body_content_type": "image/jpeg"
}
38 changes: 38 additions & 0 deletions tests/recorded/jellyfin-10.11.11/device-capabilities.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"capability": "device-capabilities",
"method": "POST",
"path": "/Sessions/Capabilities/Full",
"status": 204,
"headers": {
"Server": "Kestrel"
},
"request_body": {
"PlayableMediaTypes": [
"Video",
"Audio"
],
"SupportedCommands": [
"Play",
"PlayNext"
],
"SupportsMediaControl": true,
"SupportsPersistentIdentifier": true,
"DeviceProfile": {
"Name": "a synthetic device",
"MaxStreamingBitrate": 20000000,
"DirectPlayProfiles": [
{
"Container": "mp4",
"Type": "Video",
"VideoCodec": "h264",
"AudioCodec": "aac"
}
],
"TranscodingProfiles": [],
"CodecProfiles": [],
"SubtitleProfiles": []
}
},
"body_bytes": 0,
"body_content_type": ""
}
234 changes: 234 additions & 0 deletions tests/recorded/jellyfin-10.11.11/item-detail.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
{
"capability": "item-detail",
"method": "GET",
"path": "/Items/00000000000040008000000000000005",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=utf-8",
"Server": "Kestrel"
},
"request_body": null,
"body": {
"Name": "Synthetic Movie (2024)",
"ServerId": "00000000000040008000000000000000",
"Id": "00000000000040008000000000000005",
"Etag": "0000000000004000800000000000000f",
"DateCreated": "2026-09-18T11:39:07.0000000Z",
"CanDelete": true,
"CanDownload": true,
"Container": "mov,mp4,m4a,3gp,3g2,mj2",
"SortName": "synthetic movie (0000002024)",
"ExternalUrls": [],
"MediaSources": [
{
"Protocol": "File",
"Id": "00000000000040008000000000000005",
"Path": "/media/Filme/Synthetic Movie (2024)/Synthetic Movie (2024).mp4",
"Type": "Default",
"Container": "mp4",
"Size": 3826,
"Name": "Synthetic Movie (2024)",
"IsRemote": false,
"ETag": "0000000000004000800000000000000f",
"RunTimeTicks": 20000000,
"ReadAtNativeFramerate": false,
"IgnoreDts": false,
"IgnoreIndex": false,
"GenPtsInput": false,
"SupportsTranscoding": true,
"SupportsDirectStream": true,
"SupportsDirectPlay": true,
"IsInfiniteStream": false,
"UseMostCompatibleTranscodingProfile": false,
"RequiresOpening": false,
"RequiresClosing": false,
"RequiresLooping": false,
"SupportsProbing": true,
"VideoType": "VideoFile",
"MediaStreams": [
{
"Codec": "h264",
"CodecTag": "avc1",
"Language": "und",
"TimeBase": "1/12800",
"VideoRange": "SDR",
"VideoRangeType": "SDR",
"AudioSpatialFormat": "None",
"DisplayTitle": "240p H264 SDR",
"NalLengthSize": "4",
"IsInterlaced": false,
"IsAVC": true,
"BitRate": 5348,
"BitDepth": 8,
"RefFrames": 1,
"IsDefault": true,
"IsForced": false,
"IsHearingImpaired": false,
"Height": 180,
"Width": 320,
"AverageFrameRate": 25,
"RealFrameRate": 25,
"ReferenceFrameRate": 25,
"Profile": "Constrained Baseline",
"Type": "Video",
"AspectRatio": "16:9",
"Index": 0,
"IsExternal": false,
"IsTextSubtitleStream": false,
"SupportsExternalStream": false,
"PixelFormat": "yuv420p",
"Level": 12,
"IsAnamorphic": false
},
{
"Codec": "aac",
"CodecTag": "mp4a",
"Language": "und",
"TimeBase": "1/22050",
"VideoRange": "Unknown",
"VideoRangeType": "Unknown",
"AudioSpatialFormat": "None",
"LocalizedDefault": "Default",
"LocalizedExternal": "External",
"DisplayTitle": "AAC - Mono - Default",
"IsInterlaced": false,
"IsAVC": false,
"ChannelLayout": "mono",
"BitRate": 770,
"Channels": 1,
"SampleRate": 22050,
"IsDefault": true,
"IsForced": false,
"IsHearingImpaired": false,
"Profile": "LC",
"Type": "Audio",
"Index": 1,
"IsExternal": false,
"IsTextSubtitleStream": false,
"SupportsExternalStream": false,
"Level": 0
}
],
"MediaAttachments": [],
"Formats": [],
"Bitrate": 15304,
"RequiredHttpHeaders": {},
"TranscodingSubProtocol": "http",
"DefaultAudioStreamIndex": 1,
"HasSegments": false
}
],
"ProductionLocations": [],
"Path": "/media/Filme/Synthetic Movie (2024)/Synthetic Movie (2024).mp4",
"EnableMediaSourceDisplay": true,
"ChannelId": null,
"Taglines": [],
"Genres": [],
"RunTimeTicks": 20000000,
"PlayAccess": "Full",
"ProductionYear": 2024,
"RemoteTrailers": [],
"ProviderIds": {},
"IsFolder": false,
"ParentId": "00000000000040008000000000000006",
"Type": "Movie",
"People": [],
"Studios": [],
"GenreItems": [],
"LocalTrailerCount": 0,
"UserData": {
"PlaybackPositionTicks": 0,
"PlayCount": 0,
"IsFavorite": false,
"Played": false,
"Key": "00000000-0000-4000-8000-000000000005",
"ItemId": "00000000000040008000000000000005"
},
"SpecialFeatureCount": 0,
"DisplayPreferencesId": "0000000000004000800000000000000f",
"Tags": [],
"PrimaryImageAspectRatio": 1.7777777777777777,
"MediaStreams": [
{
"Codec": "h264",
"CodecTag": "avc1",
"Language": "und",
"TimeBase": "1/12800",
"VideoRange": "SDR",
"VideoRangeType": "SDR",
"AudioSpatialFormat": "None",
"DisplayTitle": "240p H264 SDR",
"NalLengthSize": "4",
"IsInterlaced": false,
"IsAVC": true,
"BitRate": 5348,
"BitDepth": 8,
"RefFrames": 1,
"IsDefault": true,
"IsForced": false,
"IsHearingImpaired": false,
"Height": 180,
"Width": 320,
"AverageFrameRate": 25,
"RealFrameRate": 25,
"ReferenceFrameRate": 25,
"Profile": "Constrained Baseline",
"Type": "Video",
"AspectRatio": "16:9",
"Index": 0,
"IsExternal": false,
"IsTextSubtitleStream": false,
"SupportsExternalStream": false,
"PixelFormat": "yuv420p",
"Level": 12,
"IsAnamorphic": false
},
{
"Codec": "aac",
"CodecTag": "mp4a",
"Language": "und",
"TimeBase": "1/22050",
"VideoRange": "Unknown",
"VideoRangeType": "Unknown",
"AudioSpatialFormat": "None",
"LocalizedDefault": "Default",
"LocalizedExternal": "External",
"DisplayTitle": "AAC - Mono - Default",
"IsInterlaced": false,
"IsAVC": false,
"ChannelLayout": "mono",
"BitRate": 770,
"Channels": 1,
"SampleRate": 22050,
"IsDefault": true,
"IsForced": false,
"IsHearingImpaired": false,
"Profile": "LC",
"Type": "Audio",
"Index": 1,
"IsExternal": false,
"IsTextSubtitleStream": false,
"SupportsExternalStream": false,
"Level": 0
}
],
"VideoType": "VideoFile",
"ImageTags": {
"Primary": "0000000000004000800000000000000f"
},
"BackdropImageTags": [],
"ImageBlurHashes": {
"Primary": {
"0000000000004000800000000000000f": "W00000fQfQfQfQfQfQfQfQfQfQfQfQfQfQfQfQfQfQfQfQfQfQfQ"
}
},
"Chapters": [],
"Trickplay": {},
"LocationType": "FileSystem",
"MediaType": "Video",
"LockedFields": [],
"LockData": false,
"Width": 320,
"Height": 180
}
}
20 changes: 20 additions & 0 deletions tests/recorded/jellyfin-10.11.11/item-user-data-episode.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"capability": "item-user-data-episode",
"method": "GET",
"path": "/UserItems/00000000000040008000000000000008/UserData",
"status": 200,
"headers": {
"Content-Type": "application/json; charset=utf-8",
"Server": "Kestrel"
},
"request_body": null,
"body": {
"PlaybackPositionTicks": 0,
"PlayCount": 1,
"IsFavorite": false,
"LastPlayedDate": "2026-09-18T12:07:36.3040665Z",
"Played": true,
"Key": "00000000-0000-4000-8000-000000000008",
"ItemId": "00000000000040008000000000000008"
}
}
Loading
Loading