├── .jshintrc ├── index.js ├── bin └── torrentflix ├── .gitignore ├── .dockerignore ├── .travis.yml ├── Dockerfile ├── lang.js ├── LICENSE.txt ├── package.json ├── lib ├── torrent_search.js ├── torrent_parse.js ├── subtitles.js ├── nyaa.js ├── xbit.js ├── 1337x.js ├── thepiratebay.js ├── kickass.js ├── eztv.js ├── limetorrents.js ├── yts.js ├── skytorrents.js ├── zooqle.js ├── tokyotosho.js ├── rarbg.js ├── cli.js ├── trakt.js └── main.js └── README.md /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "esversion": 6 3 | } 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./lib/cli.js'); -------------------------------------------------------------------------------- /bin/torrentflix: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('../lib/cli.js'); 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | history.json 3 | .idea 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | history.json 3 | .idea 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | 5 | node_js: 6 | - '8' 7 | 8 | cache: 9 | directories: 10 | - node_modules 11 | install: 12 | - npm install -g jshint 13 | - npm install -g npm@latest 14 | - npm install 15 | 16 | script: 17 | - 'jshint lib/' 18 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:8.9.3-alpine as build 2 | RUN mkdir -p /usr/src/app 3 | WORKDIR /usr/src/app 4 | 5 | ARG NODE_ENV 6 | ENV NODE_ENV $NODE_ENV 7 | COPY package.json /usr/src/app/ 8 | RUN apk add --no-cache python alpine-sdk && \ 9 | yarn install --ignore-engines 10 | COPY . /usr/src/app 11 | 12 | FROM node:8.9.3-alpine as app 13 | COPY --from=build /usr/src/app /usr/src/app 14 | ENTRYPOINT [ "/usr/src/app/bin/torrentflix" ] 15 | -------------------------------------------------------------------------------- /lang.js: -------------------------------------------------------------------------------- 1 | var en_torrent_site = "Select what torrent site you want to search: "; 2 | var en_torrent_site_num = "Torrent site to use (eg. k, l, e..) "; 3 | var en_search_torrent = "Search for a torrent: "; 4 | var en_select_torrent = "Torrent to stream (eg. 1, 2, 3..) or (b)ack or (e)xit: "; 5 | var en_select_file = "Select file in torrent to stream (eg. 1, 2, 3..) or (b)ack or (e)xit: "; 6 | var en_site_error = "You didn't select a correct site, Try again!"; 7 | 8 | var data_content = {}; 9 | var lang_content = []; 10 | 11 | 12 | module.exports = { 13 | getEn: function() { 14 | data_content = { 15 | torrent_site: en_torrent_site, 16 | torrent_site_num: en_torrent_site_num, 17 | search_torrent: en_search_torrent, 18 | select_torrent: en_select_torrent, 19 | select_file: en_select_file, 20 | site_error: en_site_error 21 | }; 22 | 23 | lang_content.push(data_content); 24 | 25 | return lang_content; 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 2 | 3 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 4 | 5 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "torrentflix", 3 | "description": "CLI to search torrent sites and stream with peerflix.", 4 | "version": "9.0.7", 5 | "homepage": "https://github.com/ItzBlitz98/torrentflix", 6 | "author": { 7 | "name": "ItzBlitz98" 8 | }, 9 | "contributors": { 10 | "name": "watchfulwisp " 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "https://github.com/ItzBlitz98/torrentflix.git" 15 | }, 16 | "bugs": { 17 | "url": "https://github.com/ItzBlitz98/torrentflix/issues" 18 | }, 19 | "licenses": [ 20 | { 21 | "type": "MIT" 22 | } 23 | ], 24 | "bin": { 25 | "torrentflix": "bin/torrentflix" 26 | }, 27 | "engines": { 28 | "node": ">= 0.8.0" 29 | }, 30 | "scripts": {}, 31 | "preferGlobal": true, 32 | "dependencies": { 33 | "async": "3.2.0", 34 | "chalk": "4.0.0", 35 | "cheerio": "^1.0.0-rc.10", 36 | "child": "0.0.3", 37 | "commander": "5.0.0", 38 | "configstore": "5.0.1", 39 | "display-image": "^1.1.0", 40 | "inquirer": "7.1.0", 41 | "moment": "^2.24.0", 42 | "moviedb": "^0.2.10", 43 | "open": "7.0.3", 44 | "promise": "^8.1.0", 45 | "q": "^2.0.3", 46 | "read-torrent": "^1.3.1", 47 | "readline": "^1.3.0", 48 | "request": "^2.88.2", 49 | "spawn-cmd": "^0.0.2", 50 | "subtitler": "^2.7.0", 51 | "torrent-name-parser": "^0.6.5", 52 | "torrent_project_api": "^0.0.4", 53 | "trakt.tv": "^8.1.1" 54 | }, 55 | "devDependencies": {}, 56 | "keywords": [] 57 | } 58 | -------------------------------------------------------------------------------- /lib/torrent_search.js: -------------------------------------------------------------------------------- 1 | var request = require("request"); 2 | var cheerio = require('cheerio'); 3 | var Q = require('q'); 4 | var url = require("url"); 5 | 6 | module.exports = { 7 | torrentSearch: function(torrent_site) { 8 | 9 | var deferred = Q.defer(); 10 | var theJar = request.jar(); 11 | var options = { 12 | url: torrent_site, 13 | headers: { 14 | 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2272.43 Safari/537.36' 15 | } 16 | }; 17 | 18 | 19 | request(options, function(err, response, body){ 20 | 21 | if(!err && response.statusCode === 200){ 22 | 23 | $ = cheerio.load(body); 24 | 25 | links = $(body).find('a'); 26 | 27 | var magnet_link, torrent_link; 28 | $(links).each(function(i, link){ 29 | 30 | var torrentLink = $(link).attr('href'); 31 | 32 | if(torrentLink){ 33 | if(torrentLink.indexOf("magnet:?xt=urn:btih:") > -1) { 34 | magnet_link = $(link).attr('href'); 35 | deferred.resolve(magnet_link); 36 | } 37 | else if(torrentLink.match(/\.torrent$/)) { 38 | torrent_link = $(link).attr('href'); 39 | deferred.resolve(url.resolve(torrent_site, torrent_link)); 40 | } 41 | } 42 | }); 43 | 44 | if(!magnet_link && !torrent_link) { 45 | deferred.reject("No torrent found on the page"); 46 | } 47 | 48 | 49 | } else { 50 | deferred.reject("There was a problem fetching the torrent link"); 51 | } 52 | 53 | }); 54 | 55 | return deferred.promise; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /lib/torrent_parse.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var readTorrent = require('read-torrent'); 3 | 4 | 5 | module.exports = { 6 | parseTorrent: function(torrent) { 7 | 8 | var deferred = Q.defer(); 9 | var torrent_count = 0; 10 | var data_content = {}; 11 | var torrent_content = []; 12 | 13 | //dont bother checking if magnet link 14 | if(torrent.indexOf("magnet:?xt=urn:") > -1) { 15 | //we can't check magnet links for multiple files so skip 16 | deferred.resolve(false); 17 | } else { 18 | readTorrent(torrent,function(err, torrent) { 19 | 20 | if(torrent && typeof torrent.files !== undefined){ 21 | torrent.files.forEach(function(torrent_files) { 22 | 23 | torrent_content.push(torrent_files.name); 24 | 25 | var StreamFormats = ['.mp4','.mkv', '.avi'], 26 | length = StreamFormats.length; 27 | while(length--) { 28 | 29 | //figure out how many streamable files there are 30 | if (torrent_files.name.indexOf(StreamFormats[length])!=-1) { 31 | if (torrent_files.name.indexOf("sample") == -1) { 32 | torrent_count++; 33 | } 34 | } 35 | 36 | } 37 | 38 | }); 39 | } else { 40 | //single file torrent 41 | deferred.resolve(false); 42 | } 43 | 44 | if(torrent_count > 1){ 45 | //more than one streamable files 46 | deferred.resolve(torrent_content); 47 | } else { 48 | //single file torrent 49 | deferred.resolve(false); 50 | } 51 | 52 | }); 53 | } 54 | return deferred.promise; 55 | 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /lib/subtitles.js: -------------------------------------------------------------------------------- 1 | var opensubtitles = require("subtitler"); 2 | var Q = require('q'); 3 | var os = require('os'); 4 | var fs = require('fs'); 5 | var http = require('http'); 6 | var chalk = require('chalk'); 7 | 8 | module.exports = { 9 | fetchSub: function(subtitle_language, torrent_title) { 10 | 11 | console.log(chalk.green("Searching for subtitles.")); 12 | 13 | var deferred = Q.defer(); 14 | 15 | opensubtitles.api.login() 16 | .then(function(token){ 17 | opensubtitles.api.searchForTitle(token, subtitle_language, torrent_title) 18 | .then( 19 | function(results){ 20 | if (typeof results[0] != "undefined") { 21 | console.log(chalk.green("Subtitles found!")); 22 | console.log(chalk.green("Downloading...")); 23 | 24 | //download file 25 | var url = results[0].SubDownloadLink.split('.gz').join('.srt'); 26 | var dest = os.tmpdir() + "/sub.srt"; 27 | var cb; 28 | 29 | var download = function(url, dest, cb) { 30 | var file = fs.createWriteStream(dest); 31 | var request = http.get(url, function(response) { 32 | response.pipe(file); 33 | file.on('finish', function() { 34 | file.close(cb); 35 | console.log(chalk.green("Subtitles downloaded.")); 36 | peerflix_subtitle = dest; 37 | deferred.resolve(peerflix_subtitle); 38 | }); 39 | }); 40 | }; 41 | 42 | download(url, dest, cb); 43 | 44 | } else { 45 | console.log(chalk.red("No subtitles found :( Sorry.")); 46 | deferred.resolve(false); 47 | } 48 | } 49 | ); 50 | }); 51 | 52 | return deferred.promise; 53 | 54 | } 55 | }; 56 | -------------------------------------------------------------------------------- /lib/nyaa.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | 5 | module.exports = { 6 | search: function(query, nyaa_url, cat, page, limit) { 7 | //http://www.nyaa.se/?page=search&term=Absolute+Duo&sort=2 8 | var torrent_search = query; 9 | var search_query = torrent_search.split(' ').join('+'); 10 | 11 | var search_url = nyaa_url + "/?page=search&term=" + search_query + "&sort=2"; 12 | 13 | var count = 1; 14 | var deferred = Q.defer(); 15 | var data_content = {}; 16 | var torrent_content = []; 17 | 18 | request(search_url, function(err, response, body){ 19 | 20 | if(!err && response.statusCode === 200){ 21 | 22 | $ = cheerio.load(body); 23 | 24 | $('table.torrent-list tr').slice(1).each(function () { 25 | 26 | const _getChild = (ctx, nb) => { 27 | return $(ctx).find(`td:nth-child(${nb})`); 28 | }; 29 | 30 | var title = _getChild(this, 2).find('a:not(.comments)').text().trim(); 31 | var seeds = _getChild(this, 6).text(); 32 | var leechs = _getChild(this, 7).text(); 33 | var size = _getChild(this, 4).text(); 34 | var torrent_link = nyaa_url + _getChild(this, 3).find('a:nth-child(1)').attr('href'); 35 | var date_added = _getChild(this, 5).text(); 36 | 37 | data_content = { 38 | torrent_num: count, 39 | title: title, 40 | category: "", 41 | seeds: seeds, 42 | leechs: leechs, 43 | size: size, 44 | torrent_link: torrent_link, 45 | date_added: date_added 46 | }; 47 | 48 | torrent_content.push(data_content); 49 | 50 | deferred.resolve(torrent_content); 51 | // like break 52 | if (++count > limit) { return false; } 53 | }); 54 | 55 | } else { 56 | deferred.reject("There was a problem loading Nyaa"); 57 | } 58 | 59 | 60 | }); 61 | 62 | return deferred.promise; 63 | 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /lib/xbit.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | var moment = require('moment'); 5 | 6 | module.exports = { 7 | search: function(query, xbit_url, cat, page, limit) { 8 | 9 | var torrent_search = query; 10 | var search_query = torrent_search.split(' ').join('+'); 11 | 12 | var count = 1; 13 | var deferred = Q.defer(); 14 | var data_content = {}; 15 | var torrent_content = []; 16 | 17 | //get token 18 | var url = xbit_url + "/api?search=" + encodeURIComponent(query); 19 | request(url, function (err, response, body) { 20 | if (!err && response.statusCode === 200) { 21 | 22 | data = JSON.parse(body); 23 | 24 | if(data.dht_results.length > 1){ 25 | 26 | for(var torrent in data.dht_results){ 27 | 28 | var title = data.dht_results[torrent].NAME; 29 | var torrent_link = data.dht_results[torrent].MAGNET; 30 | var size = data.dht_results[torrent].SIZE; 31 | var date_added = data.dht_results[torrent].DISCOVERED; 32 | //not supported 33 | var seeds = ""; 34 | var leechs = ""; 35 | 36 | data_content = { 37 | torrent_num: count, 38 | title: title, 39 | category: "", 40 | seeds: seeds, 41 | leechs: leechs, 42 | size: size, 43 | torrent_link: torrent_link, 44 | date_added: date_added 45 | }; 46 | 47 | if (title) { 48 | torrent_content.push(data_content); 49 | } 50 | 51 | 52 | deferred.resolve(torrent_content); 53 | // like break 54 | if (++count > limit) { return false; } 55 | 56 | } 57 | }else { 58 | deferred.reject("No torrents found"); 59 | } 60 | 61 | } else { 62 | deferred.reject("There was a problem loading x[BiT]"); 63 | } 64 | }); 65 | 66 | return deferred.promise; 67 | 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /lib/1337x.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | var moment = require('moment'); 5 | 6 | module.exports = { 7 | search: function(query, leetx_url, cat, page, limit) { 8 | 9 | var torrent_search = query; 10 | var search_query = torrent_search.split(' ').join('+'); 11 | var search_url = leetx_url + "/search/" + search_query + "/1/"; 12 | var count = 1; 13 | var deferred = Q.defer(); 14 | var data_content = {}; 15 | var torrent_content = []; 16 | 17 | request(search_url, function(err, response, body){ 18 | 19 | if(!err && response.statusCode === 200){ 20 | 21 | var leetx_link, torrent_title, torrent_size, torrent_seeds, torrent_leech, date_added; 22 | 23 | $ = cheerio.load(body); 24 | 25 | if($('.table-list tbody').length > 0){ 26 | $('.table-list tbody tr').each(function(index, torrents) { 27 | 28 | var torrent_site = $(torrents).find('.name a').next().attr('href'); 29 | var title = $(torrents).find('.name').text(); 30 | var seeds = $(torrents).find('.seeds').text(); 31 | var leechs = $(torrents).find('.leeches').text(); 32 | var size = $(torrents).find('td.coll-4').text(); 33 | var date_added = $(torrents).find('.coll-date').text(); 34 | 35 | data_content = { 36 | torrent_num: count, 37 | title: title, 38 | category: "", 39 | seeds: seeds, 40 | leechs: leechs, 41 | size: size, 42 | torrent_site: leetx_url + torrent_site, 43 | date_added: date_added 44 | }; 45 | 46 | torrent_content.push(data_content); 47 | 48 | deferred.resolve(torrent_content); 49 | // like break 50 | if (++count > limit) { return false; } 51 | 52 | }); 53 | } else { 54 | deferred.reject("No torrents found"); 55 | } 56 | 57 | } else { 58 | deferred.reject("There was a problem loading 1337x"); 59 | } 60 | 61 | }); 62 | 63 | return deferred.promise; 64 | 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Torrentflix [![Travis](https://api.travis-ci.org/ItzBlitz98/torrentflix.svg?branch=master)](https://travis-ci.org/ItzBlitz98/torrentflix) 2 | 3 | A cli tool for searching torrent sites and streaming using peerflix. 4 | 5 | It currently supports kickasstorrents, 1337x, seedpeer, Rarbg, The Pirate Bay, YTS, Extratorrent, Limetorrents, nyaa.se, tokyotosho, Cpasbien & eztv. 6 | 7 | Want more ? Create an issue with a request, Alternatively you can contribute your own scrapers. 8 | 9 | Pull requests are welcome. 10 | 11 | ## Key features 12 | 13 | * Subtitles fetched automatically. 14 | * Trakt.tv integration. 15 | * History of streamed torrents. 16 | * Stream or download torrents. 17 | 18 | ## Install (automatic) 19 | Install peerflix if you haven't already: 20 | 21 | ``` 22 | npm install -g peerflix 23 | ``` 24 | 25 | Then install torrentflix: 26 | 27 | ``` 28 | npm install -g torrentflix 29 | ``` 30 | 31 | ## Install (manual) 32 | Install peerflix if you haven't already: 33 | 34 | ``` 35 | npm install -g peerflix 36 | ``` 37 | 38 | Clone the repository: 39 | 40 | ``` 41 | git clone git@github.com:ItzBlitz98/torrentflix.git 42 | ``` 43 | 44 | Install dependencies: 45 | 46 | ``` 47 | npm install 48 | ``` 49 | 50 | You can now update by doing a git pull: 51 | 52 | ``` 53 | git pull 54 | ``` 55 | 56 | Now you can run the executable inside the bin folder. 57 | 58 | ## Preview 59 | ![peerflix](https://i.imgur.com/rre0MtK.png) 60 | 61 | ## Usage 62 | To run the app run: 63 | ``` 64 | $ torrentflix 65 | ``` 66 | 67 | ## Cli arguments 68 | 69 | Torrentflix has some handy cli arguements you can see them using the help flag. 70 | ``` 71 | $ torrentflix --help 72 | ``` 73 | 74 | ## History 75 | Torrentflix can save a history of watched torrents if enabled. 76 | 77 | Clearing the history can be done with the --clear flag ex: 78 | ``` 79 | $ torrentflix --clear 80 | ``` 81 | 82 | ## Subtitles 83 | By default subtitles are disabled but you can enable them by running `torrentflix --config=nano` and setting *use_subtitle* to true. You can also change *subtitle_language* to one of [this list](https://github.com/divhide/node-subtitler/blob/master/langs.dump.txt), just be sure to use the three letter code. 84 | 85 | 86 | ## License 87 | 88 | MIT 89 | -------------------------------------------------------------------------------- /lib/thepiratebay.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | 5 | module.exports = { 6 | search: function(query, thepiratebay_url, cat, page, limit) { 7 | 8 | var torrent_search = query; 9 | var search_query = torrent_search.split(' ').join('%20'); 10 | 11 | //use thepiratebay api https://apibay.org/q.php?q= 12 | var search_url = thepiratebay_url + "/q.php?q=" + search_query; 13 | var count = 1; 14 | var deferred = Q.defer(); 15 | var data_content = {}; 16 | var torrent_content = []; 17 | var link_content = []; 18 | 19 | request(search_url, function(err, response, body){ 20 | 21 | if(!err && response.statusCode === 200){ 22 | 23 | data = JSON.parse(body); 24 | 25 | if(data[0].id){ 26 | for(var torrent in data){ 27 | var torrent_title = data[torrent].name; 28 | var seeds = data[torrent].seeders; 29 | var leechs = data[torrent].leechers; 30 | var size = bytesToSize(data[torrent].size); 31 | var torrent_link = "magnet:?xt=urn:btih:" + data[torrent].info_hash; 32 | var date_added = ""; 33 | //var date_added = data[torrent].added; 34 | 35 | data_content = { 36 | torrent_num: count, 37 | title: torrent_title, 38 | seeds: seeds, 39 | leechs: leechs, 40 | size: size, 41 | torrent_link: torrent_link, 42 | date_added: date_added 43 | }; 44 | 45 | torrent_content.push(data_content); 46 | 47 | deferred.resolve(torrent_content); 48 | // like break 49 | if (++count > limit) { return false; } 50 | 51 | } 52 | 53 | } else { 54 | deferred.reject("No torrents found"); 55 | } 56 | 57 | } else { 58 | deferred.reject("There was a problem loading The Pirate Bay"); 59 | } 60 | 61 | 62 | }); 63 | 64 | return deferred.promise; 65 | 66 | } 67 | }; 68 | 69 | function bytesToSize(bytes) { 70 | var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; 71 | if (bytes === 0) return '0 Byte'; 72 | var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); 73 | return Math.round(bytes / Math.pow(1024, i), 2) + '' + sizes[i]; 74 | } 75 | -------------------------------------------------------------------------------- /lib/kickass.js: -------------------------------------------------------------------------------- 1 | var Q = require("q"); 2 | var request = require("request"); 3 | var cheerio = require("cheerio"); 4 | 5 | module.exports = { 6 | search: function(query, kickass_url, cat, page, limit) { 7 | var count = 1; 8 | var deferred = Q.defer(); 9 | var data_content = {}; 10 | var torrent_content = []; 11 | var torrent_verified; 12 | var search_url = kickass_url + '/usearch/torrents-search.php?q=' + encodeURIComponent(query); 13 | request.get({ 14 | url: search_url, 15 | json: true, 16 | headers: {'User-Agent': 'request'} 17 | }, function(err, response, body){ 18 | 19 | if(!err && response.statusCode === 200){ 20 | 21 | $ = cheerio.load(body); 22 | 23 | if($(".torrents_table__torrent_name").length > 2){ 24 | $("tr").each(function(index, torrents){ 25 | torrent_title = $(torrents).find(".torrents_table__torrent_title").text().trim(); 26 | if (torrent_title) { 27 | torrent_link = $(torrents).find(".torrents_table__actions").find("a.button--small").next().next().attr("href"); 28 | torrent_size = $(torrents).find("td.text--center").eq(0).text(); 29 | torrent_seeders = $(torrents).find("td.text--center").eq(3).text(); 30 | torrent_leechers = $(torrents).find("td.text--center").eq(4).text(); 31 | date_added = $(torrents).find("td.text--center").eq(2).text(); 32 | 33 | data_content = { 34 | torrent_num: count, 35 | title: torrent_title, 36 | category: "", 37 | seeds: torrent_seeders, 38 | leechs: torrent_leechers, 39 | size: torrent_size, 40 | torrent_link: torrent_link, 41 | date_added: date_added 42 | }; 43 | 44 | torrent_content.push(data_content); 45 | 46 | deferred.resolve(torrent_content); 47 | // like break 48 | if (++count > limit) { return false; } 49 | } 50 | }); 51 | } else { 52 | deferred.reject("No torrents found"); 53 | } 54 | } else { 55 | deferred.reject("There was a problem loading KickassTorrents"); 56 | } 57 | //end of request 58 | }); 59 | 60 | return deferred.promise; 61 | 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /lib/eztv.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | var moment = require('moment'); 5 | var util = require('util'); 6 | var fs = require('fs'); 7 | 8 | module.exports = { 9 | search: function(query, eztv_url, cat, page, limit) { 10 | 11 | var torrent_search = query; 12 | var search_query = torrent_search.split(' ').join('-'); 13 | var search_url = eztv_url + "/search/" + search_query; 14 | var count = 1; 15 | var deferred = Q.defer(); 16 | var data_content = {}; 17 | var torrent_content = []; 18 | 19 | request({ url: search_url, headers:{ "User-Agent": "request"}}, function(err, response, body){ 20 | 21 | try { 22 | 23 | if(!err && response.statusCode === 200){ 24 | 25 | var eztv_link, torrent_title, torrent_size, torrent_seeds, torrent_leech, date_added; 26 | $ = cheerio.load(body); 27 | if($("tr.forum_header_border").length > 0) { 28 | 29 | $("tr.forum_header_border").each(function(index, torrent){ 30 | eztv_link = $(torrent).find("a.magnet").attr('href'); 31 | torrent_title = $(torrent).find("a.epinfo").text(); 32 | torrent_size = $(torrent).find("a.epinfo").attr("title").match(/\([^)]+\)$/)[0].slice(1,-1); 33 | torrent_seeds = $("td.forum_thread_post_end", torrent).prev().text(); 34 | torrent_leech = ""; 35 | date_added = $("td.forum_thread_post_end", torrent).prev().prev().text(); 36 | 37 | data_content = { 38 | torrent_num: count, 39 | title: torrent_title, 40 | category: "", 41 | seeds: torrent_seeds, 42 | leechs: torrent_leech, 43 | size: torrent_size, 44 | torrent_link: eztv_link, 45 | date_added: date_added 46 | }; 47 | 48 | torrent_content.push(data_content); 49 | 50 | deferred.resolve(torrent_content); 51 | // like break 52 | if (++count > limit) { return false; } 53 | }); 54 | 55 | } else { 56 | deferred.reject("No torrents found"); 57 | } 58 | 59 | } else { 60 | deferred.reject("There was a problem loading Eztv"); 61 | } 62 | 63 | } catch(e) { 64 | deferred.reject(e.toString()); 65 | } 66 | 67 | }); 68 | 69 | return deferred.promise; 70 | 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /lib/limetorrents.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | 5 | module.exports = { 6 | search: function(query, limetorrents_url, cat, page, limit) { 7 | 8 | if(!cat){ 9 | cat = "all"; 10 | } 11 | 12 | var torrent_search = query; 13 | var search_query = torrent_search.split(' ').join('-'); 14 | 15 | var search_url = limetorrents_url + "/search/" + cat + "/" + search_query + "/seeds/" + page + "/"; 16 | 17 | var count = 1; 18 | var deferred = Q.defer(); 19 | var data_content = {}; 20 | var torrent_content = []; 21 | 22 | request(search_url, function(err, response, body){ 23 | 24 | if(!err && response.statusCode === 200){ 25 | 26 | $ = cheerio.load(body); 27 | if($('.table2 tr').length > 4){ 28 | $('.table2 tr').each(function(index, torrents){ 29 | 30 | if($(torrents).find('.tt-name a.csprite_dl14').attr('href')){ 31 | 32 | find_torrent_title = $(torrents).find('.tt-name a'); 33 | find_torrent_size = $(torrents).find('td.tdnormal'); 34 | find_torrent_seeders = $(torrents).find('td.tdseed'); 35 | find_torrent_leechers = $(torrents).find('td.tdleech'); 36 | find_date_added = $(torrents).find('td.tdnormal'); 37 | 38 | torrent_name = find_torrent_title.text(); 39 | torrent_size = find_torrent_size.next().first().text(); 40 | torrent_seed = find_torrent_seeders.text(); 41 | torrent_leech = find_torrent_leechers.text(); 42 | date_added = find_date_added.first().text().split(' -')[0]; 43 | 44 | var torrent_site = $(torrents).find('.tt-name a').next().attr('href'); 45 | 46 | data_content = { 47 | torrent_num: count, 48 | title: torrent_name, 49 | category: "", 50 | seeds: torrent_seed, 51 | leechs: torrent_leech, 52 | size: torrent_size, 53 | torrent_site: limetorrents_url + torrent_site, 54 | date_added: date_added 55 | }; 56 | 57 | torrent_content.push(data_content); 58 | 59 | deferred.resolve(torrent_content); 60 | // like break 61 | if (++count > limit) { return false; } 62 | } 63 | 64 | }); 65 | } else{ 66 | deferred.reject("No torrents found"); 67 | } 68 | } else { 69 | deferred.reject("There was a problem loading Limetorrents"); 70 | } 71 | 72 | }); 73 | 74 | return deferred.promise; 75 | 76 | } 77 | }; 78 | -------------------------------------------------------------------------------- /lib/yts.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var moment = require('moment'); 4 | 5 | module.exports = { 6 | search: function(query, yts_url, cat, page, limit) { 7 | var count = 1; 8 | var deferred = Q.defer(); 9 | var data_content = {}; 10 | var torrent_content = []; 11 | //https://yify.unblocked.pw/api/v2/list_movies.json?query_term=guardians&sort=seeds&order=desc&set=1 12 | //var search_url = yts_url + '/json.php?q=' + encodeURIComponent(query) + '&field=seeders&order=desc&page=' + page; 13 | var search_url = yts_url + '/api/v2/list_movies.json?query_term=' + encodeURIComponent(query) + '&sort=seeds&order=desc&set=1'; 14 | 15 | request(search_url, function(err, response, body){ 16 | 17 | if(!err && response.statusCode === 200){ 18 | 19 | data = JSON.parse(body); 20 | 21 | //console.log(data.data.movie_count); 22 | 23 | if(data.data.movie_count > 0){ 24 | 25 | for(var torrent in data.data.movies){ 26 | 27 | var title = data.data.movies[torrent].title_long; 28 | 29 | for(var torrents in data.data.movies[torrent].torrents){ 30 | 31 | var torrent_quality = data.data.movies[torrent].torrents[torrents].quality; 32 | var torrent_title = title + ' ' + torrent_quality; 33 | var seeds = data.data.movies[torrent].torrents[torrents].seeds; 34 | var leechs = data.data.movies[torrent].torrents[torrents].peers; 35 | //var torrent_link = data.data.movies[torrent].torrents[torrents].url; 36 | var hash = data.data.movies[torrent].torrents[torrents].hash; 37 | var torrent_link = yts_url + "/torrent/download/" + hash; 38 | var size = data.data.movies[torrent].torrents[torrents].size; 39 | var date_added = moment(Date.parse(data.data.movies[torrent].torrents[torrents].date_uploaded.split(' ')[0])).fromNow(); 40 | 41 | data_content = { 42 | torrent_num: count, 43 | title: torrent_title, 44 | seeds: seeds, 45 | leechs: leechs, 46 | size: size, 47 | torrent_link: torrent_link, 48 | date_added: date_added 49 | }; 50 | 51 | torrent_content.push(data_content); 52 | 53 | deferred.resolve(torrent_content); 54 | // like break 55 | if (++count > limit) { return false; } 56 | 57 | 58 | } 59 | 60 | } 61 | 62 | } else { 63 | deferred.reject("No torrents found"); 64 | } 65 | 66 | } else { 67 | deferred.reject("There was a problem loading YTS"); 68 | } 69 | 70 | }); 71 | 72 | return deferred.promise; 73 | 74 | } 75 | }; 76 | -------------------------------------------------------------------------------- /lib/skytorrents.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | 5 | module.exports = { 6 | search: function(query, skytorrents_url, cat, page, limit) { 7 | 8 | var torrent_search = query; 9 | var search_query = torrent_search.split(' ').join('+'); 10 | 11 | var search_url = skytorrents_url + "/?query=" + encodeURIComponent(search_query); 12 | var count = 1; 13 | var deferred = Q.defer(); 14 | var data_content = {}; 15 | var torrent_content = []; 16 | var link_content = []; 17 | 18 | request(search_url, function(err, response, body){ 19 | 20 | if(!err && response.statusCode === 200){ 21 | 22 | $ = cheerio.load(body); 23 | 24 | if($('table.table.is-striped.is-narrow tr').length > 0) { 25 | 26 | $('table.table.is-striped.is-narrow tr').each(function(index, torrents){ 27 | var torrent_title, torrent_link, torrent_verified; 28 | 29 | if($(torrents).find('a').text()){ 30 | find_torrent_title = $(torrents).find('td a'); 31 | find_torrent_seed = $(torrents).find('td').next().next().next().next(); 32 | find_torrent_leech = $(torrents).find('td').next().next().next().next().next(); 33 | find_torrent_size = $(torrents).find('td.is-hidden-touch'); 34 | find_torrent_date = $(torrents).find('td.is-hidden-touch').next().next(); 35 | 36 | torrent_title = find_torrent_title.first().text(); 37 | torrent_leech = find_torrent_leech.first().text(); 38 | torrent_seed = find_torrent_seed.first().text(); 39 | torrent_size = find_torrent_size.first().text(); 40 | date_added = find_torrent_date.first().text(); 41 | 42 | links = $(torrents).find('td a'); 43 | 44 | $(links).each(function(i, link){ 45 | 46 | if($(link).attr('href').indexOf("magnet:?xt=urn:") > -1) { 47 | torrent_link = $(link).attr('href'); 48 | } 49 | 50 | }); 51 | 52 | data_content = { 53 | torrent_num: count, 54 | title: torrent_title, 55 | category: "", 56 | seeds: torrent_seed, 57 | leechs: torrent_leech, 58 | size: torrent_size, 59 | torrent_link: torrent_link, 60 | date_added: date_added 61 | }; 62 | 63 | torrent_content.push(data_content); 64 | deferred.resolve(torrent_content); 65 | // like break 66 | if (++count > limit) { return false; } 67 | 68 | } 69 | 70 | }); 71 | 72 | } else { 73 | deferred.reject("No torrents found"); 74 | } 75 | } else { 76 | deferred.reject("There was a problem loading Sky Torrents"); 77 | } 78 | 79 | 80 | }); 81 | 82 | return deferred.promise; 83 | 84 | } 85 | }; 86 | -------------------------------------------------------------------------------- /lib/zooqle.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | 5 | module.exports = { 6 | search: function(query, zooqle_url, cat, page, limit) { 7 | var count = 1; 8 | var deferred = Q.defer(); 9 | var data_content = {}; 10 | var torrent_content = []; 11 | var torrent_verified; 12 | var search_url = zooqle_url + '/search?q=' + encodeURIComponent(query) + '&s=ns&v=t&sd=d'; 13 | 14 | var options = { 15 | url: search_url, 16 | headers: { 17 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.79 Safari/537.36' 18 | } 19 | }; 20 | 21 | 22 | request(options, function(err, response, body){ 23 | 24 | if(!err && response.statusCode === 200){ 25 | 26 | $ = cheerio.load(body); 27 | 28 | // console.log(body); 29 | if($('table.table-torrents tr').length > 2){ 30 | $('table.table-torrents tr').each(function(index, torrents){ 31 | var torrent_link; 32 | 33 | find_torrent_title = $(torrents).find('a.small'); 34 | find_torrent_size = $(torrents).find('div.prog-blue'); 35 | find_torrent_seeders = $(torrents).find('div.prog-green'); 36 | find_torrent_leechers = $(torrents).find('div.prog-yellow'); 37 | find_date_added = $(torrents).find('td.text-nowrap.text-muted.smaller'); 38 | 39 | links = $(torrents).find('a'); 40 | $(links).each(function(i, link){ 41 | 42 | if($(link).attr('href').indexOf("magnet:?xt=urn:") > -1 && $(link).attr('href') !== null) { 43 | torrent_link = $(link).attr('href'); 44 | } 45 | 46 | }); 47 | 48 | torrent_title = find_torrent_title.text(); 49 | torrent_size = find_torrent_size.text(); 50 | torrent_seed = find_torrent_seeders.text(); 51 | torrent_leech = find_torrent_leechers.text(); 52 | date_added = find_date_added.text(); 53 | 54 | data_content = { 55 | torrent_num: count, 56 | title: torrent_title, 57 | category: '', 58 | seeds: torrent_seed, 59 | leechs: torrent_leech, 60 | size: torrent_size, 61 | torrent_link: torrent_link, 62 | date_added: date_added 63 | }; 64 | 65 | if(torrent_title){ 66 | torrent_content.push(data_content); 67 | } 68 | 69 | 70 | deferred.resolve(torrent_content); 71 | // like break 72 | if (++count > limit) { return false; } 73 | }); 74 | } else { 75 | deferred.reject("No torrents found"); 76 | } 77 | } else { 78 | deferred.reject("There was a problem loading Zooqle"); 79 | } 80 | 81 | }); 82 | 83 | return deferred.promise; 84 | 85 | } 86 | }; 87 | -------------------------------------------------------------------------------- /lib/tokyotosho.js: -------------------------------------------------------------------------------- 1 | var Q = require('q'); 2 | var request = require("request"); 3 | var cheerio = require('cheerio'); 4 | var moment = require('moment'); 5 | 6 | module.exports = { 7 | search: function(query, tokyotosho_url, cat, page, limit) { 8 | //http://www.nyaa.se/?page=search&term=Absolute+Duo&sort=2 9 | var torrent_search = query; 10 | var search_query = torrent_search.split(' ').join('+'); 11 | 12 | var search_url = tokyotosho_url + "/search.php?terms=" + search_query + "&type=0&size_min=&size_max=&username="; 13 | 14 | var count = 1; 15 | var deferred = Q.defer(); 16 | var data_content = {}; 17 | var torrent_content = []; 18 | 19 | request(search_url, function(err, response, body){ 20 | 21 | if(!err && response.statusCode === 200){ 22 | 23 | $ = cheerio.load(body); 24 | 25 | if($('.listing').find('tr').length > "0"){ 26 | $('.listing tr').each(function(index, torrents){ 27 | 28 | if($(torrents).find('.desc-top a').next().attr('href')){ 29 | find_torrent_link = $(torrents).find('.desc-top a'); 30 | find_torrent_title = $(torrents).find('td.desc-top a'); 31 | find_torrent_seed = $(torrents).next().find('td.stats'); 32 | find_torrent_size = $(torrents).next().find('td.desc-bot').text(); 33 | 34 | torrent_link = find_torrent_link.next().attr('href'); 35 | torrent_title = find_torrent_title.text(); 36 | torrent_seed = find_torrent_seed.find('span').first().text(); 37 | torrent_leech = find_torrent_seed.find('span').first().next().text(); 38 | 39 | var regExp = /\Size: ([^)]+) \Date:/; 40 | var matches = regExp.exec(find_torrent_size); 41 | var size = matches[0].split(' | Date:').join('').split('Size: ').join(''); 42 | torrent_size = size; 43 | 44 | var regExp2 = /\Date: ([^)]+) \UTC/; 45 | var matches2 = regExp2.exec(find_torrent_size); 46 | var date_added = moment(Date.parse(matches2[1] + " UTC")).fromNow(); 47 | 48 | data_content = { 49 | torrent_num: count, 50 | title: torrent_title, 51 | category: "", 52 | seeds: torrent_seed, 53 | leechs: torrent_leech, 54 | size: torrent_size, 55 | torrent_link: torrent_link, 56 | date_added: date_added 57 | }; 58 | 59 | torrent_content.push(data_content); 60 | 61 | deferred.resolve(torrent_content); 62 | // like break 63 | if (++count > limit) { return false; } 64 | 65 | } 66 | 67 | }); 68 | } else { 69 | deferred.reject("No torrents found"); 70 | } 71 | } else { 72 | deferred.reject("There was a problem loading Tokyotosho"); 73 | } 74 | 75 | 76 | }); 77 | 78 | return deferred.promise; 79 | 80 | } 81 | }; 82 | -------------------------------------------------------------------------------- /lib/rarbg.js: -------------------------------------------------------------------------------- 1 | /*jshint esversion: 6 */ 2 | var Q = require('q'); 3 | var request = require("request"); 4 | var cheerio = require('cheerio'); 5 | var moment = require('moment'); 6 | 7 | module.exports = { 8 | search: function(query, rarbg_api_url, cat, page, limit) { 9 | 10 | var torrent_search = query; 11 | var search_query = torrent_search.split(' ').join('+'); 12 | 13 | var count = 1; 14 | var deferred = Q.defer(); 15 | var data_content = {}; 16 | var torrent_content = []; 17 | var options; 18 | 19 | //get token 20 | var url = rarbg_api_url + "/pubapi_v2.php?get_token=get_token&app_id=Torrentflix"; 21 | 22 | options = { method: 'GET', 23 | url: url, 24 | headers: { 'user-agent': 'node.js'} }; 25 | 26 | 27 | request(options, function (err, response, body) { 28 | 29 | if (!err && response.statusCode === 200) { 30 | data = JSON.parse(body); 31 | 32 | var token = data.token; 33 | var search_url = rarbg_api_url + "/pubapi_v2.php?mode=search&search_string=" + encodeURIComponent(search_query) + "&app_id=Torrentflix&sort=seeders&format=json_extended&token=" + token; 34 | 35 | options = { method: 'GET', 36 | url: search_url, 37 | headers: { 'user-agent': 'node.js'} }; 38 | 39 | const sleep = (waitTimeInMs) => new Promise(resolve => setTimeout(resolve, waitTimeInMs)); 40 | 41 | sleep(2500).then(() => { 42 | request(options, function (err, response, body) { 43 | 44 | if (!err && response.statusCode === 200) { 45 | data = JSON.parse(body); 46 | if(data.torrent_results && data.torrent_results.length > 1){ 47 | for(var torrent in data.torrent_results){ 48 | 49 | var title = data.torrent_results[torrent].title; 50 | var torrent_link = data.torrent_results[torrent].download; 51 | var seeds = data.torrent_results[torrent].seeders; 52 | var leechs = data.torrent_results[torrent].leechers; 53 | var size = bytesToSize(data.torrent_results[torrent].size); 54 | var date_added = data.torrent_results[torrent].pubdate.split('+')[0]; 55 | 56 | data_content = { 57 | torrent_num: count, 58 | title: title, 59 | category: "", 60 | seeds: seeds, 61 | leechs: leechs, 62 | size: size, 63 | torrent_link: torrent_link, 64 | date_added: date_added 65 | }; 66 | 67 | torrent_content.push(data_content); 68 | 69 | deferred.resolve(torrent_content); 70 | // like break 71 | if (++count > limit) { return false; } 72 | 73 | } 74 | } else { 75 | deferred.reject("No torrents found"); 76 | } 77 | } else { 78 | deferred.reject("There was a problem loading Rarbg"); 79 | } 80 | }); 81 | }); 82 | } else { 83 | deferred.reject("There was a problem loading Rarbg"); 84 | } 85 | }); 86 | 87 | return deferred.promise; 88 | 89 | } 90 | }; 91 | 92 | 93 | function bytesToSize(bytes) { 94 | var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; 95 | if (bytes === 0) return '0 Byte'; 96 | var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); 97 | return Math.round(bytes / Math.pow(1024, i), 2) + '' + sizes[i]; 98 | } 99 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var program = require("commander"); 3 | var fs = require('fs'); 4 | var path = require('path'); 5 | var request = require('request'); 6 | var async = require('async'); 7 | var chalk = require('chalk'); 8 | var main = require("./main"); 9 | var spawn = require('child_process').spawn; 10 | var pkg = require("../package.json"); 11 | var Configstore = require('configstore'); 12 | var trakt = require('./trakt.js'); 13 | var appDir = path.dirname(require.main.filename).split('bin').join(''); 14 | 15 | var config_object, settings_object, history_object; 16 | var blank_history = []; 17 | 18 | // definition of all options 19 | // example for source scrapers - short_name: {name: longname, url: base_url} 20 | // short name has to be equal to the name of the scraper object define in 21 | // main.js 22 | var config_vars = { 23 | "torrent_sources": { 24 | "kickass": { 25 | name: 'Kickass', 26 | url: "https://katcr.co" 27 | }, 28 | "limetorrents": { 29 | name: 'LimeTorrents', 30 | url: "http://limetorrents.info" 31 | }, 32 | "yts": { 33 | name: 'YTS', 34 | url: "https://yts.mx" 35 | }, 36 | "tpb": { 37 | name: 'The Pirate Bay', 38 | url: "https://apibay.org" 39 | }, 40 | "sky": { 41 | name: 'Sky Torrents', 42 | url: "https://skytorrents.lol" 43 | }, 44 | "leetx": { 45 | name: '1337x', 46 | url: "https://1337x.to" 47 | }, 48 | "nyaa": { 49 | name: 'Nyaa', 50 | url: "http://www.nyaa.si" 51 | }, 52 | "tokyotosho": { 53 | name: 'Tokiotosho', 54 | url: "https://www.tokyotosho.info" 55 | }, 56 | "eztv": { 57 | name: 'Eztv', 58 | url: "https://www.eztv.ag" 59 | }, 60 | "rarbg": { 61 | name: 'Rarbg', 62 | url: "https://torrentapi.org" 63 | }, 64 | "zooqle": { 65 | name: 'Zooqle', 66 | url: "https://zooqle.com" 67 | }, 68 | "xbit": { 69 | name: 'x[BiT]', 70 | url: "https://xbit.pw" 71 | } 72 | }, 73 | "options": { 74 | "peerflix_player": "--vlc", 75 | "peerflix_player_args": "", 76 | "peerflix_port": "--port=8888", 77 | "peerflix_path": "", 78 | "peerflix_command": "peerflix", 79 | "use_subtitle": "false", 80 | "subtitle_language": "eng", 81 | "history": "false", 82 | "date_added": "false", 83 | } 84 | }; 85 | 86 | //setting up command line options 87 | program 88 | .version(pkg.version) 89 | .option('--config', 'Edit torrentflix config EX: torrentflix --config="nano"') 90 | .option('-s, --search [title]', 'item to search for EX: -s title') 91 | .option('-o, --open [title]', 'open torrent with default app or xdg-open') 92 | .option('-e, --engine [name]', 'which website use for the search, EX: -e tpb') 93 | .option('-l, --limit [int]', 'limit the number of results, EX: -l 10') 94 | .option('-t, --trakt', 'Use Trakt.tv integration') 95 | //.option('--history', 'View torrentflix history EX: torrentflix --history') 96 | .option('--clear', 'Clear torrentflix history EX torrentflix --clear') 97 | //.option('--location', 'Change where torrentflix\' config & history is located EX torrentflix --location"/home/gshock/.config"') 98 | .parse(process.argv); 99 | //if config command has been called 100 | if (program.config) { 101 | if (program.args[0]) { 102 | //open up stock or custom config in the users choice of editor 103 | var edit_conf; 104 | var conf = new Configstore("torrentflix_config", {}); 105 | edit_conf = conf.path; 106 | 107 | if (conf.size < 1) { 108 | console.log(chalk.red('A config file has not been created yet.')); 109 | console.log(chalk.red('Please run torrentflix at least once to create one.')); 110 | } else { 111 | spawn(program.args[0], [edit_conf], { 112 | stdio: 'inherit' 113 | }); 114 | } 115 | //they didn't specify an editor ask the user to specify one 116 | } else { 117 | console.log('Please specify an editor'); 118 | console.log(" Example:"); 119 | console.log(''); 120 | console.log(' $ torrentflix --config="nano"'); 121 | } 122 | //history command called 123 | //} else if (program.history) { 124 | //TODO 125 | //clear history command called 126 | } else if (program.clear) { 127 | clearHistory(); 128 | } else if (program.trakt) { 129 | trakt.init(); 130 | } else { 131 | //do an update check 132 | var url = "https://raw.githubusercontent.com/ItzBlitz98/torrentflix/master/package.json"; 133 | request(url, function (err, response, body) { 134 | if (!err && response.statusCode === 200) { 135 | data = JSON.parse(body); 136 | if (data.version > pkg.version) { 137 | console.log(chalk.red('A new version of torrentflix is available run:')); 138 | console.log(""); 139 | console.log('$ npm install -g torrentflix'); 140 | console.log(""); 141 | console.log(chalk.red('Or go here to get it: https://github.com/ItzBlitz98/torrentflix')); 142 | } 143 | } 144 | AppInitialize(program); 145 | }); 146 | } 147 | 148 | function AppInitialize(prog) { 149 | var appOpts = { 150 | open: prog.open, 151 | search: prog.search, 152 | engine: prog.engine, 153 | limit: prog.limit, 154 | trakt: prog.trakt 155 | }; 156 | var conf = new Configstore("torrentflix_config", {}); 157 | var hist = new Configstore("torrentflix_history", { recentlyWatched: { items: [] }}); 158 | if (conf.size < 1) { 159 | //create config file with default 160 | conf.set(config_vars); 161 | 162 | console.log(chalk.green("A new config file has been created you can find it at: ")); 163 | console.log(chalk.green(conf.path)); 164 | 165 | } else if (conf.all.kickass_url){ 166 | //create config file with default 167 | conf.clear(); 168 | conf.set(config_vars); 169 | 170 | console.log(chalk.green("A new config file has been created you can find it at: ")); 171 | console.log(chalk.green(conf.path)); 172 | } else { 173 | 174 | // config file exist, get values 175 | var conf_file = conf.all; 176 | var need_save = false; 177 | // create these if not exists 178 | for (var type in config_vars) { 179 | for (var option in config_vars[type]) { 180 | if (!(option in conf_file[type])) { 181 | conf_file[type][option] = config_vars[type][option]; 182 | need_save = true; 183 | } 184 | } 185 | } 186 | 187 | //save updates 188 | if (need_save) { 189 | conf.set(conf_file); 190 | } 191 | } 192 | main.AppInitialize(appOpts); 193 | } 194 | 195 | function clearHistory() { 196 | var hist = new Configstore("torrentflix_history", { recentlyWatched: { items: [] }}); 197 | hist.clear(); 198 | } 199 | 200 | }).call(this); 201 | -------------------------------------------------------------------------------- /lib/trakt.js: -------------------------------------------------------------------------------- 1 | var inquirer = require("inquirer"); 2 | const Trakt = require("trakt.tv"); 3 | var Configstore = require("configstore"); 4 | var promise = require("promise"); 5 | var chalk = require("chalk"); 6 | var conf = new Configstore("trakt_config"); 7 | var tnp = require("torrent-name-parser"); 8 | const readline = require("readline"); 9 | const displayImage = require("display-image"); 10 | const mdb = require('moviedb')('8ab94034d5d6e93ba87c74637ebbd021'); 11 | var main = require("./main"); 12 | 13 | const blank = "\n".repeat(process.stdout.rows); 14 | 15 | //TRAKT API CONFIG 16 | let options = { 17 | client_id: "506de02e7b06dc15b1a8576e94a13340bb9994046f9ba6612453fe2779d43212", 18 | client_secret: "d42f93e3ed7670ad286e10c5b5d767ae19ddc144770801afe9f7ffeac96739b0", 19 | //debug: true, 20 | }; 21 | const trakt = new Trakt(options); 22 | 23 | module.exports = { 24 | init: function () { 25 | var TraktConfig = promise.resolve(conf.all); 26 | TraktConfig.then((token) => { 27 | if (isEmpty(token)) { 28 | return trakt.get_codes().then(poll => { 29 | console.log(chalk.green("**Trakt Activation**")); 30 | console.log(chalk.green("Please visit: ") + chalk.magenta(poll.verification_url)); 31 | console.log(chalk.green("Enter the code: ") + chalk.magenta(poll.user_code)); 32 | return trakt.poll_access(poll); 33 | }).catch(chalk.red(console.error)); 34 | } 35 | return trakt.import_token(token); 36 | }).then(newTokens => { 37 | return conf.set(newTokens); 38 | }).then(() => { 39 | return trakt.users.settings(); 40 | }).then(profile => { 41 | if (profile.user.username) { 42 | inquirer.prompt([{ 43 | type: "list", 44 | name: "Ttmenu", 45 | message: chalk.green("Welcome " + profile.user.username + "\n" + " Trakt Menu"), 46 | choices: ["Up next", "Movies", "Shows", "Revoke Access", "[ Exit ]"] 47 | }]).then(answer => { 48 | switch (answer.Ttmenu) { 49 | case "Up next": 50 | upNext(profile.user.username); 51 | break; 52 | case "Movies": 53 | inquirer.prompt([{ 54 | type: "list", 55 | name: "TraktMovies", 56 | message: chalk.green("Movies on Trakt"), 57 | choices: ["Trending", "Popular", "[ Exit ]"] 58 | }]).then(answer => { 59 | switch (answer.TraktMovies) { 60 | case "Trending": 61 | trendingMovies(); 62 | break; 63 | case "Popular": 64 | popularMovies(); 65 | break; 66 | } 67 | }).catch(chalk.red(console.log)); 68 | break; 69 | case "Shows": 70 | inquirer.prompt([{ 71 | type: "list", 72 | name: "TraktShows", 73 | message: chalk.green("Shows on Trakt"), 74 | choices: ["Trending", "Popular", "[ Exit ]"] 75 | }]).then(answer => { 76 | switch (answer.TraktShows) { 77 | case "Trending": 78 | trendingShows(); 79 | break; 80 | case "Popular": 81 | popularShows(); 82 | break; 83 | } 84 | }).catch(chalk.red(console.log)); 85 | break; 86 | case "Revoke Access": 87 | trakt.revoke_token(); 88 | conf.clear(); 89 | console.log(chalk.green("Trakt access revoked")); 90 | break; 91 | default: 92 | break; 93 | } 94 | }).catch(chalk.red(console.log)); 95 | } 96 | }).catch(chalk.red(console.log)); 97 | }, 98 | 99 | markaswatched: function(torrent_title){ 100 | //If a title and Trakt is enabled 101 | if (tnp(torrent_title).title && !isEmpty(conf.all)) { 102 | //Import Trakt Token 103 | trakt.import_token(conf.all); 104 | //Get Trakt ID for the show / movie 105 | if (tnp(torrent_title).season){ 106 | trakt.search.text({ 107 | query: tnp(torrent_title).title, 108 | type: "show,title" 109 | }).then(Ttid => { 110 | //Try to poll the episode 111 | if (!isEmpty(Ttid)) { 112 | trakt.episodes.summary({ 113 | id: Ttid[0].show.ids.trakt, 114 | season: zeroprefix(tnp(torrent_title).season), 115 | episode: zeroprefix(tnp(torrent_title).episode) 116 | }).then(Ttresult => { 117 | //If episode is found, mark as watched 118 | if (!isEmpty(Ttresult)) { 119 | inquirer.prompt([{ 120 | type: "confirm", 121 | name: "markaswatch", 122 | message: chalk.green("Mark: " + Ttid[0].show.title + " s" + zeroprefix(Ttresult.season) + "e" + zeroprefix(Ttresult.number)) + chalk.magenta(" as watched?"), 123 | default: true 124 | }]).then(answer => { 125 | if (answer.markaswatch) { 126 | trakt.sync.history.add({episodes: [{"ids": {"trakt": Ttresult.ids.trakt}}]}); 127 | console.log(chalk.green(Ttid[0].show.title + " s" + zeroprefix(Ttresult.season) + "e" + zeroprefix(Ttresult.number)) + chalk.magenta(" Marked as Watched")); 128 | } 129 | }).catch(chalk.red(console.log)); 130 | } 131 | }).catch(chalk.red(console.log)); 132 | } 133 | }).catch(chalk.red(console.log)); 134 | } else { 135 | //Its a movie 136 | trakt.search.text({ 137 | query: tnp(torrent_title).title + " " + tnp(torrent_title).year, 138 | type: "movie,title" 139 | }).then(Ttid => { 140 | if (!isEmpty(Ttid)) { 141 | //Take the highest score found and mark as watched 142 | inquirer.prompt([{ 143 | type: "confirm", 144 | name: "markaswatch", 145 | message: chalk.green("Mark: " + Ttid[0].movie.title + " " + Ttid[0].movie.year) + chalk.magenta(" as watched ?"), 146 | default: true 147 | }]).then(answer => { 148 | if (answer.markaswatch) { 149 | trakt.sync.history.add({movies: [{"ids": {"trakt": Ttid[0].movie.ids.trakt}}]}); 150 | console.log(chalk.green(Ttid[0].movie.title + " " + Ttid[0].movie.year) + chalk.magenta(" Marked as Watched")); 151 | } 152 | }).catch(chalk.red(console.log)); 153 | } 154 | }).catch(chalk.red(console.log)); 155 | } 156 | } 157 | } 158 | }; 159 | 160 | function trendingShows() { 161 | var rst = promise.resolve(clearterm()); 162 | rst.then(() => { 163 | trakt.shows.trending({}).then(trendingShows => { 164 | return Promise.all(trendingShows.map(element => { 165 | return element.show.title + " " + element.show.year + " " + element.show.ids.trakt; 166 | })).then(trendingShowsList => { 167 | inquirer.prompt([{ 168 | type: "list", 169 | name: "TraktTrendingShows", 170 | message: chalk.green("Trending Shows on Trakt"), 171 | pageSize: 15, 172 | choices: function(){ 173 | var choiceArray = []; 174 | for (var i = 0; i < trendingShowsList.length; i++) { 175 | choiceArray.push(trendingShowsList[i].substring(0, trendingShowsList[i].lastIndexOf(" "))); 176 | } 177 | choiceArray.push("[ Exit ]"); 178 | return choiceArray; 179 | } 180 | }]).then(answer => { 181 | if (answer.TraktTrendingShows == "[ Exit ]") return; 182 | for (var i = 0; i < trendingShowsList.length; i++) { 183 | if(trendingShowsList[i].includes(answer.TraktTrendingShows)) { 184 | var showId = trendingShowsList[i].substring(trendingShowsList[i].lastIndexOf(" "), trendingShowsList[i].length); 185 | getShownfo(showId.trim(),"ts"); 186 | } 187 | } 188 | }).catch(chalk.red(console.log)); 189 | }); 190 | }).catch(chalk.red(console.log)); 191 | }); 192 | } 193 | 194 | function popularShows() { 195 | var rst = promise.resolve(clearterm()); 196 | rst.then(() => { 197 | trakt.shows.popular({}).then(popularShows => { 198 | return Promise.all(popularShows.map(element => { 199 | return element.title + " " + element.year + " " + element.ids.trakt; 200 | })).then(popularShowsList => { 201 | inquirer.prompt([{ 202 | type: "list", 203 | name: "TraktPopularShows", 204 | message: chalk.green("Popular Shows on Trakt"), 205 | pageSize: 15, 206 | choices: function(){ 207 | var choiceArray = []; 208 | for (var i = 0; i < popularShowsList.length; i++) { 209 | choiceArray.push(popularShowsList[i].substring(0, popularShowsList[i].lastIndexOf(" "))); 210 | } 211 | choiceArray.push("[ Exit ]"); 212 | return choiceArray; 213 | } 214 | }]).then(answer => { 215 | if (answer.TraktPopularShows == "[ Exit ]") return; 216 | for (var i = 0; i < popularShowsList.length; i++) { 217 | if(popularShowsList[i].includes(answer.TraktPopularShows)) { 218 | var showId = popularShowsList[i].substring(popularShowsList[i].lastIndexOf(" "), popularShowsList[i].length); 219 | getShownfo(showId.trim(),"ps"); 220 | } 221 | } 222 | }).catch(chalk.red(console.log)); 223 | }); 224 | }).catch(chalk.red(console.log)); 225 | }); 226 | } 227 | 228 | function trendingMovies() { 229 | var rst = promise.resolve(clearterm()); 230 | rst.then(() => { 231 | trakt.movies.trending({}).then(trendingMovies => { 232 | return Promise.all(trendingMovies.map(element => { 233 | return element.movie.title + " " + element.movie.year + " " + element.movie.ids.trakt; 234 | })).then(trendingMoviesList => { 235 | inquirer.prompt([{ 236 | type: "list", 237 | name: "TraktTrendingMovies", 238 | message: chalk.green("Trending Movies on Trakt"), 239 | pageSize: 15, 240 | choices: function(){ 241 | var choiceArray = []; 242 | for (var i = 0; i < trendingMoviesList.length; i++) { 243 | choiceArray.push(trendingMoviesList[i].substring(0, trendingMoviesList[i].lastIndexOf(" "))); 244 | } 245 | choiceArray.push("[ Exit ]"); 246 | return choiceArray; 247 | } 248 | }]).then(answer => { 249 | if (answer.TraktTrendingMovies == "[ Exit ]") return; 250 | for (var i = 0; i < trendingMoviesList.length; i++) { 251 | if(trendingMoviesList[i].includes(answer.TraktTrendingMovies)) { 252 | var showId = trendingMoviesList[i].substring(trendingMoviesList[i].lastIndexOf(" "), trendingMoviesList[i].length); 253 | getMovienfo(showId.trim(),"tm"); 254 | } 255 | } 256 | }).catch(chalk.red(console.log)); 257 | }); 258 | }).catch(chalk.red(console.log)); 259 | }); 260 | } 261 | 262 | function popularMovies() { 263 | var rst = promise.resolve(clearterm()); 264 | rst.then(() => { 265 | trakt.movies.popular({}).then(popularMovies => { 266 | return Promise.all(popularMovies.map(element => { 267 | return element.title + " " + element.year + " " + element.ids.trakt; 268 | })).then(popularMoviesList => { 269 | inquirer.prompt([{ 270 | type: "list", 271 | name: "TraktPopularMovies", 272 | message: chalk.green("Popular Movies on Trakt"), 273 | pageSize: 15, 274 | choices: function(){ 275 | var choiceArray = []; 276 | for (var i = 0; i < popularMoviesList.length; i++) { 277 | choiceArray.push(popularMoviesList[i].substring(0, popularMoviesList[i].lastIndexOf(" "))); 278 | } 279 | choiceArray.push("[ Exit ]"); 280 | return choiceArray; 281 | } 282 | }]).then(answer => { 283 | if (answer.TraktPopularMovies == "[ Exit ]") return; 284 | for (var i = 0; i < popularMoviesList.length; i++) { 285 | if(popularMoviesList[i].includes(answer.TraktPopularMovies)) { 286 | var showId = popularMoviesList[i].substring(popularMoviesList[i].lastIndexOf(" "), popularMoviesList[i].length); 287 | getMovienfo(showId.trim(),"pm"); 288 | } 289 | } 290 | }).catch(chalk.red(console.log)); 291 | }); 292 | }).catch(chalk.red(console.log)); 293 | }); 294 | } 295 | 296 | function upNext(userProfile) { 297 | //get all watched shows 298 | trakt.users.watched({ 299 | username: userProfile, 300 | type: 'shows', 301 | extended: 'noseasons' 302 | }).then(watchedshows => { 303 | //get progress for all watched shows 304 | return Promise.all(watchedshows.map(element => { 305 | return trakt.shows.progress.watched({ 306 | id: element.show.ids.trakt, 307 | hidden: 'false', 308 | specials: 'false', 309 | extended: 'full' 310 | }).then(episodeProgress => { 311 | //verify if there's a next eps and if it's aired 312 | if (episodeProgress.next_episode && new Date(episodeProgress.next_episode.first_aired) <= new Date()){ 313 | return element.show.title + ' s' + zeroprefix(episodeProgress.next_episode.season) + 'e' + zeroprefix(episodeProgress.next_episode.number); 314 | } 315 | }).catch(chalk.red(console.log)); 316 | })); 317 | }).then(progress => { 318 | return progress.filter(Boolean); 319 | }).then(nextEpisode => { 320 | nextEpisode.push("[ Exit ]"); 321 | inquirer.prompt([{ 322 | type: "list", 323 | name: "UpNext", 324 | message: chalk.green("Which episode do you want to watch next?"), 325 | pageSize: 15, 326 | choices: nextEpisode 327 | }]).then(answer => { 328 | if (answer.UpNext == "[ Exit ]") return; 329 | main.AppInitialize({search: answer.UpNext}); 330 | }).catch(chalk.red(console.log)); 331 | }).catch(chalk.red(console.log)); 332 | } 333 | 334 | function getShownfo(showId,callback) { 335 | var rst = promise.resolve(clearterm()); 336 | rst.then(() => { 337 | trakt.shows.summary({ 338 | id: showId, 339 | extended: "full" 340 | }).then(answer => { 341 | var selectedShow = answer.title + " " + answer.year + " s01e01"; 342 | mdb.tvImages({ id: answer.ids.tmdb }, (err, res) => { 343 | displayImage.fromURL("https://image.tmdb.org/t/p/w154" + res.posters[0].file_path).then(image => { 344 | console.log(image + "\n\n" + chalk.bgCyan("Overview") + "\n" + answer.overview + "\n\n"); 345 | inquirer.prompt([{ 346 | type: "input", 347 | name: "confirm", 348 | message: chalk.green("(w)atch, (b)ack or (e)xit :"), 349 | }]).then(answer => { 350 | switch(answer.confirm) { 351 | case "w": 352 | main.AppInitialize({search: selectedShow}); 353 | break; 354 | case "b": 355 | if (callback == "ts") { 356 | trendingShows(); 357 | } else { 358 | popularShows(); 359 | } 360 | break; 361 | default: 362 | return; 363 | } 364 | }); 365 | }); 366 | }); 367 | }); 368 | }); 369 | } 370 | 371 | function getMovienfo(movieId,callback) { 372 | var rst = promise.resolve(clearterm()); 373 | rst.then(() => { 374 | trakt.movies.summary({ 375 | id: movieId, 376 | extended: "full" 377 | }).then(answer => { 378 | var selectedMovie = answer.title + " " + answer.year; 379 | mdb.movieImages({ id: answer.ids.tmdb }, (err, res) => { 380 | displayImage.fromURL("https://image.tmdb.org/t/p/w154" + res.posters[0].file_path).then(image => { 381 | console.log(image + "\n\n" + chalk.bgCyan("Overview") + "\n" + answer.overview + "\n\n"); 382 | inquirer.prompt([{ 383 | type: "input", 384 | name: "confirm", 385 | message: chalk.green("(w)atch, (b)ack or (e)xit :"), 386 | }]).then(answer => { 387 | switch(answer.confirm) { 388 | case "w": 389 | main.AppInitialize({search: selectedMovie}); 390 | break; 391 | case "b": 392 | if (callback == "tm") { 393 | trendingMovies(); 394 | } else { 395 | popularMovies(); 396 | } 397 | break; 398 | default: 399 | return; 400 | } 401 | }); 402 | }); 403 | }); 404 | }); 405 | }); 406 | } 407 | 408 | function zeroprefix(num) { 409 | if (num < 10) { 410 | return "0" + num; 411 | } else { 412 | return num; 413 | } 414 | } 415 | 416 | function isEmpty(obj) { 417 | for(var key in obj) { 418 | if(obj.hasOwnProperty(key)) 419 | return false; 420 | } 421 | return true; 422 | } 423 | 424 | function clearterm() { 425 | console.log(blank); 426 | readline.cursorTo(process.stdout, 0, 0); 427 | readline.clearScreenDown(process.stdout); 428 | } 429 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var Configstore = require('configstore'); 3 | var program = require("commander"); 4 | var os = require('os'); 5 | var fs = require('fs'); 6 | var http = require('http'); 7 | var kickass = require('./kickass.js'); 8 | var rarbg = require('./rarbg.js'); 9 | var subtitles = require('./subtitles.js'); 10 | var torrent_search = require('./torrent_search.js'); 11 | var limetorrents = require('./limetorrents.js'); 12 | var tpb = require('./thepiratebay.js'); 13 | var sky = require('./skytorrents.js'); 14 | var zooqle = require('./zooqle.js'); 15 | var xbit = require('./xbit.js'); 16 | var yts = require('./yts.js'); 17 | var leetx = require('./1337x.js'); 18 | var nyaa = require('./nyaa.js'); 19 | var tokyotosho = require('./tokyotosho.js'); 20 | var eztv = require('./eztv.js'); 21 | var tparse = require('./torrent_parse.js'); 22 | var language = require('../lang.js'); 23 | var trakt = require('./trakt.js'); 24 | var chalk = require('chalk'); 25 | var inquirer = require('inquirer'); 26 | var spawn = require('spawn-cmd').spawn; 27 | var path = require('path'); 28 | var opn = require('open'); 29 | var appDir = path.dirname(require.main.filename).split('bin').join(''); 30 | var isWindows = process.platform === 'win32'; 31 | var options = {}; 32 | var peerflix_player, peerflix_player_arg, peerflix_port, peerflix_command, 33 | use_subtitle, subtitle_language, history, history_location, 34 | conf_date_added, history_object, config_location, cat, page, 35 | peerflix_path, limit; 36 | 37 | //load in language settings 38 | var lang = language.getEn(); 39 | var torrent_site = lang[0].torrent_site; 40 | var search_torrent = lang[0].search_torrent; 41 | var torrent_site_num = lang[0].torrent_site_num; 42 | var select_torrent = lang[0].select_torrent; 43 | var select_file = lang[0].select_file; 44 | var site_error = lang[0].site_error; 45 | 46 | 47 | var get_conf_object = new Configstore("torrentflix_config", {}); 48 | var get_hist_object = new Configstore("torrentflix_history", {}); 49 | 50 | // link short_name and scraper object 51 | var scrapers = { 52 | 'kickass': kickass, 53 | 'rarbg': rarbg, 54 | 'limetorrents': limetorrents, 55 | 'tpb': tpb, 56 | 'sky': sky, 57 | 'yts': yts, 58 | 'zooqle': zooqle, 59 | 'xbit': xbit, 60 | 'leetx': leetx, 61 | 'nyaa': nyaa, 62 | 'tokyotosho': tokyotosho, 63 | 'eztv': eztv 64 | }; 65 | 66 | exports.AppInitialize = start = function(optns) { 67 | // get option pass in cli (-s, -o, ...) 68 | options = optns; 69 | 70 | // get all options from the config file 71 | config_object = get_conf_object.all; 72 | 73 | //setting up vars from config 74 | peerflix_player = config_object.options.peerflix_player; 75 | peerflix_player_arg = config_object.options.peerflix_player_args; 76 | peerflix_port = config_object.options.peerflix_port; 77 | peerflix_command = config_object.options.peerflix_command; 78 | use_subtitle = config_object.options.use_subtitle; 79 | subtitle_language = config_object.options.subtitle_language; 80 | history = config_object.options.history; 81 | conf_date_added = config_object.options.date_added; 82 | page = 1; 83 | peerflix_path = config_object.options.peerflix_path; 84 | 85 | firstPrompt(options); 86 | 87 | }; 88 | 89 | function firstPrompt(options) { 90 | var sites = []; 91 | var source; 92 | 93 | if (options.limit && options.limit !== true) { 94 | limit = options.limit; 95 | } 96 | if (options.engine === true) { 97 | console.log(chalk.red("Please specify the name of search engine to use :")); 98 | for (source in config_object.torrent_sources) { 99 | // show the source list 100 | console.log(config_object.torrent_sources[source].name + " -> " + 101 | chalk.green(source)); 102 | } 103 | } 104 | else if (options.engine) { 105 | engine = options.engine; 106 | // engine exist ? 107 | if (config_object.torrent_sources[options.engine]) { 108 | torrentSite(options.engine, limit); 109 | } else { 110 | console.log(chalk.red(engine + " not exist. Please specify the name "+ 111 | "of search engine to use :")); 112 | for (source in config_object.torrent_sources) { 113 | // show the source list 114 | console.log(config_object.torrent_sources[source].name + " -> " + 115 | chalk.green(source)); 116 | } 117 | } 118 | } else { 119 | for (source in config_object.torrent_sources) { 120 | // add torrent sources 121 | sites.push({ 122 | 'key': source, 123 | name: chalk.magenta(config_object.torrent_sources[source].name), 124 | value: source 125 | }); 126 | } 127 | if (history === "true") { 128 | sites.push({ 129 | 'key': "print history", 130 | name: chalk.blue('Print history'), 131 | value: "print history" 132 | }); 133 | } 134 | sites.push({'key': "exit", name: chalk.red('Exit app'), value: "exit"}); 135 | 136 | inquirer.prompt([{ 137 | type: "list", 138 | name: "site", 139 | message: chalk.green("What torrent site do you want to search?"), 140 | choices: sites 141 | }]).then(function (answer) { 142 | torrentSite(answer.site, limit); 143 | }); 144 | } 145 | } 146 | 147 | function torrentSite(site, limit) { 148 | 149 | if (site == "print history") { 150 | printHistory(); 151 | firstPrompt(options); 152 | } else if (site == "exit") { 153 | exitApp(); 154 | } else { 155 | // if -s and not empty 156 | if (options.search && options.search !== true) { 157 | Search(options.search, site, cat, page, limit); 158 | // if -o and not empty 159 | } else if (options.open && options.open !== true) { 160 | Search(options.open, site, cat, page, limit); 161 | } else { 162 | inquirer.prompt([ 163 | { 164 | type: "input", 165 | name: "search", 166 | message: chalk.green(search_torrent), 167 | }]).then(function (answer) { 168 | Search(answer.search, site, cat, page, limit); 169 | }); 170 | } 171 | } 172 | } 173 | 174 | function Search(query, site, cat, page, limit) { 175 | // general search function for all sources 176 | console.log(chalk.green("Searching for ") + chalk.blue(query) + 177 | chalk.green(" on ") + chalk.blue( 178 | config_object.torrent_sources[site].name) + chalk.green("...")); 179 | 180 | search_url = config_object.torrent_sources[site].url; 181 | scrapers[site].search(query, search_url, cat, page, limit).then( 182 | function (data) { 183 | onResolve(data); 184 | }, function (err) { 185 | onReject(err); 186 | }); 187 | } 188 | 189 | 190 | function onResolve(data) { 191 | for (var idx in data) { 192 | var torrent = data[idx]; 193 | var date_added, title; 194 | var number = torrent.torrent_num; 195 | var size = torrent.size; 196 | var seed = torrent.seeds; 197 | var leech = torrent.leechs; 198 | var torrent_verified = " "; 199 | 200 | if(torrent.torrent_verified) { 201 | torrent_verified = torrent.torrent_verified; 202 | if(torrent.torrent_verified == "vip"){ 203 | torrent_verified = chalk.green(" 💀 "); 204 | } else if(torrent.torrent_verified == "trusted"){ 205 | torrent_verified = chalk.magenta(" 💀 "); 206 | } 207 | } 208 | 209 | if(conf_date_added == "true"){ 210 | date_added = chalk.cyan("" + torrent.date_added + " "); 211 | } else { 212 | date_added = ""; 213 | } 214 | 215 | if(history == "true"){ 216 | var found = searchHistory(torrent.title); 217 | if(found){ 218 | title = chalk.red(torrent.title); 219 | } else { 220 | title = chalk.yellow(torrent.title); 221 | } 222 | } else { 223 | title = chalk.yellow(torrent.title); 224 | } 225 | console.log( 226 | chalk.magenta(number) + chalk.magenta('\) ') + title + chalk.green(torrent_verified) + date_added + chalk.blue(size) + (' ') + chalk.green(seed) + (' ') + chalk.red(leech) 227 | ); 228 | } 229 | selectTorrent(data); 230 | } 231 | 232 | function onReject(err) { 233 | console.log(chalk.red(err)); 234 | firstPrompt(options); 235 | } 236 | 237 | function selectTorrent(data) { 238 | inquirer.prompt([ 239 | { 240 | type: "input", 241 | name: "torrent", 242 | message: chalk.green(select_torrent), 243 | validate: function( value ) { 244 | if(value > data.length){ 245 | return "Please enter a valid torrent number (1-"+data.length+")"; 246 | }else if(!value){ 247 | return "Please enter a valid torrent number (1-"+data.length+")"; 248 | } else if(value == "b"){ 249 | return true; 250 | } else if(value == "e"){ 251 | return true; 252 | }else if(!value.match(/\d+/g)){ 253 | return "Please enter a valid torrent number (1-"+data.length+")"; 254 | } else { 255 | return true; 256 | } 257 | } 258 | }]).then(function (answer) { 259 | if(answer.torrent === "b"){ 260 | firstPrompt(options); 261 | }else if(answer.torrent === "e"){ 262 | exitApp(); 263 | } else { 264 | number = answer.torrent -1; 265 | torrent_title = data[number].title; 266 | 267 | //do some checking to see if we got a magnet link or a link to the torrent page 268 | //not all torrent sites have the link on the index 269 | if(data[number].torrent_link) { 270 | torrent = data[number].torrent_link; 271 | if(options.open) { 272 | console.log('Opening ' + chalk.green(torrent_title)); 273 | opn(torrent); 274 | } else { 275 | console.log('Streaming ' + chalk.green(torrent_title)); 276 | parseTorrent(torrent, torrent_title); 277 | } 278 | 279 | } else if(data[number].torrent_site) { 280 | torrent_search.torrentSearch(data[number].torrent_site).then(function(data) { 281 | torrent = data; 282 | if(options.open) { 283 | console.log('Opening ' + chalk.green(torrent_title)); 284 | opn(torrent); 285 | } else { 286 | console.log('Streaming ' + chalk.green(torrent_title)); 287 | parseTorrent(torrent, torrent_title); 288 | } 289 | 290 | }, function onReject(err) { 291 | console.log(chalk.red(err)); 292 | firstPrompt(options); 293 | }); 294 | 295 | } else if(data[number].torrent_site == null && data[number].torrent_link == null){ 296 | console.log(chalk.red("There was no torrent provided")); 297 | firstPrompt(options); 298 | } 299 | 300 | } 301 | }); 302 | } 303 | 304 | function parseTorrent(torrent, torrent_title){ 305 | 306 | tparse.parseTorrent(torrent).then(function(data) { 307 | //if true more than one file can be played 308 | if(data !== false){ 309 | console.log(chalk.green("Multiple torrent file detected.")); 310 | var torrent_count = 1; 311 | 312 | data.forEach(function(torrents) { 313 | console.log( 314 | chalk.magenta(torrent_count) + chalk.magenta('\) ') + chalk.yellow(torrents) 315 | ); 316 | torrent_count++; 317 | }); 318 | inquirer.prompt([ 319 | { 320 | type: "input", 321 | name: "torrent", 322 | message: chalk.green(select_file), 323 | validate: function( value ) { 324 | if(value > data.length){ 325 | return "Please enter a valid file number (1-"+data.length+")"; 326 | }else if(!value){ 327 | return "Please enter a valid file number (1-"+data.length+")"; 328 | } else if(value == "b"){ 329 | return true; 330 | } else if(value == "e"){ 331 | return true; 332 | }else if(!value.match(/\d+/g)){ 333 | return "Please enter a valid torrent number (1-"+data.length+")"; 334 | } else { 335 | return true; 336 | } 337 | } 338 | }]).then(function (answer) { 339 | if(answer.torrent === "b"){ 340 | firstPrompt(options); 341 | }else if(answer.torrent === "e"){ 342 | exitApp(); 343 | } else { 344 | number = answer.t; 345 | torrent_index = answer.torrent-1; 346 | torrent_title = data[torrent_index]; 347 | console.log('Streaming ' + chalk.green(torrent_title)); 348 | if(use_subtitle === "true"){ 349 | subtitles.fetchSub(subtitle_language, torrent_title).then(function(data) { 350 | if(data !== false){ 351 | peerflix_subtitle = data; 352 | streamTorrent_sub_list(torrent, torrent_index); 353 | if(history === "true"){ 354 | writeHistory(torrent_title); 355 | } 356 | } else { 357 | streamTorrent_wo_sub_list(torrent, torrent_index); 358 | if(history === "true"){ 359 | writeHistory(torrent_title); 360 | } 361 | } 362 | }); 363 | } else if(use_subtitle === "false"){ 364 | streamTorrent_wo_sub_list(torrent, torrent_index); 365 | if(history === "true"){ 366 | writeHistory(torrent_title); 367 | } 368 | } 369 | } 370 | }); 371 | 372 | } else if(data === false){ 373 | 374 | if(use_subtitle === "true"){ 375 | subtitles.fetchSub(subtitle_language, torrent_title).then(function(data) { 376 | if(data !== false){ 377 | peerflix_subtitle = data; 378 | streamTorrent_sub(torrent); 379 | if(history === "true"){ 380 | writeHistory(torrent_title); 381 | } 382 | } else { 383 | streamTorrent_wosub(torrent); 384 | if(history === "true"){ 385 | writeHistory(torrent_title); 386 | } 387 | } 388 | }); 389 | } else if(use_subtitle === "false"){ 390 | streamTorrent_wosub(torrent); 391 | if(history === "true"){ 392 | writeHistory(torrent_title); 393 | } 394 | } 395 | } 396 | 397 | }); 398 | } 399 | 400 | function getSubtitles(torrent, torrent_title){ 401 | 402 | subtitles.fetchSub(subtitle_language, torrent_title).then(function(data) { 403 | if(data !== false){ 404 | peerflix_subtitle = data; 405 | streamTorrent_sub(torrent); 406 | } else { 407 | streamTorrent_wosub(torrent); 408 | } 409 | }); 410 | 411 | } 412 | 413 | function writeHistory(torrent_name) { 414 | var history_array = get_hist_object.get('recentlyWatched.items'); 415 | if (history_array.indexOf(torrent_name) == -1) { 416 | history_array.push(torrent_name); 417 | get_hist_object.set('recentlyWatched.items', history_array); 418 | } 419 | } 420 | 421 | function exitApp(){ 422 | console.log(chalk.red("Exiting app...")); 423 | process.exit(code=0); 424 | } 425 | 426 | function printHistory(){ 427 | histcount = 1; 428 | 429 | if(history === "true"){ 430 | var all_hist = get_hist_object.get('recentlyWatched'); 431 | 432 | if(all_hist.items.length > 0){ 433 | console.log(chalk.green("Watched History: ")); 434 | Object.keys(all_hist.items).forEach(function(key) { 435 | console.log(chalk.red(histcount + ' ') + chalk.magenta(all_hist.items[key])); 436 | histcount++; 437 | }); 438 | } else { 439 | console.log(chalk.red("Your history file is empty, Go watch some torrents!")); 440 | } 441 | 442 | } else { 443 | console.log(chalk.red("History is not enabled")); 444 | } 445 | } 446 | 447 | function searchHistory(search_title) { 448 | var all_hist = get_hist_object.get('recentlyWatched.items'); 449 | if (all_hist.indexOf(search_title) > -1) { 450 | return true; 451 | } else { 452 | return false; 453 | } 454 | } 455 | 456 | function streamTorrent_wo_sub_list(torrent, index){ 457 | var argsList; 458 | 459 | if(peerflix_player === "--airplay"){ 460 | argsList = [torrent, "--i=" + index, peerflix_player]; 461 | } else { 462 | if (isWindows) { 463 | argsList = [torrent.split('&')[0], "--i=" + index, peerflix_player, peerflix_player_arg, peerflix_port]; 464 | } else { 465 | argsList = [torrent, "--i=" + index, peerflix_player, peerflix_player_arg, peerflix_port]; 466 | } 467 | } 468 | osSpecificSpawn(peerflix_command, argsList); 469 | } 470 | 471 | function streamTorrent_sub_list(torrent, index){ 472 | var argsList; 473 | 474 | if(peerflix_player === "--airplay"){ 475 | argsList = [torrent, "--i=" + index, peerflix_player]; 476 | } else { 477 | if (isWindows) { 478 | argsList = [torrent.split('&')[0], "--subtitles=\"" + peerflix_subtitle + "\"", "--i=" + index, peerflix_player, peerflix_player_arg, peerflix_port]; 479 | } else { 480 | argsList = [torrent, "--subtitles=" + peerflix_subtitle, "--i=" + index, peerflix_player, peerflix_player_arg, peerflix_port]; 481 | } 482 | } 483 | osSpecificSpawn(peerflix_command, argsList); 484 | } 485 | 486 | function streamTorrent_wosub(torrent){ 487 | var argsList; 488 | 489 | if(peerflix_player === "--airplay"){ 490 | argsList = [torrent, peerflix_player]; 491 | } else { 492 | if (isWindows) { 493 | argsList = [torrent.split('&')[0], peerflix_player, peerflix_player_arg, peerflix_port]; 494 | } else{ 495 | argsList = [torrent, peerflix_player, peerflix_player_arg, peerflix_port]; 496 | } 497 | } 498 | osSpecificSpawn(peerflix_command, argsList); 499 | } 500 | 501 | function streamTorrent_sub(torrent){ 502 | var argsList; 503 | 504 | if(peerflix_player === "--airplay"){ 505 | argsList = [torrent, peerflix_player]; 506 | } else { 507 | if (isWindows) { 508 | argsList = [torrent.split('&')[0], "--subtitles=\"" + peerflix_subtitle + "\"", peerflix_player, peerflix_player_arg, peerflix_port]; 509 | } else { 510 | argsList = [torrent, "--subtitles=" + peerflix_subtitle, peerflix_player, peerflix_player_arg, peerflix_port]; 511 | } 512 | } 513 | osSpecificSpawn(peerflix_command, argsList); 514 | } 515 | 516 | function osSpecificSpawn(command, argsList){ 517 | 518 | if(peerflix_path){ 519 | argsList.push('--path=' + peerflix_path + ''); 520 | } 521 | if (isWindows) { 522 | argsList.unshift('/c', command); 523 | const peerflix = spawn('cmd', argsList, {stdio:'inherit'}); 524 | 525 | peerflix.on('close', (code) => { 526 | if (code == 0) { 527 | trakt.markaswatched(torrent_title); 528 | //return process.exit(22); 529 | } else { 530 | //return process.exit(22); 531 | } 532 | 533 | }); 534 | } else { 535 | const peerflix = spawn(command, argsList, {stdio:'inherit'}); 536 | 537 | peerflix.on('close', (code) => { 538 | if (code == 0) { 539 | trakt.markaswatched(torrent_title); 540 | //return process.exit(22); 541 | } else { 542 | //return process.exit(22); 543 | } 544 | 545 | }); 546 | } 547 | 548 | } 549 | 550 | }).call(this); 551 | --------------------------------------------------------------------------------