├── .gitignore ├── .travis.yml ├── Dockerfile ├── README.md ├── ali213.png ├── ali213.py ├── experimental ├── getigg.js └── warezgames.py ├── smallgames.png ├── smallgames.py └── tests ├── ali213.sh └── smallgames.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | venv/ 3 | lib/ 4 | testing/ 5 | *cookie.json 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | services: 4 | - docker 5 | 6 | jobs: 7 | include: 8 | - script: 9 | - docker build -t hannsen/qbittorrent_search_plugins . 10 | - docker run hannsen/qbittorrent_search_plugins ./tests/ali213.sh 11 | name: "ali213" 12 | - script: 13 | - docker build -t hannsen/qbittorrent_search_plugins . 14 | - docker run hannsen/qbittorrent_search_plugins ./tests/smallgames.sh 15 | name: "smallgames" 16 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | 3 | WORKDIR /app 4 | 5 | RUN wget https://raw.githubusercontent.com/qbittorrent/qBittorrent/master/src/searchengine/nova3/helpers.py && \ 6 | wget https://raw.githubusercontent.com/qbittorrent/qBittorrent/master/src/searchengine/nova3/nova2.py && \ 7 | wget https://raw.githubusercontent.com/qbittorrent/qBittorrent/master/src/searchengine/nova3/nova2dl.py && \ 8 | wget https://raw.githubusercontent.com/qbittorrent/qBittorrent/master/src/searchengine/nova3/novaprinter.py && \ 9 | wget https://raw.githubusercontent.com/qbittorrent/qBittorrent/master/src/searchengine/nova3/sgmllib3.py && \ 10 | wget https://raw.githubusercontent.com/qbittorrent/qBittorrent/master/src/searchengine/nova3/socks.py 11 | 12 | COPY . /app 13 | 14 | RUN chmod -R 777 /app/tests 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [](https://travis-ci.com/hannsen/qbittorrent_search_plugins) 2 | 3 | 4 | [Plugin list](https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins) 5 | 6 | # qbit_search_plugins 7 | 8 | 9 | ## ali213.net : ali213.py 10 | Chinese Gaming Website 11 | 12 | Don't blame me if this runs slow, it has to use chinese servers 13 | 14 | Beware that they sometimes upload uncracked games on here. 15 | If you click the "Show description page" button, you will get additional non-torrent links. 16 | For more info open the file inside a text editor and read the first lines 17 | 18 | ## small-games.info : smallgames.py 19 | Russian Gaming Website 20 | 21 | Not all results return a torrent file. 22 | Click description button to see the game page for it. 23 | If there is a mediaget button, you can add &direct=1 24 | to its link to get the torrent file. 25 | 26 | ## ~~bt.3dmgame.com : threedm.py~~ 27 | ~~Chinese Gaming Website~~ 28 | 29 | REMOVED: OFFLINE 30 | 31 | ## ~~demonoid.pw : demonoid.py~~ 32 | REMOVED: Semi-private, only shows newest torrents, not searchable as non logged-in user 33 | 34 | ## ~~[Jackett](https://github.com/Jackett/Jackett) : jackett.py~~ 35 | REMOVED: is now included as a default search plugin 36 | -------------------------------------------------------------------------------- /ali213.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannsen/qbittorrent_search_plugins/058f2aba8f410edc9ae267684ac0e9018f6cd87a/ali213.png -------------------------------------------------------------------------------- /ali213.py: -------------------------------------------------------------------------------- 1 | #VERSION: 1.1 2 | #AUTHORS: hoanns 3 | # Chinese Gaming Site 4 | # Beware that they sometimes upload uncracked games on here. 5 | # 6 | # I have to do 3 page requests (to chinese servers) per game 7 | # to get to the english release name and torrent. 8 | # So I set the games_to_parse (see below) value to 5. 9 | 10 | 11 | import re 12 | import threading 13 | import time 14 | # qBt 15 | from novaprinter import prettyPrinter 16 | from helpers import retrieve_url 17 | 18 | 19 | # noinspection PyPep8Naming 20 | class ali213(object): 21 | url = "http://down.ali213.net/" 22 | name = "ali213" 23 | # The ali search is not strict and will give you all kinds of bogus games 24 | # I am fine with the 5 most relevant games to parse, since I will not use broad search terms 25 | games_to_parse = 5 26 | # first size (e.g. 40.7G) then game page (e.g. arksurvivalevolved.html) 27 | result_page_match = re.compile( 28 | '
.*?(.{2,7})') 29 | 30 | supported_categories = {'all': True, 31 | 'games': True, 32 | 'software': True} 33 | 34 | first_dl_site = "http://www.soft50.com/" 35 | final_dl_site = "http://btfile.soft5566.com/y/" 36 | 37 | def handle_gamepage(self, size_gamepage): 38 | data = retrieve_url(self.url + 'pcgame/' + size_gamepage[0]) 39 | down_url_match = re.compile('var downUrl ="/(.*?)"') 40 | url_key_soft50 = down_url_match.findall(data) 41 | if url_key_soft50: 42 | data = '' 43 | tries = 0 44 | while data == '' and tries < 20: 45 | time.sleep(2) 46 | data = retrieve_url(self.first_dl_site + url_key_soft50[0]) 47 | tries += 1 48 | 49 | down_url_match = re.compile('class="result_js" href="(.*?)" target="_blank">') 50 | url_soft5566 = down_url_match.findall(data) 51 | if url_soft5566: 52 | data = retrieve_url(url_soft5566[0]) 53 | desc_site = url_soft5566[0] 54 | down_url_match = re.compile('id="btbtn" href="' + self.final_dl_site + '(.*?)" target="_blank"') 55 | url_torrent = down_url_match.findall(data) 56 | if url_torrent: 57 | result = { 58 | 'name': url_torrent[0], 59 | 'size': size_gamepage[1], 60 | 'link': self.final_dl_site + url_torrent[0], 61 | 'desc_link': desc_site, 62 | 'seeds': -1, 63 | 'leech': -1, 64 | 'engine_url': self.url 65 | } 66 | prettyPrinter(result) 67 | return 68 | 69 | def search(self, what, cat='all'): 70 | 71 | query = "http://down.ali213.net/search?kw=" + what + "&submit=" 72 | data = retrieve_url(query) 73 | found_games = re.findall(self.result_page_match, data) 74 | 75 | if found_games: 76 | if self.games_to_parse > len(found_games): 77 | self.games_to_parse = len(found_games) 78 | # handling each gamepage in parallel, to not waste time on waiting for requests 79 | # for 10 games this speeds up from 37s to 6s run time 80 | threads = [] 81 | for i in range(self.games_to_parse): 82 | t = threading.Thread(target=self.handle_gamepage, args=(found_games[i],)) 83 | threads.append(t) 84 | t.start() 85 | 86 | # search method needs to stay alive until all threads are done 87 | for t in threads: 88 | t.join() 89 | 90 | return 91 | 92 | 93 | if __name__ == "__main__": 94 | engine = ali213() 95 | engine.search('ark.survival', 'games') 96 | -------------------------------------------------------------------------------- /experimental/getigg.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var system = require('system'); 3 | var fs = require('fs'); 4 | var CookieJar = "igg_cookie.json"; 5 | var pageResponses = {}; 6 | 7 | var page = require('webpage').create(); 8 | page.settings.userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36" 9 | 10 | 11 | // cookie shit, not sure it does anything 12 | page.onResourceReceived = function(response) { 13 | pageResponses[response.url] = response.status; 14 | fs.write(CookieJar, JSON.stringify(phantom.cookies), "w"); 15 | }; 16 | if(fs.isFile(CookieJar)) 17 | Array.prototype.forEach.call(JSON.parse(fs.read(CookieJar)), function(x){ 18 | phantom.addCookie(x); 19 | }); 20 | 21 | // actual code 22 | page.open("http://igg-games.com/?s=" + system.args[1] + "&=submit", function(status) { 23 | waitFor({ 24 | interval: 100, 25 | timeout: 45000, 26 | check: function () { 27 | return page.evaluate(function() { 28 | var titleFound = document.querySelector("#primary-content h1.title span.alt") ? true : false; 29 | 30 | if(document.querySelector('h1.title')) 31 | var noFound = document.querySelector('h1.title').textContent == "Nothing found :("; 32 | else 33 | var noFound = false; 34 | 35 | return noFound || titleFound; 36 | }); 37 | }, 38 | success: function () { 39 | console.log(page.content); 40 | phantom.exit(); 41 | }, 42 | error: function () { 43 | console.log("failure"); 44 | phantom.exit(); 45 | } 46 | }); 47 | }); 48 | 49 | 50 | 51 | function waitFor ($config) { 52 | $config._start = $config._start || new Date(); 53 | 54 | if ($config.timeout && new Date - $config._start > $config.timeout) { 55 | if ($config.error) $config.error(); 56 | if ($config.debug) console.log('timedout ' + (new Date - $config._start) + 'ms'); 57 | phantom.exit(); 58 | } 59 | 60 | if ($config.check()) { 61 | if ($config.debug) console.log('success ' + (new Date - $config._start) + 'ms'); 62 | return $config.success(); 63 | } 64 | 65 | setTimeout(waitFor, $config.interval || 0, $config); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /experimental/warezgames.py: -------------------------------------------------------------------------------- 1 | #VERSION: 0.6 2 | #AUTHORS: hoanns 3 | # getigg.js needs to be in nova2.py folder 4 | # doesnt work with qbit tho, only made to use with nova2.py 5 | # python 3 only 6 | # phantomjs needs to be installed and in path 7 | 8 | import re 9 | import subprocess 10 | import base64 11 | 12 | from novaprinter import prettyPrinter 13 | from helpers import retrieve_url 14 | 15 | 16 | # user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.79 Safari/537.36" 17 | # headers = {'User-Agent': user_agent} 18 | 19 | 20 | # noinspection PyPep8Naming 21 | class warezgames(object): 22 | url = "http://www.warezgames.com/" 23 | name = "WarezGames" 24 | 25 | def search(self, what, cat='all'): 26 | what = what.lower() 27 | 28 | process = subprocess.Popen(['phantomjs.exe', 'getigg.js', what], stdout=subprocess.PIPE, shell=True) 29 | out, err = process.communicate() 30 | igg_data = out.decode('utf-8') 31 | igg_match = re.compile('(.*?)') 32 | igg_results = re.findall(igg_match, igg_data) 33 | 34 | csrin_query = "https://cs.rin.ru/forum/search.php?keywords=" + what + "&terms=all&author=&sc=1&sf=titleonly&sk=t&sd=d&sr=topics&st=0&ch=300&t=0" 35 | csrin_data = retrieve_url(csrin_query) 36 | csrin_match = re.compile('(.*?)') 37 | cs_results = re.findall(csrin_match, csrin_data) 38 | 39 | skid_query = "https://skidrowreloadedcodex.org/?s=" + what.replace(' ', '+') 40 | skid_data = retrieve_url(skid_query) 41 | skid_match = re.compile('
MIRROR.*?
') 67 | skid_data = retrieve_url(link) 68 | return base64.b64encode(re.findall(skid_dl_match, skid_data)[0]) 69 | except: 70 | return None 71 | 72 | 73 | if __name__ == "__main__": 74 | engine = warezgames() 75 | engine.search('isaac') 76 | -------------------------------------------------------------------------------- /smallgames.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hannsen/qbittorrent_search_plugins/058f2aba8f410edc9ae267684ac0e9018f6cd87a/smallgames.png -------------------------------------------------------------------------------- /smallgames.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # VERSION: 1.03 3 | # AUTHORS: hoanns 4 | # small-games.info 5 | # Not all results return a torrent file. 6 | # Click description button to see the game page for it. 7 | # If there is a mediaget button, you can add &direct=1 8 | # to its link to get the torrent file. 9 | 10 | import os 11 | import re 12 | import ssl 13 | import tempfile 14 | 15 | from urllib.request import urlopen 16 | 17 | from helpers import retrieve_url 18 | # qBt 19 | from novaprinter import prettyPrinter 20 | 21 | 22 | # noinspection PyPep8Naming 23 | class smallgames(object): 24 | url = "http://small-games.info/" 25 | name = 'small-games.info' 26 | result = { 27 | 'seeds': -1, 28 | 'leech': -1, 29 | 'engine_url': url 30 | } 31 | supported_categories = {'all': True, 32 | 'games': True} 33 | 34 | def download_torrent(self, url): 35 | file, path = tempfile.mkstemp('.torrent') 36 | file = os.fdopen(file, "wb") 37 | 38 | dat = self.get_url(url) 39 | data = dat.decode('utf-8', 'replace') 40 | if data == 'No link found!' or data == 'some error': 41 | return None 42 | else: 43 | # Write it to a file 44 | file.write(dat) 45 | file.close() 46 | # return file path 47 | print(path + " " + url) 48 | 49 | def search(self, what, cat='all'): 50 | query = "https://small-games.info/?go=search&go=search&search_text=" + what 51 | data = self.get_url(query).decode('utf-8', 'replace') 52 | match = re.compile('