run.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. #####################################################################
  2. # #
  3. # THIS IS A SOURCE CODE FILE FROM A PROGRAM TO INTERACT WITH THE #
  4. # LBRY PROTOCOL ( lbry.com ). IT WILL USE THE LBRY SDK ( lbrynet ) #
  5. # FROM THEIR REPOSITORY ( https://github.com/lbryio/lbry-sdk ) #
  6. # WHICH I GONNA PRESENT TO YOU AS A BINARY. SINCE I DID NOT DEVELOP #
  7. # IT AND I'M LAZY TO INTEGRATE IN A MORE SMART WAY. THE SOURCE CODE #
  8. # OF THE SDK IS AVAILABLE IN THE REPOSITORY MENTIONED ABOVE. #
  9. # #
  10. # ALL THE CODE IN THIS REPOSITORY INCLUDING THIS FILE IS #
  11. # (C) J.Y.Amihud and Other Contributors 2021. EXCEPT THE LBRY SDK. #
  12. # YOU CAN USE THIS FILE AND ANY OTHER FILE IN THIS REPOSITORY UNDER #
  13. # THE TERMS OF GNU GENERAL PUBLIC LICENSE VERSION 3 OR ANY LATER #
  14. # VERSION. TO FIND THE FULL TEXT OF THE LICENSE GO TO THE GNU.ORG #
  15. # WEBSITE AT ( https://www.gnu.org/licenses/gpl-3.0.html ). #
  16. # #
  17. # THE LBRY SDK IS UNFORTUNATELY UNDER THE MIT LICENSE. IF YOU ARE #
  18. # NOT INTENDING TO USE MY CODE AND JUST THE SDK. YOU CAN FIND IT ON #
  19. # THEIR OFFICIAL REPOSITORY ABOVE. THEIR LICENSE CHOICE DOES NOT #
  20. # SPREAD ONTO THIS PROJECT. DON'T GET A FALSE ASSUMPTION THAT SINCE #
  21. # THEY USE A PUSH-OVER LICENSE, I GONNA DO THE SAME. I'M NOT. #
  22. # #
  23. # THE LICENSE CHOSEN FOR THIS PROJECT WILL PROTECT THE 4 ESSENTIAL #
  24. # FREEDOMS OF THE USER FURTHER, BY NOT ALLOWING ANY WHO TO CHANGE #
  25. # THE LICENSE AT WILL. SO NO PROPRIETARY SOFTWARE DEVELOPER COULD #
  26. # TAKE THIS CODE AND MAKE THEIR USER-SUBJUGATING SOFTWARE FROM IT. #
  27. # #
  28. #####################################################################
  29. # Preparing the executable of lbrynet to be running. If we don't that
  30. # there will be a nasty error of permission being denied.
  31. import os
  32. os.system("chmod u+x flbry/lbrynet")
  33. # I'm not trying to make it pretty. I'm trying to make it snappy.
  34. # It's FastLBRY not SlowLBRY.
  35. import gi
  36. import threading
  37. gi.require_version('Gtk', '3.0')
  38. from gi.repository import Gtk
  39. from gi.repository import Gdk
  40. from gi.repository import GLib
  41. # It's gonna take a couple of things to make the button run
  42. from flbry import connect
  43. from flbry import parse
  44. from flbry import settings
  45. from flbry import url
  46. from flbry import ui
  47. from flbry import claim_search
  48. from flbry import fetch
  49. from flbry import publish
  50. from flbry import downloads
  51. from flbry import analytics
  52. settings.make_sure_file_exists()
  53. ##########################################################################
  54. # #
  55. # THE MAIN WINDOW OF FASTLBRY GTK #
  56. # #
  57. ##########################################################################
  58. win = Gtk.Window() # Make a GTK window object
  59. win.connect("destroy", Gtk.main_quit) # If you close the window, program quits
  60. win.set_title("FastLBRY GTK") # Title
  61. win.set_default_icon_from_file("icon.png") # Icon
  62. win.set_size_request(800, 900) # Minimum size
  63. ##########################################################################
  64. # #
  65. # GLOBAL VARIABLES HACK ( adding things to 'win' ) #
  66. # #
  67. ##########################################################################
  68. # This hack is very simple. Our main Gtk.Window() is a class to which we
  69. # can add variables later on. Like the example you see below.
  70. # This way, giving some function only 'win' and nothing else, will give
  71. # that other function the entire list of global variable ( added this way ).
  72. win.settings = settings.load() # Settings
  73. win.SDK_running = connect.check() # Is the SDK running ( from 0 to 1 to draw progress bar)
  74. win.resolved = {} # Last resolved data
  75. win.commenting = {} # Data for while chatting in comments
  76. win.subs = [] # What you are subscribed to
  77. win.tabs = [] # List of Gtk.Notebook tabs
  78. win.resolve_tab = 0 # What tab to resolve the page
  79. win.notebook = Gtk.Notebook() # Tabs object
  80. win.download_buttons = {} # Keep alive handlers for Download buttons
  81. win.downloads = {} # Data for the Downloads window
  82. ##########################################################################
  83. # #
  84. # TOP PANNEL #
  85. # #
  86. ##########################################################################
  87. # Gtk.HeaderBar() is like a box but it draws itself in the headerbar insead
  88. # of in the window itself.
  89. pannel = Gtk.HeaderBar()
  90. pannel.set_show_close_button(True)
  91. win.set_titlebar(pannel) # Dumbasses wrote GTK
  92. # Untill the user connected to the SDK, search and other functions should
  93. # not work. So we split the pannel into two parts. The other one is a
  94. # normal box.
  95. restofpannel = Gtk.HBox() # H for Horrizontal
  96. pannel.pack_end(restofpannel)
  97. ############## CONNECT BUTTON ################
  98. # Connect button will also be a disconnect button
  99. # Icons for both
  100. icon_connect = ui.icon(win, "network-wired")
  101. icon_disconnect = ui.icon(win, "network-wired-disconnected")
  102. # Boxes for both
  103. connect_box = Gtk.HBox()
  104. disconnect_box = Gtk.HBox()
  105. # Connect box
  106. connect_box.pack_start(icon_connect, False, False, False)
  107. connect_box.set_tooltip_text("Connect to LBRY Network")
  108. connect_box.pack_start(Gtk.Label("Connect "), False, False, False)
  109. # Disconnect box
  110. disconnect_box.pack_start(icon_disconnect, False, False, False)
  111. disconnect_box.set_tooltip_text("Disconnect from LBRY Network")
  112. disconnect_box.pack_start(Gtk.Label("Disconnect "), False, False, False)
  113. # By whether SDK was running while the software was launched
  114. # we present the correct button to the user and set the rest-of-pannel
  115. # accordingly.
  116. if win.SDK_running:
  117. title = disconnect_box
  118. restofpannel.set_sensitive(True)
  119. else:
  120. title = connect_box
  121. restofpannel.set_sensitive(False)
  122. connect_disconncet_button = Gtk.Button()
  123. connect_disconncet_button.add(title)
  124. connect_disconncet_button.set_relief(Gtk.ReliefStyle.NONE)
  125. pannel.pack_start(connect_disconncet_button)#, False, False, False)
  126. ############### CONNECT / DISCONNECT BUTTONS FUNCTION ################
  127. # The button should do something.
  128. def connect_disconnect_function(w):
  129. w.set_sensitive(False)
  130. dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
  131. for i in dynamic_box.get_children():
  132. i.destroy()
  133. progress_connect = Gtk.ProgressBar(show_text=True)
  134. dynamic_box.pack_start(progress_connect, True, True, 30)
  135. win.show_all()
  136. def do_sdk(w, pb):
  137. wasrunning = win.SDK_running
  138. if win.SDK_running == 1:
  139. connect.stop()
  140. else:
  141. connect.start()
  142. def update_pb(pb):
  143. pb.set_fraction(win.SDK_running)
  144. pb.set_text("Connecting: "+str(int(round(win.SDK_running*100)))+"%")
  145. def update_buttons(w):
  146. for i in dynamic_box.get_children():
  147. i.destroy()
  148. w.get_child().destroy()
  149. if win.SDK_running == 1:
  150. w.add(disconnect_box)
  151. restofpannel.set_sensitive(True)
  152. else:
  153. w.add(connect_box)
  154. restofpannel.set_sensitive(False)
  155. w.show_all()
  156. w.set_sensitive(True)
  157. if win.SDK_running == 1:
  158. load_following()
  159. load_channel(win)
  160. check_lock_button()
  161. ui.notify(win, "Connected to LBRY")
  162. if wasrunning == 0:
  163. while True:
  164. win.SDK_running = connect.check()
  165. if win.SDK_running == 1:
  166. break
  167. GLib.idle_add(update_pb, pb)
  168. GLib.idle_add(update_buttons, w)
  169. load_thread = threading.Thread(target=do_sdk, args=(w, progress_connect))
  170. load_thread.setDaemon(True)
  171. load_thread.start()
  172. connect_disconncet_button.connect("clicked", connect_disconnect_function)
  173. ##########################################################################
  174. # #
  175. # LOCK BUTTON #
  176. # #
  177. ##########################################################################
  178. win.lock_button = Gtk.ToggleButton()
  179. def check_lock_button():
  180. try:
  181. wallet_status = fetch.lbrynet("wallet_status")
  182. except:
  183. wallet_status = {}
  184. if wallet_status.get("is_locked"):
  185. win.lock_button.set_active(True)
  186. if not win.settings["lock_password"]:
  187. win.lock_button.set_sensitive(False)
  188. else:
  189. win.lock_button.set_sensitive(True)
  190. check_lock_button()
  191. win.lock_button.set_tooltip_text("Lock / Unlock LBRY wallet. \n\n While the wallet is locked, no transaction could be signed. So nobody could use the running SDK to harm you.\n\nTo set the password look into settings.")
  192. win.lock_button.set_relief(Gtk.ReliefStyle.NONE)
  193. win.lock_button.add(ui.icon(win, "system-lock-screen-symbolic"))
  194. restofpannel.pack_start(win.lock_button, False, False, False)
  195. def lock_unlock(w):
  196. passw = win.settings["lock_password"]
  197. wallets = fetch.lbrynet("wallet_list")
  198. ID = wallets["items"][0]["id"]
  199. if w.get_active():
  200. # If we are locking
  201. print(fetch.lbrynet("wallet_encrypt", {"new_password":passw}))
  202. print(fetch.lbrynet("wallet_lock", {"wallet_id":ID}))
  203. else:
  204. # If decrypt
  205. print(fetch.lbrynet("wallet_unlock", {"password":passw, "wallet_id":ID}))
  206. print(fetch.lbrynet("wallet_decrypt", {"wallet_id":ID}))
  207. print("I AM FUCKING PRESSED")
  208. win.lock_button.connect("clicked", lock_unlock)
  209. ##########################################################################
  210. # #
  211. # PUBLISH BUTTON #
  212. # #
  213. ##########################################################################
  214. restofpannel.pack_start(Gtk.VSeparator(), True, True, 20)
  215. publ = Gtk.Button()
  216. publ.set_tooltip_text("Publish to LBRY")
  217. publ.set_relief(Gtk.ReliefStyle.NONE)
  218. publ.add(ui.icon(win, "list-add"))
  219. restofpannel.pack_start(publ, False, False, False)
  220. def do_publish(w):
  221. publish.window(win)
  222. publ.connect("clicked", do_publish)
  223. restofpannel.pack_start(Gtk.VSeparator(), True, True, 20)
  224. ##########################################################################
  225. # #
  226. # SEARCH / URL BAR #
  227. # #
  228. ##########################################################################
  229. # Note that I add this directly into the 'win' to make it a global variable.
  230. # This let's me to start any url from anywhere in the software.
  231. win.url = Gtk.Entry() # Gtk.SearchEntry() also looks good, but nah
  232. win.url.set_size_request(400,40)
  233. restofpannel.pack_start(win.url, True, True, False)
  234. ####### SEARCH FUNCTION #######
  235. def search(w):
  236. if win.resolve_tab == "current":
  237. win.resolve_tab = win.notebook.get_current_page()
  238. try:
  239. dynamic_box = win.tabs[win.resolve_tab]["box"]
  240. except:
  241. new_tab()
  242. dynamic_box = win.tabs[win.resolve_tab]["box"]
  243. # DRAG AND DROP FOR PUBLISH
  244. if win.url.get_text().startswith("file://") or os.path.exists(win.url.get_text()):
  245. # TODO: Some filenames include weird characters like %20 for spacebar and
  246. # stuff like that. We need to filter that out.
  247. filepath = win.url.get_text().replace("file://", "")
  248. publish.window(win, {"file_path":filepath})
  249. win.url.set_text("")
  250. return
  251. for i in dynamic_box.get_children():
  252. i.destroy()
  253. ## IF WE ARE NOT FORCING IT TO SEACH, IT WILL TRY TO RESOLVE THE LBRY URL FIRST ##
  254. if not force_search.get_active() or win.url.get_text().startswith("lbry://"):
  255. win.url.set_text(parse.bar(win.url.get_text()))
  256. ltext = win.url.get_text()
  257. ltext = ltext[ltext.rfind("/")+1:]
  258. win.tabs[win.resolve_tab]["label"].set_text(ltext[:10]+"...")
  259. win.tabs[win.resolve_tab]["label"].set_tooltip_text(win.url.get_text())
  260. resolve = ui.load(win, url.resolve, url.render_resolve, w, win, win.url.get_text())
  261. dynamic_box.pack_start(resolve, True, True, True)
  262. win.show_all()
  263. else:
  264. resolve = ui.load(win, claim_search.find, claim_search.render, win, win.url.get_text(), [], 1, {"order_by":""})
  265. dynamic_box.pack_start(resolve, True, True, True)
  266. win.show_all()
  267. ltext = win.url.get_text()
  268. win.tabs[win.resolve_tab]["label"].set_text(ltext[:10]+"...")
  269. win.tabs[win.resolve_tab]["label"].set_tooltip_text(win.url.get_text())
  270. dynamic_box.show_all()
  271. win.notebook.set_current_page(win.resolve_tab)
  272. win.resolve_tab = "current"
  273. # Button to activate seach for those who don't know that you can press Enter
  274. search_button = Gtk.Button()
  275. search_icon = ui.icon(win, "system-search")
  276. search_button.add(search_icon)
  277. search_button.set_relief(Gtk.ReliefStyle.NONE)
  278. search_button.connect("clicked", search)
  279. win.url.connect("activate", search)
  280. restofpannel.pack_start(search_button, False, False, False)
  281. ##########################################################################
  282. # #
  283. # HAMBURGER MENU #
  284. # #
  285. ##########################################################################
  286. # Popover is the new GTK menu thingy that looks like a comic book dialog
  287. # box. Which is what we want here. Because we want it to look nice I suppose.
  288. hamburger = Gtk.Popover()
  289. hambutton = Gtk.MenuButton(popover=hamburger)
  290. hambutton_icon = ui.icon(win, "system-users")
  291. hambutton.add(hambutton_icon)
  292. hambutton.set_relief(Gtk.ReliefStyle.NONE)
  293. pannel.pack_start(hambutton)
  294. # Let's now pack the hamburger menu with items
  295. hambox = Gtk.HBox()
  296. # For the elements inside the box we need a scrolled window, to fit a lot of
  297. # them there.
  298. hamscrl = Gtk.ScrolledWindow()
  299. hamscrl.set_size_request(200,200)
  300. hamburger.add(hambox)
  301. hambox.pack_start(hamscrl, False, False, False)
  302. # "hamchannelbox" will be empty untill the user connects and it loads his channel
  303. # list
  304. hamchannelbox = Gtk.VBox()
  305. hamscrl.add_with_viewport(hamchannelbox)
  306. #hambox.pack_start(hamchannelbox, False, False, False)
  307. ###### CHANNELS SELECTOR ########
  308. win.channel = False
  309. def load_channel(win):
  310. def change_channel(w, win, channel ):
  311. win.channel = channel
  312. win.settings["channel"] = win.channel["claim_id"]
  313. settings.save(win.settings)
  314. try:
  315. hambutton.get_child().destroy()
  316. try:
  317. newicon = ui.load(win, ui.net_image_calculation, ui.net_image_render, channel["value"]["thumbnail"]["url"], 40, "", False )
  318. except:
  319. newicon = ui.icon(win, "system-users")
  320. hambutton.add(newicon)
  321. pannel.show_all()
  322. except Exception as e:
  323. print("What?", e)
  324. out = fetch.lbrynet("channel_list")
  325. win.my_channels = out
  326. # We are chooseing first only if there is no channel set in the settings
  327. try:
  328. first = out["items"][0]
  329. win.channel = first
  330. except:
  331. pass
  332. if "channel" in win.settings:
  333. try:
  334. for i in out["items"]:
  335. if i["claim_id"] == win.settings["channel"]:
  336. first = i
  337. break
  338. except:
  339. pass
  340. try:
  341. change_channel(False, win, first)
  342. except:
  343. pass
  344. try:
  345. go.set_sensitive(True)
  346. for i in out["items"]:
  347. channel_button = ui.go_to_channel(win, i, resolve=False)
  348. channel_button.connect("clicked", change_channel, win, i)
  349. hamchannelbox.pack_start(channel_button, False, False, False)
  350. hamchannelbox.show_all()
  351. second_raw.show_all()
  352. except Exception as e:
  353. print("CHANNEL ERROR:", e)
  354. second_raw = Gtk.VBox()
  355. hambox.pack_start(Gtk.VSeparator(), False, False, 5)
  356. hambox.pack_start(second_raw, False, False, False)
  357. ####### Go to channel button #####
  358. def go_to_channel(w):
  359. channel_url = win.channel["name"]
  360. try:
  361. channel_url = channel_url + "#" + win.channel["claim_id"]
  362. except:
  363. pass
  364. win.url.set_text(channel_url)
  365. win.url.activate()
  366. go = Gtk.Button()
  367. b = Gtk.HBox()
  368. b.pack_start(ui.icon(win, "folder-remote"), False, False, False)
  369. b.pack_start(Gtk.Label(" Go To Channel "), True, True, False)
  370. go.add(b)
  371. go.set_sensitive(False)
  372. go.set_relief(Gtk.ReliefStyle.NONE)
  373. go.connect("clicked", go_to_channel)
  374. second_raw.pack_start(go, False, False, False)
  375. ########## UPLOADS BUTTON #########
  376. def load_uploads(w=False):
  377. dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
  378. for i in dynamic_box.get_children():
  379. i.destroy()
  380. send = {"method":"claim_list"}
  381. resolve = ui.load(win, claim_search.find, claim_search.render, win, "", [], 1, send)
  382. dynamic_box.pack_start(resolve, True, True, True)
  383. dynamic_box.show_all()
  384. win.tabs[win.notebook.get_current_page()]["label"].set_text("Uploads")
  385. win.tabs[win.notebook.get_current_page()]["label"].set_tooltip_text("Uploads")
  386. following = Gtk.Button()
  387. b = Gtk.HBox()
  388. b.pack_start(ui.icon(win, "go-up-symbolic"), False, False, False)
  389. b.pack_start(Gtk.Label(" Uploads "), True, True, False)
  390. following.add(b)
  391. following.set_relief(Gtk.ReliefStyle.NONE)
  392. following.connect("clicked", load_uploads)
  393. second_raw.pack_start(following, False, False,False)
  394. ############## ANALYTICS ################
  395. def load_analytics(w):
  396. analytics.window(win)
  397. following = Gtk.Button()
  398. b = Gtk.HBox()
  399. b.pack_start(ui.icon(win, "text-csv"), False, False, False)
  400. b.pack_start(Gtk.Label(" Wallet "), True, True, False)
  401. following.add(b)
  402. following.set_relief(Gtk.ReliefStyle.NONE)
  403. following.connect("clicked", load_analytics)
  404. second_raw.pack_start(following, False, False,False)
  405. second_raw.pack_start(Gtk.HSeparator(), False, False,5)
  406. ######## FOLLOWING BUTTON ###########
  407. def load_following( w=False):
  408. dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
  409. for i in dynamic_box.get_children():
  410. i.destroy()
  411. try:
  412. if not win.subs:
  413. out = fetch.lbrynet("preference_get")
  414. win.subs = out["shared"]["value"]["subscriptions"]
  415. subs_raw = fetch.lbrynet("resolve", {"urls":win.subs})
  416. subs = []
  417. for i in subs_raw:
  418. try:
  419. subs.append(subs_raw[i]["claim_id"])
  420. except:
  421. pass
  422. except Exception as e:
  423. print("\n\nERROR:", e, "\n\n")
  424. subs = []
  425. resolve = ui.load(win, claim_search.find, claim_search.render, win, "", subs)
  426. dynamic_box.pack_start(resolve, True, True, True)
  427. dynamic_box.show_all()
  428. win.tabs[win.notebook.get_current_page()]["label"].set_text("Following")
  429. win.tabs[win.notebook.get_current_page()]["label"].set_tooltip_text("Following")
  430. following = Gtk.Button()
  431. b = Gtk.HBox()
  432. b.pack_start(ui.icon(win, "emblem-favorite"), False, False, False)
  433. b.pack_start(Gtk.Label(" Following "), True, True, False)
  434. following.add(b)
  435. following.set_relief(Gtk.ReliefStyle.NONE)
  436. following.connect("clicked", load_following)
  437. second_raw.pack_start(following, False, False,False)
  438. ######## TRENDING BUTTONS ###########
  439. def load_trending(w=False, articles=False):
  440. dynamic_box = win.tabs[win.notebook.get_current_page()]["box"]
  441. for i in dynamic_box.get_children():
  442. i.destroy()
  443. send = {"order_by":"trending_mixed"}
  444. if articles:
  445. send["media_types"] = ["text/markdown"]
  446. resolve = ui.load(win, claim_search.find, claim_search.render, win, "", [], 1, send)
  447. dynamic_box.pack_start(resolve, True, True, True)
  448. dynamic_box.show_all()
  449. if articles:
  450. lname = "Articles"
  451. else:
  452. lname = "Trending"
  453. win.tabs[win.notebook.get_current_page()]["label"].set_text(lname)
  454. win.tabs[win.notebook.get_current_page()]["label"].set_tooltip_text(lname)
  455. following = Gtk.Button()
  456. b = Gtk.HBox()
  457. # The other one was showing web-browsers at some themes
  458. b.pack_start(ui.icon(win, "emblem-shared"), False, False, False)
  459. b.pack_start(Gtk.Label(" Trending "), True, True, False)
  460. following.add(b)
  461. following.set_relief(Gtk.ReliefStyle.NONE)
  462. following.connect("clicked", load_trending)
  463. second_raw.pack_start(following, False, False,False)
  464. following = Gtk.Button()
  465. b = Gtk.HBox()
  466. b.pack_start(ui.icon(win, "text-x-generic"), False, False, False)
  467. b.pack_start(Gtk.Label(" Articles "), True, True, False)
  468. following.add(b)
  469. following.set_relief(Gtk.ReliefStyle.NONE)
  470. following.connect("clicked", load_trending, True)
  471. second_raw.pack_start(following, False, False,False)
  472. second_raw.pack_start(Gtk.HSeparator(), False, False,5)
  473. ######## DOWNLOADS #########
  474. def load_downloads(w):
  475. downloads.window(win)
  476. following = Gtk.Button()
  477. b = Gtk.HBox()
  478. b.pack_start(ui.icon(win, "go-down-symbolic"), False, False, False)
  479. b.pack_start(Gtk.Label(" Downloads "), True, True, False)
  480. following.add(b)
  481. following.set_relief(Gtk.ReliefStyle.NONE)
  482. following.connect("clicked", load_downloads)
  483. second_raw.pack_start(following, False, False,False)
  484. second_raw.pack_start(Gtk.HSeparator(), False, False,5)
  485. ######## SETTINGS BUTTON ############
  486. second_raw.pack_start(Gtk.HSeparator(), False, False,5)
  487. settings_button = Gtk.Button()
  488. b = Gtk.HBox()
  489. b.pack_start(ui.icon(win, "preferences-system"), False, False, False)
  490. b.pack_start(Gtk.Label(" Settings "), True, True, False)
  491. settings_button.add(b)
  492. settings_button.set_relief(Gtk.ReliefStyle.NONE)
  493. settings_button.connect("clicked", settings.dialogue, win)
  494. second_raw.pack_start(settings_button, False, False, False)
  495. second_raw.pack_start(Gtk.HSeparator(), False, False,5)
  496. ########## FORCE SEARCH BUTTON #######
  497. force_search_box = Gtk.HBox()
  498. force_search = Gtk.Switch()
  499. force_search_box.pack_end(force_search, False, False, 0)
  500. force_search_box.pack_start(ui.icon(win, "system-search"), False, False, 0)
  501. force_search_box.pack_start(Gtk.Label(" Force Search "), True, True, 0)
  502. force_search.set_tooltip_text("If not activated it will try to resolve the claim first.")
  503. second_raw.pack_start(force_search_box, False, False, False)
  504. hambox.show_all()
  505. ##########################################################################
  506. # #
  507. # DYNAMIC BOX ( REST ) #
  508. # #
  509. ##########################################################################
  510. # Dynamic box is a box contents of which will change depending on the "page"
  511. # that the user is loading.
  512. box = Gtk.VBox() # I'm making a top level box just in case
  513. win.add(box)
  514. win.notebook.set_scrollable(True)
  515. def new_tab():
  516. dynamic_box = Gtk.VBox() # And here our dynamic box
  517. label = Gtk.Label("Tab "+str(len(win.tabs)+1))
  518. kill = Gtk.Button()
  519. kill.add(ui.icon(win, "delete"))
  520. kill.set_relief(Gtk.ReliefStyle.NONE)
  521. box = Gtk.HBox()
  522. box.pack_start(label, False, False, 5)
  523. box.pack_start(kill, False, False, 0)
  524. box.show_all()
  525. tab = {"box":dynamic_box, "label":label, "index":len(win.tabs)}
  526. def on_kill(w, tab):
  527. if len(win.tabs) == 1:
  528. load_following()
  529. return
  530. i = tab["index"]
  531. win.notebook.remove_page(i)
  532. del win.tabs[i]
  533. for r, t in enumerate(win.tabs):
  534. t["index"] = r
  535. kill.connect("clicked", on_kill, tab)
  536. win.tabs.append(tab)
  537. win.resolve_tab = len(win.tabs) - 1
  538. win.notebook.append_page(win.tabs[-1]["box"], box)
  539. new_tab()
  540. box.pack_start(win.notebook, True, True, False)
  541. # Just something to run if we are connected
  542. if win.SDK_running == 1:
  543. load_following()
  544. load_channel(win)
  545. else:
  546. win.tabs[0]["box"].pack_start(Gtk.Label("LBRY is not connected. Please connect."), True, True, 20)
  547. ##########################################################################
  548. # #
  549. # DRAG AND DROP #
  550. # #
  551. ##########################################################################
  552. def on_drop(widget, drag_context, x, y, data, info, time):
  553. win.url.set_text(data.get_text())
  554. win.url.activate()
  555. enforce_target = Gtk.TargetEntry.new('text/plain', Gtk.TargetFlags(4), 129)
  556. box.drag_dest_set(Gtk.DestDefaults.ALL, [enforce_target], Gdk.DragAction.COPY)
  557. box.connect("drag-data-received", on_drop)
  558. # Starting Everything
  559. win.show_all()
  560. Gtk.main()
  561. #### Clearing the cache of images ###
  562. ui.clean_image_cache()