jellyfin-sdk


Namejellyfin-sdk JSON
Version 0.1.4 PyPI version JSON
download
home_pageNone
SummaryA Possible Official Python SDK for Jellyfin.
upload_time2025-09-04 03:40:33
maintainerNone
docs_urlNone
authorWebysther Sperandio
requires_python>=3.10
licenseMPL-2.0
keywords api sdk jellyfin dataclass openapi wrapper-api
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            <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"
}
        
Elapsed time: 0.72717s