diff --git a/cli/bootstrap.js b/cli/bootstrap.js index 058b3d1..24adbcc 100755 --- a/cli/bootstrap.js +++ b/cli/bootstrap.js @@ -49,7 +49,8 @@ async function createAddon() { {name: 'stream'}, {name: 'meta'}, {name: 'subtitles'}, - {name: 'watchStatus'}, + {name: 'player'}, + {name: 'library'}, ] }, { @@ -200,11 +201,19 @@ builder.defineSubtitlesHandler(({type, id, extra}) => { }) ` -const watchStatusTmpl = () => ` -builder.defineWatchStatusHandler(({type, id, extra}) => { - console.log("request for watchStatus: "+type+" "+id+" "+extra) - // Docs: https://github.com/Stremio/stremio-addon-sdk/blob/master/docs/api/requests/defineWatchStatusHandler.md - return Promise.resolve({ watchStatus: 'success' }) +const playerTmpl = () => ` +builder.definePlayerHandler(({type, id, extra}) => { + console.log("request for player: "+type+" "+id+" "+extra) + // Docs: https://github.com/Stremio/stremio-addon-sdk/blob/master/docs/api/requests/definePlayerHandler.md + return Promise.resolve({ success: true }) +}) +` + +const libraryTmpl = () => ` +builder.defineLibraryHandler(({type, id, extra}) => { + console.log("request for library: "+type+" "+id+" "+extra) + // Docs: https://github.com/Stremio/stremio-addon-sdk/blob/master/docs/api/requests/defineLibraryHandler.md + return Promise.resolve({ success: true }) }) ` @@ -218,7 +227,8 @@ function genAddonJS(manifest, resources, types) { .concat(resources.includes('meta') ? [metaTmpl()] : []) .concat(resources.includes('stream') ? [types.includes('movie') ? streamsMovieTmpl() : streamsTmpl()] : []) .concat(resources.includes('subtitles') ? [subtitlesTmpl()] : []) - .concat(resources.includes('watchStatus') ? [watchStatusTmpl()] : []) + .concat(resources.includes('player') ? [playerTmpl()] : []) + .concat(resources.includes('library') ? [libraryTmpl()] : []) .concat(footerTmpl()) .join('') } diff --git a/docs/api/README.md b/docs/api/README.md index bd58638..4cb92f1 100644 --- a/docs/api/README.md +++ b/docs/api/README.md @@ -11,7 +11,8 @@ In order for Stremio to display addon data, the addon must first supply the reso | **streams** | [defineStreamHandler](./requests/defineStreamHandler.md) | [stream](./responses/stream.md) | Tells Stremio how to obtain the media content. It may be torrent info hash, HTTP URL, etc | | **subtitles** | [defineSubtitlesHandler](./requests/defineSubtitlesHandler.md) | [subtitles](./responses/subtitles.md) | Subtitles resource for the chosen media. | | **addon_catalog** | [defineResourceHandler](./requests/defineResourceHandler.md) | [addon_catalog](./responses/addon_catalog.md) | A catalog (list) of other addon manifests. | -| **watchStatus** | [defineWatchStatusHandler](./requests/defineWatchStatusHandler.md) | 'success' or 'error' | | +| **player** | [definePlayerHandler](./requests/definePlayerHandler.md) | [event_response](./responses/event_response.md) | | +| **library** | [defineLibraryHandler](./requests/defineLibraryHandler.md) | [event_response](./responses/event_response.md) | | The structure of those resources in Stremio is as follows: @@ -21,7 +22,6 @@ The structure of those resources in Stremio is as follows: +-- Videos (part of Meta Item) +---+-- Streams +---+---+-- Subtitles - +---+---+-- watchStatus ``` When the user opens the Discover/Board section, catalogs from all installed addons are loaded. Catalog responses include [meta preview objects](./responses/meta.md#meta-preview-object), which are just stripped down versions of the full meta object. @@ -37,6 +37,6 @@ We determine whether an addon is relevant by comparing the request against it's For catalogs, we usually request all catalogs from all addons, that are compatible with the `extra` properties that we're looking for. For example, to load the Board, we'd load all catalogs that have no `extra` properties that are required. But, if we're loading Search, we'd load all catalogs that have `search` as a supported property in their `extra` definition. -For other requests (meta, stream, subtitles, watchStatus), we apply the `types` and the optional `idPrefixes` filters (which can also be defined per-resource). For example, for `/meta/movie/tt1254207`, we'd try to load meta from all addons that have `"movie"` in `manifest.types` (or have `{ name: "meta", types: ["movie'] }` in `manifest.resources`). If `manifest.idPrefixes` is defined, `["tt"]` will match this request, but something different (e.g. `["yt_id:"]`) won't. This helps you ensure your addon does not get irrelevant requests. +For other requests (meta, stream, subtitles, player, library), we apply the `types` and the optional `idPrefixes` filters (which can also be defined per-resource). For example, for `/meta/movie/tt1254207`, we'd try to load meta from all addons that have `"movie"` in `manifest.types` (or have `{ name: "meta", types: ["movie'] }` in `manifest.resources`). If `manifest.idPrefixes` is defined, `["tt"]` will match this request, but something different (e.g. `["yt_id:"]`) won't. This helps you ensure your addon does not get irrelevant requests. For the full spec, see [manifest - filtering properties](./responses/manifest.md#filtering-properties). diff --git a/docs/api/requests/defineLibraryHandler.md b/docs/api/requests/defineLibraryHandler.md index a311c01..ce67c1e 100644 --- a/docs/api/requests/defineLibraryHandler.md +++ b/docs/api/requests/defineLibraryHandler.md @@ -1,6 +1,6 @@ ## defineLibraryHandler -This method handles library requests. +This method handles library events. ### Arguments: @@ -11,9 +11,9 @@ This method handles library requests. ## Request Parameters -``type`` - type of the item that we're requesting streams for; e.g. `movie`, `series`, `channel`, `tv` (see [Content Types](../responses/content.types.md)) +``type`` - type of the item that we're emitting player events for; e.g. `movie`, `series`, `channel`, `tv` (see [Content Types](../responses/content.types.md)) -``id`` - a **Meta ID** as described in the [Meta Object](../responses/meta.md#meta-object) +``id`` - a Meta ID as described in the [Meta Object](../responses/meta.md#meta-object) ``extra`` - object that holds additional properties; defined below @@ -22,11 +22,14 @@ This method handles library requests. ## Extra Parameters -``action`` - set in the `extra` object; a string defining the user action, can be either: `add`, `remove`. +``action`` - set in the `extra` object; a string defining the user action, can be either: `libraryAdd`, `libraryRemove`, `watched`, `unwatched`. -``duration`` - set in the `extra` object; int specifying the full duration of the video in milliseconds. +``videoId`` - a Video ID as described in the [Video Object](../responses/meta.md#video-object) + +**The Video ID is the same as the Meta ID for movies**. + +For IMDB series (provided by Cinemeta), the video ID is formed by joining the Meta ID, season and episode with a colon (e.g. `"tt0898266:9:17"`). -``currentTime`` - set in the `extra` object; int in milliseconds specifying the progress from the start of the video when the user took the action. ## Basic Example @@ -34,11 +37,11 @@ This method handles library requests. ```javascript builder.defineLibraryHandler(function(args) { if (args.type === 'movie' && args.id === 'tt1254207') { - // Library event has been successfully - return Promise.resolve({ handled: true }) + // handle the library event + return Promise.resolve({ success: true }) } else { // otherwise return false - return Promise.resolve({ handled: false }) + return Promise.resolve({ success: false }) } }) ``` diff --git a/docs/api/requests/definePlayerHandler.md b/docs/api/requests/definePlayerHandler.md index 2616999..2b9d539 100644 --- a/docs/api/requests/definePlayerHandler.md +++ b/docs/api/requests/definePlayerHandler.md @@ -1,6 +1,6 @@ ## definePlayerHandler -This method handles player requests. +This method handles player events. ### Arguments: @@ -11,13 +11,13 @@ This method handles player requests. ## Request Parameters -``type`` - type of the item that we're requesting streams for; e.g. `movie`, `series`, `channel`, `tv` (see [Content Types](../responses/content.types.md)) +``type`` - type of the item that we're emitting player events for; e.g. `movie`, `series`, `channel`, `tv` (see [Content Types](../responses/content.types.md)) -``id`` - a **Video ID** as described in the [Video Object](../responses/meta.md#video-object) +``id`` - a Video ID as described in the [Video Object](../responses/meta.md#video-object) **The Video ID is the same as the Meta ID for movies**. -For IMDb series (provided by Cinemeta), the video ID is formed by joining the Meta ID, season and episode with a colon (e.g. `"tt0898266:9:17"`). +For IMDB series (provided by Cinemeta), the video ID is formed by joining the Meta ID, season and episode with a colon (e.g. `"tt0898266:9:17"`). ``extra`` - object that holds additional properties; defined below @@ -28,9 +28,9 @@ For IMDb series (provided by Cinemeta), the video ID is formed by joining the Me ``action`` - set in the `extra` object; a string defining the user action, can be either: `start`, `end`, `pause` or `resume`. -``duration`` - set in the `extra` object; int specifying the full duration of the video in **milliseconds**. +``duration`` - set in the `extra` object; string specifying the full duration of the video in **milliseconds**. -``currentTime`` - set in the `extra` object; int in *milliseconds* specifying the progress from the start of the video when the user took the action. +``currentTime`` - set in the `extra` object; string in *milliseconds* specifying the progress from the start of the video when the user took the action. ## Basic Example @@ -38,11 +38,11 @@ For IMDb series (provided by Cinemeta), the video ID is formed by joining the Me ```javascript builder.definePlayerHandler(function(args) { if (args.type === 'movie' && args.id === 'tt1254207') { - // Player event has been successfully - return Promise.resolve({ handled: true }) + // handle the player event + return Promise.resolve({ success: true }) } else { // otherwise return false - return Promise.resolve({ handled: false }) + return Promise.resolve({ success: false }) } }) ``` diff --git a/docs/api/requests/defineStreamHandler.md b/docs/api/requests/defineStreamHandler.md index 0dcb168..56d21ea 100644 --- a/docs/api/requests/defineStreamHandler.md +++ b/docs/api/requests/defineStreamHandler.md @@ -27,7 +27,7 @@ The resolving object can also include the following cache related properties: **The Video ID is the same as the Meta ID for movies**. -For IMDb series (provided by Cinemeta), the video ID is formed by joining the Meta ID, season and episode with a colon (e.g. `"tt0898266:9:17"`). +For IMDB series (provided by Cinemeta), the video ID is formed by joining the Meta ID, season and episode with a colon (e.g. `"tt0898266:9:17"`). ``config`` - object with user settings, see [Manifest - User Data](../responses/manifest.md#user-data) diff --git a/docs/api/responses/event_response.md b/docs/api/responses/event_response.md new file mode 100644 index 0000000..062f89a --- /dev/null +++ b/docs/api/responses/event_response.md @@ -0,0 +1,5 @@ +## event response Object + +Used as a response for [`definePlayerHandler`](../requests/definePlayerHandler.md) and [`defineLibraryHandler`](../requests/defineLibraryHandler.md) + +``success`` - **required** - bool, either true or false, representing if the handling of the event was successful or not. \ No newline at end of file diff --git a/docs/api/responses/manifest.md b/docs/api/responses/manifest.md index 5627213..505cf83 100755 --- a/docs/api/responses/manifest.md +++ b/docs/api/responses/manifest.md @@ -20,7 +20,7 @@ Valid properties are: **NOTE:** In order to understand the next properties better, please check out the [protocol documentation](../../protocol.md) and keep in mind requests to addons are formed in the format of `/{resource}/{type}/{id}` -``resources`` - **required** - array of objects or strings, supported resources - for example ``["catalog", "meta", "stream", "subtitles", "addon_catalog", "watchStatus"]``, resources can also be added as objects instead of strings, for additional details on how they should be requested, example: `{ "name": "stream", "types": [ "movie" ], "idPrefixes": [ "tt" ] }` (see the **ADVANCED** note) +``resources`` - **required** - array of objects or strings, supported resources - for example ``["catalog", "meta", "stream", "subtitles", "addon_catalog", "player", "library"]``, resources can also be added as objects instead of strings, for additional details on how they should be requested, example: `{ "name": "stream", "types": [ "movie" ], "idPrefixes": [ "tt" ] }` (see the **ADVANCED** note) ``types`` - **required** - array of strings, supported types, from all the [``Content Types``](./content.types.md). If you wish to provide different sets of types for different resources, see the **ADVANCED** note. diff --git a/docs/protocol.md b/docs/protocol.md index ea1c098..b755cbc 100644 --- a/docs/protocol.md +++ b/docs/protocol.md @@ -11,7 +11,7 @@ This allows Stremio or other similar applications to aggregate content seamlessl To define a minimal addon, you only need an HTTP server/endpoint serving a `/manifest.json` file and responding to resource requests at `/{resource}/{type}/{id}.json`. -Currently used resources are: `catalog`, `meta`, `stream`, `subtitles`, `watchStatus`. +Currently used resources are: `catalog`, `meta`, `stream`, `subtitles`, `player`, `library`. `/catalog/{type}/{id}.json` - catalogs of media items; `type` denotes the type, such as `movie`, `series`, `channel`, `tv`, and `id` denotes the catalog ID, which is custom and specified in your manifest, `id` is required as an addon can hold multiple catalogs @@ -21,7 +21,9 @@ Currently used resources are: `catalog`, `meta`, `stream`, `subtitles`, `watchSt `/subtitles/{type}/{id}.json` - list of all subtitles for a particular item; `type` again denotes the type, the `id` in this case is the Open Subtitles file hash, while `extraArgs` (read below) is used for `videoID` (the ID of the particular item, as found in the catalog or a video ID) and `videoSize` (video file size in bytes) -`/player/{type}/{id}/{extraArgs}.json` - TODO +the `player` and `library` resources are events. in other resources the addon is supposed to provide data. but in event resources the addon recieves data and is expected to process that given data then respond with the success or failure of that processing. + +`/player/{type}/{videoID}/{extraArgs}.json` - a player event; `type` again denotes the type, and `videoID` is the video ID Where `extraArgs` can be one of: - Play: `action=play¤tTime={milliseconds}&duration={milliseconds}` @@ -29,6 +31,14 @@ Where `extraArgs` can be one of: - End: `action=end¤tTime={milliseconds}&duration={milliseconds}` - Pause: `action=pause¤tTime={milliseconds}&duration={milliseconds}` +`/library/{type}/{id}/{extraArgs}.json` - a library event; `type` again denotes the type, and `id` is the ID of the particular item + +Where `extraArgs` can be one of: +- Add to library: `action=libraryAdd` +- Remove from library: `action=libraryRemove` +- Mark as watched: `action=watched&videoId={videoID}` +- Mark as unwatched: `action=unwatched&videoId={videoID}` + The JSON format of the response to these resources is described [here](./api/responses/). To pass extra args, such as the ones needed for `catalog` resources (e.g. `search`, `skip`), you should define a route of the format `/{resource}/{type}/{id}/{extraArgs}.json` where `extraArgs` is the query string stringified object of extra arguments (for example `"search=game%20of%20thrones&skip=100"`) diff --git a/src/builder.js b/src/builder.js index e75d780..2a10533 100755 --- a/src/builder.js +++ b/src/builder.js @@ -67,7 +67,8 @@ function AddonBuilder(manifest) { this.defineMetaHandler = this.defineResourceHandler.bind(this, 'meta') this.defineCatalogHandler = this.defineResourceHandler.bind(this, 'catalog') this.defineSubtitlesHandler = this.defineResourceHandler.bind(this, 'subtitles') - this.defineWatchStatusHandler = this.defineResourceHandler.bind(this, 'watchStatus') + this.definePlayerHandler = this.defineResourceHandler.bind(this, 'player') + this.defineLibraryHandler = this.defineResourceHandler.bind(this, 'library') // build into an interface this.getInterface = function() {