├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── ci.yaml │ └── deploy_wiki.yaml ├── .gitignore ├── LICENSE ├── README.md ├── nova3 └── engines │ ├── __init__.py │ ├── eztv.py │ ├── jackett.py │ ├── limetorrents.py │ ├── piratebay.py │ ├── solidtorrents.py │ ├── torlock.py │ ├── torrentproject.py │ ├── torrentscsv.py │ └── versions.txt └── wiki ├── Home.md ├── How-to-configure-Jackett-plugin.md ├── How-to-write-a-search-plugin.md ├── Install-search-plugins.md ├── New-Torznab-search-engine.md ├── Request-unofficial-search-plugin.md ├── Unofficial-search-plugins.mediawiki ├── qbittorrent_torznab_search_1.png ├── qbittorrent_torznab_search_2.png ├── qbittorrent_torznab_search_3.png ├── qbittorrent_torznab_search_4.png ├── qbittorrent_torznab_search_5.png ├── qbittorrent_torznab_search_6.png ├── qbittorrent_torznab_search_7.png └── qbittorrent_torznab_search_8.png /.gitattributes: -------------------------------------------------------------------------------- 1 | core.eol=lf 2 | * text eol=lf 3 | 4 | # (binary is a macro for -text -diff) 5 | *.png binary 6 | *.jpg binary 7 | *.jpeg binary 8 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | groups: 7 | github-actions: 8 | patterns: 9 | - "*" 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: {} 6 | 7 | concurrency: 8 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 9 | cancel-in-progress: ${{ github.head_ref != '' }} 10 | 11 | jobs: 12 | ci: 13 | name: Check 14 | runs-on: ubuntu-latest 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14-dev'] 19 | 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v4 23 | with: 24 | persist-credentials: false 25 | 26 | - name: Setup python 27 | uses: actions/setup-python@v5 28 | with: 29 | python-version: ${{ matrix.python-version }} 30 | 31 | - name: Install tools 32 | run: pip install bandit isort pycodestyle pyflakes 33 | 34 | - name: Lint code 35 | run: | 36 | pyflakes nova3/engines/*.py 37 | bandit --skip B110,B310,B314,B405 nova3/engines/*.py 38 | 39 | - name: Format code 40 | run: | 41 | # skipping E265, fixing it will break plugin usage on older qbt instances (< v4.1.2) 42 | pycodestyle \ 43 | --ignore=E265,W503 \ 44 | --max-line-length=1000 \ 45 | --statistics \ 46 | nova3/engines/*.py 47 | isort \ 48 | --check \ 49 | --diff \ 50 | nova3/engines/*.py 51 | 52 | - name: Build code 53 | run: | 54 | python -m compileall nova3/engines/*.py 55 | 56 | 57 | zizmor: 58 | name: Check workflow files 59 | runs-on: ubuntu-latest 60 | permissions: 61 | security-events: write 62 | 63 | steps: 64 | - name: Checkout repository 65 | uses: actions/checkout@v4 66 | with: 67 | persist-credentials: false 68 | 69 | - name: Check GitHub Actions workflow 70 | env: 71 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 72 | run: | 73 | pip install zizmor 74 | zizmor \ 75 | --format sarif \ 76 | --persona auditor \ 77 | ./ \ 78 | | jq '(.runs[].results |= map(select(.ruleId != "zizmor/unpinned-uses"))) 79 | | (.runs[].tool.driver.rules |= map(select(.id != "zizmor/unpinned-uses")))' \ 80 | > "${{ runner.temp }}/zizmor_results.sarif" 81 | 82 | - name: Upload zizmor results 83 | uses: github/codeql-action/upload-sarif@v3 84 | with: 85 | category: zizmor 86 | sarif_file: "${{ runner.temp }}/zizmor_results.sarif" 87 | -------------------------------------------------------------------------------- /.github/workflows/deploy_wiki.yaml: -------------------------------------------------------------------------------- 1 | name: Deploy wiki 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | paths: 8 | - 'wiki/*' 9 | 10 | permissions: {} 11 | 12 | concurrency: 13 | group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} 14 | cancel-in-progress: ${{ github.head_ref != '' }} 15 | 16 | jobs: 17 | deploy: 18 | name: Deploy wiki 19 | runs-on: ubuntu-latest 20 | permissions: 21 | contents: write 22 | 23 | steps: 24 | - name: Checkout repository 25 | uses: actions/checkout@v4 26 | with: 27 | persist-credentials: true 28 | 29 | - name: Deploy 30 | run: | 31 | mv .git wiki 32 | cd wiki 33 | git config user.name "qbt_search-plugins_bot" 34 | git config user.email "qbt_search-plugins_bot@example.com" 35 | git checkout --orphan tmp 36 | git add -A 37 | git commit -m "Import" 38 | git branch -D master 39 | git branch -m master 40 | git push https://github.com/qbittorrent/search-plugins.wiki.git --force 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Editors 2 | .vscode/ 3 | .idea/ 4 | 5 | # Python 6 | *.pyc 7 | 8 | # Plugin config 9 | /nova3/engines/jackett.json 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Search Plugins 2 | === 3 | [![GitHub Actions CI Status](https://github.com/qbittorrent/search-plugins/workflows/CI/badge.svg)](https://github.com/qbittorrent/search-plugins/actions) 4 | 5 | This repository contains search plugins for the search feature in [qBittorrent](https://github.com/qbittorrent/qBittorrent). 6 | 7 | :warning: We removed support for Python 2. Please, upgrade to Python 3 to continue using the search function. 8 | 9 | Jackett search plugin is enabled by default but you have to install an external program to make it work. You can disable the Jackett search plugin or [install Jackett](https://github.com/qbittorrent/search-plugins/wiki/How-to-configure-Jackett-plugin). 10 | 11 | Most probably, you want to head over to the [wiki](https://github.com/qbittorrent/search-plugins/wiki): 12 | * [List of unofficial search plugins](https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins) 13 | * [Request unofficial search plugin](https://github.com/qbittorrent/search-plugins/wiki/Request-unofficial-search-plugin) 14 | * [How to configure Jackett plugin](https://github.com/qbittorrent/search-plugins/wiki/How-to-configure-Jackett-plugin) 15 | * [How to write a search plugin](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin) 16 | * [How to install search plugins](https://github.com/qbittorrent/search-plugins/wiki/Install-search-plugins) 17 | * [New Torznab search engine](https://github.com/qbittorrent/search-plugins/wiki/New-Torznab-search-engine) 18 | 19 | Everyone is welcome to submit PRs that fix problems or add new plugins. 20 | 21 | This repository isn't managed by the core team directly. Its purpose is to allow a place where 3rd party contributors can gather and submit their plugins. 22 | 23 | **Use the plugins and the websites they refer to at your own risk. You are personally responsible for following your country's copyright laws.** 24 | -------------------------------------------------------------------------------- /nova3/engines/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/nova3/engines/__init__.py -------------------------------------------------------------------------------- /nova3/engines/eztv.py: -------------------------------------------------------------------------------- 1 | # VERSION: 1.17 2 | # AUTHORS: nindogo 3 | # CONTRIBUTORS: Diego de las Heras (ngosang@hotmail.es) 4 | 5 | import re 6 | import urllib.error 7 | import urllib.parse 8 | import urllib.request 9 | from datetime import datetime, timedelta 10 | from html.parser import HTMLParser 11 | 12 | from helpers import retrieve_url 13 | from novaprinter import prettyPrinter 14 | 15 | 16 | class eztv(object): 17 | name = "EZTV" 18 | url = 'https://eztvx.to/' 19 | supported_categories = {'all': 'all', 'tv': 'tv'} 20 | 21 | class MyHtmlParser(HTMLParser): 22 | A, TD, TR, TABLE = ('a', 'td', 'tr', 'table') 23 | 24 | """ Sub-class for parsing results """ 25 | def __init__(self, url): 26 | HTMLParser.__init__(self) 27 | self.url = url 28 | 29 | now = datetime.now() 30 | self.date_parsers = { 31 | r"(\d+)h\s+(\d+)m": lambda m: now - timedelta(hours=int(m[1]), minutes=int(m[2])), 32 | r"(\d+)d\s+(\d+)h": lambda m: now - timedelta(days=int(m[1]), hours=int(m[2])), 33 | r"(\d+)\s+weeks?": lambda m: now - timedelta(weeks=int(m[1])), 34 | r"(\d+)\s+mo": lambda m: now - timedelta(days=int(m[1]) * 30), 35 | r"(\d+)\s+years?": lambda m: now - timedelta(days=int(m[1]) * 365), 36 | } 37 | self.in_table_row = False 38 | self.current_item = {} 39 | 40 | def handle_starttag(self, tag, attrs): 41 | params = dict(attrs) 42 | 43 | if (params.get('class') == 'forum_header_border' 44 | and params.get('name') == 'hover'): 45 | self.in_table_row = True 46 | self.current_item = {} 47 | self.current_item['seeds'] = -1 48 | self.current_item['leech'] = -1 49 | self.current_item['size'] = -1 50 | self.current_item['engine_url'] = self.url 51 | self.current_item['pub_date'] = -1 52 | 53 | if (tag == self.A 54 | and self.in_table_row and params.get('class') == 'magnet'): 55 | self.current_item['link'] = params.get('href') 56 | 57 | if (tag == self.A 58 | and self.in_table_row and params.get('class') == 'epinfo'): 59 | self.current_item['desc_link'] = self.url + params.get('href') 60 | self.current_item['name'] = params.get('title').split(' (')[0] 61 | 62 | def handle_data(self, data): 63 | data = data.replace(',', '') 64 | if (self.in_table_row 65 | and (data.endswith(' KB') or data.endswith(' MB') or data.endswith(' GB'))): 66 | self.current_item['size'] = data 67 | 68 | elif self.in_table_row and data.isnumeric(): 69 | self.current_item['seeds'] = int(data) 70 | 71 | elif self.in_table_row: # Check for a relative time 72 | for pattern, calc in self.date_parsers.items(): 73 | m = re.match(pattern, data) 74 | if m: 75 | self.current_item["pub_date"] = int(calc(m).timestamp()) 76 | break 77 | 78 | def handle_endtag(self, tag): 79 | if self.in_table_row and tag == self.TR: 80 | prettyPrinter(self.current_item) 81 | self.in_table_row = False 82 | 83 | def do_query(self, what): 84 | url = f"{self.url}/search/{what.replace('%20', '-')}" 85 | data = b"layout=def_wlinks" 86 | try: 87 | return retrieve_url(url, request_data=data) 88 | except TypeError: 89 | # Older versions of retrieve_url did not support request_data/POST, se we must do the 90 | # request ourselves... 91 | user_agent = 'Mozilla/5.0 (X11; Linux x86_64; rv:125.0) Gecko/20100101 Firefox/125.0' 92 | req = urllib.request.Request(url, data, {'User-Agent': user_agent}) 93 | try: 94 | response = urllib.request.urlopen(req) # nosec B310 95 | return response.read().decode('utf-8') 96 | except urllib.error.URLError as errno: 97 | print(f"Connection error: {errno.reason}") 98 | return "" 99 | 100 | def search(self, what, cat='all'): 101 | eztv_html = self.do_query(what) 102 | 103 | eztv_parser = self.MyHtmlParser(self.url) 104 | eztv_parser.feed(eztv_html) 105 | eztv_parser.close() 106 | 107 | 108 | if __name__ == '__main__': 109 | eztv_se = eztv() 110 | eztv_se.search('Acre', 'all') 111 | -------------------------------------------------------------------------------- /nova3/engines/jackett.py: -------------------------------------------------------------------------------- 1 | # VERSION: 4.3 2 | # AUTHORS: Diego de las Heras (ngosang@hotmail.es) 3 | # CONTRIBUTORS: ukharley 4 | # hannsen (github.com/hannsen) 5 | # Alexander Georgievskiy 6 | 7 | import json 8 | import os 9 | import urllib.request 10 | import xml.etree.ElementTree 11 | from datetime import datetime 12 | from http.cookiejar import CookieJar 13 | from multiprocessing.dummy import Pool 14 | from threading import Lock 15 | from urllib.parse import unquote, urlencode 16 | 17 | import helpers 18 | from novaprinter import prettyPrinter 19 | 20 | 21 | ############################################################################### 22 | class ProxyManager: 23 | HTTP_PROXY_KEY = "http_proxy" 24 | HTTPS_PROXY_KEY = "https_proxy" 25 | 26 | def __init__(self) -> None: 27 | self.http_proxy = os.environ.get(self.HTTP_PROXY_KEY, "") 28 | self.https_proxy = os.environ.get(self.HTTPS_PROXY_KEY, "") 29 | 30 | def enable_proxy(self, enable: bool) -> None: 31 | # http proxy 32 | if enable: 33 | os.environ[self.HTTP_PROXY_KEY] = self.http_proxy 34 | os.environ[self.HTTPS_PROXY_KEY] = self.https_proxy 35 | else: 36 | os.environ.pop(self.HTTP_PROXY_KEY, None) 37 | os.environ.pop(self.HTTPS_PROXY_KEY, None) 38 | 39 | # SOCKS proxy 40 | # best effort and avoid breaking older qbt versions 41 | try: 42 | helpers.enable_socks_proxy(enable) 43 | except AttributeError: 44 | pass 45 | 46 | 47 | # initialize it early to ensure env vars were not tampered 48 | proxy_manager = ProxyManager() 49 | proxy_manager.enable_proxy(False) # off by default 50 | 51 | 52 | ############################################################################### 53 | # load configuration from file 54 | CONFIG_FILE = 'jackett.json' 55 | CONFIG_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), CONFIG_FILE) 56 | CONFIG_DATA = { 57 | 'api_key': 'YOUR_API_KEY_HERE', # jackett api 58 | 'url': 'http://127.0.0.1:9117', # jackett url 59 | 'tracker_first': False, # (False/True) add tracker name to beginning of search result 60 | 'thread_count': 20, # number of threads to use for http requests 61 | } 62 | PRINTER_THREAD_LOCK = Lock() 63 | 64 | 65 | def load_configuration(): 66 | global CONFIG_DATA 67 | try: 68 | # try to load user data from file 69 | with open(CONFIG_PATH) as f: 70 | CONFIG_DATA = json.load(f) 71 | except ValueError: 72 | # if file exists, but it's malformed we load add a flag 73 | CONFIG_DATA['malformed'] = True 74 | except Exception: 75 | # if file doesn't exist, we create it 76 | save_configuration() 77 | 78 | # do some checks 79 | if any(item not in CONFIG_DATA for item in ['api_key', 'tracker_first', 'url']): 80 | CONFIG_DATA['malformed'] = True 81 | 82 | # add missing keys 83 | if 'thread_count' not in CONFIG_DATA: 84 | CONFIG_DATA['thread_count'] = 20 85 | save_configuration() 86 | 87 | 88 | def save_configuration(): 89 | with open(CONFIG_PATH, 'w') as f: 90 | f.write(json.dumps(CONFIG_DATA, indent=4, sort_keys=True)) 91 | 92 | 93 | load_configuration() 94 | ############################################################################### 95 | 96 | 97 | class jackett(object): 98 | name = 'Jackett' 99 | url = CONFIG_DATA['url'] if CONFIG_DATA['url'][-1] != '/' else CONFIG_DATA['url'][:-1] 100 | api_key = CONFIG_DATA['api_key'] 101 | thread_count = CONFIG_DATA['thread_count'] 102 | supported_categories = { 103 | 'all': None, 104 | 'anime': ['5070'], 105 | 'books': ['8000'], 106 | 'games': ['1000', '4000'], 107 | 'movies': ['2000'], 108 | 'music': ['3000'], 109 | 'software': ['4000'], 110 | 'tv': ['5000'], 111 | } 112 | 113 | def download_torrent(self, download_url): 114 | # fix for some indexers with magnet link inside .torrent file 115 | if download_url.startswith('magnet:?'): 116 | print(download_url + " " + download_url) 117 | proxy_manager.enable_proxy(True) 118 | response = self.get_response(download_url) 119 | proxy_manager.enable_proxy(False) 120 | if response is not None and response.startswith('magnet:?'): 121 | print(response + " " + download_url) 122 | else: 123 | print(helpers.download_file(download_url)) 124 | 125 | def search(self, what, cat='all'): 126 | what = unquote(what) 127 | category = self.supported_categories[cat.lower()] 128 | 129 | # check for malformed configuration 130 | if 'malformed' in CONFIG_DATA: 131 | self.handle_error("malformed configuration file", what) 132 | return 133 | 134 | # check api_key 135 | if self.api_key == "YOUR_API_KEY_HERE": 136 | self.handle_error("api key error", what) 137 | return 138 | 139 | # search in Jackett API 140 | if self.thread_count > 1: 141 | args = [] 142 | indexers = self.get_jackett_indexers(what) 143 | for indexer in indexers: 144 | args.append((what, category, indexer)) 145 | with Pool(min(len(indexers), self.thread_count)) as pool: 146 | pool.starmap(self.search_jackett_indexer, args) 147 | else: 148 | self.search_jackett_indexer(what, category, 'all') 149 | 150 | def get_jackett_indexers(self, what): 151 | params = [ 152 | ('apikey', self.api_key), 153 | ('t', 'indexers'), 154 | ('configured', 'true') 155 | ] 156 | params = urlencode(params) 157 | jacket_url = self.url + "/api/v2.0/indexers/all/results/torznab/api?%s" % params 158 | response = self.get_response(jacket_url) 159 | if response is None: 160 | self.handle_error("connection error getting indexer list", what) 161 | return 162 | # process results 163 | response_xml = xml.etree.ElementTree.fromstring(response) 164 | indexers = [] 165 | for indexer in response_xml.findall('indexer'): 166 | indexers.append(indexer.attrib['id']) 167 | return indexers 168 | 169 | def search_jackett_indexer(self, what, category, indexer_id): 170 | # prepare jackett url 171 | params = [ 172 | ('apikey', self.api_key), 173 | ('q', what) 174 | ] 175 | if category is not None: 176 | params.append(('cat', ','.join(category))) 177 | params = urlencode(params) 178 | jacket_url = self.url + "/api/v2.0/indexers/" + indexer_id + "/results/torznab/api?%s" % params # noqa 179 | response = self.get_response(jacket_url) 180 | if response is None: 181 | self.handle_error("connection error for indexer: " + indexer_id, what) 182 | return 183 | # process search results 184 | response_xml = xml.etree.ElementTree.fromstring(response) 185 | for result in response_xml.find('channel').findall('item'): 186 | res = {} 187 | 188 | title = result.find('title') 189 | if title is not None: 190 | title = title.text 191 | else: 192 | continue 193 | 194 | tracker = result.find('jackettindexer') 195 | tracker = '' if tracker is None else tracker.text 196 | if CONFIG_DATA['tracker_first']: 197 | res['name'] = '[%s] %s' % (tracker, title) 198 | else: 199 | res['name'] = '%s [%s]' % (title, tracker) 200 | 201 | res['link'] = result.find(self.generate_xpath('magneturl')) 202 | if res['link'] is not None: 203 | res['link'] = res['link'].attrib['value'] 204 | else: 205 | res['link'] = result.find('link') 206 | if res['link'] is not None: 207 | res['link'] = res['link'].text 208 | else: 209 | continue 210 | 211 | res['size'] = result.find('size') 212 | res['size'] = -1 if res['size'] is None else (res['size'].text + ' B') 213 | 214 | res['seeds'] = result.find(self.generate_xpath('seeders')) 215 | res['seeds'] = -1 if res['seeds'] is None else int(res['seeds'].attrib['value']) 216 | 217 | res['leech'] = result.find(self.generate_xpath('peers')) 218 | res['leech'] = -1 if res['leech'] is None else int(res['leech'].attrib['value']) 219 | 220 | if res['seeds'] != -1 and res['leech'] != -1: 221 | res['leech'] -= res['seeds'] 222 | 223 | res['desc_link'] = result.find('comments') 224 | if res['desc_link'] is not None: 225 | res['desc_link'] = res['desc_link'].text 226 | else: 227 | res['desc_link'] = result.find('guid') 228 | res['desc_link'] = '' if res['desc_link'] is None else res['desc_link'].text 229 | 230 | # note: engine_url can't be changed, torrent download stops working 231 | res['engine_url'] = self.url 232 | 233 | try: 234 | date = datetime.strptime(result.find('pubDate').text, '%a, %d %b %Y %H:%M:%S %z') 235 | res['pub_date'] = int(date.timestamp()) 236 | except Exception: 237 | res['pub_date'] = -1 238 | 239 | self.pretty_printer_thread_safe(res) 240 | 241 | def generate_xpath(self, tag): 242 | return './{http://torznab.com/schemas/2015/feed}attr[@name="%s"]' % tag 243 | 244 | def get_response(self, query): 245 | response = None 246 | try: 247 | # we can't use helpers.retrieve_url because of redirects 248 | # we need the cookie processor to handle redirects 249 | opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(CookieJar())) 250 | response = opener.open(query).read().decode('utf-8') 251 | except urllib.request.HTTPError as e: 252 | # if the page returns a magnet redirect, used in download_torrent 253 | if e.code == 302: 254 | response = e.url 255 | except Exception: 256 | pass 257 | return response 258 | 259 | def handle_error(self, error_msg, what): 260 | # we need to print the search text to be displayed in qBittorrent when 261 | # 'Torrent names only' is enabled 262 | self.pretty_printer_thread_safe({ 263 | 'seeds': -1, 264 | 'size': -1, 265 | 'leech': -1, 266 | 'engine_url': self.url, 267 | 'link': self.url, 268 | 'desc_link': 'https://github.com/qbittorrent/search-plugins/wiki/How-to-configure-Jackett-plugin', # noqa 269 | 'name': "Jackett: %s! Right-click this row and select 'Open description page' to open help. Configuration file: '%s' Search: '%s'" % (error_msg, CONFIG_PATH, what) # noqa 270 | }) 271 | 272 | def pretty_printer_thread_safe(self, dictionary): 273 | with PRINTER_THREAD_LOCK: 274 | prettyPrinter(self.escape_pipe(dictionary)) 275 | 276 | def escape_pipe(self, dictionary): 277 | # Safety measure until it's fixed in prettyPrinter 278 | for key in dictionary.keys(): 279 | if isinstance(dictionary[key], str): 280 | dictionary[key] = dictionary[key].replace('|', '%7C') 281 | return dictionary 282 | 283 | 284 | if __name__ == "__main__": 285 | jackett_se = jackett() 286 | jackett_se.search("ubuntu server", 'software') 287 | -------------------------------------------------------------------------------- /nova3/engines/limetorrents.py: -------------------------------------------------------------------------------- 1 | # VERSION: 4.11 2 | # AUTHORS: Lima66 3 | # CONTRIBUTORS: Diego de las Heras (ngosang@hotmail.es) 4 | 5 | import re 6 | from datetime import datetime, timedelta 7 | from html.parser import HTMLParser 8 | from urllib.parse import quote 9 | 10 | from helpers import retrieve_url 11 | from novaprinter import prettyPrinter 12 | 13 | 14 | class limetorrents(object): 15 | url = "https://www.limetorrents.lol" 16 | name = "LimeTorrents" 17 | supported_categories = {'all': 'all', 18 | 'anime': 'anime', 19 | 'software': 'applications', 20 | 'games': 'games', 21 | 'movies': 'movies', 22 | 'music': 'music', 23 | 'tv': 'tv'} 24 | 25 | class MyHtmlParser(HTMLParser): 26 | """ Sub-class for parsing results """ 27 | 28 | def error(self, message): 29 | pass 30 | 31 | A, TD, TR, HREF = ('a', 'td', 'tr', 'href') 32 | 33 | def __init__(self, url): 34 | HTMLParser.__init__(self) 35 | self.url = url 36 | self.current_item = {} # dict for found item 37 | self.page_items = 0 38 | self.inside_table = False 39 | self.inside_tr = False 40 | self.column_index = -1 41 | self.column_name = None # key's name in current_item dict 42 | self.columns = ["name", "pub_date", "size", "seeds", "leech"] 43 | 44 | now = datetime.now() 45 | self.date_parsers = { 46 | r"yesterday": lambda m: now - timedelta(days=1), 47 | r"last\s+month": lambda m: now - timedelta(days=30), 48 | r"(\d+)\s+years?": lambda m: now - timedelta(days=int(m[1]) * 365), 49 | r"(\d+)\s+months?": lambda m: now - timedelta(days=int(m[1]) * 30), 50 | r"(\d+)\s+days?": lambda m: now - timedelta(days=int(m[1])), 51 | r"(\d+)\s+hours?": lambda m: now - timedelta(hours=int(m[1])), 52 | r"(\d+)\s+minutes?": lambda m: now - timedelta(minutes=int(m[1])), 53 | } 54 | 55 | def handle_starttag(self, tag, attrs): 56 | params = dict(attrs) 57 | 58 | if params.get('class') == 'table2': 59 | self.inside_table = True 60 | elif not self.inside_table: 61 | return 62 | 63 | if tag == self.TR and (params.get('bgcolor') == '#F4F4F4' or params.get('bgcolor') == '#FFFFFF'): # noqa 64 | self.inside_tr = True 65 | self.column_index = -1 66 | self.current_item = {"engine_url": self.url} 67 | elif not self.inside_tr: 68 | return 69 | 70 | if tag == self.TD: 71 | self.column_index += 1 72 | if self.column_index < len(self.columns): 73 | self.column_name = self.columns[self.column_index] 74 | else: 75 | self.column_name = None 76 | 77 | if self.column_name == "name" and tag == self.A and self.HREF in params: 78 | link = params["href"] 79 | if link.endswith(".html"): 80 | try: 81 | safe_link = quote(self.url + link, safe='/:') 82 | except KeyError: 83 | safe_link = self.url + link 84 | self.current_item["link"] = safe_link 85 | self.current_item["desc_link"] = safe_link 86 | 87 | def handle_data(self, data): 88 | if self.column_name: 89 | if self.column_name in ["size", "seeds", "leech"]: 90 | data = data.replace(',', '') 91 | elif self.column_name == "pub_date": 92 | timestamp = -1 93 | for pattern, calc in self.date_parsers.items(): 94 | m = re.match(pattern, data, re.IGNORECASE) 95 | if m: 96 | timestamp = int(calc(m).timestamp()) 97 | break 98 | data = str(timestamp) 99 | self.current_item[self.column_name] = data.strip() 100 | self.column_name = None 101 | 102 | def handle_endtag(self, tag): 103 | if tag == 'table': 104 | self.inside_table = False 105 | 106 | if self.inside_tr and tag == self.TR: 107 | self.inside_tr = False 108 | self.column_name = None 109 | if "link" in self.current_item: 110 | prettyPrinter(self.current_item) 111 | self.page_items += 1 112 | 113 | def download_torrent(self, info): 114 | # since limetorrents provides torrent links in itorrent (cloudflare protected), 115 | # we have to fetch the info page and extract the magnet link 116 | info_page = retrieve_url(info) 117 | magnet_match = re.search(r"href\s*\=\s*\"(magnet[^\"]+)\"", info_page) 118 | if magnet_match and magnet_match.groups(): 119 | print(magnet_match.groups()[0] + " " + info) 120 | else: 121 | raise Exception('Error, please fill a bug report!') 122 | 123 | def search(self, query, cat='all'): 124 | """ Performs search """ 125 | query = query.replace("%20", "-") 126 | category = self.supported_categories[cat] 127 | 128 | for page in range(1, 5): 129 | page_url = f"{self.url}/search/{category}/{query}/seeds/{page}/" 130 | html = retrieve_url(page_url) 131 | parser = self.MyHtmlParser(self.url) 132 | parser.feed(html) 133 | parser.close() 134 | if parser.page_items < 20: 135 | break 136 | -------------------------------------------------------------------------------- /nova3/engines/piratebay.py: -------------------------------------------------------------------------------- 1 | # VERSION: 3.7 2 | # AUTHORS: Fabien Devaux (fab@gnux.info) 3 | # CONTRIBUTORS: Christophe Dumez (chris@qbittorrent.org) 4 | # Arthur (custparasite@gmx.se) 5 | # Diego de las Heras (ngosang@hotmail.es) 6 | 7 | # Redistribution and use in source and binary forms, with or without 8 | # modification, are permitted provided that the following conditions are met: 9 | # 10 | # * Redistributions of source code must retain the above copyright notice, 11 | # this list of conditions and the following disclaimer. 12 | # * Redistributions in binary form must reproduce the above copyright 13 | # notice, this list of conditions and the following disclaimer in the 14 | # documentation and/or other materials provided with the distribution. 15 | # * Neither the name of the author nor the names of its contributors may be 16 | # used to endorse or promote products derived from this software without 17 | # specific prior written permission. 18 | # 19 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 | # POSSIBILITY OF SUCH DAMAGE. 30 | 31 | import datetime 32 | import gzip 33 | import html 34 | import io 35 | import json 36 | import urllib.error 37 | import urllib.request 38 | from urllib.parse import unquote, urlencode 39 | 40 | import helpers # for setting SOCKS proxy side-effect 41 | from novaprinter import prettyPrinter 42 | 43 | helpers.htmlentitydecode # dirty workaround to surpress static checkers 44 | 45 | 46 | class piratebay(object): 47 | url = 'https://thepiratebay.org' 48 | name = 'The Pirate Bay' 49 | supported_categories = { 50 | 'all': '0', 51 | 'music': '100', 52 | 'movies': '200', 53 | 'games': '400', 54 | 'software': '300' 55 | } 56 | 57 | # initialize trackers for magnet links 58 | trackers_list = [ 59 | 'udp://tracker.internetwarriors.net:1337/announce', 60 | 'udp://tracker.opentrackr.org:1337/announce', 61 | 'udp://p4p.arenabg.ch:1337/announce', 62 | 'udp://tracker.openbittorrent.com:6969/announce', 63 | 'udp://www.torrent.eu.org:451/announce', 64 | 'udp://tracker.torrent.eu.org:451/announce', 65 | 'udp://retracker.lanta-net.ru:2710/announce', 66 | 'udp://open.stealth.si:80/announce', 67 | 'udp://exodus.desync.com:6969/announce', 68 | 'udp://tracker.tiny-vps.com:6969/announce' 69 | ] 70 | trackers = '&'.join(urlencode({'tr': tracker}) for tracker in trackers_list) 71 | 72 | def search(self, what, cat='all'): 73 | base_url = "https://apibay.org/q.php?%s" 74 | 75 | # get response json 76 | what = unquote(what) 77 | category = self.supported_categories[cat] 78 | params = {'q': what} 79 | if category != '0': 80 | params['cat'] = category 81 | 82 | # Calling custom `retrieve_url` function with adequate escaping 83 | data = self.retrieve_url(base_url % urlencode(params)) 84 | response_json = json.loads(data) 85 | 86 | # check empty response 87 | if len(response_json) == 0: 88 | return 89 | 90 | # parse results 91 | for result in response_json: 92 | if result['info_hash'] == '0000000000000000000000000000000000000000': 93 | continue 94 | res = { 95 | 'link': self.download_link(result), 96 | 'name': result['name'], 97 | 'size': str(result['size']) + " B", 98 | 'seeds': result['seeders'], 99 | 'leech': result['leechers'], 100 | 'engine_url': self.url, 101 | 'desc_link': self.url + '/description.php?id=' + result['id'], 102 | 'pub_date': result['added'], 103 | } 104 | prettyPrinter(res) 105 | 106 | def download_link(self, result): 107 | return "magnet:?xt=urn:btih:{}&{}&{}".format( 108 | result['info_hash'], urlencode({'dn': result['name']}), self.trackers) 109 | 110 | def retrieve_url(self, url): 111 | def getBrowserUserAgent(): 112 | """ Disguise as browser to circumvent website blocking """ 113 | 114 | # Firefox release calendar 115 | # https://whattrainisitnow.com/calendar/ 116 | # https://wiki.mozilla.org/index.php?title=Release_Management/Calendar&redirect=no 117 | 118 | baseDate = datetime.date(2024, 4, 16) 119 | baseVersion = 125 120 | 121 | nowDate = datetime.date.today() 122 | nowVersion = baseVersion + ((nowDate - baseDate).days // 30) 123 | 124 | return f"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:{nowVersion}.0) Gecko/20100101 Firefox/{nowVersion}.0" 125 | 126 | # Request data from API 127 | request = urllib.request.Request(url, None, {'User-Agent': getBrowserUserAgent()}) 128 | 129 | try: 130 | response = urllib.request.urlopen(request) 131 | except urllib.error.HTTPError: 132 | return "" 133 | 134 | data = response.read() 135 | 136 | if data[:2] == b'\x1f\x8b': 137 | # Data is gzip encoded, decode it 138 | with io.BytesIO(data) as stream, gzip.GzipFile(fileobj=stream) as gzipper: 139 | data = gzipper.read() 140 | 141 | charset = 'utf-8' 142 | try: 143 | charset = response.getheader('Content-Type', '').split('charset=', 1)[1] 144 | except IndexError: 145 | pass 146 | 147 | dataStr = data.decode(charset, 'replace') 148 | dataStr = dataStr.replace('"', '\\"') # Manually escape " before 149 | dataStr = html.unescape(dataStr) 150 | 151 | return dataStr 152 | -------------------------------------------------------------------------------- /nova3/engines/solidtorrents.py: -------------------------------------------------------------------------------- 1 | # VERSION: 2.5 2 | # AUTHORS: nKlido 3 | 4 | # LICENSING INFORMATION 5 | # Permission is hereby granted, free of charge, to any person obtaining a copy 6 | # of this software and associated documentation files (the "Software"), to deal 7 | # in the Software without restriction, including without limitation the rights 8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | # copies of the Software, and to permit persons to whom the Software is 10 | # furnished to do so, subject to the following conditions: 11 | # 12 | # The above copyright notice and this permission notice shall be included in 13 | # all copies or substantial portions of the Software. 14 | # 15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | # SOFTWARE. 22 | 23 | from datetime import datetime 24 | from html.parser import HTMLParser 25 | 26 | from helpers import retrieve_url 27 | from novaprinter import prettyPrinter 28 | 29 | 30 | class solidtorrents(object): 31 | url = 'https://solidtorrents.to' 32 | name = 'Solid Torrents' 33 | supported_categories = {'all': 'all', 'music': 'Audio', 'books': 'eBook'} 34 | 35 | class TorrentInfoParser(HTMLParser): 36 | 37 | def __init__(self, url): 38 | HTMLParser.__init__(self) 39 | self.url = url 40 | self.foundResult = False 41 | self.foundTitle = False 42 | self.parseTitle = False 43 | self.foundStats = False 44 | self.parseSeeders = False 45 | self.parseLeechers = False 46 | self.parseSize = False 47 | self.parseDate = False 48 | self.column = 0 49 | self.torrentReady = False 50 | self.totalResults = 0 51 | 52 | self.torrent_info = self.empty_torrent_info() 53 | 54 | def empty_torrent_info(self): 55 | return { 56 | 'link': '', 57 | 'name': '', 58 | 'size': '-1', 59 | 'seeds': '-1', 60 | 'leech': '-1', 61 | 'engine_url': self.url, 62 | 'desc_link': '', 63 | 'pub_date': -1, 64 | } 65 | 66 | def handle_starttag(self, tag, attrs): 67 | params = dict(attrs) 68 | 69 | if 'search-result' in params.get('class', ''): 70 | self.foundResult = True 71 | return 72 | 73 | if (self.foundResult and 'title' in params.get('class', '') and tag == 'h5'): 74 | self.foundTitle = True 75 | 76 | if (self.foundTitle and tag == 'a'): 77 | self.torrent_info['desc_link'] = self.url + params.get('href') 78 | self.parseTitle = True 79 | 80 | if (self.foundResult and 'stats' in params.get('class', '')): 81 | self.foundStats = True 82 | self.column = -1 83 | 84 | if (self.foundStats and tag == 'div'): 85 | self.column = self.column + 1 86 | 87 | if (self.column == 2): 88 | self.parseSize = True 89 | 90 | if (self.foundStats and tag == 'font' and self.column == 3): 91 | self.parseSeeders = True 92 | 93 | if (self.foundStats and tag == 'font' and self.column == 4): 94 | self.parseLeechers = True 95 | 96 | if (self.foundStats and tag == 'div' and self.column == 5): 97 | self.parseDate = True 98 | 99 | if (self.foundResult and 'dl-magnet' in params.get('class', '') and tag == 'a'): 100 | self.torrent_info['link'] = params.get('href') 101 | self.foundResult = False 102 | self.torrentReady = True 103 | 104 | def handle_endtag(self, tag): 105 | if (self.torrentReady): 106 | prettyPrinter(self.torrent_info) 107 | self.torrentReady = False 108 | self.torrent_info = self.empty_torrent_info() 109 | self.totalResults += 1 110 | 111 | def handle_data(self, data): 112 | 113 | if (self.parseTitle): 114 | if (bool(data.strip()) and data != '\n'): 115 | self.torrent_info['name'] = data 116 | self.parseTitle = False 117 | self.foundTitle = False 118 | 119 | if (self.parseSize): 120 | self.torrent_info['size'] = data 121 | self.parseSize = False 122 | 123 | if (self.parseSeeders): 124 | self.torrent_info['seeds'] = data 125 | self.parseSeeders = False 126 | 127 | if (self.parseLeechers): 128 | self.torrent_info['leech'] = data 129 | self.parseLeechers = False 130 | 131 | if (self.parseDate): 132 | try: 133 | # I chose not to use strptime here because it depends on user's locale 134 | months = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 135 | 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'] 136 | [month, day, year] = data.replace(',', '').lower().split() 137 | date = datetime(int(year), int(months.index(month) + 1), int(day)) 138 | self.torrent_info['pub_date'] = int(date.timestamp()) 139 | except Exception: 140 | self.torrent_info['pub_date'] = -1 141 | self.parseDate = False 142 | self.foundStats = False 143 | 144 | def request(self, searchTerm, category, page=1): 145 | return retrieve_url( 146 | self.url + '/search?q=' + searchTerm + '&category=' + category 147 | + '&sort=seeders&sort=desc&page=' + str(page)) 148 | 149 | def search(self, what, cat='all'): 150 | category = self.supported_categories[cat] 151 | 152 | for page in range(1, 5): 153 | parser = self.TorrentInfoParser(self.url) 154 | parser.feed(self.request(what, category, page)) 155 | parser.close() 156 | if parser.totalResults < 15: 157 | break 158 | -------------------------------------------------------------------------------- /nova3/engines/torlock.py: -------------------------------------------------------------------------------- 1 | # VERSION: 2.26 2 | # AUTHORS: Douman (custparasite@gmx.se) 3 | # CONTRIBUTORS: Diego de las Heras (ngosang@hotmail.es) 4 | 5 | from datetime import datetime, timedelta 6 | from html.parser import HTMLParser 7 | 8 | from helpers import download_file, retrieve_url 9 | from novaprinter import prettyPrinter 10 | 11 | 12 | class torlock(object): 13 | url = "https://www.torlock.com" 14 | name = "TorLock" 15 | supported_categories = {'all': 'all', 16 | 'anime': 'anime', 17 | 'software': 'software', 18 | 'games': 'game', 19 | 'movies': 'movie', 20 | 'music': 'music', 21 | 'tv': 'television', 22 | 'books': 'ebooks'} 23 | 24 | def download_torrent(self, info): 25 | print(download_file(info)) 26 | 27 | class MyHtmlParser(HTMLParser): 28 | """ Sub-class for parsing results """ 29 | def __init__(self, url): 30 | HTMLParser.__init__(self) 31 | self.url = url 32 | self.article_found = False # true when
with results is found 33 | self.item_found = False 34 | self.item_bad = False # set to True for malicious links 35 | self.current_item = None # dict for found item 36 | self.item_name = None # key's name in current_item dict 37 | self.page_items = 0 38 | self.parser_class = {"td": "pub_date", 39 | "ts": "size", 40 | "tul": "seeds", 41 | "tdl": "leech"} 42 | 43 | def handle_starttag(self, tag, attrs): 44 | params = dict(attrs) 45 | if self.item_found: 46 | if tag == "td": 47 | if "class" in params: 48 | self.item_name = self.parser_class.get(params["class"], None) 49 | if self.item_name: 50 | self.current_item[self.item_name] = "" 51 | 52 | elif self.article_found and tag == "a": 53 | if "href" in params: 54 | link = params["href"] 55 | if link.startswith("/torrent"): 56 | self.current_item["desc_link"] = "".join((self.url, link)) 57 | self.current_item["link"] = "".join((self.url, "/tor/", 58 | link.split('/')[2], ".torrent")) 59 | self.current_item["engine_url"] = self.url 60 | self.item_found = True 61 | self.item_name = "name" 62 | self.current_item["name"] = "" 63 | self.item_bad = "rel" in params and params["rel"] == "nofollow" 64 | 65 | elif tag == "article": 66 | self.article_found = True 67 | self.current_item = {} 68 | 69 | def handle_data(self, data): 70 | if self.item_name: 71 | self.current_item[self.item_name] += data 72 | 73 | def handle_endtag(self, tag): 74 | if tag == "article": 75 | self.article_found = False 76 | elif self.item_name and (tag == "a" or tag == "td"): 77 | self.item_name = None 78 | elif self.item_found and tag == "tr": 79 | self.item_found = False 80 | if not self.item_bad: 81 | try: 82 | # Date seems like it can be Today, Yesterday, or M/D/YYYY (Timezone unknown) 83 | if self.current_item["pub_date"] == "Today": 84 | date = datetime.now() 85 | elif self.current_item["pub_date"] == "Yesterday": 86 | date = datetime.now() - timedelta(days=1) 87 | else: 88 | date = datetime.strptime(self.current_item["pub_date"], '%m/%d/%Y') 89 | date = date.replace(hour=0, minute=0, second=0, microsecond=0) 90 | self.current_item["pub_date"] = int(date.timestamp()) 91 | except Exception: 92 | self.current_item["pub_date"] = -1 93 | prettyPrinter(self.current_item) 94 | self.page_items += 1 95 | self.current_item = {} 96 | 97 | def search(self, query, cat='all'): 98 | """ Performs search """ 99 | query = query.replace("%20", "-") 100 | category = self.supported_categories[cat] 101 | 102 | for page in range(1, 5): 103 | parser = self.MyHtmlParser(self.url) 104 | page_url = f"{self.url}/{category}/torrents/{query}.html?sort=seeds&page={page}" 105 | html = retrieve_url(page_url) 106 | parser.feed(html) 107 | parser.close() 108 | if parser.page_items < 20: 109 | break 110 | -------------------------------------------------------------------------------- /nova3/engines/torrentproject.py: -------------------------------------------------------------------------------- 1 | # VERSION: 1.6 2 | # AUTHORS: mauricci 3 | 4 | import re 5 | from datetime import datetime 6 | from html.parser import HTMLParser 7 | from urllib.parse import unquote 8 | 9 | from helpers import retrieve_url 10 | from novaprinter import prettyPrinter 11 | 12 | 13 | class torrentproject(object): 14 | url = 'https://torrentproject.cc' 15 | name = 'TorrentProject' 16 | supported_categories = {'all': '0'} 17 | 18 | class MyHTMLParser(HTMLParser): 19 | 20 | def __init__(self, url): 21 | HTMLParser.__init__(self) 22 | self.url = url 23 | self.insideResults = False 24 | self.insideDataDiv = False 25 | self.pageComplete = False 26 | self.spanCount = -1 27 | self.infoMap = { 28 | "name": 0, 29 | "torrLink": 0, 30 | "seeds": 2, 31 | "leech": 3, 32 | "pub_date": 4, 33 | "size": 5, 34 | } 35 | self.fullResData = [] 36 | self.pageRes = [] 37 | self.singleResData = self.get_single_data() 38 | 39 | def get_single_data(self): 40 | return { 41 | 'name': '-1', 42 | 'seeds': '-1', 43 | 'leech': '-1', 44 | 'size': '-1', 45 | 'link': '-1', 46 | 'desc_link': '-1', 47 | 'engine_url': self.url, 48 | 'pub_date': '-1', 49 | } 50 | 51 | def handle_starttag(self, tag, attrs): 52 | attributes = dict(attrs) 53 | if tag == 'div' and 'nav' in attributes.get('id', ''): 54 | self.pageComplete = True 55 | if tag == 'div' and attributes.get('id', '') == 'similarfiles': 56 | self.insideResults = True 57 | if tag == 'div' and self.insideResults and 'gac_bb' not in attributes.get('class', ''): 58 | self.insideDataDiv = True 59 | elif tag == 'span' and self.insideDataDiv and 'verified' != attributes.get('title', ''): 60 | self.spanCount += 1 61 | if self.insideDataDiv and tag == 'a' and len(attrs) > 0: 62 | if self.infoMap['torrLink'] == self.spanCount and 'href' in attributes: 63 | self.singleResData['link'] = self.url + attributes['href'] 64 | if self.infoMap['name'] == self.spanCount and 'href' in attributes: 65 | self.singleResData['desc_link'] = self.url + attributes['href'] 66 | 67 | def handle_endtag(self, tag): 68 | if not self.pageComplete: 69 | if tag == 'div': 70 | self.insideDataDiv = False 71 | self.spanCount = -1 72 | if len(self.singleResData) > 0: 73 | # ignore trash stuff 74 | if self.singleResData['name'] != '-1' \ 75 | and self.singleResData['size'] != '-1' \ 76 | and self.singleResData['name'].lower() != 'nome': 77 | # ignore those with link and desc_link equals to -1 78 | if self.singleResData['desc_link'] != '-1' \ 79 | or self.singleResData['link'] != '-1': 80 | try: 81 | date_string = self.singleResData['pub_date'] 82 | date = datetime.strptime(date_string, '%Y-%m-%d %H:%M:%S') 83 | self.singleResData['pub_date'] = int(date.timestamp()) 84 | except Exception: 85 | pass 86 | try: 87 | prettyPrinter(self.singleResData) 88 | except Exception: 89 | print(self.singleResData) 90 | self.pageRes.append(self.singleResData) 91 | self.fullResData.append(self.singleResData) 92 | self.singleResData = self.get_single_data() 93 | 94 | def handle_data(self, data): 95 | if self.insideDataDiv: 96 | for key, val in self.infoMap.items(): 97 | if self.spanCount == val: 98 | curr_key = key 99 | if curr_key in self.singleResData and data.strip() != '': 100 | if self.singleResData[curr_key] == '-1': 101 | self.singleResData[curr_key] = data.strip() 102 | elif curr_key != 'name': 103 | self.singleResData[curr_key] += data.strip() 104 | 105 | def search(self, what, cat='all'): 106 | # curr_cat = self.supported_categories[cat] 107 | what = what.replace('%20', '+') 108 | # analyze first 5 pages of results 109 | for currPage in range(0, 5): 110 | url = self.url + '/browse?t={0}&p={1}'.format(what, currPage) 111 | html = retrieve_url(url) 112 | parser = self.MyHTMLParser(self.url) 113 | parser.feed(html) 114 | parser.close() 115 | if len(parser.pageRes) < 20: 116 | break 117 | 118 | def download_torrent(self, info): 119 | """ Downloader """ 120 | html = retrieve_url(info) 121 | m = re.search('href=[\'\"].*?(magnet.+?)[\'\"]', html) 122 | if m and len(m.groups()) > 0: 123 | magnet = unquote(m.group(1)) 124 | print(magnet + ' ' + info) 125 | -------------------------------------------------------------------------------- /nova3/engines/torrentscsv.py: -------------------------------------------------------------------------------- 1 | # VERSION: 1.6 2 | # AUTHORS: Dessalines 3 | 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # 7 | # * Redistributions of source code must retain the above copyright notice, 8 | # this list of conditions and the following disclaimer. 9 | # * Redistributions in binary form must reproduce the above copyright 10 | # notice, this list of conditions and the following disclaimer in the 11 | # documentation and/or other materials provided with the distribution. 12 | # * Neither the name of the author nor the names of its contributors may be 13 | # used to endorse or promote products derived from this software without 14 | # specific prior written permission. 15 | # 16 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | # POSSIBILITY OF SUCH DAMAGE. 27 | 28 | import json 29 | from urllib.parse import urlencode 30 | 31 | from helpers import retrieve_url 32 | from novaprinter import prettyPrinter 33 | 34 | 35 | class torrentscsv(object): 36 | url = 'https://torrents-csv.com' 37 | name = 'torrents-csv' 38 | supported_categories = {'all': ''} 39 | 40 | # initialize trackers for magnet links 41 | trackers_list = [ 42 | 'udp://tracker.internetwarriors.net:1337/announce', 43 | 'udp://tracker.opentrackr.org:1337/announce', 44 | 'udp://p4p.arenabg.ch:1337/announce', 45 | 'udp://tracker.openbittorrent.com:6969/announce', 46 | 'udp://www.torrent.eu.org:451/announce', 47 | 'udp://tracker.torrent.eu.org:451/announce', 48 | 'udp://retracker.lanta-net.ru:2710/announce', 49 | 'udp://open.stealth.si:80/announce', 50 | 'udp://exodus.desync.com:6969/announce', 51 | 'udp://tracker.tiny-vps.com:6969/announce' 52 | ] 53 | trackers = '&'.join(urlencode({'tr': tracker}) for tracker in trackers_list) 54 | 55 | def search(self, what, cat='all'): 56 | search_url = "{}/service/search?size=100&q={}".format(self.url, what) 57 | desc_url = "{}/#/search/torrent/{}/1".format(self.url, what) 58 | 59 | # get response json 60 | response = retrieve_url(search_url) 61 | response_json = json.loads(response) 62 | 63 | # parse results 64 | for result in response_json["torrents"]: 65 | res = {'link': self.download_link(result), 66 | 'name': result['name'], 67 | 'size': str(result['size_bytes']) + " B", 68 | 'seeds': result['seeders'], 69 | 'leech': result['leechers'], 70 | 'engine_url': self.url, 71 | 'desc_link': desc_url, 72 | 'pub_date': result['created_unix']} 73 | prettyPrinter(res) 74 | 75 | def download_link(self, result): 76 | return "magnet:?xt=urn:btih:{}&{}&{}".format( 77 | result['infohash'], urlencode({'dn': result['name']}), self.trackers) 78 | -------------------------------------------------------------------------------- /nova3/engines/versions.txt: -------------------------------------------------------------------------------- 1 | eztv: 1.17 2 | jackett: 4.3 3 | limetorrents: 4.11 4 | piratebay: 3.7 5 | solidtorrents: 2.5 6 | torlock: 2.26 7 | torrentproject: 1.6 8 | torrentscsv: 1.6 9 | -------------------------------------------------------------------------------- /wiki/Home.md: -------------------------------------------------------------------------------- 1 | Welcome to the search-plugins wiki! 2 | 3 | The wiki source code is hosted at https://github.com/qbittorrent/search-plugins/tree/master/wiki and is accepting Pull Requests. 4 | 5 | * [List of unofficial search plugins](https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins) 6 | * [Request unofficial search plugin](https://github.com/qbittorrent/search-plugins/wiki/Request-unofficial-search-plugin) 7 | * [How to configure Jackett plugin](https://github.com/qbittorrent/search-plugins/wiki/How-to-configure-Jackett-plugin) 8 | * [How to install search plugins](https://github.com/qbittorrent/search-plugins/wiki/Install-search-plugins) 9 | * [How to write a search plugin](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin) 10 | * [New Torznab search engine](https://github.com/qbittorrent/search-plugins/wiki/New-Torznab-search-engine) 11 | -------------------------------------------------------------------------------- /wiki/How-to-configure-Jackett-plugin.md: -------------------------------------------------------------------------------- 1 | # Jackett integration for qBittorrent 2 | 3 | **qBittorrent** comes with a few search plugins. Although these are often 4 | sufficient for most users, those who wish to perform searches at a wider array 5 | of indexing sites have the option of installing **[Jackett][jackett]** and 6 | running it in tandem with qBittorrent to take advantage of its much larger 7 | catalog of indexers (575, as of June 2024) and efficiency in retrieving results 8 | from them.configure the **Jackett qBittorrent plugin** (essentially, set the API key). 9 | 10 | ## What is Jackett? 11 | 12 | As explained in the project's [README.md file][jackett-readme] (emphasis added): 13 | 14 | > Jackett works as a proxy server: it translates queries from apps ([including] 15 | > qBittorrent […]) into site-specific HTTP queries for any number of 16 | > [BitTorrent] trackers, parses the HTML or JSON responses, then sends the 17 | > results back to the requesting software. This allows for getting recent 18 | > uploads (like RSS) and performing searches. Jackett is a single repository of 19 | > **maintained indexer scraping and translation logic** — removing the burden 20 | > from other apps. 21 | 22 | More plainly, while qBittorrent is a download manager which has evolved to 23 | include some built-in facilities for torrent discovery, Jackett is purpose-built 24 | software designed for performing those same searches on a much larger scale. An 25 | application such as qBittorrent can present the searches it's asked to perform 26 | to Jackett, which broadcasts them to a user-defined list of potentially hundreds 27 | of indexing sites all at once, and then feeds the results back as they come in. 28 | The primary advantages to this arragement are threefold: 29 | 30 | - As performing searches is its only function, it is much faster at conducting 31 | them and processing the results. 32 | - The ability to perform searches at a much wider list indexes that is quick to 33 | add new sites and remove dead ones. 34 | - It is much better at reacting to the frequent changes that occur on the 35 | indexer sites that arise as they work to mitigate attempts to interrupt their 36 | operation. 37 | 38 | Updates to their catalog of indexers take place almost daily and it includes 39 | hundreds of sites which never had nor were ever likely to get their own 40 | qBittorrent search plugin. 41 | 42 | ## Installation 43 | 44 | ### Prerequisites 45 | 46 | Jackett is built using the .NET framework and requires that you have the .NET 8 47 | Runtime present on your system prior to installation. Microsoft provides 48 | installer files for the runtime for [Windows][dotnet-windows-support], 49 | [macOS][dotnet-macos-support] and [GNU/Linux][dotnet-linux-support] (click the 50 | preceding links to see the minimum requirements for each operating system). 51 | 52 | **[Microsoft .NET Downloads][dotnet-downloads]** 53 | 54 | **Official .NET installation guides**: 55 | 56 | - [Windows][dotnet-windows-install] 57 | - [macOS][dotnet-macos-install] 58 | - [Linux][dotnet-linux-install] 59 | 60 | ### Jackett 61 | 62 | Once the .NET runtime is installed, follow the official documentation linked 63 | below to install and configure Jackett. 64 | 65 | - [Installation on Windows][install-windows] 66 | - Installation on Linux: 67 | - [AMD64 (x86_64)][install-linux-amd64] 68 | - [ARMv7 and newer][install-linux-armv7] 69 | - [ARMv6 and older][install-linux-armv6] 70 | 71 | ### qBittorrent plugin 72 | 73 | > [!NOTE] 74 | > The full download URL for the plugin file is 75 | > `https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/jackett.py` 76 | 77 | Follow these steps to manually install the plugin: 78 | 79 | 1. Launch qBittorrent and click on the Search tab (only shown when "Search 80 | Engine" is active in the View menu) 81 | 1. Highlight the URL shown above or right-click [this link][plugin-file] and 82 | **copy** it to the clipboard 83 | 1. Click the **Search plugins…** button in the bottom-right corner, then click 84 | **Install a new one**, and finally **Web link** as the "Search plugin source" 85 | 1. qBittorrent tries to automatically fill the input field if a URL is found on 86 | the clipboard, but if not, manually paste the URL there 87 | 88 | ## Configuration 89 | 90 | > [!IMPORTANT] 91 | > Remember to [start Jackett](https://github.com/Jackett/Jackett#supported-systems) 92 | > first. :) 93 | 94 | The Jackett plugin uses an external configuration file, ensuring that any 95 | updates to the plugin file will not erase or reset your settings. The name of 96 | the configuration file is `jackett.json` and it must reside in the same folder 97 | as the qBittorrent search plugin files, the defaults for which are: 98 | 99 | - **Windows:** 100 | - CMD syntax: `%LOCALAPPDATA%\qBittorrent\nova3\engines` 101 | - PowerShell syntax: `"${Env:LOCALAPPDATA}\qBittorrent\nova3\engines"` 102 | - **Linux:** 103 | - `"${XDG_DATA_HOME:-$HOME/.local/share}/qBittorrent/nova3/engines"` (current) 104 | - `"${XDG_DATA_HOME:-$HOME/.local/share}/data/qBittorrent/nova3/engines"` (former) 105 | - `"${HOME}/.var/app/org.qbittorrent.qBittorrent/data/qBittorrent/nova3/engines"` 106 | - **macOS:** `"~/Library/Application Support/qBittorrent/nova3/engines"` 107 | 108 | If for some reason the configuration file doesn't exist, create one with the 109 | following contents: 110 | 111 | ```json 112 | { 113 | "api_key": "YOUR_API_KEY_HERE", 114 | "url": "http://127.0.0.1:9117", 115 | "tracker_first": false, 116 | "thread_count": 20 117 | } 118 | ``` 119 | 120 | > [!TIP] 121 | > If running qBittorrent in headless mode and accessing its web interface 122 | > remotely, Jackett's default configuration to bind to the loopback address 123 | > (127.0.0.1) must be replaced with a routable address (for instance, using DDNS 124 | > or an IPv6 Global Unicast Address) to allow traffic to pass between it and 125 | > qBittorrent. Additional firewall rules or port forwarding may also be needed. 126 | > 127 | > The change must be made in both the Jackett UI and the plugin configuration 128 | > file, specifically its `url` key. For example: 129 | 130 | ```diff 131 | { 132 | "api_key": "YOUR_API_KEY_HERE", 133 | - "url": "http://127.0.0.1:9117", 134 | + "url": "http://yourserver.ddnsprovider.host:9117", 135 | "tracker_first": false, 136 | "thread_count": 20 137 | } 138 | ``` 139 | 140 | ### Configuration file properties 141 | 142 | | Property name | Initial value | Description | 143 | |:----------------|:------------------------|:----------------------------------------------------------------------------------------------------| 144 | | `api_key` | `YOUR_API_KEY_HERE` | Jackett API Key, shown in the upper-right corner of the Jackett UI ([screenshot below][api-key-ss]) | 145 | | `url` | `http://127.0.0.1:9117` | Jackett service address (without a terminating forward slash) | 146 | | `tracker_first` | `false` | Prepend indexer site name to each search result (takes Boolean value) | 147 | | `thread_count` | `20` | Maximum number of concurrent requests to Jackett (to disable concurrent requests, set value to `1`) | 148 | 149 | ## Disabling/Removing the Jackett plugin 150 | 151 | The Jackett plugin is enabled by default in qBittorrent. However, you can 152 | disable it or removing it entirely at any time by following these steps: 153 | 154 | 1. In the **Search** tab, click the **Search plugins…** button in the 155 | bottom-right corner. 156 | 1. Locate the entry named **Jackett** in the list. 157 | 1. To disable the plugin: 158 | - Right-click the entry and clear the checkmark from the **Enabled** option. 159 | 160 | Or to uninstall the plugin: 161 | - Right-click the entry and select **Uninstall**. 162 | 1. Click the **Close** button. 163 | 164 | ## Screenshots 165 | 166 | ### Jackett API Key 167 | 168 | ![Jackett UI screenshot showing API Key location][api-key] 169 | 170 | ### Search results 171 | 172 | After successfully installing Jackett and integrating it with qBittorrent, the 173 | results it provides appear as seen below. 174 | 175 | ![qBittorrent search tab with Jackett results][search-tab-results] 176 | 177 | [jackett]: https://github.com/Jackett/Jackett "Jackett: API support for your favorite torrent trackers" 178 | [jackett-readme]: https://github.com/Jackett/Jackett/blob/master/README.md "Jackett: README.md" 179 | [dotnet-windows-support]: https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md#windows 180 | [dotnet-macos-support]: https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md#macos 181 | [dotnet-linux-support]: https://github.com/dotnet/core/blob/main/release-notes/8.0/supported-os.md#linux 182 | [dotnet-downloads]: https://dotnet.microsoft.com/download/dotnet/8.0 183 | [dotnet-windows-install]: https://github.com/dotnet/core/blob/main/release-notes/8.0/install-windows.md 184 | [dotnet-macos-install]: https://github.com/dotnet/core/blob/main/release-notes/8.0/install-macos.md 185 | [dotnet-linux-install]: https://github.com/dotnet/core/blob/main/release-notes/8.0/install-linux.md 186 | [install-windows]: https://github.com/Jackett/Jackett#installation-on-windows 187 | [install-linux-amd64]: https://github.com/Jackett/Jackett#installation-on-linux-amdx64 188 | [install-linux-armv7]: https://github.com/Jackett/Jackett#installation-on-linux-armv7-or-above 189 | [install-linux-armv6]: https://github.com/Jackett/Jackett#installation-on-linux-armv6-or-below 190 | [plugin-file]: https://raw.githubusercontent.com/qbittorrent/search-plugins/master/nova3/engines/jackett.py 191 | [api-key-ss]: #jackett-api-key 192 | [api-key]: https://i.imgur.com/87yZeAU.png 193 | [search-tab-results]: https://i.imgur.com/uCawgLa.png 194 | -------------------------------------------------------------------------------- /wiki/How-to-write-a-search-plugin.md: -------------------------------------------------------------------------------- 1 | qBittorrent provides a search engine plugins management system. 2 | Thanks to this, you can *easily* write your own plugins to look for torrents in your favorite Bittorrent search engines and extend qBittorrent integrated search engine. 3 | 4 | * All you need is some motivation and some knowledge of [Python language](https://www.python.org). 5 | * **The minimum supported python version is specified [here](https://github.com/qbittorrent/qBittorrent/blob/master/INSTALL#L21-L23), make sure your plugin can work with it and every later versions.** 6 | * **Only import libraries from [Python Standard Library](https://docs.python.org/3/library/index.html)**. \ 7 | Third party libraries (such as those installed from [PyPI](https://pypi.org/)) are ***not*** guaranteed to be present in user's environment. 8 | * You are encouraged to ensure good quality of your plugin: [Python Code Quality: Tools & Best Practices](https://realpython.com/python-code-quality/). \ 9 | For example, here is how the official plugins are checked: [ci.yaml](https://github.com/qbittorrent/search-plugins/blob/60a3f4d9c97a5d1f94e75789a72ee054044c5802/.github/workflows/ci.yaml#L29-L44). 10 | 11 | 12 | # INDEX 13 | ## [Plugins Specification](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#plugins-specification-1) 14 | 15 | ### 1.1 [Search Results Format](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin/#search-results-format) 16 | 17 | ### 1.2 [Python Class File Structure](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin/#python-class-file-structure) 18 | 19 | ### 1.3 [Parsing Results From Web Pages](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin/#parsing-results-from-web-pages) 20 | 21 | ## [Understanding The Code](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#understanding-the-code-1) 22 | 23 | ### 2.1 [PrettyPrinter Helper Function](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#prettyprinter-helper-function) 24 | 25 | ### 2.2 [Retrieve_URL Helper Function](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#retrieve_url-helper-function) 26 | 27 | ### 2.3 [Download_File helper Function](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#download_file-helper-function) 28 | 29 | ## [Testing & Finalizing Your Code](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#testing--finalizing-your-code-1) 30 | 31 | ### 3.1 [Code Examples](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin/#code-examples) 32 | 33 | ### 3.2 [Testing Your Plugin](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#testing-your-plugin) 34 | 35 | ### 3.3 [Install Your Plugin](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#install-your-plugin) 36 | 37 | ### 3.4 [Publish Your Plugin](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#publish-your-plugin) 38 | 39 | ### 3.5 [Notes](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin#notes) 40 | 41 | 42 | # Plugins Specification 43 | 44 | *⚠️The plugin communicate data back to qBittorrent via stdout and that means you must NOT print debug/error messages to stdout under any circumstances. You can print the debug/error messages to stderr instead.* 45 | 46 | ## Search Results Format 47 | First, you must understand that a qBittorrent search engine plugin is actually a Python class file whose task is to contact a search engine website (e.g. [The Pirate Bay](https://www.thepiratebay.org)), parse the results displayed by the web page and print them on stdout with the following syntax: 48 | ``` 49 | link|name|size|seeds|leech|engine_url|desc_link|pub_date 50 | ``` 51 | 52 | One search result per line. 53 | 54 | For example: 55 | ``` 56 | magnet:?xt=urn:btih:5F5E8848426129AB63CB4DB717BB54193C1C1AD7&dn=ubuntu-20.04.6-desktop-amd64.iso|ubuntu-20.04.6-desktop-amd64.iso|4351463424|15|2|https://thepiratebay.org|https://thepiratebay.org/description.php?id=72774917|1696870394 57 | magnet:?xt=urn:btih:07053761979D09DEAD94D09E8326DB919797B078&dn=ubuntu-10.04-server-i386.iso|ubuntu-10.04-server-i386.iso|700413952|1|0|https://thepiratebay.org|https://thepiratebay.org/description.php?id=5551290|1273547377 58 | ``` 59 | 60 | ## Python Class File Structure 61 | Your plugin should be named "engine_name.py", in lowercase and without spaces nor any special characters. 62 | You'll also need the other files for the project ([Link](https://github.com/qbittorrent/qBittorrent/tree/master/src/searchengine/nova3)) 63 | 64 | The Files Are: 65 | 66 | ``` 67 | -> nova2.py # the main search engine script which calls the plugins 68 | -> nova2dl.py # standalone script called by qBittorrent to download a torrent using a particular search plugin 69 | -> helpers.py # contains helper functions you can use in your plugins such as retrieve_url() and download_file() 70 | -> novaprinter.py # contains some useful functions like prettyPrint(my_dict) to display your search results 71 | -> socks.py # Required by helpers.py. This module provides a standard socket-like interface. 72 | ``` 73 | 74 | 75 | Here is the basic structure of engine_name.py: 76 | ```python 77 | #VERSION: 1.00 78 | # AUTHORS: YOUR_NAME (YOUR_MAIL) 79 | # LICENSING INFORMATION 80 | 81 | from html.parser import HTMLParser 82 | from helpers import download_file, retrieve_url 83 | from novaprinter import prettyPrinter 84 | # some other imports if necessary 85 | 86 | class engine_name(object): 87 | """ 88 | `url`, `name`, `supported_categories` should be static variables of the engine_name class, 89 | otherwise qbt won't install the plugin. 90 | 91 | `url`: The URL of the search engine. 92 | `name`: The name of the search engine, spaces and special characters are allowed here. 93 | `supported_categories`: What categories are supported by the search engine and their corresponding id, 94 | possible categories are ('all', 'anime', 'books', 'games', 'movies', 'music', 'pictures', 'software', 'tv'). 95 | """ 96 | 97 | url = 'https://www.engine-url.org' 98 | name = 'Full engine name' 99 | supported_categories = { 100 | 'all': '0', 101 | 'anime': '7', 102 | 'games': '2', 103 | 'movies': '6', 104 | 'music': '1', 105 | 'software': '3', 106 | 'tv': '4' 107 | } 108 | 109 | def __init__(self): 110 | """ 111 | Some initialization 112 | """ 113 | 114 | def download_torrent(self, info): 115 | """ 116 | Providing this function is optional. 117 | It can however be interesting to provide your own torrent download 118 | implementation in case the search engine in question does not allow 119 | traditional downloads (for example, cookie-based download). 120 | """ 121 | print(download_file(info)) 122 | 123 | # DO NOT CHANGE the name and parameters of this function 124 | # This function will be the one called by nova2.py 125 | def search(self, what, cat='all'): 126 | """ 127 | Here you can do what you want to get the result from the search engine website. 128 | Everytime you parse a result line, store it in a dictionary 129 | and call the prettyPrint(your_dict) function. 130 | 131 | `what` is a string with the search tokens, already escaped (e.g. "Ubuntu+Linux") 132 | `cat` is the name of a search category in ('all', 'anime', 'books', 'games', 'movies', 'music', 'pictures', 'software', 'tv') 133 | """ 134 | ``` 135 | 136 | **PLEASE note that the filename (without .py extension) must be identical to the class name. Otherwise, qBittorrent will refuse to install it!** 137 | 138 | ## Parsing Results from Web Pages 139 | After downloading the content of the web page containing the results (using `retrieve_url()`), you will want to parse it in order to create a `dict` per search result and call `prettyPrint(your_dict)` function to display it on stdout (in a format understandable by qBittorrent). 140 | 141 | In order to parse the pages, you can use the following python modules (not exhaustive): 142 | * **[ADVISED METHOD]** [HTMLParser](https://docs.python.org/2/library/htmlparser.html) / [html.parser](https://docs.python.org/3/library/html.parser.html): Builtin python parser which replaces deprecated SGMLParser. Mostly similar to the SMGLParser 143 | * `xml.dom.minidom`: XML parser. Be careful, this parser is very sensitive and the website must be fully XHTML compliant for this to work. 144 | * `re`: If you like using regular expressions (regex) 145 | 146 | Note that the size is in provided bytes. 147 | 148 | To achieve this task we provide several helper functions such as `prettyPrinter()`. 149 | 150 | # Understanding The Code 151 | ## `prettyPrinter()` helper function 152 | In fact, you don't really need to pay attention to the output syntax because we provide a function for this called `prettyPrinter(dictionary)`. You can import it using the following command: 153 | ```python 154 | from novaprinter import prettyPrinter 155 | ``` 156 | 157 | You must pass to this function a dictionary containing the following keys (value should be `-1` if you do not have the info): 158 | * `link` => A string corresponding the the download link (the .torrent file or magnet link) 159 | * `name` => A unicode string corresponding to the torrent's name (i.e: "Ubuntu Linux v6.06") 160 | * `size` => A string corresponding to the torrent size (i.e: "6 MB" or "200 KB" or "1.2 GB"...) 161 | * `seeds` => The number of seeds for this torrent (as a string) 162 | * `leech` => The number of leechers for this torrent (a a string) 163 | * `engine_url` => The search engine url (i.e: https://www.mininova.org) 164 | * `desc_link` => A string corresponding to the description page for the torrent 165 | * `pub_date` => A unix timestamp corresponding to published date of the torrent (i.e: 1696870394) 166 | 167 | ## `retrieve_url()` helper function 168 | The `retrieve_url()` method takes an URL as parameter and returns the content of the URL as a string.
169 | This function is useful to get the search results from a Bittorrent search engine site. All you need to do is to pass the properly formatted URL to the function (the URL usually include GET parameters relative to search tokens, category, sorting, page number). 170 | 171 | ```python 172 | from helpers import retrieve_url 173 | dat = retrieve_url(self.url + '/search?q=%s&c=%s&o=52&p=%d' % (what, self.supported_categories[cat], i)) 174 | ``` 175 | 176 | ## `download_file()` helper function 177 | The `download_file()` functions takes as a parameter the URL to a torrent file. This function will download the torrent to a temporary location and print on stdout: 178 | ```shell 179 | path_to_temporary_file url 180 | ``` 181 | 182 | It prints two values separated by a space: 183 | * The path to the downloaded file (usually in /tmp folder) 184 | * The URL from which the file was downloaded 185 | 186 | Here is an example: 187 | ```python 188 | from helpers import retrieve_url, download_file 189 | print download_file(url) 190 | > /tmp/esdzes https://www.mininova.org/get/123456 191 | ``` 192 | # Testing & Finalizing Your Code 193 | 194 | ## Code Examples 195 | Do not hesitate to use the official search engine plugins as an example. They are available [here](https://github.com/qbittorrent/search-plugins/tree/master/nova3/engines). 196 | * kickasstorrents.py uses json module 197 | * torrentreactor.py uses HTMLParser module 198 | 199 | ## Testing Your Plugin 200 | Before installing your plugin (in Qbittorrent) you can test run the plugin while debugging it. Hence, we advise that you download [these files](https://github.com/qbittorrent/qBittorrent/tree/master/src/searchengine/nova3). 201 | 202 | You will get the following structure: 203 | ``` 204 | your_search_engine 205 | -> nova2.py # the main search engine script which calls the plugins 206 | -> nova2dl.py # standalone script called by qBittorrent to download a torrent using a particular search plugin 207 | -> helpers.py # contains helper functions you can use in your plugins such as retrieve_url() and download_file() 208 | -> novaprinter.py # contains some useful functions like prettyPrint(my_dict) to display your search results 209 | -> socks.py # Required by helpers.py. This module provides a standard socket-like interface. 210 | ``` 211 | 212 | Put your plugin in `engines/` folder ( %localappdata%\qBittorrent\nova3\engines\ ) and then in CMD execute nova2.py script like this: 213 | ```shell 214 | ..\nova2.py your_search_engine_name category search_tokens 215 | # e.g.: ..\nova2.py mininova all kubuntu linux 216 | # e.g.: ..\nova2.py btjunkie books ubuntu 217 | ``` 218 | 219 | A successful result will output: 220 | ``` 221 | DEBUG:root:C:\users\user\appdata\local\qbittorrent\nova3\qbt\qbt 222 | the app will start listing links it finds in the following format: 223 | link|name|size|#seeds|#leechers|engine|page url 224 | ``` 225 | 226 | ## Install Your Plugin 227 | 1. Go to search tab in main window, click on "Search engines..." button. 228 | 2. Then, a new window will pop up, containing the list of installed search engine plugins. 229 | 3. Click on "Install a new one" at the bottom and select your `*.py` python script on you filesystem.
230 | If everything goes well, qBittorrent should notify you that it was successfully installed and your plugin should appear in the list. 231 | 232 | ## Publish Your Plugin 233 | Once you managed to write a search engine plugin for qBittorrent that works, feel free to post it on [this](https://plugins.qbittorrent.org) wiki page so that the other users can use it too.
234 | If you are lucky, your plugin may also be included in the [official repository](https://github.com/qbittorrent/search-plugins). 235 | 236 | ## Notes 237 | * As a convention, it is advised that you print the results sorted by number of seeds (the most seeds at the top) because these are usually the most interesting torrents. 238 | * Please note that search engines usually display results on several pages. Hence, it is better to parse all these pages to get all results. All official plugins have multipage support. 239 | * Some search engines do not provide all the informations required by `prettyPrinter()`. If it is the case, set `-1` as value for the given key (i.e.: `torrent_info['seeds'] = -1`) 240 | * Plugins packaged in a python are no longer directly installable since qBittorrent v2.0.0. You must provide qBittorrent with the python file. 241 | -------------------------------------------------------------------------------- /wiki/Install-search-plugins.md: -------------------------------------------------------------------------------- 1 | ### Steps to install search plugins for qBittorrent version 3.1.10 or more recent 2 | 3 | 0. Note that python plugins/scripts are, by its nature, not considered to be safe. Therefore any use of the unofficial plugins is at your own risk. It is a good practice to audit/take a look at the plugin/script before you install. 4 | 5 | 1. Go to https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins 6 | 1. Under `Download` column, click on the appropriate `Download` link 7 | 1. Save the `.py` file into a temporary location on your local storage 8 | 9 | 1. Using qBittorrent 10 | Using the main window, click on `View` -> `Search Engine` to show search tab 11 | ![screenshot](https://user-images.githubusercontent.com/14078661/51446055-a4431080-1cf3-11e9-8180-1994bdcbb672.png) 12 | 1. Go to the `Search tab` 13 | 1. Click on `Search plugins...` button. Which is located around the bottom right side. 14 | 1. The `Search plugins` window will open. It shows a list of installed search engine plugins. 15 | 1. Click on `Install a new one` button
16 | ![screenshot](https://user-images.githubusercontent.com/14078661/51446120-bf625000-1cf4-11e9-98e1-b7e8b771c457.png)) 17 | 1. The `Plugin source` window will open 18 | 1. Click on `Local file` button 19 | 1. Navigate to the `.py` file you downloaded in the step above. Select the `.py` file. 20 | 1. If successful the following message will be display 21 | > search engine plugin was successfully installed. 22 | 1. If not successful the following message will be display 23 | > search engine plugin could not be installed. 24 | 1. Using [this page](https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins) under the `Comment` column, double check that your system meets the minimum requirements for each search plugin. Maybe your present system does not have the requirements. 25 | 1. Click on `Close` button 26 | 1. You can delete the `.py` file from your temporary location on your local storage, as it is no longer needed. 27 | 1. Optionally, you can use the `Search plugins` window to Enable or Deactivate search plugins, or check for updates. 28 | 1. Done. You have successfully installed a new search plugin for qBittorrent. 29 | -------------------------------------------------------------------------------- /wiki/New-Torznab-search-engine.md: -------------------------------------------------------------------------------- 1 | This guide will help you to configure the the new qBittorrent search engine. 2 | 3 | ## Deprecation notice 4 | 5 | Until version 4.5.0, qBittorrent had a native search engine based on Python. qBittorrent team was in charge of checking the installation of Python and the maintenance of the [search plugins](https://github.com/qbittorrent/search-plugins) for the torrent sites. There were also [unofficial plugins](https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins) maintained by the community. 6 | 7 | Over the time, maintaining this system has become a burden due to the large number of torrent sites and the lack of developers with knowledge of Python. 8 | Since version 4.5.0 the native search engine is replaced with a new search engine that makes calls to [Torznab compatible APIs](https://torznab.github.io/spec-1.3-draft/torznab/Specification-v1.3.html). This implies that the end user has to install additional software to perform searches in qBittorrent. 9 | 10 | ## Torznab clients 11 | 12 | [Torznab](https://torznab.github.io/spec-1.3-draft/torznab/Specification-v1.3.html) is an API specification based on the Newznab WebAPI. The API is built around a simple XML/RSS feed with filtering and paging capabilities. 13 | 14 | There are several software compatible with this specification. Its goal is to support as many torrent sites as possible, parse the content and convert the results into Torznab format so it can be consumed by other applications such as qBittorrent. 15 | 16 | These are the most popular applications: 17 | * [Jackett](https://github.com/Jackett/Jackett): **(recommended)**. It supports more than 500 torrent sites and has the biggest user base. 18 | * [Prowlarr](https://github.com/Prowlarr/Prowlarr): It supports the same sites as Jackett but with more modern UI. 19 | * [NZB Hydra](https://github.com/theotherp/nzbhydra2): It includes more features but supports less torrent sites. 20 | * [Cardigann](https://github.com/cardigann/cardigann): Some sites still work, but it is no longer maintained. 21 | 22 | All of them work fine on qBittorrent, but we only provide instructions for Jackett. 23 | 24 | ## Jackett installation 25 | [Jackett](https://github.com/Jackett/Jackett) is available for Windows, Linux and macOS. It's also available as Docker container and Linux distribution package. 26 | 27 | You can find the installation instructions [here](https://github.com/Jackett/Jackett#installation-on-windows). It's really recommended to install Jackett as a system service. In this way it will start automatically when you start the computer and it will always be up to date. 28 | 29 | Once Jackett is installed. You can open the Web UI to configure the torrent sites. The Jackett URL is usually http://127.0.0.1:9117 The next step is to set up your favorite torrent sites. Click the "Add indexer" button and follow the instructions. 30 | 31 | ![](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/wiki/qbittorrent_torznab_search_1.png) 32 | 33 | When you're done, use the "Manual search" to check that it works correctly. 34 | 35 | ![](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/wiki/qbittorrent_torznab_search_2.png) 36 | 37 | ## qBittorrent search engine 38 | 39 | By default the search engine is disabled. You can enable it in "View => Search engine". 40 | 41 | ![](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/wiki/qbittorrent_torznab_search_3.png) 42 | 43 | Now you will see a new tab where you can search and configure the "Indexers" (torrent sites). 44 | 45 | ![](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/wiki/qbittorrent_torznab_search_4.png) 46 | 47 | You have to add the indexers one by one. The name can be anything. The Toznab URL and API Key are copied from the Jackett Web UI. 48 | 49 | ![](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/wiki/qbittorrent_torznab_search_5.png) 50 | 51 | ![](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/wiki/qbittorrent_torznab_search_6.png) 52 | 53 | The indexers can be disabled and edited with the "right-click menu". 54 | 55 | ![](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/wiki/qbittorrent_torznab_search_7.png) 56 | 57 | You can perform searches in all enabled indexers as usual. 58 | 59 | ![](https://raw.githubusercontent.com/qbittorrent/search-plugins/master/wiki/qbittorrent_torznab_search_8.png) 60 | 61 | If some indexer is not working as expected (or you don't get results at all) check the qBittorrent and Jackett logs for further details. 62 | -------------------------------------------------------------------------------- /wiki/Request-unofficial-search-plugin.md: -------------------------------------------------------------------------------- 1 | In qBittorrent there are two kind of search plugins: 2 | * Official: maintained by qBittorrent developers and can be updated through qBittorrent client. You can find them [here](https://github.com/qbittorrent/search-plugins/tree/master/nova3/engines). 3 | * Unofficial: maintained by third parties. You can find them [here](https://github.com/qbittorrent/search-plugins/wiki/Unofficial-search-plugins). 4 | 5 | If you know a torrent site that is not in the official/unofficial list, you can code it yourself with the instructions [here](https://github.com/qbittorrent/search-plugins/wiki/How-to-write-a-search-plugin) and update the following table. 6 | 7 | **Developers:** You could work on any plugin. It would make the person who made the request very happy. Sites in progress are already being worked on by someone. It is advisable to contact them and offer to help if you want to work on the same site. 8 | 9 | # Requested plugins 10 | 11 | Please keep the list sorted alphabetically by `Site` column 12 | 13 | | Site | In progress? | Plugin repository (Author) | Notes | 14 | | -------------------- | :-----------: | :-------------------------: | ------------------------------ | 15 | | [1tamilmv.com](https://1tamilmv.com) | NO | N/A | fast uploads & good quality indian movies/tv shows, no login required, [rss-feed](https://1tamilmv.com/index.php?/discover/all.xml/) | 16 | | 720pier.ru | NO | N/A | Sport-focused. Fast with new uploads. Requires login | 17 | | [anidex.info](https://github.com/nindogo/qbtSearchScripts/raw/master/anidex.py) | DONE | [Ni Ndogo](https://github.com/nindogo) | | 18 | | [animetosho.org](https://animetosho.org) | DONE | [AlaaBrahim](https://github.com/AlaaBrahim/qBitTorrent-animetosho-search-plugin) | | 19 | | Archive.org | NO | N/A | Jackett already supports archive, use jackett plugin | 20 | | audiobookbay.nl | NO | N/A | | 21 | | beyond-hd.me | NO | N/A | Amazing tracker for good quality movies/tv shows. Private tracker & requires login. | 22 | | bit-titan.net | NO | N/A | good german tracker | 23 | | [bitsearch.to](https://bitsearch.to/) | DONE | [BurningMop](https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/main/bitsearch.py) | BitSearch is a DHT based torrent search engine. | 24 | | Btdb.eu | NO | N/A | | 25 | | [btdig.com](https://btdig.com/) | DONE | [galaris](https://raw.githubusercontent.com/galaris/BTDigg-qBittorrent-plugin/main/btdig.py) | DHT search engine. Great for torrents that may not be in mainstream sites like TBP, 1337x or (the late) RARBG | 26 | | demonoid.is | NO | N/A | | 27 | | Descargas2020.org | NO | N/A | ~Inglés / Latino / Castellano~ This is no longer working | 28 | | dirtytorrents.com | NO | N/A | ~Torrent search engine from different trackers~ This has been discontinued | 29 | | dontorrent.org | NO | N/A | ~Inglés / Castellano~ moved to tomadivx.net | 30 | | ex-torrenty.org | NO | N/A | | 31 | | extremlymtorrents.ws | NO | N/A | | 32 | | eztv.io | NO | N/A | This is no longer working. Use eztv.it instead. | 33 | | gay-torrents.net | NO | N/A | LGBT Content, requires login | 34 | | GranTorrent.eu | NO | N/A | ~Inglés / Latino / Castellano~ This is no longer working | 35 | | idope.se | NO | N/A |Public, has hard to find stuff | 36 | | limetorrents.info | NO | N/A | | 37 | | mejortorrentt.net | NO | N/A | ~Inglés / Latino / Castellano~ This is no longer working | 38 | | mobilism.org | NO | N/A | requires login | 39 | | MVGROUP.org | NO | N/A | requires login | 40 | | myanonamouse.net | NO | N/A | Requires Login | 41 | | NewPCT (pctmix.com) | NO | N/A | Inglés / Castellano | 42 | | [online-fix](https://online-fix.me) | DONE| [caiocinel](https://raw.githubusercontent.com/caiocinel/onlinefix-qbittorrent-plugin/main/onlinefix.py) | Multiplayer Games, Password-protected Archives, Requires Login | 43 | | openpirate.org | NO | N/A | This is no longer working | 44 | | Partis.si | NO | N/A | Nice Slovenian rep | 45 | | pirateiro.com | NO | N/A | This is no longer working | 46 | | pornleech.ch | NO | N/A | ~good seed count, terrible interface~ This is no longer working | 47 | | rarbg.is | DONE | N/A | Already an official search plugin | 48 | | rutracker.guru | NO | N/A | Easily search for Rutracker torrents without account | 49 | | sharewood.tv | NO | N/A | French torrent | 50 | | sktorrent.eu | NO | N/A | Requires Login | 51 | | sound-park.world | NO | N/A | ~Torrent for music~ This is no longer working | 52 | | speed.cd | NO | N/A | a nice private tracker | 53 | | [tamilblasters.com](https://tamilblasters.com) | NO | N/A | latest movies fast uploads, indian movies/tv shows, login not required, [rss-feed](https://tamilblasters.com/index.php?/discover/all.xml/) | 54 | | thepiratebay.org | NO | N/A | | 55 | | [TheRarBg](https://therarbg.com) | DONE | [BurningMop](https://github.com/BurningMop/qBittorrent-Search-Plugins/blob/main/therarbg.py) | Great torrent indexer, RarBg successor | 56 | | [toloka.to](https://toloka.to) | NO | N/A | The most popular Ukrainian tracker. Have the biggest content library in the Ukrainian language. Requires Login. Behind Cloudflare protection | 57 | | torrent-paradise.ml | NO | N/A | This is no longer working | 58 | | torrentday.com | NO | N/A | have invite | 59 | | torrentdownloads.me | DONE | [BurningMop](https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/main/torrentdownloads.py) | Huge torrent indexer, moved to https://torrentdownloads.pro | 60 | | torrenthashes.com | NO | N/A | This is no longer working | 61 | | torrentleech.org | DONE | [444995](https://github.com/444995/qbit-search-plugins/blob/main/engines/torrentleech.py) | Great private tracker with a lot of content | 62 | | [torrentmac.net](https://www.torrentmac.net/) | YES | [Golyb-q](https://raw.githubusercontent.com/Golyb-q/qbittorrent-search-plugins/main/torrentmac.py) | It's the best site for finding updated paid versions of software for macOS users, and I swear by it!| 63 | | torrentz.io | NO | N/A | | 64 | | Torrentz2.eu | NO | N/A | This is no longer working | 65 | | tupelihd.com | NO | N/A | ~Inglés / Latino / Castellano~ This is no longer working | 66 | | watchsomuch.org | NO | N/A | Requires Login | 67 | | WorldWide torrents | NO | N/A | This is no longer working | 68 | | xspeeds.eu | NO | N/A | Private Tracker, Requires Login | 69 | | yinyueso.com | NO | N/A | This is no longer working | 70 | | yts.gd | NO | N/A | moved to https://yts.mx/ | 71 | | zamunda.net | YES | N/A | Supper stacked, Requires Login | 72 | | [zetorrents.com](https://www.zetorrents.com/) | NO | [alexandre-eliot](https://raw.githubusercontent.com/alexandre-eliot/zetorrents_qbittorrent_search_plugin/main/zetorrents.py) | French, handles categories and subcategories, multiple pages search and french to english size conversion | 73 | | [zooqle.skin](https://zooqle.skin/) | DONE | [444995](https://github.com/444995/qbit-search-plugins/blob/main/engines/zooqle.py) | Rich resources, very fast updates, and support for multilingual search. | -------------------------------------------------------------------------------- /wiki/Unofficial-search-plugins.mediawiki: -------------------------------------------------------------------------------- 1 | Here you can find unofficial search engine plugins for qBittorrent that are made available by the community 2 | 3 | = Read First = 4 | * Note that python plugins/scripts are, by its nature, not considered to be safe. Therefore any use of the unofficial plugins is at your own risk. It is a good practice to audit/take a look at the plugin/script before you install. 5 | * To install search engine plugins, follow [[Install-search-plugins#steps-to-install-search-plugins-qbittorrent-version-3110-or-more-recent|this tutorial]]. 6 | * To request search plugins not listed in this page, update [[Request-unofficial-search-plugin|this page]]. 7 | * To write your own search plugins, please follow [[How-to-write-a-search-plugin|this tutorial]]. 8 | * If you wrote one, you're welcome to add it to these tables. Please keep the list sorted by Search Engine name. 9 | * '''If you experience issues with any of the plugins posted here, please report to the author directly.''' In case the author is unresponsive, you can try to fix it yourself. Then you can edit this wiki page and update the link to your fixed plugin. 10 | * The plugins shown as ✖ or ❗ will result in the slowdown and malfunction of other plugins as well, hence the use of these plugins is strongly discouraged. 11 | 12 | ⚠️ We removed support for Python 2. Please upgrade to Python 3 to continue using the search function. 13 | The minimum supported Python version (across all platforms) is specified at [https://github.com/qbittorrent/qBittorrent/blob/master/INSTALL#L21-L23 here]. 14 | 15 | = Plugins for Public Sites = 16 | 17 | {|class="sortable" 18 | |- 19 | ! Search Engine 20 | ! Author (Repository) 21 | ! Version 22 | ! Last update 23 | ! Download link 24 | ! Comments 25 | |- 26 | | [[https://www.google.com/s2/favicons?domain=1337x.to#.png]] [http://1337x.to/ 1337x] 27 | | [https://github.com/sa3dany sa3dany], [https://github.com/Alyetama Alyetama], [https://github.com/BurningMop BurningMop], [https://github.com/scadams scadams] 28 | | 2.2 29 | | 20/Aug
2023 30 | | [https://gist.githubusercontent.com/scadams/56635407b8dfb8f5f7ede6873922ac8b/raw/f654c10468a0b9945bec9bf31e216993c9b7a961/one337x.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 31 | | ✔ qbt 4.4.x / python 3.6.0 32 | |- 33 | |[[https://www.google.com/s2/favicons?domain=academictorrents.com#.png]] [https://academictorrents.com/ Academic Torrents] 34 | |[https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 35 | |1.2 36 | |19/Mar
2023 37 | |[https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/academictorrents.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 38 | |✔ qbt 4.3.x / python 3.8.5
**READ REPOSITORY NOTES** 39 | |- 40 | |[[https://raw.githubusercontent.com/Cc050511/qBit-search-plugins/main/favicon.png]] [https://acg.rip/ acgrip] 41 | |[https://github.com/Cc050511/qBit-search-plugins Yun] 42 | |1.0 43 | |24/Apr
2023 44 | |[https://raw.githubusercontent.com/Cc050511/qBit-search-plugins/main/acgrip.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 45 | |✔ qbt 4.5.2 / python 3.10
46 | |- 47 | | [[https://raw.githubusercontent.com/hannsen/qbittorrent_search_plugins/master/ali213.png]] [http://down.ali213.net/ ali213.net] 48 | | [https://github.com/hannsen/qbittorrent_search_plugins/ hannsen] 49 | | 1.00 50 | | 25/Dec
2017 51 | | [https://raw.githubusercontent.com/hannsen/qbittorrent_search_plugins/master/ali213.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/hannsen/qbittorrent_search_plugins#user-content-ali213net--ali213py [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 52 | | ✔ qbt 4.1.x / python 3.5.0
❗ qbt 4.3.0.1 / python 3.9 53 | |- 54 | | [[https://www.google.com/s2/favicons?domain=anidex.info#.png]] [http://anidex.info/ anidex.info] 55 | | [https://github.com/nindogo Ni Ndogo] 56 | | 0.02 57 | | 06/Jul
2019 58 | | [https://raw.githubusercontent.com/nindogo/qbtSearchScripts/master/anidex.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 59 | | ✔ qbt 4.1.x / python 3.5.0 60 | |- 61 | | [[https://github.com/AlaaBrahim/qBitTorrent-animetosho-search-plugin/blob/main/screenshots/animetosho.png]] [http://animetosho.org/ animetosho.org] 62 | | [https://github.com/AlaaBrahim AlaaBrahim] 63 | | 1.1.0 64 | | 14/Nov
2024 65 | | [https://raw.githubusercontent.com/AlaaBrahim/qBitTorrent-animetosho-search-plugin/main/animetosho.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 66 | | ✔ qbt 4.5.x / python 3.x.x 67 | |- 68 | |[[https://raw.githubusercontent.com/nklido/qBittorrent_search_engines/master/engines/audiobookbay_icon_16x16.png]] [http://theaudiobookbay.se/ AudioBook Bay (ABB) ] 69 | |[https://github.com/nklido/qBittorrent_search_engines nKlido] 70 | |0.4 71 | |22/Feb
2025 72 | |[https://raw.githubusercontent.com/nklido/qBittorrent_search_engines/master/engines/audiobookbay.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 73 | |✔ qbt 5.0.x / python 3.12.x
74 | |- 75 | | [[https://www.google.com/s2/favicons?domain=bitsearch.to#.png]] [https://bitsearch.to/ Bit Search] 76 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 77 | | 1.1 78 | | 13/Apr/2024 79 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/bitsearch.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 80 | | ✔ qbt 4.6.x / python 3.9.x 81 | |- 82 | | [[https://www.google.com/s2/favicons?domain=bt4gprx.com#.png]] [https://bt4gprx.com/ bt4gprx] 83 | | [https://github.com/TuckerWarlock/qbittorrent-search-plugins TuckerWarlock] 84 | | 2.0 85 | | 27/Aug
2023 86 | | [https://raw.githubusercontent.com/TuckerWarlock/qbittorrent-search-plugins/main/bt4gprx.com/bt4gprx.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 87 | | ✔ qbt 4.5.x / python 3.10.x
❗ Working when DDOS cloudfare
protection is disabled 88 | |- 89 | | [[https://www.google.com/s2/favicons?domain=btdig.com#.png]] [https://btdig.com/ btdig] 90 | | [https://github.com/galaris/BTDigg-qBittorrent-plugin galaris] 91 | | 1.1 92 | | 24/Jul
2024 93 | | [https://raw.githubusercontent.com/galaris/BTDigg-qBittorrent-plugin/main/btdig.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 94 | | ✔ qbt 4.6.4 / python 3.9.x 95 | |- 96 | | [[https://www.google.com/s2/favicons?domain=calidadtorrent.com#.png]] [https://calidadtorrent.com/ CalidadTorrent] 97 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 98 | | 1.0 99 | | 24/Nov/2024 100 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/calidadtorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 101 | | ✔ qbt 5.0.x / python 3.9.x 102 | |- 103 | | [[https://www.google.com/s2/favicons?domain=cloudtorrents.com#.png]] [https://cloudtorrents.com/ CloudTorrents] 104 | | [https://github.com/elazar elazar] 105 | | 1.0 106 | | 31/Dec
2024 107 | | [https://raw.githubusercontent.com/elazar/qbittorrent-search-plugins/refs/heads/add-cloudtorrents-plugin/nova3/engines/cloudtorrents.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 108 | | ✔ qbt 5.0.3 / python 3.9.0 109 | |- 110 | | [[https://github.com/menegop/qbfrench/blob/master/cpasbien.png]] 111 | [http://www.cpasbien.moe Cpasbien] 112 | | [https://github.com/MarcBresson/cpasbien MarcBresson] 113 | | 2.2 114 | |24/Dec
2023 115 | | [https://raw.githubusercontent.com/MarcBresson/cpasbien/master/src/cpasbien.py [[https://github.com/MarcBresson/cpasbien/blob/master/assets/Download.gif]]] 116 | | ✔ qbt 4.5.x / python 3.11.x 117 | |- 118 | | [[https://github.com/bugsbringer/qbit-plugins/blob/master/darklibria.png]] [https://dark-libria.it/ dark-libria] 119 | | [https://github.com/bugsbringer/qbit-plugins Bugsbringer] 120 | | 0.10 121 | | 20/Jun
2020 122 | | [https://raw.githubusercontent.com/bugsbringer/qbit-plugins/master/darklibria.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/bugsbringer/qbit-plugins/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 123 | | ✔ qbt 4.2.x / python 3.5.0 124 | |- 125 | | [[https://www.google.com/s2/favicons?domain=divxtotal.wtf#.png]] [https://divxtotal.wtf/ divxtotal] 126 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 127 | | 1.0 128 | | 07/Nov/2024 129 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/divxtotal.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 130 | | ✔ qbt 5.0.x / python 3.9.x 131 | |- 132 | 133 | | [[https://i.imgur.com/2QEr3r0.png]] [https://share.dmhy.org/ DMHY] 134 | | [https://github.com/ZH1637/dmhy ZH] 135 | | 1.0 136 | | 25/Nov
2023 137 | | [https://raw.githubusercontent.com/ZH1637/dmhy/main/dmhy.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
138 | | ✔ qbt 4.6.x / python 3.10.0 139 | |- 140 | | [[https://i.imgur.com/2QEr3r0.png]] [https://share.dmhy.org/ DMHY] 141 | | [https://github.com/diazchika/dmhy dchika] 142 | | 1.0 143 | | 8/Jul
2024 144 | | [https://raw.githubusercontent.com/diazchika/dmhy/main/dmhy.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
145 | | ✔ qbt 4.6.x / python >= 3.7 146 | |- 147 | |- 148 | | [[https://github.com/Bioux1/qbtSearchPlugins/blob/main/dodi_repacks.png]] [https://dodi-repacks.site/ DODI Repacks] 149 | | [https://github.com/Bioux1/qbtSearchPlugins Bioux1] 150 | | 1.1 151 | | 01/May
2025 152 | | [https://raw.githubusercontent.com/Bioux1/qbtSearchPlugins/main/dodi_repacks.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
153 | | ✔ qbt 5.1.0 / python 3.13.3 154 | |- 155 | | [[https://github.com/dangar16/dontorrent-plugin/blob/main/icono%20dontorrent.png]] [https://dontorrent.cologne/ Dontorrent] 156 | | [https://github.com/dangar16/dontorrent-plugin dangar16] 157 | | 1.0 158 | | 24/Sep
2024 159 | | [https://raw.githubusercontent.com/dangar16/dontorrent-plugin/main/dontorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
160 | | ✔ qbt 4.6.5 / python 3.9.7 161 | |- 162 | | [[https://www.google.com/s2/favicons?domain=dontorrent.equipment#.png]] [https://dontorrent.equipment/ dontorrent] 163 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 164 | | 1.0 165 | | 07/Nov/2024 166 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/dontorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 167 | | ✔ qbt 5.0.x / python 3.9.x 168 | |- 169 | | [[https://github.com/iordic/qbittorrent-search-plugins/raw/master/images/icons/elitetorrent.png]] [https://www.elitetorrent.com/ Elitetorrent] 170 | | [https://github.com/iordic/qbittorrent-search-plugins iordic] 171 | | 1.5 172 | | 21/Sep
2024 173 | | [https://raw.githubusercontent.com/iordic/qbittorrent-search-plugins/master/engines/elitetorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 174 | | ✔ qbt 4.6.7 / python 3.9.5 175 | |- 176 | | [[https://www.google.com/s2/favicons?domain=esmeraldatorrent.com#.png]] [https://esmeraldatorrent.com/ esmeraldatorrent] 177 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 178 | | 1.0 179 | | 07/Nov/2024 180 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/esmeraldatorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 181 | | ✔ qbt 5.0.x / python 3.9.x 182 | |- 183 | | [[https://github.com/Bioux1/qbtSearchPlugins/blob/main/fitgirl_repacks.jpg]] [https://fitgirl-repacks.site/ FitGirl Repacks] 184 | | [https://github.com/Bioux1/qbtSearchPlugins Bioux1] 185 | | 1.1 186 | | 01/May
2025 187 | | [https://raw.githubusercontent.com/Bioux1/qbtSearchPlugins/main/fitgirl_repacks.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
188 | | ✔ qbt 5.1.0 / python 3.13.3 189 | |- 190 | | [[https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/glotorrents.png]] [https://glodls.to/ GloTorrents] 191 | | [https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 192 | | 1.5 193 | | 28/Jul
2022 194 | | [https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/glotorrents.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 195 | | ✔ qbt 4.3.5 / python 3.8.5 196 | |- 197 | | [[https://github.com/LightDestory/qBittorrent-Search-Plugins/raw/master/src/engines/kickasstorrents.png]] [https://katcr.to/ Kickass Torrent] 198 | | [https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 199 | | 1.0 200 | | 28/Jul
2022 201 | | [https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/kickasstorrents.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 202 | | ✔ qbt 4.3.x / python 3.8.5 203 | |- 204 | | [[https://www.google.com/s2/favicons?domain=linuxtracker.org#.png]] [http://linuxtracker.org/ Linux Tracker] 205 | | [https://github.com/MadeOfMagicAndWires/qBit-plugins Made Of Magic
And Wires] 206 | | 1.00 207 | | 12/Apr
2017 208 | | [https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/6074a7cccb90dfd5c81b7eaddd3138adec7f3377/engines/linuxtracker.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 209 | | ✔ qbt 4.1.x / python 3.5.0 210 | |- 211 | | [[https://raw.githubusercontent.com/hannsen/qbittorrent_search_plugins/00e876a51f2cb45ee22071c56fc7ba52dc117721/magnetdl.png]] [http://www.magnetdl.com/ MagnetDL] 212 | | [https://github.com/nindogo/qbtSearchScripts Ni Ndogo] 213 | | 1.3 214 | | 25/Jul
2018 215 | | [https://raw.githubusercontent.com/nindogo/qbtSearchScripts/master/magnetdl.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 216 | | ✔ qbt 4.0.x / python 3.5.0 217 | |- 218 | | [[https://raw.githubusercontent.com/hannsen/qbittorrent_search_plugins/00e876a51f2cb45ee22071c56fc7ba52dc117721/magnetdl.png]] [http://www.magnetdl.com/ MagnetDL with categories] 219 | | [https://Scare.ca/dl/qBittorrent/ Scare!] 220 | | 2.0 221 | | 8/Sep
2022 222 | | [https://Scare.ca/dl/qBittorrent/magnetdl.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 223 | | ✔ qbt 4.4.4 / python 3.8.10 224 | |- 225 | | [[https://www.google.com/s2/favicons?domain=anidex.info#.png]] 226 | [https://maxitorrent.com/ MaxiTorrent] 227 | | [https://github.com/joseeloren/qbittorrent-search-plugins joseeloren] 228 | | 1.25 229 | | 16/Apr
2021 230 | | [https://raw.githubusercontent.com/joseeloren/search-plugins/master/nova3/engines/maxitorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 231 | | ✔ qbt 4.3.x / python 3.5.0 232 | |- 233 | | [[https://github.com/iordic/qbittorrent-search-plugins/raw/master/images/icons/mejortorrent.png]] [https://www21.mejortorrent.zip/ MejorTorrent] 234 | | [https://github.com/iordic/qbittorrent-search-plugins iordic] 235 | | 1.0 236 | | 27/Sep
2024 237 | | [https://raw.githubusercontent.com/iordic/qbittorrent-search-plugins/master/engines/mejortorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 238 | | ✔ qbt 4.6.7 / python 3.9.5 239 | |- 240 | | [[https://www.google.com/s2/favicons?domain=mikanime.tv#.png]] [https://mikanime.tv Mikan Project] 241 | | [https://github.com/Cycloctane/qBittorrent-plugins Cycloctane] 242 | | 0.4 243 | | 08/May
/2025 244 | | [https://raw.githubusercontent.com/Cycloctane/qBittorrent-plugins/master/engines/mikan.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]]] 245 | | ✔ qbt 4.5.x / python 3.9.x 246 | |- 247 | |[[https://raw.githubusercontent.com/Cc050511/qBit-search-plugins/main/mikan-pic.png]] [https://mikanani.me mikanani] 248 | |[https://github.com/Cc050511/qBit-search-plugins Yun] 249 | |1.2 250 | |11/Feb
2024 251 | |[https://raw.githubusercontent.com/Cc050511/qBit-search-plugins/main/mikanani.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 252 | |✔ qbt 4.5.2 / python 3.10
253 | |- 254 | | [[https://www.google.com/s2/favicons?domain=myporn.club#.png]] [https://myporn.club/ My Porn Club] 255 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 256 | | 1.1 257 | | 09/Nov/2024 258 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/mypornclub.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 259 | | ✔ qbt 4.6.x / python 3.9.x 260 | |- 261 | | [[https://www.google.com/s2/favicons?domain=naranjatorrent.com#.png]] [https://naranjatorrent.com/ naranjatorrent] 262 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 263 | | 1.0 264 | | 07/Nov/2024 265 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/naranjatorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 266 | | ✔ qbt 5.0.x / python 3.9.x 267 | |- 268 | | [[https://raw.githubusercontent.com/4chenz/pantsu-plugin/master/pantsu.png]] [https://nyaa.pantsu.cat/ Nyaa.Pantsu] 269 | | [https://github.com/4chenz/pantsu-plugin/ 4chenz] 270 | | 1.21 271 | | 02/Jan
2021 272 | | [https://raw.githubusercontent.com/libellula/qbt-plugins/main/pantsu.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 273 | | ✔ qbt 4.0.x / python 3.5.0
✖ qbt 4.1.3 (intermittent failure) 274 | |- 275 | | [[https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/master/engines/nyaapantsu.png]] [https://nyaa.pantsu.cat/ Nyaa.pantsu] 276 | | [https://github.com/MadeOfMagicAndWires/qBit-plugins Made Of Magic
And Wires] 277 | | 1.3 278 | | 02/Jan
2021 279 | | [https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/refs/heads/main/engines/nyaapantsu.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 280 | | ✔ qbt 4.0.x / python 3.5.0 281 | |- 282 | | [[https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/master/engines/nyaasi.png]] [https://nyaa.si/ Nyaa.si] 283 | | [https://github.com/MadeOfMagicAndWires/qBit-plugins Made Of Magic
And Wires] 284 | | 1.1 285 | | 01/Mar
2019 286 | | [https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/master/engines/nyaasi.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 287 | | ✔ qbt 4.4.3.1 / python 3.10.5 288 | |- 289 | | [[https://github.com/caiocinel/onlinefix-qbittorrent-plugin/raw/main/onlinefix.png]] [https://online-fix.me/ Online-Fix] 290 | | [https://github.com/caiocinel/onlinefix-qbittorrent-plugin caiocinel] 291 | | 1.0 292 | | 10/Aug
2024 293 | | [https://raw.githubusercontent.com/caiocinel/onlinefix-qbittorrent-plugin/main/onlinefix.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
294 | | ✔ qbt 4.6.5 / python 3.12.4 295 | |- 296 | | [[https://pediatorrent.com/images/pelispedia/icon-109x109.png]] [https://pediatorrent.com/ PediaTorrent] 297 | | [https://github.com/dangar16/pediatorrent-plugin dangar16] 298 | | 1.0 299 | | 24/Sep
2024 300 | | [https://raw.githubusercontent.com/dangar16/pediatorrent-plugin/refs/heads/main/pediatorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
301 | | ✔ qbt 4.6.5 / python 3.x 302 | |- 303 | | [[https://www.google.com/s2/favicons?domain=pediatorrent.com#.png]] [https://pediatorrent.com/ PediaTorrent] 304 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 305 | | 1.0 306 | | 24/Nov/2024 307 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/pediatorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 308 | | ✔ qbt 5.0.x / python 3.9.x 309 | |- 310 | | [[https://github.com/LightDestory/qBittorrent-Search-Plugins/raw/master/src/engines/pirateiro.png]] [https://pirateiro.com/ Pirateiro] 311 | | [https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 312 | | 1.0 313 | | 28/Jul
2022 314 | | [https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/pirateiro.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 315 | | ✔ qbt 4.3.x / python 3.8.5 316 | |- 317 | | [[https://raw.githubusercontent.com/Larsluph/qbittorrent-search-plugins/prt/nova3/engines/pornrips.png]] [https://pornrips.to/ Pornrips] 318 | | [https://github.com/Larsluph/qbittorrent-search-plugins Larsluph] 319 | | 1.0 320 | | 20/Oct
2023 321 | | [https://raw.githubusercontent.com/Larsluph/qbittorrent-search-plugins/prt/nova3/engines/pornrips.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 322 | | ✔ qbt 4.5.x / python 3.11.6 323 | |- 324 | | [[https://github.com/Pireo/hello-world/blob/master/rockbox.png]] [https://rawkbawx.rocks/ RockBox] 325 | | [https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 326 | | 1.0 327 | | 17/Jun
2021 328 | | [https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/rockbox.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 329 | | ✔ qbt 4.3.x / python 3.8.5 330 | |- 331 | | [[https://github.com/imDMG/qBt_SE/blob/master/engines/rutor.png]] [http://rutor.info/ Rutor] 332 | | [https://github.com/imDMG/qBt_SE imDMG] 333 | | 1.11 334 | | 13/May
2025 335 | | [https://raw.githubusercontent.com/imDMG/qBt_SE/master/engines/rutor.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/imDMG/qBt_SE/blob/master/README.md#rutrackerorg [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 336 | | ✔ qbt 4.2.x / python 3.7+ 337 | |- 338 | | [[https://raw.githubusercontent.com/hannsen/qbittorrent_search_plugins/master/smallgames.png]] [http://small-games.info/ small-games.info] 339 | | [https://github.com/hannsen/qbittorrent_search_plugins/ hannsen] 340 | | 1.00 341 | | 25/Dec
2017 342 | | [https://raw.githubusercontent.com/hannsen/qbittorrent_search_plugins/master/smallgames.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/hannsen/qbittorrent_search_plugins#user-content-small-gamesinfo--smallgamespy [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 343 | | ✔ qbt 4.0.x / python 3.5.0 344 | |- 345 | |[[https://www.google.com/s2/favicons?domain=snowfl.com#.png]] [https://snowfl.com Snowfl] 346 | |[https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 347 | |1.3 348 | |28/Jul
2022 349 | |[https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/snowfl.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 350 | |✔ qbt 4.3.x / python 3.8.5
**READ REPOSITORY NOTES** 351 | |- 352 | | [[https://www.google.com/s2/favicons?domain=solidtorrents.to#.png]] [https://solidtorrents.to/ SolidTorrents.to] 353 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 354 | | 1.0 355 | | 05/Jan/2024 356 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/solidtorrents.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 357 | | ✔ qbt 4.6.x / python 3.9.x 358 | |- 359 | | [[https://www.google.com/s2/favicons?domain=subsplease.org#.png]] [https://subsplease.org/ SubsPlease.org] 360 | | [https://github.com/kli885/qBittorent-SubsPlease-Search-Plugin PlutoMonkey (kli885)] 361 | | 1.0 362 | | 07/Sep
2024 363 | | [https://raw.githubusercontent.com/kli885/qBittorent-SubsPlease-Search-Plugin/main/subsplease.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 364 | | ✔ qbt 4.5.0 / python 3.8.x 365 | |- 366 | | [[https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/master/engines/nyaasi.png]] [https://sukebei.nyaa.si/ Sukebei (Nyaa)] 367 | | [https://github.com/vt-idiot/qBit-SukebeiNyaa-plugin vt-idiot] 368 | | 1.11 369 | | 21/Jun
2022 370 | | [https://github.com/vt-idiot/qBit-SukebeiNyaa-plugin/raw/master/engines/sukebeisi.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 371 | | ✔ qbt 4.4.3.1 / python 3.10.5 372 | |- 373 | | [[https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/master/engines/nyaasi.png]] [https://sukebei.nyaa.si/ Sukebei Nyaa] 374 | | [https://github.com/phuongtailtranminh/qBittorrent-Nyaa-Search-Plugin/ phuongtail
tranminh] 375 | | 1.01 376 | | 19/May
2017 377 | | [https://raw.githubusercontent.com/phuongtailtranminh/qBittorrent-Nyaa-Search-Plugin/master/nyaa.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 378 | | ✔ qbt 4.0.x / python 3.5.0 379 | |- 380 | | [[https://raw.githubusercontent.com/4chenz/pantsu-plugin/master/pantsu.png]] [https://sukebei.pantsu.cat/ Sukebei.Pantsu] 381 | | [https://github.com/4chenz/pantsu-plugin/ 4chenz] 382 | | 1.21 383 | | 02/Jan
2021 384 | | [https://raw.githubusercontent.com/libellula/qbt-plugins/main/sukebei.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 385 | | ✔ qbt 4.0.x / python 3.5.0
✖ qbt 4.1.3 (intermittent failure) 386 | |- 387 | | [[https://github.com/LightDestory/qBittorrent-Search-Plugins/raw/master/src/engines/thepiratebay.png]] [https://thepiratebay.org/ ThePirateBay] 388 | | [https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 389 | | 1.0 390 | | 13/Nov
2021 391 | | [https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/thepiratebay.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 392 | | ✔ qbt 4.3.x / python 3.8.5 393 | |- 394 | | [[https://github.com/LightDestory/qBittorrent-Search-Plugins/raw/master/src/engines/thepiratebay.png]] [https://thepiratebay.org/ ThePirateBay with categories] 395 | | [https://Scare.ca/dl/qBittorrent Scare!] 396 | | 2.0 397 | | 1/Sep
2022 398 | | [https://Scare.ca/dl/qBittorrent/thepiratebay.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 399 | | ✔ qbt 4.4.4 / python 3.8.10 400 | |- 401 | | [[https://www.google.com/s2/favicons?domain=therarbg.com#.png]] [https://therarbg.com/ The RarBg] 402 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 403 | | 1.3 404 | | 20/Oct/2024 405 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/therarbg.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 406 | | ✔ qbt 4.6.x / python 3.9.x 407 | |- 408 | | [[https://www.google.com/s2/favicons?domain=tomadivx.net#.png]] [https://tomadivx.net/ TomaDivx] 409 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 410 | | 1.1 411 | | 07/Nov/2024 412 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/tomadivx.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 413 | | ✔ qbt 5.0.x / python 3.9.x 414 | |- 415 | | [[https://raw.githubusercontent.com/BrunoReX/qBittorrent-Search-Plugin-TokyoToshokan/master/tokyotoshokan.png]] [https://tokyotosho.info/index.php Tokyo Toshokan] 416 | | [https://github.com/BrunoReX/qBittorrent-Search-Plugin-TokyoToshokan BrunoReX] 417 | | 2.3 418 | | 18/Mar
2018 419 | | [https://raw.githubusercontent.com/BrunoReX/qBittorrent-Search-Plugin-TokyoToshokan/master/tokyotoshokan.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 420 | | ✔ qbt 4.0.x / python 3.5.0
❌qbt 4.6+ Will break the plugin system. [https://github.com/qbittorrent/search-plugins/issues/274#issuecomment-2312625898 #274] / [https://github.com/qbittorrent/search-plugins/issues/284#issuecomment-2312601684 #284] 421 | |- 422 | | [[https://github.com/menegop/qbfrench/blob/master/torrent9.png]] 423 | [https://www.torrent9.fm Torrent9] 424 | | [https://raw.githubusercontent.com/menegop/qbfrench menegop] 425 | | 2.0 426 | |01/Jan
2023 427 | | [https://raw.githubusercontent.com/menegop/qbfrench/master/torrent9.py [[https://github.com/menegop/qbfrench/blob/master/Download.gif]]] 428 | | ✔ qbt 4.3.6 / python 3.8 429 | |- 430 | | [[https://github.com/LightDestory/qBittorrent-Search-Plugins/raw/master/src/engines/torrentdownload.png]] [https://torrentdownload.info/ TorrentDownload] 431 | | [https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 432 | | 1.0 433 | | 28/Jul
2022 434 | | [https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/torrentdownload.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 435 | | ✔ qbt 4.3.x / python 3.8.5 436 | |- 437 | | [[https://github.com/LightDestory/qBittorrent-Search-Plugins/raw/master/src/engines/torrentdownload.png]] [https://torrentdownload.info/ TorrentDownload with categories] 438 | | [https://Scare.ca/dl/qBittorrent/ Scare!] 439 | | 2.0 440 | | 7/Sep
2022 441 | | [https://Scare.ca/dl/qBittorrent/torrentdownload.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 442 | | ✔ qbt 4.4.4 / python 3.8.10 443 | |- 444 | | [[https://www.google.com/s2/favicons?domain=torrentdownloads.pro#.png]] [https://torrentdownloads.pro/ Torrent Downloads Pro] 445 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 446 | | 1.1 447 | | 20/Oct/2024 448 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/torrentdownloads.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 449 | | ✔ qbt 4.6.x / python 3.9.x 450 | |- 451 | | [[https://www.google.com/s2/favicons?domain=torrenflix.com#.png]] [https://torrenflix.com/ Torrenflix] 452 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 453 | | 1.0 454 | | 23/Nov/2024 455 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/torrenflix.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 456 | | ✔ qbt 5.0.x / python 3.9.x 457 | |- 458 | | [[https://www.google.com/s2/favicons?domain=torrentgalaxy.to#.png]] [https://torrentgalaxy.to/ TorrentGalaxy] 459 | | [https://github.com/nindogo Ni Ndogo] 460 | | 0.08 461 | | 9/Nov
2024 462 | | [https://raw.githubusercontent.com/nindogo/qbtSearchScripts/master/torrentgalaxy.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 463 | | ✔ qbt 4.1.6+ / python 3.11.4 464 | |- 465 | | [[https://www.google.com/s2/favicons?domain=traht.org#.png]] [https://traht.org/ TrahT] 466 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 467 | | 1.0 468 | | 27/Dec/2023 469 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/traht.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 470 | | ✔ qbt 4.6.x / python 3.9.x 471 | |- 472 | | [[https://github.com/msagca/qbittorrent-plugins/blob/main/uniondht_icon.png]] [http://uniondht.org/ UnionDHT] 473 | | [https://github.com/msagca/qbittorrent-plugins/ msagca] 474 | | 1.2 475 | | 09/Oct
2024 476 | | [https://raw.githubusercontent.com/msagca/qbittorrent-plugins/main/uniondht.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 477 | | ✔ qbt 5.0 / python 3.12 478 | |- 479 | | [[https://www.google.com/s2/favicons?domain=xxxclub.to#.png]] [https://xxxclub.to/ XXXClub] 480 | | [https://github.com/BurningMop/qBittorrent-Search-Plugins BurningMop] 481 | | 1.3 482 | | 29/Oct/2024 483 | | [https://raw.githubusercontent.com/BurningMop/qBittorrent-Search-Plugins/refs/heads/main/xxxclubto.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 484 | | ✔ qbt 5.0.x / python 3.9.x 485 | |- 486 | | [[https://www.google.com/s2/favicons?domain=yourbittorrent.com#.png]] [https://yourbittorrent.com/ YourBittorrent] 487 | | [https://github.com/LightDestory/qBittorrent-Search-Plugins LightDestory] 488 | | 1.0 489 | | 17/Jun
2021 490 | | [https://raw.githubusercontent.com/LightDestory/qBittorrent-Search-Plugins/master/src/engines/yourbittorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 491 | | ✔ qbt 4.3.x / python 3.8.5 492 | |- 493 | | [[https://github.com/Pireo/hello-world/blob/master/yts.png]] [http://yts.mx/ YTS.MX] 494 | | [https://github.com/lazulyra/qbit-plugins lazulyra] 495 | | 1.2 496 | | 07/Jan
2024 497 | | [https://raw.githubusercontent.com/lazulyra/qbit-plugins/main/yts_mx/yts_mx.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]]] 498 | | ✔ qbt 4.6.2 / python 3.12.0 499 | |- 500 | | 🔍 501 | [https://github.com/YGGverse/YGGtracker YGGtracker] 502 | | [https://github.com/YGGverse/qbittorrent-yggtracker-search-plugin YGGverse] 503 | | 1.1.0 504 | | 19/Oct
2023 505 | | [https://raw.githubusercontent.com/YGGverse/qbittorrent-yggtracker-search-plugin/main/yggtracker.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 506 | | ✔ qbt 4.5.1 / v5.0.0alpha1 / python 3.11.4
Requires [https://github.com/yggdrasil-network/ Yggdrasil] connection 507 | |- 508 | | [[https://i.imgur.com/EiYFI5M.png]] [https://zooqle.skin/ Zooqle] 509 | | [https://github.com/444995/qbit-search-plugins 444995] 510 | | 1.10 511 | | 07/Aug
2024 512 | | [https://raw.githubusercontent.com/444995/qbit-search-plugins/main/engines/zooqle.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 513 | | ✔ qbt v4.6.5 / python 3.11.1 514 | |- 515 | |} 516 | 517 | 518 | = Plugins for Private Sites = 519 | * The plugin/script may require editing before you can use it. 520 | * Those sites may require registration and require adding your credentials to the plugin/script. 521 | 522 | {| 523 | |- 524 | ! Search Engine 525 | ! Author (Repository) 526 | ! Version 527 | ! Last update 528 | ! Download link 529 | ! Comments 530 | |- 531 | | [[https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/master/engines/bakabt.png]] [https://bakabt.me BakaBT] 532 | | [https://github.com/MadeOfMagicAndWires/qBit-plugins Made Of Magic
And Wires] 533 | | 1.30 534 | | 13/Apr
2017 535 | | [https://raw.githubusercontent.com/MadeOfMagicAndWires/qBit-plugins/master/engines/bakabt.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/MadeOfMagicAndWires/qBit-plugins/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 536 | | ✔ qbt 4.3.x / python 3.9.x 537 | |- 538 | | [[https://i.imgur.com/ien7TCt.png]] [https://danishbytes.club DanishBytes] 539 | | [https://github.com/444995/qbit-search-plugins 444995] 540 | | 1.50 541 | | 22/Jul
2024 542 | | [https://raw.githubusercontent.com/444995/qbit-search-plugins/main/engines/danishbytes.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 543 | | ✔ qbt v4.6.5 / python 3.11.1 544 | |- 545 | | [[https://github.com/victorBuzdugan/QbittorrentFilelistSearchPlugin/blob/master/filelist.png]] [https://filelist.io FileList] 546 | | [https://github.com/victorBuzdugan/QbittorrentFilelistSearchPlugin victor] 547 | | 1.10 548 | | 07/Sep
2023 549 | | [https://raw.githubusercontent.com/victorBuzdugan/QbittorrentFilelistSearchPlugin/master/filelist.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/victorBuzdugan/QbittorrentFilelistSearchPlugin/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 550 | | ✔ qbt 4.5.x / python 3.8.x 551 | |- 552 | | [[https://github.com/Ooggle/qbittorrent-search-plugins/raw/master/engines/gazellegames.png]] [https://gazellegames.net GazelleGames] 553 | | [https://github.com/Ooggle/qbittorrent-search-plugins Ooggle] 554 | | 1.30 555 | | 07/Oct
2022 556 | | [https://raw.githubusercontent.com/Ooggle/qbittorrent-search-plugins/master/engines/gazellegames.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/Ooggle/qbittorrent-search-plugins/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 557 | | ✔ qbt 4.4.x / python 3.9+ 558 | |- 559 | | [[https://github.com/txtsd/qB-IPT/raw/master/iptorrents.png]] [https://iptorrents.com IPTorrents] 560 | | [https://github.com/txtsd/qB-IPT txtsd (qB-IPT)] 561 | | 1.01 562 | | 22/Oct
2019 563 | | [https://raw.githubusercontent.com/txtsd/qB-IPT/master/iptorrents.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/txtsd/qB-IPT/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 564 | | ✔ qbt 4.1.x / python 3.5.0 565 | |- 566 | | [[https://raw.githubusercontent.com/imDMG/qBt_SE/master/engines/kinozal.png]] [http://kinozal.tv/ Kinozal] 567 | | [https://github.com/imDMG/qBt_SE imDMG] 568 | | 2.15 569 | | 13/May
2025 570 | | [https://raw.githubusercontent.com/imDMG/qBt_SE/master/engines/kinozal.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/imDMG/qBt_SE/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 571 | | ✔ qbt 4.2.x / python 3.7+ 572 | |- 573 | | [[https://github.com/bugsbringer/qbit-plugins/blob/master/lostfilm.png]] [https://www.lostfilm.tv/ LostFilm.TV] 574 | | [https://github.com/bugsbringer/qbit-plugins Bugsbringer] 575 | | 0.14 576 | | 13/Jun
2020 577 | | [https://raw.githubusercontent.com/bugsbringer/qbit-plugins/master/lostfilm.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/bugsbringer/qbit-plugins/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 578 | | ✔ qbt 4.2.x / python 3.5.0 579 | |- 580 | | [[https://raw.githubusercontent.com/darktohka/qbittorrent-plugins/master/resources/ncore.png]] [https://ncore.pro/ nCore] 581 | | [https://github.com/darktohka/qbittorrent-plugins darktohka] 582 | | 1.3 583 | | 16/Feb
2021 584 | | [https://raw.githubusercontent.com/darktohka/qbittorrent-plugins/master/ncore.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/darktohka/qbittorrent-plugins/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 585 | | ✔ qbt 4.1.x / python 3.6+ 586 | |- 587 | | [[https://raw.githubusercontent.com/imDMG/qBt_SE/master/engines/nnmclub.png]] [https://nnm-club.me/ NoNaMe-Club] 588 | | [https://github.com/imDMG/qBt_SE imDMG] 589 | | 2.16 590 | | 13/May
2025 591 | | [https://raw.githubusercontent.com/imDMG/qBt_SE/master/engines/nnmclub.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/imDMG/qBt_SE/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 592 | | ✔ qbt 4.2.x / python 3.7+ 593 | |- 594 | | [[https://raw.githubusercontent.com/TainakaDrums/qbPornolab/master/pornolab.png]] [https://pornolab.net/ Pornolab] 595 | | [https://github.com/TainakaDrums/qbPornolab TainakaDrums] 596 | | 1.0 597 | | 09/Mar
2021 598 | | [https://raw.githubusercontent.com/TainakaDrums/qbPornolab/master/pornolab.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/TainakaDrums/qbPornolab/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 599 | | ✔ qbt 4.2.x / python 3.5.0 600 | |- 601 | | [[https://i.imgur.com/28j2OFz.png]] [https://redacted.ch Redacted] 602 | | [https://github.com/evyd13/search-plugins Evyd13] 603 | | 1.00 604 | | 10/Oct
2021 605 | | [https://raw.githubusercontent.com/evyd13/search-plugins/master/nova3/engines/redacted_ch.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 606 | | ✔ qbt 4.3.x / python 3.10.x 607 | |- 608 | | [[https://raw.githubusercontent.com/imDMG/qBt_SE/master/engines/rutracker.png]] [https://rutracker.org/ RuTracker] 609 | | [https://github.com/imDMG/qBt_SE imDMG] 610 | | 1.12 611 | | 13/May
2025 612 | | [https://raw.githubusercontent.com/imDMG/qBt_SE/master/engines/rutracker.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/imDMG/qBt_SE/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 613 | | ✔ qbt 4.2.x / python 3.7+ 614 | |- 615 | | [[https://raw.githubusercontent.com/nbusseneau/qBittorrent-RuTracker-plugin/master/rutracker.png]] [https://rutracker.org/ RuTracker] 616 | | [https://github.com/nbusseneau/qBittorrent-rutracker-plugin nbusseneau] 617 | | 2.2.0 618 | | 01/May
2025 619 | | [https://raw.githubusercontent.com/nbusseneau/qBittorrent-rutracker-plugin/master/rutracker.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/nbusseneau/qBittorrent-rutracker-plugin/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 620 | | ✔ qbt 5.1.x / python 3.10.x
621 | |- 622 | | [[https://i.imgur.com/M5UA6tt.png]] [https://www.torrentleech.org/ TorrentLeech] 623 | | [https://github.com/444995/qbit-search-plugins 444995] 624 | | 1.00 625 | | 06/Aug
2024 626 | | [https://raw.githubusercontent.com/444995/qbit-search-plugins/main/engines/torrentleech.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 627 | | ✔ qbt v4.6.5 / python 3.11.1 628 | |- 629 | | [[https://raw.githubusercontent.com/swannie-eire/prowlarr-qbittorrent-plugins/main/prowlarr-logo-lq.png]] [https://github.com/Prowlarr/Prowlarr Prowlarr] 630 | | [https://github.com/swannie-eire/prowlarr-qbittorrent-plugins swannie-eire] 631 | | 1.0 632 | | 17/Dec
2021 633 | | [https://raw.githubusercontent.com/swannie-eire/prowlarr-qbittorrent-plugins/main/prowlarr.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/swannie-eire/prowlarr-qbittorrent-plugins [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 634 | | ✔ qbt 4.3.x / python 3.+ 635 | |- 636 | | [[https://www.google.com/s2/favicons?domain=sharewood.tv#.png]] [https://sharewood.tv Sharewood] 637 | | [https://gist.github.com/etn406/2300dd7e8d97ea39442fcdf44c244fe2 etn] 638 | | 1.1 639 | | 24/Apr
2025 640 | | [https://gist.githubusercontent.com/etn406/2300dd7e8d97ea39442fcdf44c244fe2/raw/48eba68c0e32f9321ef2e47f4f8ecb437b093a61/sharewood.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ] 641 | | ✔ qbt 5.0.3 / python 3.+ 642 | |- 643 | | [[https://www.google.com/s2/favicons?domain=speedapp.io#.png]] [https://speedapp.io SpeedApp.IO] 644 | | [https://github.com/miIiano/SpeedApp.io-qBittorent-search-plugin miIiano] 645 | | 1.1 646 | | 11/Aug
2023 647 | | [https://raw.githubusercontent.com/miIiano/SpeedApp.io-qBittorent-search-plugin/main/speedapp.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/miIiano/SpeedApp.io-qBittorent-search-plugin [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 648 | | ✔ qbt 4.5.x / python 3.+ 649 | |- 650 | | [[https://www.google.com/s2/favicons?domain=unionfansub.com#.png]] [https://torrent.unionfansub.com/ UnionFansub] 651 | | [https://gitlab.com/CrimsonKoba/qb-search-plugin CrimsonKoba] 652 | | 1.2 653 | | 05/Jan
2024 654 | | [https://gitlab.com/CrimsonKoba/qb-search-plugin/-/raw/master/unionfansub.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://gitlab.com/CrimsonKoba/qb-search-plugin [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 655 | | ✔ qbt 4.5.x / python 3.+ 656 | |- 657 | | [[https://raw.githubusercontent.com/CravateRouge/qBittorrentSearchPlugins/master/yggtorrent.png]] [https://www.ygg.re/ YggTorrent] 658 | | [https://github.com/CravateRouge/qBittorrentSearchPlugins CravateRouge] 659 | | 1.0 660 | | 25/Nov
2019 661 | | [https://raw.githubusercontent.com/CravateRouge/qBittorrentSearchPlugins/master/yggtorrent.py [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/CravateRouge/qBittorrentSearchPlugins/blob/master/README.md [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 662 | | ❗ Working when DDOS cloudfare
protection is disabled 663 | |- 664 | | [https://yggapi.eu YggAPI] 665 | | [https://github.com/Laiteux/YggAPI-qBittorrent-Search-Plugin Laiteux] 666 | | 1.1 667 | | 31/Jan
2025 668 | | [https://github.com/Laiteux/YggAPI-qBittorrent-Search-Plugin/blob/main/yggapi.py#L13 [[https://raw.githubusercontent.com/Pireo/hello-world/master/Download.gif]] ]
[https://github.com/Laiteux/YggAPI-qBittorrent-Search-Plugin [[https://github.com/Pireo/hello-world/blob/master/Help%20book.gif]] ] 669 | | ✔ qbt 4.1.0+ / python 3.6+ 670 | |} 671 | -------------------------------------------------------------------------------- /wiki/qbittorrent_torznab_search_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/wiki/qbittorrent_torznab_search_1.png -------------------------------------------------------------------------------- /wiki/qbittorrent_torznab_search_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/wiki/qbittorrent_torznab_search_2.png -------------------------------------------------------------------------------- /wiki/qbittorrent_torznab_search_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/wiki/qbittorrent_torznab_search_3.png -------------------------------------------------------------------------------- /wiki/qbittorrent_torznab_search_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/wiki/qbittorrent_torznab_search_4.png -------------------------------------------------------------------------------- /wiki/qbittorrent_torznab_search_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/wiki/qbittorrent_torznab_search_5.png -------------------------------------------------------------------------------- /wiki/qbittorrent_torznab_search_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/wiki/qbittorrent_torznab_search_6.png -------------------------------------------------------------------------------- /wiki/qbittorrent_torznab_search_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/wiki/qbittorrent_torznab_search_7.png -------------------------------------------------------------------------------- /wiki/qbittorrent_torznab_search_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qbittorrent/search-plugins/188c3152ca927d9a9e0b89907f25bb6be85bfe20/wiki/qbittorrent_torznab_search_8.png --------------------------------------------------------------------------------