{"id":13466308,"url":"https://github.com/jaruba/stremio-imdb-list","last_synced_at":"2025-04-13T12:05:10.782Z","repository":{"id":86484227,"uuid":"171869898","full_name":"jaruba/stremio-imdb-list","owner":"jaruba","description":"Add-on to create a Stremio catalog from a IMDB list","archived":false,"fork":false,"pushed_at":"2023-12-22T20:40:07.000Z","size":32,"stargazers_count":7,"open_issues_count":1,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-12-23T18:07:42.955Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jaruba.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-21T12:43:00.000Z","updated_at":"2024-11-17T00:57:12.000Z","dependencies_parsed_at":"2024-07-31T15:13:05.900Z","dependency_job_id":null,"html_url":"https://github.com/jaruba/stremio-imdb-list","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaruba%2Fstremio-imdb-list","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaruba%2Fstremio-imdb-list/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaruba%2Fstremio-imdb-list/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jaruba%2Fstremio-imdb-list/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jaruba","download_url":"https://codeload.github.com/jaruba/stremio-imdb-list/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":232787235,"owners_count":18576552,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-07-31T15:00:42.297Z","updated_at":"2025-01-07T22:00:05.526Z","avatar_url":"https://github.com/jaruba.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","Addon Developer Resources"],"sub_categories":["Catalogs"],"readme":"# Stremio Add-on to Add an IMDB List as a Catalog\n\nThis is a simple add-on that uses an ajax call to get a list of items from IMDB, then converts those items to Stremio supported Meta Objects.\n\n\n## Using locally\n\n**Pre-requisites: Node.js, Git**\n\n```\ngit clone https://github.com/jaruba/stremio-imdb-list.git\ncd stremio-imdb-list\nnpm i\nnpm start\n```\n\nThis will print `http://127.0.0.1:7515/[imdb-list-id]/manifest.json`. Add a IMDB list id instead of `[imdb-list-id]` in this URL and [load the add-on in Stremio](https://github.com/jaruba/stremio-imdb-list#6-install-add-on-in-stremio).\n\n\n## Using remotely\n\nUse `https://1fe84bc728af-imdb-list.beamup.dev/[imdb-list-id]/manifest.json`. Add a IMDB list id instead of `[imdb-list-id]` in this URL and [load the add-on in Stremio](https://github.com/jaruba/stremio-imdb-list#6-install-add-on-in-stremio).\n\n\n## What is a IMDB List ID\n\nPresuming that the list you want to add is `https://www.imdb.com/list/ls058289969/`, the IMDB list id in this case is `ls058289969`.\n\n\n## Sorting Lists\n\nYou can also sort these lists, supported sorting tags: `list_order`, `popularity`, `alphabetical`, `rating`, `votes`, `released`, `date_added`\n\nThe default sorting is: `list_order`\n\nTo get a list of sorted items, use: `https://1fe84bc728af-imdb-list.beamup.dev/[imdb-list-id]/[tag-id]/manifest.json`\n\nExample: `https://1fe84bc728af-imdb-list.beamup.dev/ls058289969/alphabetical/manifest.json`\n\n\n## How this add-on was made\n\n\n### 1. Create a `package.json` and add dependencies\n\n```json\n{\n  \"name\": \"stremio-imdb-list\",\n  \"version\": \"0.0.1\",\n  \"description\": \"Add-on to create a Stremio catalog from a IMDB list.\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start\": \"node index.js\"\n  },\n  \"dependencies\": {\n    \"needle\": \"^2.2.4\",\n    \"express\": \"^4.16.4\",\n    \"cors\": \"^2.8.5\",\n    \"named-queue\": \"^2.2.1\"\n  }\n}\n```\n\nWe will use `needle` to make the ajax request, `express` to create the add-on http server, `cors` to easily add CORS to our http server responses and `named-queue` because although we'll get two catalog requests (one for movies and one for series), we only need to do one ajax request as IMDB lists include both. That's where `named-queue` comes in, as it merges tasks by `id`, so we only do one ajax request to respond to both catalog requests.\n\n\n### 2. Add-on manifest\n\nIn this step, we define the add-on name, description and purpose.\n\nCreate an `index.js` file:\n\n```javascript\nconst manifest = {\n\n  // set add-on id, any string unique between add-ons\n  id: 'org.imdblist',\n\n  // setting a semver add-on version is mandatory\n  version: '0.0.1',\n\n  // human readable add-on name\n  name: 'IMDB List Add-on',\n\n  // description of the add-on\n  description: 'Add-on to create a catalog from a IMDB list.',\n\n  // we only need 'catalog' for this add-on, can also be 'meta', 'stream' and 'subtitles'\n  resources: ['catalog'],\n\n  // we set the add-on types, can also be 'tv', 'channel' and 'other'\n  types: ['movie', 'series'],\n\n  // we define our catalogs, we'll make one for 'movies' and one for 'series'\n  catalogs: [\n    {\n      // id of catalog, any string unique between this add-ons catalogs\n      id: 'imdb-movie-list',\n\n      // human readable catalog name\n      name: 'IMDB Movie List',\n\n      // the type of this catalog provides\n      type: 'movie'\n    }, {\n      id: 'imdb-series-list',\n      name: 'IMDB Series List',\n      type: 'series'\n    }\n  ]\n}\n\n// create add-on server\nconst express = require('express')\nconst app = express()\nconst cors = require('cors')\n\n// add CORS to server responses\napp.use(cors())\n\n// respond to the manifest request\napp.get('/:listId/manifest.json', (req, res) =\u003e {\n  res.setHeader('Cache-Control', 'max-age=604800') // one week\n  res.setHeader('Content-Type', 'application/json')\n  res.send(manifest)\n})\n```\n\n### 3. Get List Items\n\nNow we need to get the list items based on list id (we'll use an ajax call for that), then convert the items in the list to Stremio meta objects, and also resize the list item poster (by modifying the poster url) to something significantly smaller for the Stremio catalog.\n\n```javascript\n// we'll use a helper function to resize IMDB posters\n// their normally too big for catalog responses\nfunction imageResize(posterUrl, width) {\n  if (!posterUrl) return null\n  if (!posterUrl.includes('amazon.com') \u0026\u0026 !posterUrl.includes('imdb.com')) return posterUrl\n  if (posterUrl.includes('._V1_.')) posterUrl = posterUrl.replace('._V1_.', '._V1_SX' + width + '.')\n  else if (posterUrl.includes('._V1_')) {\n    var extension = posterUrl.split('.').pop()\n    posterUrl = posterUrl.substr(0,posterUrl.indexOf('._V1_')) + '._V1_SX' + width + '.' + extension\n  }\n  return posterUrl\n}\n\n// we'll also need a function to convert the IMDB List\n// items to a Stremio Meta object\nfunction toMeta(obj) {\n  // we need minimal data for catalogs, we'll set the IMDB id as\n  // the meta object id, so the cinemeta add-on can handle the\n  // meta requests for them afterwards\n  return {\n    id: obj.id || null,\n    name: obj.primary \u0026\u0026 obj.primary.title ? obj.primary.title : null,\n    poster: obj.poster \u0026\u0026 obj.poster.url ? imageResize(obj.poster.url, 250) : null,\n    type: obj.type == 'featureFilm' ? 'movie' : 'series'\n  }\n}\n\nconst needle = require('needle')\n\n// request headers for the ajax call\nconst headers = {\n  // we set the user agent of Chrome on Android\n  'User-Agent': 'Mozilla/5.0 (Linux; Android 8.0.0; TA-1053 Build/OPR1.170623.026) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3368.0 Mobile Safari/537.36',\n  // we set the language we expect from the page\n  'Accept-Language': 'en-US,en;q=0.8',\n}\n\n// declare our cache object\nconst cache = { movie: {}, series: {} }\n\n// we make a function to handle fetching the IMDB list\nfunction getList(listId, cb) {\n\n  if (listId) {\n\n    // we set the normal url of IMDB lists as the\n    // referer for the request\n    headers.referer = 'https://m.imdb.com/list/'+listId+'/'\n\n    // this is our ajax call, based on IMDB list ID\n    const getUrl = 'https://m.imdb.com/list/'+listId+'/search?sort=date_added%2Cdesc\u0026view=grid\u0026tracking_tag=\u0026pageId='+listId+'\u0026pageType=list'\n\n    needle.get(getUrl, { headers }, (err, resp) =\u003e {\n      if (!err \u0026\u0026 resp \u0026\u0026 resp.body) {\n        // our request is successful and we have a body\n        const jObj = resp.body\n        if (jObj.titles \u0026\u0026 Object.keys(jObj.titles).length) {\n\n          // this list has items\n\n          // we empty the cache for this list\n          manifest.types.forEach(el =\u003e { cache[el][listId] = [] })\n\n          // iterate through items object and add to our cache\n          for (let key in jObj.titles) {\n            const el = jObj.titles[key]\n            const metaType = el.type == 'featureFilm' ? 'movie' : el.type == 'series' ? 'series' : null\n            if (metaType) {\n              cache[metaType][listId].push(toMeta(el))\n            }\n          }\n\n          // remove cache after 1 day\n          setTimeout(() =\u003e {\n            manifest.types.forEach(el =\u003e { cache[el][listId] = [] })\n          }, 86400000)\n\n          // respond with no error, cache has been updated succesfully\n          cb(false, true)\n        } else {\n          // send error\n          cb('Parsing error on ajax call')\n        }\n      } else {\n        // send error\n        cb(err || 'Error on requesting ajax call')\n      }\n    })\n  } else {\n    // send error\n    cb('No list id')\n  }\n}\n```\n\n\n### 4. Catalog Handler\n\nWe create the catalog handler, get the list id from the user as it's part of the add-on url and merge http requests for the same list id.\n\n```javascript\n\n// we use `named-queue` to merge more tasks\n// with the same list id\nconst namedQueue = require('named-queue')\n\nconst queue = new namedQueue((task, cb) =\u003e {\n  getList(task.id, cb)\n}, Infinity)\n\n// users pass the list id in the add-on url\n// this will be available as `req.params.listId`\napp.get('/:listId/catalog/:type/:id.json', (req, res) =\u003e {\n\n  // handle failures\n  function fail(err) {\n    console.error(err)\n    res.writeHead(500)\n    res.end(JSON.stringify({ err: 'handler error' }))\n  }\n\n  // handle response\n  function respond(msg) {\n    res.setHeader('Cache-Control', 'max-age=86400') // one day\n    res.setHeader('Content-Type', 'application/json')\n    res.send(msg)\n  }\n\n  // handle importing and updating cache\n  function fetch() {\n    queue.push({ id: req.params.listId }, (err, done) =\u003e {\n      if (done) {\n        const userData = cache[req.params.type][req.params.listId]\n        respond(JSON.stringify({ metas: userData }))\n      } else \n        fail(err || 'Could not get list items')\n    })\n  }\n\n  // ensure request parameters are known\n  if (req.params.listId \u0026\u0026 ['movie','series'].indexOf(req.params.type) \u003e -1) {\n\n    // if we already have it in the cache, use the cache\n    if (cache[req.params.type][req.params.listId]) {\n      const userData = cache[req.params.type][req.params.listId]\n      if (userData.length)\n        respond(JSON.stringify({ metas: userData }))\n      else\n        fetch()\n    } else\n      fetch()\n\n  } else\n    fail('Unknown request parameters')\n})\n```\n\n### 5. Run the Add-on Server\n\n```javascript\napp.listen(7515, () =\u003e {\n    console.log('http://127.0.0.1:7515/[imdb-list-id]/manifest.json')\n})\n```\n\n### 6. Install Add-on in Stremio\n\n![addlink](https://user-images.githubusercontent.com/1777923/43146711-65a33ccc-8f6a-11e8-978e-4c69640e63e3.png)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaruba%2Fstremio-imdb-list","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjaruba%2Fstremio-imdb-list","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjaruba%2Fstremio-imdb-list/lists"}