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