<h1 align="center">Jellyfin SDK for Python</h1>
---
<p align="center">
<img alt="Logo Banner" src="https://raw.githubusercontent.com/jellyfin/jellyfin-ux/master/branding/SVG/banner-logo-solid.svg?sanitize=true"/>
</p>
A High-level Wrapper for OpenAPI Generated Bindings for Jellyfin API.
> Warning: API changes will occur only in the final classes, bindings and legacy don't change
The main goal of this project is to be a wrapper for the API but with high level of abstraction using the power of [OpenAPI Specs bindings](https://github.com/OpenAPITools/openapi-generator) and good patterns such as [Inversion of Control](https://en.wikipedia.org/wiki/Inversion_of_control), [Method Chaining](https://en.wikipedia.org/wiki/Method_chaining), [JSONPath](https://en.wikipedia.org/wiki/JSONPath), and more.
Main unique features:
- Enables targeting a specific Jellyfin server version to ensure compatibility and prevent breaking changes.
- Supports accessing multiple servers, each potentially running different Jellyfin versions.
- Allows reducing the level of abstraction to access advanced or unavailable options through lower-level interfaces.
- Works like [AWS CDK Constructs Level](https://blog.shikisoft.com/aws-cdk-construct-levels/), more abstraction, more simple.
<div align="center">
<img width="682" height="762" alt="image" src="https://github.com/user-attachments/assets/5e878d51-6c0f-441b-a35b-94e93d9c3340" />
<em><small>How modules work together</small></em>
</div>
<small>
There is a thin layer that builds the high-level abstraction (green box/jellyfin) consuming only the bindings that already contain dataclasses and api built using the OpenAPI Generator (blue box/generated), which in turn also allows use only if the user requests jellyfin_apiclient_python (purple box/legacy) to allow for refactoring and incremental development. Both legacy and generated have classes that allow low-level access, being practically just an envelope method for requests that must communicate with the actual jellyfin API (lilac box).
</small>
This project is mainly inspired by good python library like these:
- [tmdbsimple](https://github.com/celiao/tmdbsimple)
- [plexapi](https://github.com/pushingkarmaorg/python-plexapi)
- [tensorflow](https://github.com/tensorflow/tensorflow)
## Install
```sh
pip install jellyfin-sdk
```
or
```sh
uv add jellyfin-sdk
```
## Usage
### Drop-in replacement for [jellyfin-apiclient-python](https://github.com/jellyfin/jellyfin-apiclient-python)
This library includes the old legacy client (which is almost unmaintained) to help with migration:
```sh
pip uninstall jellyfin-apiclient-python
pip install jellyfin-sdk[legacy]
```
```python
# change from
from jellyfin_apiclient_python import JellyfinClient
from jellyfin_apiclient_python.api import API
# to this
from jellyfin.legacy import JellyfinClient
from jellyfin.legacy.api import API
```
### Login
```python
import os
os.environ["URL"] = "https://jellyfin.example.com"
os.environ["API_KEY"] = "MY_TOKEN"
```
#### Using SDK
```python
import jellyfin
api = jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY")
)
print(
api.system.info.version,
api.system.info.server_name
)
```
#### Direct with Generated Bindings
```python
from jellyfin.generated.api_10_10 import Configuration, ApiClient, SystemApi
configuration = Configuration(
host = os.getenv("URL"),
api_key={'CustomAuthentication': f'Token="{os.getenv("API_KEY")}"'},
api_key_prefix={'CustomAuthentication': 'MediaBrowser'}
)
client = ApiClient(configuration)
system = SystemApi(client)
print(
system.get_system_info().version,
system.get_system_info().server_name
)
```
#### Legacy
```python
from jellyfin.legacy import JellyfinClient
client = JellyfinClient()
client.authenticate(
{"Servers": [{
"AccessToken": os.getenv("API_KEY"),
"address": os.getenv("URL")
}]},
discover=False
)
system_info = client.jellyfin.get_system_info()
print(
system_info.get("Version"),
system_info.get("ServerName")
)
```
### Jellyfin Server API Version
This is important because when a new API version is released, breaking changes can affect the entire project.
To avoid this, you can set an API target version, similar to how it's done in Android development:
```python
from jellyfin.api import Version
import jellyfin
# By default will use the lastest stable
jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY")
)
# now let's test the new API (version 10.11) for breaking changes in same endpoint
jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY"),
Version.V10_11
)
# but str is allow to: 10.10, 10.11 and etc
jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY"),
'10.11'
)
# let's test a wrong version
jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY"),
'99'
)
> ValueError: Unsupported version: 99. Supported versions are: ['10.10', '10.11']
```
### List all libraries of an user
When using `API_KEY` some endpoints need the user_id (don't me ask why!), almost all issues with jellyfin is around this.
To help to identify this not-so-much-edge-cases we raise a exception to help with that:
```python
api = jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY")
)
api.users.libraries
> ValueError: User ID is not set. Use the 'of(user_id)' method to set the user context.
api.users.of('f674245b84ea4d3ea9cf11').libraries
# works also with the user name
api.users.of('niels').libraries
# when using 'of' the attribute of dataclasses
# user and user_view can be accessed directly
api.users.of('niels').id
```
### List all items
Item can be any object in the server, in fact that's how works, one huge table recursive linked.
```python
api = jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY")
)
api.items.all
# Same command but without shorthand
search = api.items.search
search
<ItemSearch (no filters set)>
search.paginate(1000)
<ItemSearch filters={
start_index=0,
limit=1000,
enable_total_record_count=True
}>
search.recursive()
<ItemSearch filters={
start_index=0,
limit=1000,
enable_total_record_count=True,
recursive=True
}>
```
All filter options is available [here](https://webysther.github.io/jellyfin-sdk-python.github.io/api_10_10/docs/ItemsApi/#get_items).
The pagination uses a Iterator:
```python
api = jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY")
)
for item in api.items.search.paginate(100).recursive().all:
print(item.name)
```
### Let's get the User ID by name or ID
```python
api = jellyfin.api(
os.getenv("URL"),
os.getenv("API_KEY")
)
uuid = api.user.by_name('joshua').id
api.user.by_id(uuid).name
```
### Documentation
- [SDK Reference](https://webysther.github.io/jellyfin-sdk-python.github.io/sdk/)
- [Jellyfin API 10.10](https://webysther.github.io/jellyfin-sdk-python.github.io/api_10_10/) (Stable)
- [Jellyfin API 10.11](https://webysther.github.io/jellyfin-sdk-python.github.io/api_10_11/) (Release Candidate)
### Supported Jellyfin Versions
| SDK Version | Jellyfin API Target |
|:-:|:-:|
| 0.1.x | 10.10.x-10.11.x |
Raw data
{
"_id": null,
"home_page": null,
"name": "jellyfin-sdk",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "api, sdk, jellyfin, dataclass, openapi, wrapper-api",
"author": "Webysther Sperandio",
"author_email": "Webysther Sperandio <webysther@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/43/91/06b75f3870690d7aca0b7a58a67ad87b7ac84db48669bf82a06c83c4ac2e/jellyfin_sdk-0.1.4.tar.gz",
"platform": null,
"description": "<h1 align=\"center\">Jellyfin SDK for Python</h1>\n\n---\n\n<p align=\"center\">\n<img alt=\"Logo Banner\" src=\"https://raw.githubusercontent.com/jellyfin/jellyfin-ux/master/branding/SVG/banner-logo-solid.svg?sanitize=true\"/>\n</p>\n\nA High-level Wrapper for OpenAPI Generated Bindings for Jellyfin API.\n\n> Warning: API changes will occur only in the final classes, bindings and legacy don't change\n\nThe main goal of this project is to be a wrapper for the API but with high level of abstraction using the power of [OpenAPI Specs bindings](https://github.com/OpenAPITools/openapi-generator) and good patterns such as [Inversion of Control](https://en.wikipedia.org/wiki/Inversion_of_control), [Method Chaining](https://en.wikipedia.org/wiki/Method_chaining), [JSONPath](https://en.wikipedia.org/wiki/JSONPath), and more.\n\nMain unique features:\n- Enables targeting a specific Jellyfin server version to ensure compatibility and prevent breaking changes.\n- Supports accessing multiple servers, each potentially running different Jellyfin versions.\n- Allows reducing the level of abstraction to access advanced or unavailable options through lower-level interfaces.\n- Works like [AWS CDK Constructs Level](https://blog.shikisoft.com/aws-cdk-construct-levels/), more abstraction, more simple.\n\n<div align=\"center\">\n<img width=\"682\" height=\"762\" alt=\"image\" src=\"https://github.com/user-attachments/assets/5e878d51-6c0f-441b-a35b-94e93d9c3340\" />\n\n\n<em><small>How modules work together</small></em>\n</div>\n\n<small>\nThere is a thin layer that builds the high-level abstraction (green box/jellyfin) consuming only the bindings that already contain dataclasses and api built using the OpenAPI Generator (blue box/generated), which in turn also allows use only if the user requests jellyfin_apiclient_python (purple box/legacy) to allow for refactoring and incremental development. Both legacy and generated have classes that allow low-level access, being practically just an envelope method for requests that must communicate with the actual jellyfin API (lilac box).\n</small>\n\nThis project is mainly inspired by good python library like these:\n- [tmdbsimple](https://github.com/celiao/tmdbsimple)\n- [plexapi](https://github.com/pushingkarmaorg/python-plexapi)\n- [tensorflow](https://github.com/tensorflow/tensorflow)\n\n## Install\n\n```sh\npip install jellyfin-sdk\n```\n\nor\n\n```sh\nuv add jellyfin-sdk\n```\n\n## Usage\n\n### Drop-in replacement for [jellyfin-apiclient-python](https://github.com/jellyfin/jellyfin-apiclient-python)\n\nThis library includes the old legacy client (which is almost unmaintained) to help with migration:\n\n```sh\npip uninstall jellyfin-apiclient-python\npip install jellyfin-sdk[legacy]\n```\n\n```python\n# change from\nfrom jellyfin_apiclient_python import JellyfinClient\nfrom jellyfin_apiclient_python.api import API\n\n# to this\nfrom jellyfin.legacy import JellyfinClient\nfrom jellyfin.legacy.api import API\n```\n\n### Login\n\n```python\nimport os\n\nos.environ[\"URL\"] = \"https://jellyfin.example.com\"\nos.environ[\"API_KEY\"] = \"MY_TOKEN\"\n```\n\n#### Using SDK\n\n```python\nimport jellyfin\n\napi = jellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\")\n)\n\nprint(\n api.system.info.version,\n api.system.info.server_name\n)\n```\n\n#### Direct with Generated Bindings\n\n```python\nfrom jellyfin.generated.api_10_10 import Configuration, ApiClient, SystemApi\n\nconfiguration = Configuration(\n host = os.getenv(\"URL\"),\n api_key={'CustomAuthentication': f'Token=\"{os.getenv(\"API_KEY\")}\"'}, \n api_key_prefix={'CustomAuthentication': 'MediaBrowser'}\n)\n\nclient = ApiClient(configuration)\nsystem = SystemApi(client)\n\nprint(\n system.get_system_info().version, \n system.get_system_info().server_name\n)\n```\n\n#### Legacy\n\n```python\nfrom jellyfin.legacy import JellyfinClient\nclient = JellyfinClient()\nclient.authenticate(\n {\"Servers\": [{\n \"AccessToken\": os.getenv(\"API_KEY\"), \n \"address\": os.getenv(\"URL\")\n }]}, \n discover=False\n)\nsystem_info = client.jellyfin.get_system_info()\n\nprint(\n system_info.get(\"Version\"), \n system_info.get(\"ServerName\")\n)\n```\n\n### Jellyfin Server API Version\n\nThis is important because when a new API version is released, breaking changes can affect the entire project. \nTo avoid this, you can set an API target version, similar to how it's done in Android development:\n\n```python\nfrom jellyfin.api import Version\nimport jellyfin\n\n# By default will use the lastest stable\njellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\")\n)\n\n# now let's test the new API (version 10.11) for breaking changes in same endpoint\njellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\"), \n Version.V10_11\n)\n\n# but str is allow to: 10.10, 10.11 and etc\njellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\"), \n '10.11'\n)\n\n# let's test a wrong version\njellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\"), \n '99'\n)\n\n> ValueError: Unsupported version: 99. Supported versions are: ['10.10', '10.11']\n```\n\n### List all libraries of an user\n\nWhen using `API_KEY` some endpoints need the user_id (don't me ask why!), almost all issues with jellyfin is around this.\nTo help to identify this not-so-much-edge-cases we raise a exception to help with that:\n\n```python\n\napi = jellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\")\n)\n\napi.users.libraries\n\n> ValueError: User ID is not set. Use the 'of(user_id)' method to set the user context.\n\n\napi.users.of('f674245b84ea4d3ea9cf11').libraries\n\n# works also with the user name\napi.users.of('niels').libraries\n\n# when using 'of' the attribute of dataclasses\n# user and user_view can be accessed directly\napi.users.of('niels').id\n```\n\n### List all items\n\nItem can be any object in the server, in fact that's how works, one huge table recursive linked.\n\n```python\napi = jellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\")\n)\n\napi.items.all\n\n# Same command but without shorthand\nsearch = api.items.search\nsearch\n\n<ItemSearch (no filters set)>\n\nsearch.paginate(1000)\n\n<ItemSearch filters={\n start_index=0,\n limit=1000,\n enable_total_record_count=True\n}>\n\nsearch.recursive()\n\n<ItemSearch filters={\n start_index=0,\n limit=1000,\n enable_total_record_count=True,\n recursive=True\n}>\n```\n\nAll filter options is available [here](https://webysther.github.io/jellyfin-sdk-python.github.io/api_10_10/docs/ItemsApi/#get_items).\n\nThe pagination uses a Iterator:\n\n```python\napi = jellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\")\n)\n\nfor item in api.items.search.paginate(100).recursive().all:\n print(item.name)\n```\n\n### Let's get the User ID by name or ID\n\n```python\napi = jellyfin.api(\n os.getenv(\"URL\"), \n os.getenv(\"API_KEY\")\n)\n\nuuid = api.user.by_name('joshua').id\n\napi.user.by_id(uuid).name\n```\n\n### Documentation\n\n- [SDK Reference](https://webysther.github.io/jellyfin-sdk-python.github.io/sdk/)\n- [Jellyfin API 10.10](https://webysther.github.io/jellyfin-sdk-python.github.io/api_10_10/) (Stable)\n- [Jellyfin API 10.11](https://webysther.github.io/jellyfin-sdk-python.github.io/api_10_11/) (Release Candidate)\n\n### Supported Jellyfin Versions\n\n| SDK Version | Jellyfin API Target |\n|:-:|:-:|\n| 0.1.x | 10.10.x-10.11.x |\n",
"bugtrack_url": null,
"license": "MPL-2.0",
"summary": "A Possible Official Python SDK for Jellyfin.",
"version": "0.1.4",
"project_urls": {
"Documentation": "https://webysther.github.io/jellyfin-sdk-python.github.io",
"GitHub": "https://github.com/webysther/jellyfin-sdk-python"
},
"split_keywords": [
"api",
" sdk",
" jellyfin",
" dataclass",
" openapi",
" wrapper-api"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "41141c013f0c6113852cd7330134fc66cfee9f6c7dd7799add6d64ba8466ea54",
"md5": "d566cb37b9be890d3ad01aa27f22fb54",
"sha256": "860c53bf6a3b0422f49cc2d43f426dc0f4d8e3c701c69847fc62ef23c7228c44"
},
"downloads": -1,
"filename": "jellyfin_sdk-0.1.4-py3-none-any.whl",
"has_sig": false,
"md5_digest": "d566cb37b9be890d3ad01aa27f22fb54",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 1723134,
"upload_time": "2025-09-04T03:40:32",
"upload_time_iso_8601": "2025-09-04T03:40:32.451355Z",
"url": "https://files.pythonhosted.org/packages/41/14/1c013f0c6113852cd7330134fc66cfee9f6c7dd7799add6d64ba8466ea54/jellyfin_sdk-0.1.4-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "439106b75f3870690d7aca0b7a58a67ad87b7ac84db48669bf82a06c83c4ac2e",
"md5": "bd46795dd8405c2bf79a6403d795bc02",
"sha256": "1a50c2c6ee2990eb57e899f585255217add05390375a8289f7b6e294d9f028fa"
},
"downloads": -1,
"filename": "jellyfin_sdk-0.1.4.tar.gz",
"has_sig": false,
"md5_digest": "bd46795dd8405c2bf79a6403d795bc02",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 785696,
"upload_time": "2025-09-04T03:40:33",
"upload_time_iso_8601": "2025-09-04T03:40:33.934620Z",
"url": "https://files.pythonhosted.org/packages/43/91/06b75f3870690d7aca0b7a58a67ad87b7ac84db48669bf82a06c83c4ac2e/jellyfin_sdk-0.1.4.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-04 03:40:33",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "webysther",
"github_project": "jellyfin-sdk-python",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "jellyfin-sdk"
}