mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
feat: update Python plugin documentation and usage instructions for host function wrappers
Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
cbd74a3a96
commit
9fbcf6ceb3
@ -248,16 +248,36 @@ def cache_get_string(key: str) -> CacheGetStringResult:
|
||||
...
|
||||
```
|
||||
|
||||
#### Example Python Plugin Usage
|
||||
#### Python Plugin Usage
|
||||
|
||||
> **Important:** Due to a limitation in extism-py, you cannot directly import the generated Python wrappers.
|
||||
> The `@extism.import_fn` decorators are only detected when defined in the plugin's main `__init__.py` file.
|
||||
> Generated Python files serve as **reference/template code** - copy the needed functions into your plugin.
|
||||
|
||||
Example of copying the generated wrapper into your plugin's `__init__.py`:
|
||||
|
||||
```python
|
||||
from nd_host_subsonicapi import subsonicapi_call, HostFunctionError
|
||||
import extism
|
||||
import json
|
||||
|
||||
try:
|
||||
response = subsonicapi_call("getAlbumList2?type=random&size=10")
|
||||
data = json.loads(response)
|
||||
except HostFunctionError as e:
|
||||
print(f"API error: {e}")
|
||||
# Copy host function declarations from generated files into your __init__.py
|
||||
@extism.import_fn("extism:host/user", "subsonicapi_call")
|
||||
def _host_subsonicapi_call(input_ptr: extism.JsonI64) -> extism.JsonI64:
|
||||
pass
|
||||
|
||||
def subsonicapi_call(endpoint: str) -> str:
|
||||
"""Call the SubsonicAPI with the given endpoint."""
|
||||
result = _host_subsonicapi_call(endpoint)
|
||||
return result
|
||||
|
||||
# Now use it in your plugin
|
||||
@extism.plugin_fn
|
||||
def my_plugin_function():
|
||||
try:
|
||||
response = subsonicapi_call("getAlbumList2?type=random&size=10")
|
||||
data = json.loads(response)
|
||||
except Exception as e:
|
||||
extism.log(extism.LogLevel.Error, f"API error: {e}")
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the {{.Service.Name}} host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_{{.Service.Name | lower}} import {{range $i, $m := .Service.Methods}}{{if $i}}, {{end}}{{pythonFunc $m}}{{end}}
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Codec host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_codec import codec_encode
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Counter host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_counter import counter_count
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Echo host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_echo import echo_echo
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the List host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_list import list_items
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Math host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_math import math_add
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Meta host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_meta import meta_get, meta_set
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Ping host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_ping import ping_ping
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Search host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_search import search_find
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Store host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_store import store_save
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Users host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_users import users_get
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -43,8 +43,10 @@ else
|
||||
endif
|
||||
|
||||
# Python plugin builds (generic rule for any folder with plugin/__init__.py)
|
||||
$(PYTHON_PLUGINS:%=%.wasm): %.wasm: %/plugin/__init__.py
|
||||
# Use secondary expansion to get all .py files in the plugin directory as dependencies
|
||||
.SECONDEXPANSION:
|
||||
$(PYTHON_PLUGINS:%=%.wasm): %.wasm: $$(wildcard %/plugin/*.py)
|
||||
ifndef EXTISM_PY
|
||||
$(error extism-py is not installed. Install from https://github.com/extism/python-pdk)
|
||||
endif
|
||||
cd $* && extism-py plugin/__init__.py -o ../$@
|
||||
cd $* && PYTHONPATH=plugin extism-py plugin/__init__.py -o ../$@
|
||||
|
||||
@ -5,8 +5,8 @@ WASM_FILE = nowplaying-py.wasm
|
||||
|
||||
build: $(WASM_FILE)
|
||||
|
||||
$(WASM_FILE): plugin/__init__.py plugin/nd_host_scheduler.py plugin/nd_host_subsonicapi.py
|
||||
PYTHONPATH=plugin extism-py plugin/__init__.py -o $(WASM_FILE)
|
||||
$(WASM_FILE): plugin/__init__.py
|
||||
extism-py plugin/__init__.py -o $(WASM_FILE)
|
||||
|
||||
clean:
|
||||
rm -f $(WASM_FILE)
|
||||
|
||||
@ -4,10 +4,10 @@ A Python example plugin that demonstrates the **Scheduler** and **SubsonicAPI**
|
||||
|
||||
## Features
|
||||
|
||||
- Uses `scheduler_schedule_recurring` host function to set up a recurring task
|
||||
- Uses `scheduler_schedulerecurring` host function to set up a recurring task
|
||||
- Uses `subsonicapi_call` host function to query the `getNowPlaying` API
|
||||
- Configurable cron expression and user via plugin config
|
||||
- Uses generated Python host function wrappers from `plugins/host/python/`
|
||||
- Demonstrates Python host function imports using `@extism.import_fn`
|
||||
|
||||
## Prerequisites
|
||||
|
||||
@ -29,7 +29,7 @@ make nowplaying-py.wasm
|
||||
Or directly:
|
||||
|
||||
```bash
|
||||
PYTHONPATH=plugin extism-py plugin/__init__.py -o nowplaying-py.wasm
|
||||
extism-py plugin/__init__.py -o nowplaying-py.wasm
|
||||
```
|
||||
|
||||
## Installation
|
||||
@ -86,27 +86,31 @@ Or when no one is playing:
|
||||
|
||||
2. **Callback (`nd_scheduler_callback`)**: When the scheduled task fires, calls the SubsonicAPI `getNowPlaying` endpoint and logs the results.
|
||||
|
||||
## Using Generated Host Function Wrappers
|
||||
## Host Function Usage (Python)
|
||||
|
||||
This plugin uses the generated Python host function wrappers from `plugins/host/python/`. These wrappers are generated by `hostgen` and provide type-safe, Pythonic interfaces to Navidrome host functions:
|
||||
This plugin demonstrates how to call Navidrome host functions from Python:
|
||||
|
||||
```python
|
||||
# Import generated host function wrappers
|
||||
from nd_host_scheduler import scheduler_schedule_recurring, HostFunctionError
|
||||
from nd_host_subsonicapi import subsonicapi_call
|
||||
import extism
|
||||
import json
|
||||
|
||||
# Use them directly - no manual JSON marshalling needed!
|
||||
schedule_id = scheduler_schedule_recurring(
|
||||
cron_expression="*/1 * * * *",
|
||||
payload="check",
|
||||
schedule_i_d="nowplaying-check"
|
||||
)
|
||||
# Import the host function
|
||||
@extism.import_fn("extism:host/user", "subsonicapi_call")
|
||||
def _subsonicapi_call(offset: int) -> int:
|
||||
"""Raw host function - returns memory offset."""
|
||||
...
|
||||
|
||||
response_json = subsonicapi_call(uri="getNowPlaying")
|
||||
```
|
||||
|
||||
The wrappers handle:
|
||||
- JSON marshalling/unmarshalling
|
||||
- Memory allocation and management
|
||||
- Error handling (raises `HostFunctionError` on failure)
|
||||
- Type hints for better IDE support
|
||||
# Wrapper for JSON marshalling
|
||||
def subsonicapi_call(uri: str) -> dict:
|
||||
request = {"uri": uri}
|
||||
request_bytes = json.dumps(request).encode('utf-8')
|
||||
request_mem = extism.memory.alloc(request_bytes)
|
||||
response_offset = _subsonicapi_call(request_mem.offset)
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
if response.get("error"):
|
||||
raise Exception(response["error"])
|
||||
|
||||
return json.loads(response.get("responseJSON", "{}"))
|
||||
```
|
||||
@ -17,28 +17,86 @@
|
||||
import extism
|
||||
import json
|
||||
|
||||
# Import generated host function wrappers
|
||||
from nd_host_scheduler import scheduler_schedule_recurring, HostFunctionError
|
||||
from nd_host_subsonicapi import subsonicapi_call as _subsonicapi_call_raw
|
||||
|
||||
# Schedule ID for our recurring task
|
||||
SCHEDULE_ID = "nowplaying-check"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Host Function Imports
|
||||
# =============================================================================
|
||||
# These are custom host functions provided by Navidrome.
|
||||
# We import them using the extism:host/user namespace.
|
||||
|
||||
|
||||
@extism.import_fn("extism:host/user", "scheduler_schedulerecurring")
|
||||
def _scheduler_schedulerecurring(offset: int) -> int:
|
||||
"""Raw host function - do not call directly."""
|
||||
...
|
||||
|
||||
|
||||
@extism.import_fn("extism:host/user", "subsonicapi_call")
|
||||
def _subsonicapi_call(offset: int) -> int:
|
||||
"""Raw host function - do not call directly."""
|
||||
...
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Host Function Wrappers
|
||||
# =============================================================================
|
||||
# These wrappers handle JSON marshalling/unmarshalling and memory management.
|
||||
# They were copied from plugins/host/python due to extism-py limitations.
|
||||
|
||||
|
||||
def scheduler_schedule_recurring(cron_expression: str, payload: str, schedule_id: str) -> str:
|
||||
"""Schedule a recurring task using a cron expression.
|
||||
|
||||
Args:
|
||||
cron_expression: Cron format (e.g., "*/1 * * * *" for every minute)
|
||||
payload: Data to pass to the callback
|
||||
schedule_id: Unique identifier for the schedule
|
||||
|
||||
Returns:
|
||||
The schedule ID (same as input or auto-generated)
|
||||
"""
|
||||
request = {
|
||||
"cronExpression": cron_expression,
|
||||
"payload": payload,
|
||||
"scheduleID": schedule_id
|
||||
}
|
||||
request_bytes = json.dumps(request).encode('utf-8')
|
||||
request_mem = extism.memory.alloc(request_bytes)
|
||||
response_offset = _scheduler_schedulerecurring(request_mem.offset)
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
if response.get("error"):
|
||||
raise Exception(response["error"])
|
||||
|
||||
return response.get("newScheduleID", schedule_id)
|
||||
|
||||
|
||||
def subsonicapi_call(uri: str) -> dict:
|
||||
"""Call a Subsonic API endpoint and parse the response.
|
||||
|
||||
This is a convenience wrapper around the generated subsonicapi_call
|
||||
that parses the JSON response string into a dict.
|
||||
|
||||
"""Call a Subsonic API endpoint.
|
||||
|
||||
Args:
|
||||
uri: API path (e.g., "getNowPlaying")
|
||||
|
||||
|
||||
Returns:
|
||||
Parsed JSON response from the API
|
||||
"""
|
||||
response_json = _subsonicapi_call_raw(uri)
|
||||
return json.loads(response_json) if response_json else {}
|
||||
request = {"uri": uri}
|
||||
request_bytes = json.dumps(request).encode('utf-8')
|
||||
request_mem = extism.memory.alloc(request_bytes)
|
||||
response_offset = _subsonicapi_call(request_mem.offset)
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
if response.get("error"):
|
||||
raise Exception(response["error"])
|
||||
|
||||
# Parse the nested JSON response
|
||||
response_json = response.get("responseJSON", "{}")
|
||||
return json.loads(response_json)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
@ -1,142 +0,0 @@
|
||||
# Code generated by hostgen. DO NOT EDIT.
|
||||
#
|
||||
# This file contains client wrappers for the Scheduler host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_scheduler import scheduler_schedule_one_time, scheduler_schedule_recurring, scheduler_cancel_schedule
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import extism
|
||||
import json
|
||||
|
||||
|
||||
class HostFunctionError(Exception):
|
||||
"""Raised when a host function returns an error."""
|
||||
pass
|
||||
|
||||
|
||||
@extism.import_fn("extism:host/user", "scheduler_scheduleonetime")
|
||||
def _scheduler_scheduleonetime(offset: int) -> int:
|
||||
"""Raw host function - do not call directly."""
|
||||
...
|
||||
|
||||
|
||||
@extism.import_fn("extism:host/user", "scheduler_schedulerecurring")
|
||||
def _scheduler_schedulerecurring(offset: int) -> int:
|
||||
"""Raw host function - do not call directly."""
|
||||
...
|
||||
|
||||
|
||||
@extism.import_fn("extism:host/user", "scheduler_cancelschedule")
|
||||
def _scheduler_cancelschedule(offset: int) -> int:
|
||||
"""Raw host function - do not call directly."""
|
||||
...
|
||||
|
||||
|
||||
def scheduler_schedule_one_time(delay_seconds: int, payload: str, schedule_i_d: str) -> str:
|
||||
"""ScheduleOneTime schedules a one-time event to be triggered after the specified delay.
|
||||
Plugins that use this function must also implement the SchedulerCallback capability
|
||||
|
||||
Parameters:
|
||||
- delaySeconds: Number of seconds to wait before triggering the event
|
||||
- payload: Data to be passed to the scheduled event handler
|
||||
- scheduleID: Optional unique identifier for the scheduled job. If empty, one will be generated
|
||||
|
||||
Returns the schedule ID that can be used to cancel the job, or an error if scheduling fails.
|
||||
|
||||
Args:
|
||||
delay_seconds: int parameter.
|
||||
payload: str parameter.
|
||||
schedule_i_d: str parameter.
|
||||
|
||||
Returns:
|
||||
str: The result value.
|
||||
|
||||
Raises:
|
||||
HostFunctionError: If the host function returns an error.
|
||||
"""
|
||||
request = {
|
||||
"delaySeconds": delay_seconds,
|
||||
"payload": payload,
|
||||
"scheduleID": schedule_i_d,
|
||||
}
|
||||
request_bytes = json.dumps(request).encode("utf-8")
|
||||
request_mem = extism.memory.alloc(request_bytes)
|
||||
response_offset = _scheduler_scheduleonetime(request_mem.offset)
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
if response.get("error"):
|
||||
raise HostFunctionError(response["error"])
|
||||
|
||||
return response.get("newScheduleID", "")
|
||||
|
||||
|
||||
def scheduler_schedule_recurring(cron_expression: str, payload: str, schedule_i_d: str) -> str:
|
||||
"""ScheduleRecurring schedules a recurring event using a cron expression.
|
||||
Plugins that use this function must also implement the SchedulerCallback capability
|
||||
|
||||
Parameters:
|
||||
- cronExpression: Standard cron format expression (e.g., "0 0 * * *" for daily at midnight)
|
||||
- payload: Data to be passed to each scheduled event handler invocation
|
||||
- scheduleID: Optional unique identifier for the scheduled job. If empty, one will be generated
|
||||
|
||||
Returns the schedule ID that can be used to cancel the job, or an error if scheduling fails.
|
||||
|
||||
Args:
|
||||
cron_expression: str parameter.
|
||||
payload: str parameter.
|
||||
schedule_i_d: str parameter.
|
||||
|
||||
Returns:
|
||||
str: The result value.
|
||||
|
||||
Raises:
|
||||
HostFunctionError: If the host function returns an error.
|
||||
"""
|
||||
request = {
|
||||
"cronExpression": cron_expression,
|
||||
"payload": payload,
|
||||
"scheduleID": schedule_i_d,
|
||||
}
|
||||
request_bytes = json.dumps(request).encode("utf-8")
|
||||
request_mem = extism.memory.alloc(request_bytes)
|
||||
response_offset = _scheduler_schedulerecurring(request_mem.offset)
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
if response.get("error"):
|
||||
raise HostFunctionError(response["error"])
|
||||
|
||||
return response.get("newScheduleID", "")
|
||||
|
||||
|
||||
def scheduler_cancel_schedule(schedule_i_d: str) -> None:
|
||||
"""CancelSchedule cancels a scheduled job identified by its schedule ID.
|
||||
|
||||
This works for both one-time and recurring schedules. Once cancelled, the job will not trigger
|
||||
any future events.
|
||||
|
||||
Returns an error if the schedule ID is not found or if cancellation fails.
|
||||
|
||||
Args:
|
||||
schedule_i_d: str parameter.
|
||||
|
||||
Raises:
|
||||
HostFunctionError: If the host function returns an error.
|
||||
"""
|
||||
request = {
|
||||
"scheduleID": schedule_i_d,
|
||||
}
|
||||
request_bytes = json.dumps(request).encode("utf-8")
|
||||
request_mem = extism.memory.alloc(request_bytes)
|
||||
response_offset = _scheduler_cancelschedule(request_mem.offset)
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
if response.get("error"):
|
||||
raise HostFunctionError(response["error"])
|
||||
|
||||
@ -1,54 +0,0 @@
|
||||
# Code generated by hostgen. DO NOT EDIT.
|
||||
#
|
||||
# This file contains client wrappers for the SubsonicAPI host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_subsonicapi import subsonicapi_call
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
import extism
|
||||
import json
|
||||
|
||||
|
||||
class HostFunctionError(Exception):
|
||||
"""Raised when a host function returns an error."""
|
||||
pass
|
||||
|
||||
|
||||
@extism.import_fn("extism:host/user", "subsonicapi_call")
|
||||
def _subsonicapi_call(offset: int) -> int:
|
||||
"""Raw host function - do not call directly."""
|
||||
...
|
||||
|
||||
|
||||
def subsonicapi_call(uri: str) -> str:
|
||||
"""Call executes a Subsonic API request and returns the JSON response.
|
||||
|
||||
The uri parameter should be the Subsonic API path without the server prefix,
|
||||
e.g., "getAlbumList2?type=random&size=10". The response is returned as raw JSON.
|
||||
|
||||
Args:
|
||||
uri: str parameter.
|
||||
|
||||
Returns:
|
||||
str: The result value.
|
||||
|
||||
Raises:
|
||||
HostFunctionError: If the host function returns an error.
|
||||
"""
|
||||
request = {
|
||||
"uri": uri,
|
||||
}
|
||||
request_bytes = json.dumps(request).encode("utf-8")
|
||||
request_mem = extism.memory.alloc(request_bytes)
|
||||
response_offset = _subsonicapi_call(request_mem.offset)
|
||||
response_mem = extism.memory.find(response_offset)
|
||||
response = json.loads(extism.memory.string(response_mem))
|
||||
|
||||
if response.get("error"):
|
||||
raise HostFunctionError(response["error"])
|
||||
|
||||
return response.get("responseJSON", "")
|
||||
@ -37,5 +37,5 @@
|
||||
// Generated files follow the pattern <servicename>_gen.go and include a header comment
|
||||
// indicating they should not be edited manually.
|
||||
//
|
||||
//go:generate go run ../cmd/hostgen -input=. -output=.
|
||||
//go:generate go run ../cmd/hostgen -input=. -output=. -python -go
|
||||
package host
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Artwork host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_artwork import artwork_get_artist_url, artwork_get_album_url, artwork_get_track_url, artwork_get_playlist_url
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Cache host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_cache import cache_set_string, cache_get_string, cache_set_int, cache_get_int, cache_set_float, cache_get_float, cache_set_bytes, cache_get_bytes, cache_has, cache_remove
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the Scheduler host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_scheduler import scheduler_schedule_one_time, scheduler_schedule_recurring, scheduler_cancel_schedule
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the SubsonicAPI host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_subsonicapi import subsonicapi_call
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
@ -3,8 +3,9 @@
|
||||
# This file contains client wrappers for the WebSocket host service.
|
||||
# It is intended for use in Navidrome plugins built with extism-py.
|
||||
#
|
||||
# Usage:
|
||||
# from nd_host_websocket import websocket_connect, websocket_send_text, websocket_send_binary, websocket_close_connection
|
||||
# IMPORTANT: Due to a limitation in extism-py, you cannot import this file directly.
|
||||
# The @extism.import_fn decorators are only detected when defined in the plugin's
|
||||
# main __init__.py file. Copy the needed functions from this file into your plugin.
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import Any
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user