Spaces:
Paused
Paused
File size: 14,729 Bytes
95f4e64 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 |
# Advanced Usage
- [Understanding Catalogs](#understanding-catalogs) (searching, filtering, paginating)
- [Understanding Cinemeta](#understanding-cinemeta)
- [Adding Stream Results to Cinemeta Items](#adding-stream-results-to-cinemeta-items)
- [Getting Metadata from Cinemeta](#getting-metadata-from-cinemeta)
- [Resolving Movie / Series names to IMDB ID](#resolving-movie--series-names-to-imdb-id)
- [Using User Data in Addons](#using-user-data-in-addons)
- [Using Deep Links in Addons](#using-deep-links-in-addons)
- [Proxying Other Addons](#proxying-other-addons)
- [Crawler (Scraping) Addons](#crawler--scraping-addons)
## Understanding Catalogs
The `catalog` resource in Stremio addons can be used to:
- show one or more catalogs in the Board and Discover pages, these responses can also be filtered and paginated
- show search results from catalogs
Let's first look at how `catalog` is declared in the [manifest](./api/responses/manifest.md):
```json
{
"resources": ["catalog"],
"catalogs": [
{
"id": "testcatalog",
"type": "movie"
}
]
}
```
This is normally all you'd need to make a standard catalog, but it won't support filtering, paginating and it won't be searchable.
### Searching in Catalogs
To state that your catalog supports searching, you'd need to set it in the `extra` property:
```json
catalogs: [
{
"id": "testcatalog",
"type": "movie",
"extra": [
{
"name": "search",
"isRequired": false
}
]
}
]
```
But then, what if you want your catalog to support only search (as in, not show in the Board or Discover pages at all)?
Then you'd need to state that your catalog supports only searching, and you can do that with:
```json
catalogs: [
{
"id": "testcatalog",
"type": "movie",
"extra": [
{
"name": "search",
"isRequired": true
}
]
}
]
```
Once you've set `search` in `extra`, your catalog handler will receive `args.extra.search` as the search query (if it is a search request), so here's an example of a search response:
```javascript
const meta = {
id: 'tt1254207',
name: 'Big Buck Bunny',
releaseInfo: '2008',
poster: 'https://image.tmdb.org/t/p/w600_and_h900_bestv2/uVEFQvFMMsg4e6yb03xOfVsDz4o.jpg',
posterShape: 'poster',
banner: 'https://image.tmdb.org/t/p/original/aHLST0g8sOE1ixCxRDgM35SKwwp.jpg',
type: 'movie'
}
builder.defineCatalogHandler(function(args) {
return new Promise(function(resolve, reject) {
if (args.id == 'testcatalog') {
// this is a request to our catalog id
if (args.extra.search) {
// this is a search request
if (args.extra.search == 'big buck bunny') {
// if someone searched for "big buck bunny" (exact match)
// respond with our meta item
resolve({ metas: [meta] })
} else {
reject(new Error('No search results found'))
}
} else {
// this is a standard catalog request
// just respond with our meta item
resolve({ metas: [meta] })
}
} else {
reject(new Error('Unknown catalog request'))
}
})
})
```
### Filtering in Catalogs
Maybe you would like your catalog to be filtered by `genre`, in this case, we'll set that in the catalog definition:
```json
catalogs: [
{
"id": "testcatalog",
"type": "movie",
"extra": [
{
"name": "genre",
"options": [ "Drama", "Action" ],
"isRequired": false
}
]
}
]
```
Now we'll receive `genre` in our catalog handler:
```javascript
const meta = {
id: 'tt1254207',
name: 'Big Buck Bunny',
releaseInfo: '2008',
poster: 'https://image.tmdb.org/t/p/w600_and_h900_bestv2/uVEFQvFMMsg4e6yb03xOfVsDz4o.jpg',
posterShape: 'poster',
banner: 'https://image.tmdb.org/t/p/original/aHLST0g8sOE1ixCxRDgM35SKwwp.jpg',
type: 'movie'
}
builder.defineCatalogHandler(function(args) {
return new Promise(function(resolve, reject) {
if (args.id == 'testcatalog') {
// this is a request to our catalog id
if (args.extra.genre) {
// this is a filter request
if (args.extra.genre == "Action") {
// in this example we'll only respon with our
// meta item if the genre is "Action"
resolve({ metas: [meta] })
} else {
// otherwise with no meta item
resolve({ metas: [] })
}
} else {
// this is a standard catalog request
// just respond with our meta item
resolve({ metas: [meta] })
}
} else {
reject(new Error('Unknown catalog request'))
}
})
})
```
## Pagination in Catalogs
If we want our catalogs to be paginated, we can use `skip` as follows:
```json
catalogs: [
{
"id": "testcatalog",
"type": "movie",
"extra": [
{
"name": "skip",
"isRequired": false
}
]
}
]
```
Optionally, we can also set the steps in which the catalog will request the next items, for example:
```json
catalogs: [
{
"id": "testcatalog",
"type": "movie",
"extra": [
{
"name": "skip",
"options": ["0", "100", "200"],
"isRequired": false
}
]
}
]
```
This is not a requirement though, as if we don't set `options` Stremio will request `skip` once it comes to the end of your catalog.
Here's an example of using `skip`:
```javascript
// we only have one meta item
const meta = {
id: 'tt1254207',
name: 'Big Buck Bunny',
releaseInfo: '2008',
poster: 'https://image.tmdb.org/t/p/w600_and_h900_bestv2/uVEFQvFMMsg4e6yb03xOfVsDz4o.jpg',
posterShape: 'poster',
banner: 'https://image.tmdb.org/t/p/original/aHLST0g8sOE1ixCxRDgM35SKwwp.jpg',
type: 'movie'
}
const metaList = []
// but we'll make an array that includes our meta 60 times
for (let i = 0; i++; i < 60) {
metaList.push(meta)
}
builder.defineCatalogHandler(function(args) {
return new Promise(function(resolve, reject) {
if (args.id == 'testcatalog') {
// we'll slice our meta list using
// skip as the starting point
const skip = args.extra.skip || 0
resolve({ metas: metaList.slice(skip, skip + 20) })
} else {
reject(new Error('Unknown catalog request'))
}
})
})
```
## Understanding Cinemeta
Cinemeta is the primary addon that Stremio uses to show Movie, Series and Anime items. Other addons can choose to create their own catalogs of items or respond with streams to the Cinemeta items.
Cinemeta uses IMDB IDs for their metadata, to understand it's pattern:
- `tt0111161` is the meta ID (and video ID) of a movie
- `tt3107288` is the meta ID of a series, and `tt3107288:1:1` is the video ID for season 1, episode 1 of the series with the `tt3107288` meta ID
## Adding Stream Results to Cinemeta Items
To add only stream results to Cinemeta items, you will first need to state that your addons id prefix is `tt` (as for IMDB IDs).
Add these to your [manifest](./api/responses/manifest.md):
- `resources: ["stream"]`
- `idPrefixes: ["tt"]`
Now here is an example of returning stream responses for Cinemeta items:
```javascript
builder.defineStreamHandler(function(args) {
return new Promise(function(resolve, reject) {
if (args.type === 'movie' && args.id === 'tt1254207') {
// serve one stream for big buck bunny
const stream = { url: 'http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4' }
resolve({ streams: [stream] })
} else if (args.type === 'series' && args.id === 'tt8633518:1:1') {
// return one stream for the series Weird City, Season 1 Episode 1
// (free Youtube Originals series)
const stream = { id: 'yt_id::fMnq5v8yZp4' }
resolve({ streams: [stream] })
} else {
reject(new Error('No streams available for: ' + args.id))
}
})
})
```
## Getting Metadata from Cinemeta
There might be cases where you would need metadata based on IMDB ID. To do this, you will need both IMDB ID and the type of the item (either `movie` or `series`).
Because Cinemeta is also an addon, you can request the metadata from it.
Here is an example using `needle` to do a HTTP request to Cinemeta for metadata:
```javascript
var needle = require('needle')
// we will get metadata for the movie: Big Buck Bunny
var itemType = 'movie'
var itemImdbId = 'tt1254207'
needle.get('https://v3-cinemeta.strem.io/meta/' + itemType + '/' + itemImdbId + '.json', function(err, resp, body) {
if (body && body.meta) {
// log Big Buck Bunny's metadata
console.log(body.meta)
}
})
```
## Resolving Movie / Series names to IMDB ID
What if you have a movie or series name, but you need it's IMDB ID?
We recommend using [name-to-imdb](https://github.com/Ivshti/name-to-imdb) in this case, and it's really easy to use:
```javascript
var nameToImdb = require("name-to-imdb");
nameToImdb({ name: "south park" }, function(err, res, inf) {
console.log(res); // prints "tt0121955"
console.log(inf); // inf contains info on where we matched that name - e.g. metadata, or on imdb
})
```
Also setting the `type` and `year` in the request helps on ensuring that the IMDB ID that is returned is correct.
## Using User Data in Addons
**The Addon SDK now [supports user data](./api/responses/manifest.md#user-data), this part of the docs will remain here as it is valid for use with the Express module.**
This example does not use the Stremio Addon SDK, it uses Node.js and Express to serve replies.
User data is passed in the Addon Repository URL, so instead of users installing addons from the normal manifest url (for example: `https://www.mydomain.com/manifest.json`), users will also need to add the data they want to pass to the addon in the URL (for example: `https://www.mydomain.com/c9y2kz0c26c3w4csaqne71eu4jqko7e1/manifest.json`, where `c9y2kz0c26c3w4csaqne71eu4jqko7e1` could be their API Authentication Token)
Simplistic Example:
```javascript
const express = require('express')
const addon = express()
addon.get('/:someParameter/manifest.json', function (req, res) {
res.send({
id: 'org.parameterized.'+req.params.someParameter,
name: 'addon for '+req.params.someParameter,
resources: ['stream'],
types: ['series'],
})
})
addon.get('/:someParameter/stream/:type/:id.json', function(req, res) {
// @TODO do something depending on req.params.someParameter
res.send({ streams: [] })
})
addon.listen(7000, function() {
console.log('http://127.0.0.1:7000/[someParameter]/manifest.json')
})
```
This is not a working example, it simply shows how data can be inserted by users in the Addon Repository URL so addons can then make use of it.
For working examples, you can check these addons:
- [IMDB Lists](https://github.com/jaruba/stremio-imdb-list)
- [IMDB Watchlist](https://github.com/jaruba/stremio-imdb-watchlist)
- [Jackett Addon for Stremio](https://github.com/BoredLama/stremio-jackett-addon) (community built)
Another use case for passing user data through the Addon Repository URL is creating proxy addons. This case presumes that the id of a different addon is sent in the Addon Repository URL, then the proxy addon connects to the addon of which the id it got, requests streams, passes the stream url to some API (for example Real Debrid, Premiumize, etc) to get a different streaming url that it then responds with for Stremio.
## Creating Addon Configuration Pages
This guide extends [Using User Data in Addons](#using-user-data-in-addons) by explaining how to create an Addon Configuration Page.
In order to allow Addons to request user data, you will first need to create a web page on the `/configure` path of your addon and set `manifest.behaviorHints.configurable` to `true`. (you can also set `manifest.behaviorHints.configurationRequired` to `true` if your addon cannot be installed without user data)
The `/configure` web page should include a form with all required data, the form data should be set within the Addon Repository URL (as explained in the [Using User Data in Addons](#using-user-data-in-addons)) section.
An "Install Addon" button should be available on the page that will use the `stremio://` protocol, for example, if your Addon Repository URL is `https://my.addon.com/some-user-data/manifest.json`, the "Install Addon" button should point to `stremio://my.addon.com/some-user-data/manifest.json`. (the `stremio://` protocol links will open or focus the Stremio app with a prompt to install the addon)
## Using Deep Links in Addons
Stremio supports [deep links](./deep-links.md), such links can also be used in addons to link internally to Stremio.
First, set the `stream` resource in your [manifest](./api/responses/manifest.md):
- `resources: ["stream"]`
Here's an example:
```javascript
// this responds with one stream for the Big Buck Bunny
// movie, that if clicked, will redirect Stremio to the
// Board page
builder.defineStreamHandler(function(args) {
return new Promise(function(resolve, reject) {
if (args.type === 'movie' && args.id === 'tt1254207') {
// serve one stream for big buck bunny
const stream = { externalUrl: 'stremio://board' }
resolve({ streams: [stream] })
} else {
reject(new Error('No streams found for: ' + args.id))
}
})
})
```
## Proxying Other Addons
Stremio addons use a HTTP server to handle requests and responses, this means that other addons can also request their responses.
This can be useful for many reasons, a guide on how this can be done is included in the readme of the [IMDB Watchlist](https://github.com/jaruba/stremio-imdb-watchlist) Addon which proxies the [IMDB Lists](https://github.com/jaruba/stremio-imdb-list) addon to get the IMDB List for a particular IMDB user.
IMDB Watchlist only proxies the catalog from IMDB Lists, to proxy other resources you can use the same pattern as IMDB Watchlist does, and check the endpoints and patterns for other resources on the [Protocol Documentation](./protocol.md) page.
## Crawler / Scraping Addons
Scraping HTML pages presumes downloading the HTML source of a web page in order to get specific data from it.
A guide showing a simplistic version of doing this is in the readme of the [IMDB Watchlist Addon](https://github.com/jaruba/stremio-imdb-watchlist). The addon uses [needle](https://www.npmjs.com/package/needle) to request the HTML source and [cheerio](https://www.npmjs.com/package/cheerio) to start a jQuery instance in order to simplify getting the desired information.
Cheerio is not the only module that can help with crawling / scraping though, other modules that can aid in this: [jsdom](https://www.npmjs.com/package/jsdom), [xpath](https://www.npmjs.com/package/xpath), etc
|