From 277feac742ff141fb46585d0a44ecd6e7505b75a Mon Sep 17 00:00:00 2001 From: Chris Punches Date: Sun, 7 Oct 2018 23:08:35 -0400 Subject: [PATCH] first commit, ARGGGGGH! --- README.md | 8 + Scallywag | 156 +++++++++++++ config.ini | 2 + rsrc/Scraper/__init__.py | 0 .../__pycache__/__init__.cpython-36.pyc | Bin 0 -> 172 bytes .../__pycache__/proxylister.cpython-36.pyc | Bin 0 -> 1664 bytes .../__pycache__/searcher.cpython-36.pyc | Bin 0 -> 3633 bytes rsrc/Scraper/proxylister.py | 33 +++ rsrc/Scraper/searcher.py | 108 +++++++++ rsrc/gui/#winMain.glade# | 211 +++++++++++++++++ rsrc/gui/proxyselector.glade~ | 80 +++++++ rsrc/gui/winMain.glade | 212 ++++++++++++++++++ rsrc/gui/winMain.glade~ | 210 +++++++++++++++++ 13 files changed, 1020 insertions(+) create mode 100644 README.md create mode 100755 Scallywag create mode 100644 config.ini create mode 100644 rsrc/Scraper/__init__.py create mode 100644 rsrc/Scraper/__pycache__/__init__.cpython-36.pyc create mode 100644 rsrc/Scraper/__pycache__/proxylister.cpython-36.pyc create mode 100644 rsrc/Scraper/__pycache__/searcher.cpython-36.pyc create mode 100644 rsrc/Scraper/proxylister.py create mode 100644 rsrc/Scraper/searcher.py create mode 100644 rsrc/gui/#winMain.glade# create mode 100644 rsrc/gui/proxyselector.glade~ create mode 100644 rsrc/gui/winMain.glade create mode 100644 rsrc/gui/winMain.glade~ diff --git a/README.md b/README.md new file mode 100644 index 0000000..c0bc31a --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# Scallywag +Any swashbuckler's favorite tool. + +# Purpose +A piratebay browser that deliberately circumvents processor-sharing exploitation being sent to browsers. + +# Not Purpose +Not a tool to steal things with. Magnet links and torrents are a perfectly valid technology and must be used responsibly by the user. diff --git a/Scallywag b/Scallywag new file mode 100755 index 0000000..ad8f8a8 --- /dev/null +++ b/Scallywag @@ -0,0 +1,156 @@ +#!/usr/bin/env python3 + +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk, Gdk + +from rsrc.Scraper import proxylister, searcher + +from configparser import ConfigParser + +import subprocess + +class Config: + def __init__(self, config_file): + settings = ConfigParser(allow_no_value=True) + settings.read(config_file) + + # the url used to list out proxies + self.proxylist_url = settings.get("list_source", "piratebay_proxy_list") + + +class Scallywag: + def on_btnRefresh_clicked( self, object, data=None ): + self.status("refresh pressed") + + def on_btnSearch_clicked( self, object, data=None ): + self.status("search pressed") + + + + + # clear the results_store + # seeders, leechers, size, name + self.results_store.clear() + + for row in self.results_store: + self.results_store.remove(row) + + # prove to me that the results_store is populated + for row in self.results_store: + print(row[:]) + + for column in self.results_tree_view.get_columns(): + self.results_tree_view.remove_column(column) + + # associate new results_store with the treeview + self.results_tree_view.set_model(self.results_store) + + # add search result entries to the results store + # TODO add retrieval from search textentry + search_field = self.builder.get_object("txtSearch") + search_terms = search_field.get_text() + + for result in self.get_results( search_terms ): + print( result.__str__() ) + self.results_store.append( [ result.seeders, result.leechers, result.size, result.title, result.author, result.url ]) + + # prove to me that the results_store is populated + for row in self.results_store: + print(row[:]) + + for i, col_title in enumerate( [ "Seeders", "Leechers", "Size", "Title", "Author", "Url" ] ): + # renderer creation + renderer = Gtk.CellRendererText() + + # text is column number + column = Gtk.TreeViewColumn(col_title, renderer, text=i) + + # add column to tvw + self.results_tree_view.append_column(column) + + + + def get_current_proxy(self): + return self.mnuPulldown.get_active_text() + + def on_mnuPulldown_changed(self, object, data=None ): + new_proxy = self.get_current_proxy() + self.config.proxy = new_proxy + + self.status( str.format( "Changed PirateBay proxy site to {0}", self.config.proxy ) ) + + + def get_results(self, search_terms): + + self.searcher = searcher.Scraper( self.config ) + + results = self.searcher.get_results( search_terms ) + + for result in results: + yield result + + + def on_btnDownload_clicked( self, object, data=None, **args ): + selection = self.results_tree_view.get_selection() + (tm, ti) = selection.get_selected() + url = tm.get_value(ti, 5) + # TODO scrape url for magnet link then pass to xdg-open + + magnet = self.searcher.get_magnet( url ) + + subprocess.call(["xdg-open", magnet]) + + self.status("Opening Magnet with xdg-open...") + + def status( self, msg ): + # GTK team, your API is bullshit. + self.statusbar.push( self.statusbar.get_context_id("stsBar"), msg ) + + def on_winMain_destroy(self, object, data=None): + print("quit by exiting") + Gtk.main_quit() + + def __init__(self, configFile): + self.config = Config( configFile ) + + self.gladefile = "./rsrc/gui/winMain.glade" + self.builder = Gtk.Builder() + self.builder.add_from_file(self.gladefile) + self.builder.connect_signals(self) + self.window = self.builder.get_object("winMain") + self.statusbar = self.builder.get_object("stsBar") + + self.status("Choose your PirateBay Proxy") + + self.mnuPulldown = self.builder.get_object("mnuPulldown") + + self.proxy_store = Gtk.ListStore(str) + + self.mnuPulldown.set_model(self.proxy_store) + + self.proxylister = proxylister.Scraper( self.config ) + for proxy in self.proxylister.get_proxies(): + self.proxy_store.append([proxy]) + + self.mnuPulldown.set_active(0) + + + self.results_store = Gtk.ListStore(int, int, str, str, str, str) + + self.window.set_focus(self.builder.get_object("txtSearch")) + + # treeview + self.results_tree_view = self.builder.get_object("tvwResults") + + # wtf. why doesn't this work? + self.results_tree_view.connect("row-activated", self.on_btnDownload_clicked ) + + self.window.show_all() + + + +if __name__ == "__main__": + main = Scallywag("config.ini") + + Gtk.main() diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..a3b3b8e --- /dev/null +++ b/config.ini @@ -0,0 +1,2 @@ +[list_source] +piratebay_proxy_list = thepiratebay-proxylist.se diff --git a/rsrc/Scraper/__init__.py b/rsrc/Scraper/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/rsrc/Scraper/__pycache__/__init__.cpython-36.pyc b/rsrc/Scraper/__pycache__/__init__.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..08dedf6d3b9eccafbb45935b59498f2b6074b775 GIT binary patch literal 172 zcmXr!<>mThv?H1U2p)q77+?f49Dul(1xTbY1T$zd`mJOr0tq9CUy=G5`MIh3Nr~y1 zMTz<;sb#4-`31SDc_sRpc_pbud5JkdMm#q0;1ZzXV)w+N#Pn4C;N+sjg481Y`1s7c b%#!$cy@JYH95%W6DWy57b|5Q@ftUdRpO`P1 literal 0 HcmV?d00001 diff --git a/rsrc/Scraper/__pycache__/proxylister.cpython-36.pyc b/rsrc/Scraper/__pycache__/proxylister.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..58896eb815dfcfd4e464c0096d53052497f7f80e GIT binary patch literal 1664 zcmZ`(&5qkP5GJV~YaQ=)lWv-Bfwn*p6xE@tLvBGD7$}0=i~`$}(m>#fTw4YuIV2r; z4d>*%Oy8i-!fQ@_g`PS?S z2&zbqZ>DI?az@D;A_5V9A|l+fJP`Dfq|rZMOC~9G;mp>m#IODV{0{F0D3atwT+8QRmsM}yKSzkY06w^q`KBI0R2UD0RVsYb= zqNtk676l$@uuy~z>H2hMe$j826u02P-r({H{|w58%pqj~$SFU zRP!U-FepMWStm1V7v@ElxuK7vz(CT0jsV96Q)zwX?sy+$vDC`NzjJM*cCqorcLS)F zg#x639)M$hd@XG`E3`CAWsQCS|9t5>afH|p0J}icN*dfZm@c7b^pvi@?sL6mQ{s02 zV7g;i<{5~dJ`!k$1lrO(1l^Me^hiXIYP>$_LA%)Zd_k-|U%rJ8L6I?YR#7a|hMbcP z-6Emc#AgCYqK`g7fuW~Cek8c%ix&FtLMvC+MI|@V93-v30_%scy0!)*wtjp!s*A3m zcY1p#I1FvmbreDr5ZJDlY_iU>%b@?Tn1&wkm6BXRYuBJfsueNsXNH9XZ7a@YW=B zH1L1!Fb5MJqX|xio;hCz4|F+PpY=iShQe#D+y9v_LqPFU1%@H`!c?Iy`oPsvrp#Xj zeGV3fl|ru{VHu2u(DnEC9k{>fFsbxou+!h5c!B}}Zh`JA;6}GY{sFA~5ee1bfj&u- zdx4OVzEbY!^{SK$3xm)*+;@cMK28UNrzSLslIY~b|AjcQ@Oh|Kwer;JE{YHDi}2S! OdD->*6;83fU%`JJA#S|@ literal 0 HcmV?d00001 diff --git a/rsrc/Scraper/__pycache__/searcher.cpython-36.pyc b/rsrc/Scraper/__pycache__/searcher.cpython-36.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e69a64b54ec1e4009fe27f45beeee48277f3e326 GIT binary patch literal 3633 zcmaJ^&668P6`!6jjXqY{*ba^p5*9;&hlHKPP8C#eh#+58R7yo*swlMOnwp(%?MjR^ za(Bz@j-``w;+S*(0j?Z#=C9~0C-Wz8;`e%_S$Q!TRlj+!yXSTHuiuv*92|7M{pYtQ z|L!@?zns0t13y4hUxILlv%(qC+b!749l5OT^G2Q>^GCjY2czH%hkM-r%HjUT9fgnr z9zqHswK#j^#I5Jh=nP|K{Bu1ka*}qB3ub_(z7Hat5#!Ft<&3*uIatZ+#YzFRgeLrh zP|HH+Elj0{-t_$^XlekWofX@#m6I~V@6y;(j<~qTGLe8@SO!~6^M;epW7n#h?MDi$? z*+R%fiA>VQju)3EO4G@FqSKU?SGZ-zVV&kzy;6gCyqlFXnt_LqBpa}3{tnE9PCJi?p& zsm(j^rw;iOq%QA4>WOIMjoSPG==M!(YX~`AB0cn`W-s#=7>(=O;1W|@9Vnc*Hh14d zQao7-r4_UYr6#~R%!>(Z5$|$7o}6s~mv2DN^J~-AX6#Wq2Z*l0e>eU?%&3JP= z1O)BM0`WN*jc~hRi~<-ym?CsB;ymuwGTg{p6Yoz03T$f+Jlu=gQ2www z_+04xd@?^f8q0EKf^)4G%Jig-oGL9QO2=(F8sbcSp+CaCI7OeNca2u7T>^36P?K(!mUMSM+AOdXe6!`}*d4R}-w= z6_fd2;?^Dnbb9$SBJU7+m&ngSV&58uJ+3@PhY4#H*U#CZ-Pc18FilbXb=V<}i6h?F zKVm&8r}5oGCmf(DI^ixh2=WhP!VMew;B7VpAAq+x7JSHCIAK)vclzs_YtSRT)IK5I zZ-bDROGw*WyB(AkUOg z*C4SVKBSe&?Hw-!7S(Gn?(|q$6Km2C84u-5yWxL;p{=d}0g@3mPJXg>wYPEB-o@7| z_fzNb-^ltg0>9wi9cLX_3Bkikp_P#Ct<S*{HZ?D=gqwcCJ zzg~5xA%ZYl_uz9a9j$^@xN5C>t7z5PKqGUW9Q_F)4Ip-h)!Rv;v(rMH3?}@eyLAYu z)6U(;iI&ytnxEW%obbuhllLDd84<$qUTi~M)x+?EU6++UXr!Cj1S}o_BQ%4|_ zpE_;`+Q0gFJs0(X=d;(n>dkAmx!V$*w6RcfrzW>j?)zU0tzczmC6wD?nP|sqVLM48VpQtf6J5I5)qTX1wV{CFI8mIY=Q~$J`uvv zv_HGZ#X_U*vY+mqpjpfY;WsharcM->K@>*4DC!^E5me8&Nt0h(%!=BGen9F!ByvcE dOty~XFFQ)~u&#K2O%A_ZqQ|fdi`@RL{{rr~BUAtY literal 0 HcmV?d00001 diff --git a/rsrc/Scraper/proxylister.py b/rsrc/Scraper/proxylister.py new file mode 100644 index 0000000..9c4ad97 --- /dev/null +++ b/rsrc/Scraper/proxylister.py @@ -0,0 +1,33 @@ +import requests +from lxml import html + + +class Scraper: + def __init__( self, config ): + # the request client, belongs to session even if no "user session" is needed + self.client = requests.Session() + self.config = config + + def get_proxies(self): + fetch_results = self.client.get( "https://" + self.config.proxylist_url ) + proxy_list = self.Parser.scrape( "proxy_list", fetch_results.content ) + return proxy_list + + class Parser: + @staticmethod + def scrape( datapoint, text ): + cases = { + "proxy_list": Scraper.Parser.proxy_list + } + return cases[ datapoint ]( text ) + + @staticmethod + def proxy_list( text ): + proxyTable = html.fromstring( text ) + proxyTable_xpath = proxyTable.xpath( '//table[@class="proxies"]/tbody/tr/@data-domain' ) + return proxyTable_xpath + + class SessionError( Exception ): + def __init__( self, value ): + self.value = value + diff --git a/rsrc/Scraper/searcher.py b/rsrc/Scraper/searcher.py new file mode 100644 index 0000000..8a1b5d3 --- /dev/null +++ b/rsrc/Scraper/searcher.py @@ -0,0 +1,108 @@ +import requests +from lxml import html +import urllib +import re +import json + +class Result: + def __init__(self, title, seeders, leechers, size, author, url): + self.title = str(title) + self.seeders = int(seeders) + self.leechers = int(leechers) + self.size = str(size) + self.author = str(author) + self.url = str(url) + + def __str__(self): + myjson = {} + myjson['title'] = self.title + myjson['seeders'] = self.seeders + myjson['leechers'] = self.leechers + myjson['size'] = self.size + myjson['author'] = self.author + myjson['url'] = self.url + + return json.dumps(myjson) + +class Scraper: + def __init__( self, config ): + # the request client, belongs to session even if no "user session" is needed + self.client = requests.Session() + self.config = config + + def craft_url(self, protocol, proxy, search_terms): + # https://pirate.blue/s/?q=Raising+Arizona&category=0&page=0&orderby=99 + f = { 'q': search_terms, 'category': 0, 'page': 0, 'orderby': 99 } + return str.format( "{0}://{1}/s/?{2}", protocol, proxy, urllib.parse.urlencode(f) ) + + + def get_results(self, search_terms): + print("Fetching from") + print(self.config.proxy) + + url = self.craft_url( "https", self.config.proxy, search_terms ) + + fetch_results = self.client.get( url ) + results_list = self.Parser.scrape( "results_list", fetch_results.content ) + + return results_list + + + def get_magnet(self, url): + url = "https://" + self.config.proxy + url + fetch_results = self.client.get(url) + + magnet = self.Parser.scrape( "magnet_link", fetch_results.content ) + + return magnet + + class Parser: + @staticmethod + def scrape( datapoint, text ): + cases = { + "results_list": Scraper.Parser.results_list, + "magnet_link": Scraper.Parser.magnet_link + } + return cases[ datapoint ]( text ) + + @staticmethod + def results_list( text ): + resultsTable = html.fromstring( text ) + resultsTable_xpath = resultsTable.xpath( '//table[@id="searchResult"]/tr' ) + + results_buffer = list() + + for tr in resultsTable_xpath: + title = tr.xpath('td[2]/div[1]/a[1]/text()')[0] + seeders = tr.xpath('td[3]/text()')[0] + leechers = tr.xpath('td[4]/text()')[0] + author = tr.xpath('td[2]/font/a/text()')[0] + size_unprocessed = tr.xpath('td[2]/font/text()')[0] + url = tr.xpath('td/div[@class="detName"]/a[@class="detLink"]/@href')[0] + + + m = re.search('Size (.+?),', size_unprocessed) + + if m: + size = m.group(1) + + + results_buffer.append( + Result(title, seeders, leechers, size, author, url) + ) + + return results_buffer + + + @staticmethod + def magnet_link( text ): + link_page = html.fromstring( text ) + magnet_link = link_page.xpath('//div[@class="download"]/a/@href')[0] + return magnet_link + + + + class SessionError( Exception ): + def __init__( self, value ): + self.value = value + diff --git a/rsrc/gui/#winMain.glade# b/rsrc/gui/#winMain.glade# new file mode 100644 index 0000000..9dd5ab0 --- /dev/null +++ b/rsrc/gui/#winMain.glade# @@ -0,0 +1,211 @@ + + + + + + winMain + False + 500 + 600 + + + + boxMain + True + False + vertical + + + True + False + + + False + True + 0 + + + + + True + False + + + mnuPulldown + True + False + 6 + 6 + 6 + + + + True + True + 0 + + + + + gtk-refresh + btnRefresh + True + True + True + 6 + 6 + True + True + + + + False + False + 3 + + + + + False + True + 0 + + + + + stsBar + True + False + 10 + 10 + 10 + 10 + 6 + 6 + True + 2 + + + False + True + end + 0 + + + + + True + False + + + False + True + 6 + 3 + + + + + Open in Client + btnDownload + True + True + True + + + + False + True + end + 4 + + + + + True + True + in + + + True + False + + + tvwResults + True + True + + + + + + + + + + True + True + end + 5 + + + + + boxSearch + True + False + + + txtSearch + True + True + True + True + True + 6 + 6 + True + + + + True + True + 0 + + + + + gtk-find + btnSearch + True + True + True + True + 6 + True + True + + + + False + True + 2 + + + + + False + True + 6 + + + + + + + True + False + + + + diff --git a/rsrc/gui/proxyselector.glade~ b/rsrc/gui/proxyselector.glade~ new file mode 100644 index 0000000..14fdcd3 --- /dev/null +++ b/rsrc/gui/proxyselector.glade~ @@ -0,0 +1,80 @@ + + + + + + False + 440 + 250 + + + True + False + vertical + + + True + False + Select a PirateBay Proxy + + + True + False + 0 + + + + + True + False + + + True + False + + + True + True + 0 + + + + + Select + True + True + True + + + False + True + 1 + + + + + Refresh + True + True + True + + + False + True + 3 + + + + + False + True + 1 + + + + + + + + + diff --git a/rsrc/gui/winMain.glade b/rsrc/gui/winMain.glade new file mode 100644 index 0000000..94155d1 --- /dev/null +++ b/rsrc/gui/winMain.glade @@ -0,0 +1,212 @@ + + + + + + winMain + False + 500 + 600 + + + + boxMain + True + False + vertical + + + True + False + + + False + True + 0 + + + + + True + False + + + mnuPulldown + True + False + 6 + 6 + 6 + + + + True + True + 0 + + + + + gtk-refresh + btnRefresh + True + True + True + 6 + 6 + True + True + + + + False + False + 3 + + + + + False + True + 0 + + + + + stsBar + True + False + 10 + 10 + 10 + 10 + 6 + 6 + True + 2 + + + False + True + end + 0 + + + + + True + False + + + False + True + 6 + 3 + + + + + Open in Client + btnDownload + True + True + True + + + + False + True + end + 4 + + + + + True + True + in + + + True + False + + + tvwResults + True + True + + + + + + + + + + + True + True + end + 5 + + + + + boxSearch + True + False + + + txtSearch + True + True + True + True + True + 6 + 6 + True + + + + True + True + 0 + + + + + gtk-find + btnSearch + True + True + True + True + 6 + True + True + + + + False + True + 2 + + + + + False + True + 6 + + + + + + + True + False + + + + diff --git a/rsrc/gui/winMain.glade~ b/rsrc/gui/winMain.glade~ new file mode 100644 index 0000000..5daefcf --- /dev/null +++ b/rsrc/gui/winMain.glade~ @@ -0,0 +1,210 @@ + + + + + + winMain + False + 500 + 600 + + + + boxMain + True + False + vertical + + + True + False + + + False + True + 0 + + + + + True + False + + + mnuPulldown + True + False + 6 + 6 + 6 + + + + True + True + 0 + + + + + gtk-refresh + btnRefresh + True + True + True + 6 + 6 + True + True + + + + False + False + 3 + + + + + False + True + 0 + + + + + stsBar + True + False + 10 + 10 + 10 + 10 + 6 + 6 + True + 2 + + + False + True + end + 0 + + + + + True + False + + + False + True + 6 + 3 + + + + + Open in Client + btnDownload + True + True + True + + + + False + True + end + 4 + + + + + True + True + in + + + True + False + + + tvwResults + True + True + + + + + + + + + + True + True + end + 5 + + + + + boxSearch + True + False + + + txtSearch + True + True + True + True + 6 + 6 + True + + + + True + True + 0 + + + + + gtk-find + btnSearch + True + True + True + True + 6 + True + True + + + + False + True + 2 + + + + + False + True + 6 + + + + + + + True + False + + + +