url.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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 file will fetch an LBRY URL directly and print out various
  30. # options that the user may do with the publication.
  31. from subprocess import *
  32. import json
  33. import os
  34. from flbry.variables import *
  35. from flbry import markdown
  36. from flbry import channel
  37. from flbry import search
  38. from flbry import comments
  39. def get(url=""):
  40. # The user might type the word url and nothing else.
  41. if not url:
  42. url = input(" LBRY url :: ")
  43. # Then let's fetch the url from our beloved SDK.
  44. out = check_output(["flbry/lbrynet",
  45. "resolve", url])
  46. # Now we want to parse the json
  47. try:
  48. out = json.loads(out)
  49. except:
  50. print(" Connect to LBRY first.")
  51. return
  52. out = out[url]
  53. #### FORCE SEARCH ###
  54. # Sometimes user might type something that is not a url
  55. # in this case ["value_type"] will not be loaded. And in
  56. # this case we can load search instead.
  57. if "value_type" not in out:
  58. search.simple(url)
  59. return
  60. # Now that we know that don't search for it. We can make
  61. # one thing less broken. Sometimes a user might type a
  62. # urls that's going to be resolved but that doesn't have
  63. # the lbry:// in the beginning of it. Like typing
  64. # @blenderdumbass instead of lbry://blenderdumbass
  65. # I want to add the lbry:// to it anyway. So non of the
  66. # stuff later will break.
  67. if not url.startswith("lbry://") and not url.startswith("@"):
  68. url = "lbry://" + url
  69. # Now let's print some useful information
  70. ##### NAME URL INFORMATION #####
  71. center("Publication Information")
  72. d = {"categories":["lbry url", "title"],
  73. "size":[1,1],
  74. "data":[[url]]}
  75. try:
  76. # This prints out the title
  77. d["data"][0].append(out["value"]["title"])
  78. except:
  79. d["data"][0] = [url]
  80. d["data"][0].append("[no title]")
  81. table(d, False)
  82. #### LICENSE ####
  83. try:
  84. d = {"categories":["License"],
  85. "size":[1],
  86. "data":[[out["value"]["license"]]]}
  87. except:
  88. d = {"categories":["License"],
  89. "size":[1],
  90. "data":[["[failed to load license]"]]}
  91. table(d, False)
  92. #### TAGS #####
  93. d = {"categories":[],
  94. "size":[],
  95. "data":[[]]}
  96. try:
  97. for tag in out["value"]["tags"]:
  98. d["categories"].append(" ")
  99. d["size"].append(1)
  100. d["data"][0].append(tag)
  101. except:
  102. d = {"categories":[" "],
  103. "size":[1],
  104. "data":[["[no tags found]"]]}
  105. table(d, False)
  106. #### FILE INFO #####
  107. d = {"categories":["Value Type", "File Type", "File Size", "Duration"],
  108. "size":[1,1,1, 1],
  109. "data":[[]]}
  110. try:
  111. d["data"][0].append(what[out["value_type"]])
  112. except:
  113. d["data"][0].append("[no value type]")
  114. try:
  115. d["data"][0].append(out["value"]["source"]["media_type"])
  116. except:
  117. d["data"][0].append("[no file type]")
  118. try:
  119. d["data"][0].append(csize(out["value"]["source"]["size"]))
  120. except:
  121. d["data"][0].append("[no file size]")
  122. try:
  123. d["data"][0].append(timestring(float(out["value"]["video"]["duration"])))
  124. except:
  125. d["data"][0].append("[no duration]")
  126. table(d, False)
  127. ##### CHANNEL INFORMATION ####
  128. center("Channel Information")
  129. d = {"categories":["lbry url", "title"],
  130. "size":[1,1],
  131. "data":[[]]}
  132. try:
  133. # This prints out the title
  134. d["data"][0].append(out["signing_channel"]["name"])
  135. d["data"][0].append(out["signing_channel"]["value"]["title"])
  136. except:
  137. d["data"][0] = []
  138. d["data"][0].append("[no url]")
  139. d["data"][0].append("[anonymous publisher]")
  140. table(d, False)
  141. #### LBC INFORMATION ####
  142. center("LBRY Coin ( LBC ) Information")
  143. d = {"categories":["combined", "at upload", "support"],
  144. "size":[1,1,1],
  145. "data":[[]]}
  146. try:
  147. fullamount = float(out["amount"]) + float(out["meta"]["support_amount"])
  148. # This prints out the title
  149. d["data"][0].append(fullamount)
  150. d["data"][0].append(out["amount"])
  151. d["data"][0].append(out["meta"]["support_amount"])
  152. except:
  153. d["data"][0] = []
  154. d["data"][0].append("[no data]")
  155. d["data"][0].append("[no data]")
  156. d["data"][0].append("[no data]")
  157. table(d, False)
  158. #### PRICE ####
  159. try:
  160. # Print the prince of this publication in LBC
  161. center("PRICE: "+out["value"]["fee"]["amount"]+" "+out["value"]["fee"]["currency"], "bdrd", blink=True)
  162. except:
  163. pass
  164. ### REPOST ####
  165. # Sometimes a user wants to select a repost. This will not
  166. # load anything of a value. A repost is an empty blob that
  167. # links to another blob. So I want to automatically load
  168. # the actuall publication it self here.
  169. if out["value_type"] == "repost":
  170. get(out["reposted_claim"]["canonical_url"])
  171. return
  172. # Some things are too big to output like this in the terminal
  173. # so for them I want the user to type a command.
  174. center("--- for publication commands list type help --- ")
  175. # So we are going to start a new while loop here. IK crazy.
  176. # this one will handle all the commands associated with the
  177. # currently selected publication.
  178. while True:
  179. c = input(typing_dots())
  180. if not c:
  181. break
  182. elif c == "help":
  183. markdown.draw("help/url.md", "Publication Help")
  184. elif c == "https":
  185. Popen(['xdg-open',
  186. url.replace("lbry://", "https://spee.ch/").replace("#", ":").replace("(", "%28").replace(")", "%29")],
  187. stdout=DEVNULL,
  188. stderr=STDOUT)
  189. elif c == "odysee":
  190. Popen(['xdg-open',
  191. url.replace("lbry://", "https://odysee.com/").replace("#", ":").replace("(", "%28").replace(")", "%29")],
  192. stdout=DEVNULL,
  193. stderr=STDOUT)
  194. elif c.startswith("open"):
  195. # Selecting the software command in a smart way
  196. if len(c) < 6:
  197. p = input(" Open in : ")
  198. else:
  199. p = c[5:]
  200. Popen([p,
  201. url.replace("lbry://", "https://spee.ch/").replace("#", ":").replace("(", "%28").replace(")", "%29")],
  202. stdout=DEVNULL,
  203. stderr=STDOUT)
  204. elif c == "description":
  205. #print(out["value"]["description"])
  206. # Here I want to print out the description of the publication.
  207. # but since, they are most likely in the markdown format I
  208. # need to implement a simple markdown parser. Oh wait.... I
  209. # have one. For the article read function. How about using it
  210. # here?
  211. # First we need to save the description into a file. Let's use
  212. # /tmp/ since there files are automatically cleaned up by the
  213. # system.
  214. try:
  215. savedes = open("/tmp/fastlbrylastdescription.md", "w")
  216. savedes.write(out["value"]["description"])
  217. savedes.close()
  218. except:
  219. savedes = open("/tmp/fastlbrylastdescription.md", "w")
  220. savedes.write("This file has no description.")
  221. savedes.close()
  222. # Now let's just simply load the markdown on this file.
  223. markdown.draw("/tmp/fastlbrylastdescription.md", "Description")
  224. elif c == "play":
  225. # Then we want to tell the SDK to start downloading.
  226. playout = check_output(["flbry/lbrynet",
  227. "get", url])
  228. # Parsing the Json
  229. playout = json.loads(playout)
  230. # Then we want to launch the player
  231. Popen(["xdg-open",
  232. playout['download_path']],
  233. stdout=DEVNULL,
  234. stderr=STDOUT)
  235. elif c == "save":
  236. # Then we want to tell the SDK to start downloading.
  237. playout = check_output(["flbry/lbrynet",
  238. "get", url])
  239. # Parsing the Json
  240. playout = json.loads(playout)
  241. print(" Saved to :", playout['download_path'])
  242. elif c == "read":
  243. # Then we want to tell the SDK to start downloading.
  244. playout = check_output(["flbry/lbrynet",
  245. "get", url])
  246. # Parsing the Json
  247. playout = json.loads(playout)
  248. # Present the article to the user.
  249. markdown.draw(playout['download_path'], out["value"]["title"])
  250. elif c == "channel":
  251. # This a weird one. If the publication is a channel we
  252. # want it to list the publications by that channel.
  253. # If a publication is a publication. We want it to list
  254. # publications by the channel that made the publication.
  255. if out["value_type"] == "channel":
  256. channel.simple(url)
  257. else:
  258. channel.simple(out["signing_channel"]["canonical_url"].replace("lbry://",""))
  259. elif c == "comments":
  260. comments.list(out["claim_id"], url)
  261. elif c.startswith("reply"):
  262. c = c + ' '
  263. comments.post(out["claim_id"], c[c.find(" "):])