index.dcgi - gopherbay - piratebay gopher interface
(HTM) git clone git://bitreich.org/gopherbay git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/gopherbay
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) Tags
(DIR) README
(DIR) LICENSE
---
index.dcgi (6863B)
---
1 #!/usr/bin/env python
2 # coding=utf-8
3 #
4 # © 2025-2026 Christoph Lohmann <20h@r-36.net>
5 #
6 # This file is published under the terms of the GPLv3.
7 #
8 # Adopted from parazd's first gopherbay version.
9
10 import os
11 import sys
12 import getopt
13 import requests
14 import random
15 import time
16 from collections import OrderedDict
17 from urllib.parse import quote
18
19 categories = OrderedDict({
20 100: "Audio",
21 101: "Music",
22 102: "Audio Books",
23 103: "Sound Clips",
24 104: "FLAC",
25 199: "Other",
26 200: "Video",
27 201: "Movies",
28 202: "Movies DVDR",
29 203: "Music Videos",
30 204: "Movie Clips",
31 205: "TV-Shows",
32 206: "Handheld",
33 207: "HD Movies",
34 208: "HD TV-Shows",
35 209: "3D",
36 299: "Other",
37 300: "Applications",
38 301: "Windows",
39 302: "Mac/Apple",
40 303: "UNIX",
41 304: "Handheld",
42 305: "IOS(iPad/iPhone)",
43 306: "Android",
44 399: "Other OS",
45 400: "Games",
46 401: "PC",
47 402: "Mac/Apple",
48 403: "PSx",
49 404: "XBOX360",
50 405: "Wii",
51 406: "Handheld",
52 407: "IOS(iPad/iPhone)",
53 408: "Android",
54 499: "Other OS",
55 500: "Porn",
56 501: "Movies",
57 502: "Movies DVDR",
58 503: "Pictures",
59 504: "Games",
60 505: "HD-Movies",
61 506: "Movie Clips",
62 599: "Cartoon",
63 600: "Other",
64 601: "E-books",
65 602: "Comics",
66 603: "Pictures",
67 604: "Covers",
68 605: "Physibles",
69 699: "Other",
70 })
71
72 trackers = [
73 "udp://tracker.coppersurfer.tk:6969/announce",
74 "udp://tracker.openbittorrent.com:6969/announce",
75 "udp://9.rarbg.to:2710/announce",
76 "udp://9.rarbg.me:2780/announce",
77 "udp://9.rarbg.to:2730/announce",
78 "udp://tracker.opentrackr.org:1337",
79 "http://p4p.arenabg.com:1337/announce",
80 "udp://tracker.torrent.eu.org:451/announce",
81 "udp://tracker.tiny-vps.com:6969/announce",
82 "udp://open.stealth.si:80/announce"
83 ]
84
85 proxies = {
86 "http": "socks5h://localhost:9050",
87 "https": "socks5h://localhost:9050"
88 }
89
90 headers = {
91 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3"
92 }
93
94 def main(args):
95 if len(args) != 7:
96 sys.stderr.write("Must be run as geomyidae dcgi.\n")
97 return 1
98 g_search = args[1]
99 g_arguments = args[2]
100 g_host = args[3]
101 g_port = args[4]
102 g_traversal = args[5]
103 g_base = g_selector = args[6]
104 if len(g_traversal) > 0:
105 g_base = g_selector[:-len(g_traversal)]
106
107 pb_base = "https://apibay.org"
108 # search for torrents q=$query
109 pb_search = "%s/q.php" % (pb_base)
110 # get torrent info q=$id
111 pb_torrent = "%s/t.php" % (pb_base)
112 pb_precompiled = "%s/precompiled" % (pb_base)
113 # categories: (pb_base, (top100, top100_48h), (all, recent, categories{}))
114 pb_data = "%s/data_%s_%s.json"
115
116 def name2gph(name):
117 return name.replace("|", "\\|")
118
119 def size2human(num, suffix="B"):
120 for unit in ("", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"):
121 if abs(num) < 1024.0:
122 return "%3.1f%s" % (num, suffix)
123 num /= 1024.0
124 return "%.1fYi%s" % (num, suffix)
125
126 def logo():
127 return "☠ ⚔ 🚢\n"
128
129 def index2gph():
130 gph = logo()
131 gph += "Get torrents ...\n"
132 gph += "[7|by search|%s/search|server|port]\n" % (g_base)
133 gph += "[1|by category|%s/category|server|port]\n" % (g_base)
134 gph += "[1|by top 100|%s/top|server|port]\n" % (g_base)
135 gph += "[1|by recent (48h) top 100|%s/recent|server|port]\n" % (g_base)
136 return gph
137
138 def category2gph(kind):
139 gph = logo()
140 begin_category = list(categories.keys())[0]
141 end_category = list(categories.keys())[-1]
142 if kind == "top" or kind == "recent" or kind == "category":
143 gph += "[1|all %s|%s/search/%s|server|port]\n" % \
144 (kind, g_base, kind)
145 else:
146 try:
147 c = int(kind)
148 except ValueError:
149 return "[3|Invalid category.||server|port]\n"
150 begin_category = c - (c % 100)
151 end_category = begin_category + 99
152
153 for c in categories.keys():
154 if c < begin_category or c > end_category:
155 continue
156 if (c % 100) == 0:
157 gph += "[1|= %s =|%s/search/%s:%s|server|port]\n" % \
158 (categories[c], g_base, kind, c)
159 else:
160 gph += "[1|%s|%s/search/%s:%s|server|port]\n" % \
161 (categories[c], g_base, kind, c)
162 return gph
163
164 def search(q=""):
165 if q == "":
166 return requests.get(pb_data % (pb_precompiled,\
167 "top100", "all"),\
168 headers=headers,\
169 proxies=proxies).json()
170 elif q.startswith("recent"):
171 if ":" in q:
172 (q, category) = q.split(":", 1)
173 return requests.get(pb_data % (pb_precompiled,\
174 "top100_48h", category),\
175 headers=headers,\
176 proxies=proxies).json()
177 else:
178 return requests.get(pb_data % (pb_precompiled,\
179 "top100", "recent"),\
180 headers=headers,\
181 proxies=proxies).json()
182 elif q.startswith("top"):
183 if ":" in q:
184 (q, category) = q.split(":", 1)
185 return requests.get(pb_data % (pb_precompiled,\
186 "top100", category),\
187 headers=headers,\
188 proxies=proxies).json()
189 else:
190 return requests.get(pb_data % (pb_precompiled,\
191 "top100", "all"),\
192 headers=headers,\
193 proxies=proxies).json()
194 else:
195 return requests.get(pb_search, params={"q":q},\
196 headers=headers,\
197 proxies=proxies).json()
198
199 # Proudly taken from parazyd.
200 def print_category(c):
201 c = int(c)
202 if c in categories:
203 masterc = str(c)[0] + "00"
204 if masterc in categories:
205 return "%s > %s" \
206 % (categories[masterc],\
207 categories[c])
208 return categories[c]
209 else:
210 return "n/a"
211
212 # Proudly taken from parazyd.
213 def magnet_link(h, name):
214 qtrackers = [quote(t) for t in trackers]
215 trs = "&trs=".join(qtrackers)
216 return "magnet:?xt=urn:btih:%s&dn%s&tr=%s" % \
217 (h, quote(name), trs)
218
219 def search2gph(results):
220 gph = logo()
221 gph += "= search results =\n"
222 for r in results:
223 gph += "[h|= %s|%s|server|port]\n" \
224 % (name2gph(r["name"]),\
225 magnet_link(r["info_hash"], r["name"]))
226 gph += "[1|Category: %s|%s/category/%s|server|port]\n" % \
227 (name2gph(print_category(r["category"])),\
228 g_base, r["category"])
229 gph += "Seeders:%d,Leechers:%d,Files:%d,Size:%s,T:%s,U:%s\n" % \
230 (int(r["seeders"]), int(r["leechers"]),\
231 int(r["num_files"]), size2human(int(r["size"])),\
232 time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(r["added"]))),\
233 name2gph(r["username"]))
234 return gph
235
236 category = "all"
237 cmds = g_traversal.split("/")
238 if len(cmds) == 0:
239 gph = index2gph()
240 elif len(cmds) == 1:
241 gph = index2gph()
242 elif cmds[1] == "":
243 gph = index2gph()
244 elif cmds[1] == "category" or cmds[1] == "top" or cmds[1] == "recent":
245 if len(cmds) > 2:
246 gph = category2gph(cmds[2])
247 else:
248 gph = category2gph(cmds[1])
249 elif cmds[1] == "search":
250 # https://apibay.org/q.php?q=Example
251 # scm:apibay
252 params = None
253 if len(cmds) > 2:
254 results = search(cmds[2])
255 elif len(g_search) > 0:
256 results = search(g_search)
257 else:
258 results = search()
259 try:
260 gph = search2gph(results)
261 except TypeError:
262 gph = "[3|We got hit by clownflare.||server|port]\n"
263 else:
264 gph = "[3|Not found.||server|port]\n"
265
266 sys.stdout.write(gph)
267 sys.stdout.flush()
268
269 return 0
270
271 if __name__ == "__main__":
272 sys.exit(main(sys.argv))
273