pluginengine01 / wit /plugin.wit
krystv's picture
Upload 107 files
3374e90 verified
package bex:plugin@1.0.0;
interface common {
record request-context {
request-id: string,
locale: option<string>,
region: option<string>,
safe-mode: bool,
hints: list<string>,
}
record attr { key: string, value: string }
enum image-layout { portrait, landscape, square, banner, circular, unknown }
record image {
url: string,
layout: image-layout,
width: option<u32>,
height: option<u32>,
blurhash: option<string>,
}
record image-set {
low: option<image>,
medium: option<image>,
high: option<image>,
backdrop: option<image>,
logo: option<image>,
}
record linked-id { source: string, id: string }
enum media-kind { movie, series, anime, short, special, documentary, music, podcast, book, live, unknown }
enum status { unknown, upcoming, ongoing, completed, cancelled, paused }
enum card-layout { carousel, grid, vertical-list, banner, compact }
record page-cursor { token: option<string>, limit: option<u32> }
record media-card {
id: string,
title: string,
kind: option<media-kind>,
images: option<image-set>,
original-title: option<string>,
tagline: option<string>,
year: option<string>,
score: option<u32>,
genres: list<string>,
status: option<status>,
content-rating: option<string>,
url: option<string>,
ids: list<linked-id>,
extra: list<attr>,
}
record category-link { id: string, title: string, subtitle: option<string>, image: option<image> }
record home-section {
id: string,
title: string,
subtitle: option<string>,
items: list<media-card>,
next-page: option<string>,
layout: card-layout,
show-rank: bool,
categories: list<category-link>,
extra: list<attr>,
}
record paged-result {
items: list<media-card>,
categories: list<category-link>,
next-page: option<string>,
}
record search-filters { kind: option<media-kind>, page: page-cursor, fast-match: bool }
record episode {
id: string,
title: string,
number: option<f64>,
season: option<f64>,
images: option<image-set>,
description: option<string>,
released: option<string>,
score: option<u32>,
url: option<string>,
tags: list<string>,
extra: list<attr>,
}
record season { id: string, title: string, number: option<f64>, year: option<u32>, episodes: list<episode> }
record person { id: string, name: string, image: option<image-set>, role: option<string>, url: option<string> }
record media-info {
id: string,
title: string,
kind: media-kind,
images: option<image-set>,
original-title: option<string>,
description: option<string>,
score: option<u32>,
scored-by: option<u64>,
year: option<string>,
release-date: option<string>,
genres: list<string>,
tags: list<string>,
status: option<status>,
content-rating: option<string>,
seasons: list<season>,
cast: list<person>,
crew: list<person>,
runtime-minutes: option<u32>,
trailer-url: option<string>,
ids: list<linked-id>,
studio: option<string>,
country: option<string>,
language: option<string>,
url: option<string>,
extra: list<attr>,
}
record video-resolution { width: u32, height: u32, hdr: bool, label: string }
enum stream-format { hls, dash, progressive, unknown }
record video-track {
resolution: video-resolution,
url: string,
mime-type: option<string>,
bitrate: option<u64>,
codecs: option<string>,
}
record subtitle-track { label: string, url: string, language: option<string>, format: option<string> }
record server { id: string, label: string, url: string, priority: u8, extra: list<attr> }
record stream-source {
id: string,
label: string,
format: stream-format,
manifest-url: option<string>,
videos: list<video-track>,
subtitles: list<subtitle-track>,
headers: list<attr>,
extra: list<attr>,
}
record subtitle-query {
title: option<string>,
year: option<u32>,
season: option<u32>,
episode: option<u32>,
language: option<string>,
fps: option<f32>,
file-hash: option<string>,
file-size: option<u64>,
identifiers: list<linked-id>,
}
record subtitle-entry {
id: string,
title: string,
language: string,
format: string,
url: option<string>,
release: option<string>,
fps: option<f32>,
downloads: option<u64>,
score: option<u32>,
hearing-impaired: bool,
machine-translated: bool,
file-hash: option<string>,
extra: list<attr>,
}
record subtitle-file { format: string, content: list<u8> }
record article {
id: string,
title: string,
summary: option<string>,
url: string,
published: option<string>,
author: option<string>,
thumbnail: option<image-set>,
tags: list<string>,
extra: list<attr>,
}
record article-section { id: string, title: string, items: list<article>, next-page: option<string> }
variant plugin-error {
network(string),
parse(string),
not-found,
unauthorized,
forbidden,
rate-limited(option<u32>),
timeout,
cancelled,
unsupported,
invalid-input(string),
internal(string),
}
}
interface http {
use common.{attr, plugin-error};
enum method { get, post, put, delete, head, patch, options }
enum cache-mode { normal, no-store, only-cache, force-refresh }
record request {
method: method,
url: string,
headers: list<attr>,
body: option<list<u8>>,
timeout-ms: option<u32>,
follow-redirects: bool,
cache-mode: cache-mode,
max-bytes: option<u64>,
}
record response {
status: u16,
headers: list<attr>,
body: list<u8>,
cached: bool,
final-url: string,
}
/// Send an HTTP request and return the response.
/// This is a simple function-based API (no resource types) for simplicity.
send-request: func(req: request) -> result<response, plugin-error>;
}
interface kv {
use common.{attr};
set: func(key: string, value: list<u8>, ttl-seconds: option<u32>) -> bool;
get: func(key: string) -> option<list<u8>>;
remove: func(key: string) -> bool;
keys: func(prefix: string) -> list<string>;
}
interface secrets {
get: func(key: string) -> option<string>;
}
interface log {
use common.{attr};
enum level { trace, debug, info, warn, error }
write: func(level: level, msg: string, fields: list<attr>);
}
interface clock {
now-ms: func() -> u64;
monotonic: func() -> u64;
}
interface rng {
bytes: func(len: u32) -> list<u8>;
}
interface js {
use common.{plugin-error};
/// Options for JS evaluation with fine-grained control.
record js-opts {
/// Name for the script (appears in JS error stack traces).
filename: option<string>,
/// Timeout in milliseconds. 0 = use pool default (10s).
timeout-ms: u32,
}
/// Evaluate JavaScript. `input` is injected as the global variable `input`.
/// The last expression value is returned as a JSON string.
/// Use `JSON.parse(input)` in JS if structured data is needed.
eval-js: func(code: string, input: string) -> result<string, plugin-error>;
/// Evaluate JavaScript with options (timeout, filename for error traces).
eval-js-opts: func(
code: string,
input: string,
opts: js-opts,
) -> result<string, plugin-error>;
/// Register + call a named JS function. Faster than eval-js for repeated calls.
///
/// `fn-name` : Function name as defined in `fn-source`.
/// `fn-source` : JavaScript defining exactly one function named `fn-name`.
/// Parsed and registered on first call; reused on subsequent calls.
/// Auto-re-registers if `fn-source` content changes.
/// `args-json` : Passed to the function as a single string argument.
/// In JS: `function myFn(args) { const d = JSON.parse(args); ... }`
call-js-fn: func(
fn-name: string,
fn-source: string,
args-json: string,
) -> result<string, plugin-error>;
/// Remove a named JS function from this plugin's context.
/// Use when a cipher function is rotated (player update).
/// Returns 0 on success.
clear-js-fn: func(fn-name: string) -> result<u8, plugin-error>;
}
world plugin {
import http;
import kv;
import secrets;
import log;
import clock;
import rng;
import js;
export api: interface {
use common.{
request-context, page-cursor, paged-result, search-filters,
home-section, media-info, server, stream-source,
subtitle-query, subtitle-entry, subtitle-file,
article-section, article, plugin-error
};
get-home: func(ctx: request-context) -> result<list<home-section>, plugin-error>;
get-category: func(ctx: request-context, id: string, page: page-cursor) -> result<paged-result, plugin-error>;
search: func(ctx: request-context, query: string, filters: search-filters) -> result<paged-result, plugin-error>;
get-info: func(ctx: request-context, id: string) -> result<media-info, plugin-error>;
get-servers: func(ctx: request-context, id: string) -> result<list<server>, plugin-error>;
resolve-stream: func(ctx: request-context, server: server) -> result<stream-source, plugin-error>;
search-subtitles: func(ctx: request-context, query: subtitle-query) -> result<list<subtitle-entry>, plugin-error>;
download-subtitle: func(ctx: request-context, id: string) -> result<subtitle-file, plugin-error>;
get-articles: func(ctx: request-context) -> result<list<article-section>, plugin-error>;
search-articles: func(ctx: request-context, query: string) -> result<list<article>, plugin-error>;
}
}