claim_search.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  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. # This is the seach mechanism
  30. import threading
  31. from flbry import ui
  32. from flbry import fetch
  33. from gi.repository import Gtk
  34. from gi.repository import GLib
  35. def find(win, arg="", channel_ids=[], page=1, r={}, flowbox=False):
  36. # This is very dumb. I did a mess with the inputs of this command
  37. # now I'm trying to add a new feature, without rewriting a whole
  38. # lot. And it requires form me to give it a weird kind of thing.
  39. sr = r.copy()
  40. if "method" in r:
  41. method = r["method"]
  42. del r["method"]
  43. c = {}
  44. c["page"] = page
  45. else:
  46. method = "claim_search"
  47. c = {}
  48. c["text"] = arg
  49. c["channel_ids"] = channel_ids
  50. c["page"] = page
  51. c["order_by"] = "creation_height" #{"order_by":"release_time"}
  52. c["remove_duplicates"] = True
  53. # TAGS TO EXCLUDE ( E.G. 'mature', 'porn' )
  54. tags = win.settings["filter_tags"] # It's set in the settings
  55. c["not_tags"] = tags
  56. # Any overwrites ?
  57. for i in r:
  58. if r[i]:
  59. c[i] = r[i]
  60. elif c[i]:
  61. del c[i]
  62. channel_load = True
  63. if len(channel_ids) == 1:
  64. channel_load = False
  65. out = fetch.lbrynet(method, c)
  66. same = [win, arg, channel_ids, page+1, sr]
  67. if flowbox:
  68. def add_to_flowbox(flowbox, out):
  69. for i in out["items"]:
  70. flowbox.add(ui.search_item(win, i, channel_load))
  71. if len(out["items"]) > 1:
  72. lastthing(win, same, flowbox)
  73. flowbox.show_all()
  74. GLib.idle_add(add_to_flowbox, flowbox, out)
  75. else:
  76. return [win, out, channel_load, same, sr]
  77. def render(out):
  78. win, out, channel_load, same, r = out
  79. overlay = Gtk.Overlay()
  80. scrolled = Gtk.ScrolledWindow()
  81. scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
  82. flowbox = Gtk.FlowBox()
  83. flowbox.set_valign(Gtk.Align.START)
  84. flowbox.set_max_children_per_line(30)
  85. flowbox.set_selection_mode(Gtk.SelectionMode.NONE)
  86. scrolled.add(flowbox)
  87. box = Gtk.VBox()
  88. for i in out["items"]:
  89. flowbox.add(ui.search_item(win, i, channel_load))
  90. if len(out["items"]) > 1:
  91. lastthing(win, same, flowbox)
  92. overlay.add(scrolled)
  93. ############ SEARCH MENU ##############
  94. settings_menu = Gtk.Popover()
  95. settings_scroll = Gtk.ScrolledWindow()
  96. settings_menu.add(settings_scroll)
  97. settings_scroll.set_size_request(400,400)
  98. menu_box = Gtk.VBox()
  99. settings_scroll.add(menu_box)
  100. menu_box.pack_start(Gtk.Label(" Search Options: "), 0,0,5)
  101. #### SEARCH TERMS ###
  102. # name - the LBRY url of publication.
  103. collapsable = Gtk.Expander(label=" By Text Query: ")
  104. menu_box.pack_start(collapsable, 0,0,5)
  105. term_box = Gtk.VBox()
  106. collapsable.add(term_box)
  107. hbox = Gtk.HBox()
  108. term_box.pack_start(hbox, 0,0,5)
  109. hbox.pack_start(Gtk.Label(" LBRY url: "), 0,0,0)
  110. lbry_name_entry = Gtk.Entry()
  111. if same[-1].get("name"):
  112. lbry_name_entry.set_text(same[-1]["name"])
  113. hbox.pack_end(lbry_name_entry, 1,1,0)
  114. # text - the text in title
  115. hbox = Gtk.HBox()
  116. term_box.pack_start(hbox, 0,0,5)
  117. hbox.pack_start(Gtk.Label(" Search by Text: "), 0,0,0)
  118. text_entry = Gtk.Entry()
  119. if same[1]:
  120. text_entry.set_text(same[1])
  121. elif same[-1].get("text"):
  122. text_entry.set_text(same[-1]["text"])
  123. hbox.pack_end(text_entry, 1,1,0)
  124. # claim_id - search partial of full claim_id
  125. collapsable = Gtk.Expander(label=" By Claim ID: ")
  126. menu_box.pack_start(collapsable, 0,0,5)
  127. term_box = Gtk.VBox()
  128. collapsable.add(term_box)
  129. hbox = Gtk.HBox()
  130. term_box.pack_start(hbox, 0,0,5)
  131. hbox.pack_start(Gtk.Label(" Claim ID: "), 0,0,0)
  132. claim_id_entry = Gtk.Entry()
  133. if same[-1].get("claim_id"):
  134. claim_id_entry.set_text(same[-1]["claim_id"])
  135. hbox.pack_start(claim_id_entry, 1,1,0)
  136. # claim_ids - search partial of full claim_id
  137. term_box.pack_start(Gtk.Label(" Many Full Claim IDs "), 0,0,5)
  138. claim_ids_list = []
  139. if same[-1].get("claim_ids"):
  140. claim_ids_list = same[-1].get("claim_ids")
  141. claim_ids_editor = ui.tags_editor(win, claim_ids_list)
  142. term_box.pack_start(claim_ids_editor, 0,0,0)
  143. ## TAGS ##
  144. collapsable = Gtk.Expander(label=" Tags: ")
  145. menu_box.pack_start(collapsable, 0,0,5)
  146. term_box = Gtk.VBox()
  147. collapsable.add(term_box)
  148. term_box.pack_start(Gtk.Label(" Any of: "), 0,0,5)
  149. any_tags_list = []
  150. if same[-1].get("any_tags"):
  151. any_tags_list = same[-1].get("any_tags")
  152. tags_editor = ui.tags_editor(win, any_tags_list)
  153. term_box.pack_start(tags_editor, 0,0,0)
  154. term_box.pack_start(Gtk.Label(" All of: "), 0,0,5)
  155. all_tags_list = []
  156. if same[-1].get("all_tags"):
  157. all_tags_list = same[-1].get("all_tags")
  158. tags_editor = ui.tags_editor(win, all_tags_list)
  159. term_box.pack_start(tags_editor, 0,0,0)
  160. term_box.pack_start(Gtk.Label(" Excluding: "), 0,0,5)
  161. not_tags_list = []
  162. if same[-1].get("not_tags"):
  163. not_tags_list = same[-1].get("not_tags")
  164. tags_editor = ui.tags_editor(win, not_tags_list)
  165. term_box.pack_start(tags_editor, 0,0,0)
  166. ## CHANNELS ##
  167. collapsable = Gtk.Expander(label=" Channels: ")
  168. menu_box.pack_start(collapsable, 0,0,5)
  169. term_box = Gtk.VBox()
  170. collapsable.add(term_box)
  171. hbox = Gtk.HBox()
  172. term_box.pack_start(hbox, 0,0,5)
  173. hbox.pack_start(Gtk.Label(" Channel Name: "), 0,0,0)
  174. channel_entry = Gtk.Entry()
  175. if same[-1].get("channel"):
  176. channel_entry.set_text(same[-1]["channel"])
  177. hbox.pack_start(channel_entry, 1,1,0)
  178. term_box.pack_start(Gtk.Label(" Anything from (channel's claim IDs): "), 0,0,5)
  179. any_channels_list = []
  180. if same[2]:
  181. any_channels_list = same[2]
  182. elif same[-1].get("channel_ids"):
  183. any_channels_list = same[-1]["channel_ids"]
  184. tags_editor = ui.tags_editor(win, any_channels_list)
  185. term_box.pack_start(tags_editor, 0,0,0)
  186. term_box.pack_start(Gtk.Label(" Excluding (channel's claim IDs): "), 0,0,5)
  187. not_channels_list = []
  188. if same[-1].get("not_channel_ids"):
  189. not_channels_list = same[-1]["not_channel_ids"]
  190. tags_editor = ui.tags_editor(win, not_channels_list)
  191. term_box.pack_start(tags_editor, 0,0,0)
  192. ## ORDER BY ##
  193. collapsable = Gtk.Expander(label=" Order: ")
  194. menu_box.pack_start(collapsable, 0,0,5)
  195. term_box = Gtk.VBox()
  196. collapsable.add(term_box)
  197. order_by_rules = {
  198. "Name":"name",
  199. "Release Time":"release_time",
  200. "Trending":"trending_mixed",
  201. "Trending (Global)":"trending_global",
  202. "Trending (Group)":"trending_group",
  203. "Trending (Local)":"trending_local",
  204. "Bid":"amount",
  205. "Support":"support_amount",
  206. "Support plus Bid":"effective_amount",
  207. "Block Height":"height",
  208. "Start Block":"activation_height"
  209. }
  210. order_by = Gtk.ComboBoxText()
  211. was_set = False
  212. for n, i in enumerate(order_by_rules):
  213. order_by.append_text(i)
  214. if order_by_rules[i] in str(same[-1].get("order_by")):
  215. order_by.set_active(n)
  216. was_set = True
  217. if not was_set:
  218. order_by.set_active(1)
  219. term_box.pack_start(order_by, 0,0,5)
  220. hbox = Gtk.HBox()
  221. term_box.pack_start(hbox, 0,0,5)
  222. hbox.pack_start(Gtk.Label(" Reverse: "), 0,0,0)
  223. order_reverse = Gtk.Switch()
  224. if "^" in str(same[-1].get("order_by")):
  225. order_reverse.set_active(True)
  226. hbox.pack_end(order_reverse, 0,0,0)
  227. ## ORDER BY ##
  228. collapsable = Gtk.Expander(label=" Type: ")
  229. menu_box.pack_start(collapsable, 0,0,5)
  230. term_box = Gtk.VBox()
  231. collapsable.add(term_box)
  232. claim_types = {
  233. "Every Claim Type":"",
  234. "Channel":"channel",
  235. "File":"stream",
  236. "Re-Post":"repost",
  237. "Collection":"collection"
  238. }
  239. claim_type = Gtk.ComboBoxText()
  240. was_set = False
  241. for n, i in enumerate(claim_types):
  242. claim_type.append_text(i)
  243. if claim_types[i] in str(same[-1].get("claim_type")):
  244. claim_type.set_active(n)
  245. was_set = True
  246. if not was_set:
  247. claim_type.set_active(0)
  248. term_box.pack_start(claim_type, 0,0,5)
  249. ## FILETYPES ##
  250. term_box.pack_start(Gtk.Label(" Filetypes: "), 0,0,5)
  251. stream_types = []
  252. if same[-1].get("stream_types"):
  253. stream_types = same[-1]["stream_types"]
  254. stream_types_editor = ui.tags_editor(win, stream_types)
  255. stream_types_editor.set_tooltip_text("Types of a file. For example: video, audio, image, document, binary.")
  256. term_box.pack_start(stream_types_editor, 0,0,5)
  257. ## MIME-TYPES ##
  258. term_box.pack_start(Gtk.Label(" Mime-Types: "), 0,0,5)
  259. media_types = []
  260. if same[-1].get("media_types"):
  261. media_types = same[-1]["media_types"]
  262. media_types_editor = ui.tags_editor(win, media_types)
  263. media_types_editor.set_tooltip_text("Precise Formats. For example: image/png, audio/ogg, application/x-ext-blend")
  264. term_box.pack_start(media_types_editor, 0,0,5)
  265. ####### !!! RE _ SEARCH !!! #######
  266. def do_re_search(w):
  267. request = {}
  268. ## TEXT ##
  269. if lbry_name_entry.get_text():
  270. request["name"] = lbry_name_entry.get_text()
  271. if text_entry.get_text():
  272. request["text"] = text_entry.get_text()
  273. ## CLAIM ID ##
  274. if claim_id_entry.get_text():
  275. request["claim_id"] = claim_id_entry.get_text()
  276. if claim_ids_list:
  277. request["claim_ids"] = claim_ids_list
  278. ## TAGS ##
  279. if any_tags_list:
  280. request["any_tags"] = any_tags_list
  281. if all_tags_list:
  282. request["all_tags"] = all_tags_list
  283. if any_tags_list:
  284. request["not_tags"] = not_tags_list
  285. ## CHANNELS ##
  286. if channel_entry.get_text():
  287. request["channel"] = channel_entry.get_text()
  288. if any_channels_list:
  289. request["channel_ids"] = any_channels_list
  290. if not_channels_list:
  291. request["not_channel_ids"] = not_channels_list
  292. ## Order by ##
  293. prefix = ""
  294. if order_reverse.get_active():
  295. prefix = "^"
  296. request["order_by"] = prefix+list(order_by_rules.values())[order_by.get_active()]
  297. ## CLAIM TYPE ##
  298. if list(claim_types.values())[claim_type.get_active()]:
  299. request["claim_type"] = list(claim_types.values())[claim_type.get_active()]
  300. # Some logic related to what the user will percieve
  301. if request["channel_ids"] and not request.get("claim_ids") and request["claim_type"] == "channel":
  302. request["claim_ids"] = request["channel_ids"]
  303. request["channel_ids"] = []
  304. ## STREAM TYPE ##
  305. if stream_types:
  306. request["stream_types"] = stream_types
  307. ## MIME TYPES ##
  308. if media_types:
  309. request["media_types"] = media_types
  310. box = overlay.get_parent()
  311. overlay.destroy()
  312. resolve = ui.load(win, find, render, win, "", [], 1, request)
  313. box.pack_start(resolve, 1,1,0)
  314. box.show_all()
  315. re_search = Gtk.Button()
  316. re_search.connect("clicked", do_re_search)
  317. re_search.set_relief(Gtk.ReliefStyle.NONE)
  318. b = Gtk.HBox()
  319. b.pack_start(ui.icon(win, "system-search"),0,0,0)
  320. b.pack_start(Gtk.Label(" Re-Search "),0,0,0)
  321. re_search.add(b)
  322. menu_box.pack_end(re_search, 0,0,0)
  323. settings_scroll.show_all()
  324. b = Gtk.MenuButton(popover=settings_menu)
  325. b.add(ui.icon(win, "preferences-system"))
  326. b.set_halign(Gtk.Align.END)
  327. b.set_valign(Gtk.Align.END)
  328. overlay.add_overlay(b)
  329. return overlay
  330. def lastthing(win, same, flowbox):
  331. # THis is a hack. I use a spinner to get a draw event
  332. # when the user scrolls far enough, it will execute it
  333. # to load more stuff
  334. spinner_more = ui.icon(win, "loading", "gif")
  335. flowbox.add(spinner_more)
  336. def draw_event(w, e):
  337. print("EVENT MOTHERFUCKER")
  338. w.destroy()
  339. same.append(flowbox)
  340. print("SAME:", same)
  341. load_thread = threading.Thread(target=find, args=[*same])
  342. load_thread.setDaemon(True)
  343. load_thread.start()
  344. spinner_more.connect("draw", draw_event)