├── .npmignore ├── .gitignore ├── .travis.yml ├── src ├── index.js ├── list.js ├── search.js ├── constants.js └── utils.js ├── .drone.yml ├── .github └── workflows │ └── nodejs.yml ├── test ├── search.spec.js └── list.spec.js ├── package.json ├── LICENSE └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | !lib 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | lib 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6.2.0" 4 | script: npm i && npm run build && npm run test 5 | cache: 6 | directories: 7 | - node_modules 8 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | const list = require('./list') 2 | const search = require('./search') 3 | const constants = require('./constants') 4 | 5 | module.exports = { 6 | list: list, 7 | search: search, 8 | CATEGORY: constants.CATEGORY 9 | } 10 | -------------------------------------------------------------------------------- /.drone.yml: -------------------------------------------------------------------------------- 1 | pipeline: 2 | test: 3 | image: node:${NODE_VERSION} 4 | commands: 5 | - npm install 6 | - npm run build 7 | - npm run test 8 | publish: 9 | image: plugins/npm 10 | secrets: [ npm_username, npm_password, npm_email ] 11 | when: 12 | matrix: 13 | NODE_VERSION: 6 14 | matrix: 15 | NODE_VERSION: 16 | - 6 17 | - 7 18 | - 8 19 | -------------------------------------------------------------------------------- /src/list.js: -------------------------------------------------------------------------------- 1 | const utils = require('./utils') 2 | const constants = require('./constants') 3 | const request = utils.request 4 | const proceedExtraParams = utils.proceedExtraParams 5 | 6 | module.exports = function list(options) { 7 | const extraParams = proceedExtraParams(options) 8 | return request(constants.BASE_URL, Object.assign({}, { 9 | mode: 'list', 10 | }, extraParams)).then(res => { 11 | if (res.body.error) { 12 | return Promise.reject(res.body) 13 | } else { 14 | return res.body.torrent_results 15 | } 16 | }) 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | strategy: 11 | matrix: 12 | node-version: [8.x, 10.x, 12.x] 13 | 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v1 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - name: npm install, build, and test 21 | run: | 22 | npm install 23 | npm run build 24 | npm run test 25 | env: 26 | CI: true 27 | -------------------------------------------------------------------------------- /test/search.spec.js: -------------------------------------------------------------------------------- 1 | const should = require('chai').should 2 | const search = require('../lib/index').search 3 | 4 | should() 5 | 6 | describe('search api test', function() { 7 | beforeEach(function() { 8 | this.timeout(60000) 9 | }) 10 | this.timeout(60000) 11 | 12 | it('search torrent using keyword', function() { 13 | return search('prison break').then(data => { 14 | data.length.should.above(0) 15 | data[0].title.toLowerCase().should.include('prison') 16 | }) 17 | }) 18 | 19 | it('search torrent from imdb using a imdb id', function() { 20 | // tt0944947 is Game.Of.Thrones 21 | return search('tt0944947', null, 'imdb').then(data => { 22 | data.length.should.above(0) 23 | data[0].title.toLowerCase().should.include('game') 24 | }) 25 | }) 26 | }) 27 | -------------------------------------------------------------------------------- /src/search.js: -------------------------------------------------------------------------------- 1 | const utils = require('./utils') 2 | const constants = require('./constants') 3 | const request = utils.request 4 | const proceedExtraParams = utils.proceedExtraParams 5 | 6 | module.exports = function search(keyword, options, type) { 7 | const searchParams = {} 8 | if (type && ~['imdb', 'tvdb', 'themoviedb', 'tvrage'].indexOf(type)) { 9 | searchParams[`search_${type}`] = keyword 10 | } else { 11 | searchParams.search_string = keyword 12 | } 13 | const extraParams = proceedExtraParams(options) 14 | return request(constants.BASE_URL, Object.assign({}, { 15 | mode: 'search' 16 | }, searchParams, extraParams)).then(res => { 17 | if (res.body.error) { 18 | return Promise.reject(res.body) 19 | } else { 20 | return res.body.torrent_results 21 | } 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rarbg-api", 3 | "version": "1.1.4", 4 | "description": "A simple node.js wrapper for rarbg.to api", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "test": "NODE_ENV=test mocha test/*.spec.js", 8 | "build": "babel src -d lib" 9 | }, 10 | "homepage": "https://github.com/serenader2014/rarbg-api", 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/serenader2014/rarbg-api" 14 | }, 15 | "keywords": [ 16 | "torrent", 17 | "rarbg.to", 18 | "api", 19 | "torrent download", 20 | "rarbg api" 21 | ], 22 | "author": "serenader", 23 | "license": "MIT", 24 | "dependencies": {}, 25 | "devDependencies": { 26 | "@babel/cli": "^7.0.0", 27 | "@babel/core": "^7.0.0", 28 | "@babel/preset-env": "^7.0.0", 29 | "chai": "^3.5.0", 30 | "mocha": "^3.2.0" 31 | }, 32 | "babel": { 33 | "presets": [ 34 | [ 35 | "@babel/preset-env", 36 | { 37 | "targets": { 38 | "node": "0.10.0" 39 | } 40 | } 41 | ] 42 | ] 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 serenader 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/constants.js: -------------------------------------------------------------------------------- 1 | const BASE_URL = 'https://torrentapi.org/pubapi_v2.php' 2 | const APP_ID = 'rarbg-api-nodejs' 3 | const UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36' 4 | const CATEGORY = { 5 | '4K_MOVIES_X264_4k': [50], // left for compatibility reasons 6 | '4K_X265_4k': [51], // left for compatibility reasons 7 | '4k_X264_4k_HDR': [52], // left for compatibility reasons 8 | XXX: [4], 9 | MOVIES_XVID: [14], 10 | MOVIES_XVID_720P: [48], 11 | MOVIES_X264: [17], 12 | MOVIES_X264_1080P: [44], 13 | MOVIES_X264_720P: [45], 14 | MOVIES_X264_3D: [47], 15 | MOVIES_X264_4K: [50], 16 | MOVIES_X265_1080P: [54], 17 | MOVIES_X265_4K: [51], 18 | MOVIES_X265_4K_HDR: [52], 19 | MOVIES_FULL_BD: [42], 20 | MOVIES_BD_REMUX: [46], 21 | TV_EPISODES: [18], 22 | TV_UHD_EPISODES: [49], 23 | TV_HD_EPISODES: [41], 24 | MUSIC_MP3: [23], 25 | MUSIC_FLAC: [25], 26 | GAMES_PC_ISO: [27], 27 | GAMES_PC_RIP: [28], 28 | GAMES_PS3: [40], 29 | GAMES_XBOX_360: [32], 30 | SOFTWARE_PC_ISO: [33], 31 | EBOOKS: [35] 32 | } 33 | 34 | const majorCategory = ['4K', 'MOVIES', 'TV', 'GAMES', 'MUSIC'] 35 | 36 | majorCategory.forEach(c => { 37 | const reg = new RegExp(c, 'i') 38 | CATEGORY[c] = Object.keys(CATEGORY).filter(category => reg.test(category)).reduce((arr, category) => { 39 | return arr.concat(CATEGORY[category]) 40 | }, []) 41 | }) 42 | 43 | CATEGORY.NON_XXX = Object.keys(CATEGORY).filter(category => category != 'XXX').reduce((arr, category) => { 44 | return arr.concat(CATEGORY[category]) 45 | }, []) 46 | 47 | module.exports = { 48 | BASE_URL, 49 | CATEGORY, 50 | APP_ID, 51 | UA 52 | } 53 | -------------------------------------------------------------------------------- /test/list.spec.js: -------------------------------------------------------------------------------- 1 | const list = require('../lib/index').list 2 | const should = require('chai').should 3 | const constants = require('../src/constants') 4 | should() 5 | 6 | 7 | describe('list api test', function() { 8 | beforeEach(function() { 9 | this.timeout(60000) 10 | }) 11 | 12 | this.timeout(60000) 13 | it('should list torrent', function() { 14 | return list().then(data => { 15 | data.length.should.above(0) 16 | }) 17 | }) 18 | 19 | it('should list torrent using movie category', function() { 20 | return list({ category: constants.CATEGORY.MOVIES_FULL_BD }).then(data => { 21 | data.length.should.above(0) 22 | data[0].category.toLowerCase().should.equal('movies/full bd') 23 | }) 24 | }) 25 | 26 | it('should list torrent using the general 4K category', function() { 27 | return list({ category: constants.CATEGORY['4K'] }).then(data => { 28 | data.length.should.above(0) 29 | data[0].category.toLowerCase().should.contains('x265/4k') 30 | }) 31 | }) 32 | 33 | it('should list torrent using the Movies/x264/4k movie category', function() { 34 | return list({ category: constants.CATEGORY['4K_MOVIES_X264_4k'] }).then(data => { 35 | data.length.should.above(0) 36 | data[0].category.toLowerCase().should.equal('movies/x264/4k') 37 | }) 38 | }) 39 | 40 | it('should list torrent using the Movies/x265/4k movie category', function() { 41 | return list({ category: constants.CATEGORY['4K_X265_4k']}).then(data => { 42 | data.length.should.above(0) 43 | data[0].category.toLowerCase().should.equal('movies/x265/4k') 44 | }) 45 | }) 46 | 47 | it('should list torrent using the Movies/x265/4k/HDR movie category', function() { 48 | return list({ category: constants.CATEGORY['4k_X264_4k_HDR']}).then(data => { 49 | data.length.should.above(0) 50 | data[0].category.toLowerCase().should.equal('movs/x265/4k/hdr') 51 | }) 52 | }) 53 | 54 | it('should list torrent and limit 100 torrent', function() { 55 | return list({ limit: 100 }).then(data => { 56 | data.length.should.equal(100) 57 | }) 58 | }) 59 | 60 | it('should list torrent sort by seeders', function() { 61 | return list({ sort: 'seeders' }).then(data => { 62 | data.length.should.above(0) 63 | data[0].seeders.should.above(data[1].seeders) 64 | }) 65 | }) 66 | 67 | it('should list torrent using simple json format', function() { 68 | return list({ format: 'json' }).then(data => { 69 | data.length.should.above(0) 70 | Object.keys(data[0]).length.should.equal(3) 71 | }) 72 | }) 73 | }) 74 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | const https = require('https') 2 | const parseUrl = require('url').parse 3 | const querystring = require('querystring') 4 | const baseUrl = require('./constants').BASE_URL 5 | const UA = require('./constants').UA 6 | const APP_ID = require('./constants').APP_ID 7 | 8 | const debug = {} 9 | const ENV = process.env.NODE_ENV 10 | Object.keys(console).forEach(method => { 11 | debug[method] = function() { 12 | if (ENV === 'debug' || ENV === 'test') { 13 | const args = [new Date()].concat([].slice.call(arguments)) 14 | console[method].apply(console, args) 15 | } 16 | } 17 | }) 18 | 19 | function sleep(second) { 20 | second = second || 1 21 | return new Promise(resolve => { 22 | setTimeout(() => { 23 | resolve() 24 | }, second * 1000) 25 | }) 26 | } 27 | 28 | const token = (() => { 29 | let currentToken = '' 30 | return { 31 | get() { 32 | return currentToken 33 | }, 34 | set(newToken) { 35 | currentToken = newToken 36 | return currentToken 37 | } 38 | } 39 | })() 40 | 41 | function r(url, options) { 42 | return new Promise((resolve, reject) => { 43 | const qs = options ? `?${querystring.stringify(options)}` : '' 44 | const finalUrl = `${url}${qs}` 45 | debug.log(`request url: ${finalUrl}`) 46 | let requestOptions = { 47 | headers: { 48 | 'User-Agent': UA 49 | }, 50 | }; 51 | if(process.env.LOCAL_ADDRESS) 52 | requestOptions.localAddress = process.env.LOCAL_ADDRESS; 53 | const req = https.request(Object.assign(parseUrl(finalUrl), requestOptions), res => { 54 | let body = '' 55 | res.on('data', chunk => { 56 | body += chunk 57 | }) 58 | res.on('end', () => { 59 | try { 60 | body = JSON.parse(body) 61 | } catch (e) { 62 | debug.error(`request error: ${e}`) 63 | } 64 | resolve({ 65 | status: res.statusCode, 66 | headers: res.headers, 67 | body: body 68 | }) 69 | }) 70 | }) 71 | 72 | req.on('error', err => { 73 | debug.error(`request failed: ${err}`) 74 | reject(err) 75 | }) 76 | req.end() 77 | }) 78 | } 79 | 80 | function getToken() { 81 | return r(baseUrl, { 82 | get_token: 'get_token', 83 | app_id: APP_ID 84 | }).then(res => token.set(res.body.token)) 85 | } 86 | 87 | function request(url, options) { 88 | return Promise.resolve(token.get() || getToken()).then(currentToken => { 89 | options = options || {} 90 | options.token = currentToken 91 | return r(url, options) 92 | }).then(res => { 93 | if (res.body && res.body.error) { 94 | if (res.body.error_code == 4) { 95 | // token expired 96 | debug.warn(`token expired: ${token.get()}`) 97 | token.set(null) 98 | return request(url, options) 99 | } else if (res.body.error_code == 5 || res.body.error_code == 20) { 100 | // Too many requests per second 101 | debug.warn(`too many request`) 102 | return sleep(2).then(() => request(url, options)) 103 | } 104 | return res 105 | } else if (!res.body) { 106 | // Too many requests per second 107 | debug.warn(`too many request`) 108 | return sleep(2).then(() => request(url, options)) 109 | } else { 110 | return res 111 | } 112 | }) 113 | } 114 | 115 | function proceedExtraParams(params) { 116 | params = params || {} 117 | const defaultParams = { 118 | category: null, 119 | limit: 25, 120 | sort: 'last', 121 | min_seeders: null, 122 | min_leechers: null, 123 | format: 'json_extended', 124 | ranked: null, 125 | app_id: APP_ID 126 | } 127 | 128 | const result = {} 129 | Object.keys(defaultParams).forEach(key => { 130 | const value = params[key] || defaultParams[key] 131 | if (!value) return 132 | result[key] = value 133 | }) 134 | 135 | if (result.category) { 136 | result.category = result.category.join(';') 137 | } 138 | 139 | if (!~[25, 50, 100].indexOf(result.limit)) { 140 | result.limit = 25 141 | } 142 | 143 | if (!~['last', 'seeders', 'leechers'].indexOf(result.sort)) { 144 | result.sort = 'last' 145 | } 146 | 147 | if (typeof result.min_leechers !== 'number') { 148 | delete result.min_leechers 149 | } 150 | 151 | if (typeof result.min_seeders !== 'number') { 152 | delete result.min_seeders 153 | } 154 | 155 | if (!~['json', 'json_extended'].indexOf(result.format)) { 156 | result.format = 'json_extended' 157 | } 158 | 159 | if (result.ranked != 0) { 160 | delete result.ranked 161 | } 162 | 163 | return result 164 | } 165 | 166 | module.exports = { 167 | request, 168 | proceedExtraParams 169 | } 170 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rarbg.to API 2 | 3 | This is an unofficial nodejs api wrapper for rarbg.to website. 4 | 5 | [![Build Status](https://travis-ci.org/serenader2014/rarbg-api.svg?branch=master)](https://travis-ci.org/serenader2014/rarbg-api) 6 | [![npm module](https://badge.fury.io/js/rarbg-api.svg)](https://www.npmjs.org/package/rarbg-api) 7 | [![dependencies](https://david-dm.org/serenader2014/rarbg-api.svg)](https://david-dm.org/serenader2014/rarbg-api.svg) 8 | 9 | # Installation 10 | 11 | First download this package from npm registry 12 | 13 | ```bash 14 | npm i --save rarbg-api 15 | ``` 16 | 17 | and require it from your project: 18 | 19 | ```javascript 20 | const rarbgApi = require('rarbg-api') 21 | ``` 22 | 23 | # Environment Flags 24 | #### **NODE_ENV** 25 | - Can be set to `debug` to see debug messages and errors 26 | #### **LOCAL_ADDRESS** 27 | - Can be set to a network interface ip address in order to send requests from that source 28 | - See [http.request.options](https://nodejs.org/api/http.html#http_http_request_url_options_callback) for more details 29 | 30 | 31 | 32 | # API 33 | 34 | ### .list([options: Object]): Array 35 | 36 | List torrent. 37 | 38 | #### Parameters 39 | 40 | - **options** 41 | + Object 42 | + Optional 43 | 44 | See [additional options section](#additional-options) 45 | 46 | 47 | #### Returns 48 | 49 | The api returns a promise which will resolve a list of torrent. 50 | 51 | ### .search(keyword[, options, type]): Array 52 | 53 | Search torrent using a keyword. 54 | 55 | #### Parameters 56 | 57 | - **keyword** 58 | + String 59 | 60 | Specify a keyword to search. 61 | 62 | - **options** 63 | + Object 64 | + Optional 65 | 66 | See [additional options section](#additional-options) 67 | 68 | - **type** 69 | + String 70 | + Optional 71 | 72 | Specify a search mode to use. Available type is: `['imdb', 'tvdb', 'themoviedb', 'tvrage']`. If search type is provided, the search keyword is a specific id, for example, if you provide `imdb` search type, the keyword must be a `imdb` id. Eg: `search('tt0944947', null, 'imdb')`. 73 | 74 | #### Returns 75 | 76 | The api returns a promise which will resolve the search result. 77 | 78 | # Additional options 79 | 80 | Some of the apis support category filtering and sorting, and other options. All available options are: 81 | 82 | ```javascript 83 | const defaultParams = { 84 | category: null, 85 | limit: 25, 86 | sort: 'last', 87 | min_seeders: null, 88 | min_leechers: null, 89 | format: 'json_extended', 90 | ranked: null, 91 | } 92 | ``` 93 | 94 | ### category 95 | 96 | You can specify a category to filter the torrent. Category information can be imported by `require('./index').CATEGORY`. This options support an array. 97 | 98 | Eg: 99 | 100 | ```javascript 101 | const rarbgApi = require('./index') 102 | 103 | rarbgApi.list({ 104 | category: rarbgApi.CATEGORY.MOVIES 105 | }).then(data => console.log(data)) 106 | ``` 107 | 108 | The above example will list latest movie torrents. 109 | 110 | ## 4K Support 111 | ```javascript 112 | const rarbgApi = require('./index') 113 | 114 | rarbgApi.list({ 115 | category: rarbgApi.CATEGORY['4K'] 116 | }).then(data => console.log(data)) 117 | ``` 118 | 119 | The above example will list latest 4K movie torrents. 120 | 121 | 122 | ### limit 123 | 124 | Limit the result torrent's size. Default size is 25, all supported options are: **25, 50, 100** 125 | 126 | Eg: 127 | 128 | ```javascript 129 | const rarbgApi = require('./index') 130 | 131 | rarbgApi.list({ 132 | limit: 50 133 | }).then(data => console.log(data.length)) 134 | ``` 135 | 136 | ### sort 137 | 138 | Specify the sorting. Default sorting is `last`. Available options are: **last, seeders, leechers** 139 | 140 | Eg: 141 | 142 | ```javascript 143 | const rarbgApi = require('./index') 144 | 145 | rarbgApi.list({ 146 | sort: 'seeders' 147 | }).then(data => console.log(data)) 148 | ``` 149 | 150 | ### min_seeders, min_leechers 151 | 152 | Filtering the torrent by specify the torrent's minimal seeders or minimal leechers. It's value is a number. Default is `null`. 153 | 154 | Eg: 155 | 156 | ```javascript 157 | const rarbgApi = require('./index') 158 | rarbgApi.list({ 159 | min_seeders: 100 160 | }).then(data => console.log(data)) 161 | ``` 162 | 163 | ### format 164 | 165 | Specify which format will the api returns. Default is `json_extended`, which will include the detail infomations of each torrent. Other supported option is **json**. 166 | 167 | The `json_extended` format is: 168 | 169 | ```json 170 | { 171 | "title": "Logan.2017.1080p.WEB-DL.DD5.1.H264-FGT", 172 | "category": "Movies/x264/1080", 173 | "download": "magnet:?xt=urn:btih:d2d6a72b60cdb2cc5e80d3277d89d5df18c3ecbc&dn=Logan.2017.1080p.WEB-DL.DD5.1.H264-FGT&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce", 174 | "seeders": 848, 175 | "leechers": 116, 176 | "size": 5100226269, 177 | "pubdate": "2017-05-15 09:37:27 +0000", 178 | "episode_info": { 179 | "imdb": "tt3315342", 180 | "tvrage": null, 181 | "tvdb": null, 182 | "themoviedb": "263115" 183 | } 184 | } 185 | ``` 186 | 187 | 188 | The `json` format is: 189 | 190 | ```json 191 | { 192 | "filename": "Real.Time.With.Bill.Maher.2017.06.09.1080p.WEB.h264-TBS[rartv]", 193 | "category": "TV HD Episodes", 194 | "download": "magnet:?xt=urn:btih:f6afb0028270ccca6d4535be4c42a0583a5a5737&dn=Real.Time.With.Bill.Maher.2017.06.09.1080p.WEB.h264-TBS%5Brartv%5D&tr=http%3A%2F%2Ftracker.trackerfix.com%3A80%2Fannounce&tr=udp%3A%2F%2F9.rarbg.me%3A2710&tr=udp%3A%2F%2F9.rarbg.to%3A2710&tr=udp%3A%2F%2Fopen.demonii.com%3A1337%2Fannounce" 195 | } 196 | ``` 197 | 198 | 199 | ### ranked 200 | 201 | By default the api will return only ranked torrents ( internal ) , scene releases + -rarbg releases + -rartv releases. 202 | 203 | If you want other groups included in the results use the ranked parameter with a value of 0 to get them included. 204 | 205 | # Test 206 | 207 | Clone this project, and install the dependencies `npm i`, `npm run build` and run `npm run test` to see the test result. 208 | 209 | Note that sometimes the test will fail because of the network problem. Currently all the tests timeout is 60000ms, if your network is poor, you may encounter test timeout error. 210 | 211 | # Limitation 212 | 213 | Due to the rarbg api's limitation, you may encounter error like: 214 | 215 | ```json 216 | { 217 | "error": "Too many requests per second. Maximum requests allowed are 1req/2sec Please try again later!", 218 | "error_code": 5 219 | } 220 | ``` 221 | 222 | The api is limit to 1req/2sec, so you should control the frequency. 223 | --------------------------------------------------------------------------------