├── .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 | [](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 | 
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 | )
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 | 
32 |
33 | When you're done, use the "Manual search" to check that it works correctly.
34 |
35 | 
36 |
37 | ## qBittorrent search engine
38 |
39 | By default the search engine is disabled. You can enable it in "View => Search engine".
40 |
41 | 
42 |
43 | Now you will see a new tab where you can search and configure the "Indexers" (torrent sites).
44 |
45 | 
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 | 
50 |
51 | 
52 |
53 | The indexers can be disabled and edited with the "right-click menu".
54 |
55 | 
56 |
57 | You can perform searches in all enabled indexers as usual.
58 |
59 | 
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
--------------------------------------------------------------------------------