publish.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  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 publish a selected file into LBRY Network.
  30. from subprocess import *
  31. import json
  32. import os
  33. import random
  34. from flbry import url
  35. from flbry import channel
  36. from flbry import markdown
  37. from flbry.variables import *
  38. from flbry import settings
  39. from flbry import plugin
  40. def upload(data):
  41. data = plugin.run(data)
  42. # This function actually will upload the file.
  43. # reference:
  44. # --name | lbry:// url to publish to
  45. # --bid | LBC to use while publishing
  46. # --fee_amount | How much does one need to pay for the publication
  47. # --file_path | The path to a file that's going to be uploaded
  48. # --title | Title of the publication on the LBRY network
  49. # --license | License of the publication
  50. # --license_url | Link to the license
  51. # --thumbnail_url | Link to a thumbnail image
  52. # --description | A string of text describing the publication
  53. # --tags | List of tags.
  54. # --channel_name | Name of a channel to which to upload
  55. # ( without it will be anonymous)
  56. # More commands to upload function you can see at:
  57. # https://lbry.tech/api/sdk#publish
  58. # An example of a working publish command:
  59. # ./lbrynet publish --name="testing_upload_via_sdk_v2" --bid=0.01
  60. # --file_path="/home/vcs/Desktop/upload_test_file.md"
  61. # --title="Testing Uploading Directly from the LBRY SDK v2"
  62. # --license="CC-BY-SA" --channel_name="@blenderdumbass"
  63. p = [lbrynet_binary["b"], "publish", "--name="+data["name"],
  64. "--bid="+str(data["bid"]), "--file_path="+data["file_path"]]
  65. data["thumbnail_url"] = speech_upload(data["thumbnail_url"])
  66. for i in ["title", "license", "license_url", "thumbnail_url", "description", "channel_name", "fee_amount"]:
  67. if i in data:
  68. if data[i]:
  69. p.append("--"+i+"="+str(data[i]))
  70. if data["fee_amount"]:
  71. p.append("--fee_currency=LBC")
  72. if "tags" in data:
  73. if data["tags"]:
  74. for i in data["tags"]:
  75. p.append("--tags="+i) # THIS IS STUPID IK. BUT IT WORKS
  76. out = check_output(p)
  77. try:
  78. out = json.loads(out)
  79. except:
  80. center("Connect to LBRY first.", "bdrd")
  81. return
  82. return out
  83. def view_data(data):
  84. # this function will print the data
  85. # LBRY URL
  86. d = {"categories": ["LBRY URL"],
  87. "size":[1],
  88. "data":[["lbry://"+data["name"]]]}
  89. table(d, False)
  90. # FILE PATH
  91. d = {"categories": ["File Path"],
  92. "size":[1],
  93. "data":[[data["file_path"]]]}
  94. table(d, False)
  95. # CHANNEL, BID AND PRICE
  96. if not data["channel_name"]:
  97. channel = "[anonymous]"
  98. else:
  99. channel = data["channel_name"]
  100. if not data["fee_amount"]:
  101. price = "Gratis"
  102. else:
  103. price = str(data["fee_amount"])+" LBC"
  104. d = {"categories": ["Channel ID", "LBC BID", "Price"],
  105. "size":[1, 1, 1],
  106. "data":[[channel, str(data["bid"])+" LBC", price]]}
  107. table(d, False)
  108. # TITLE AND THUMBNAIL
  109. if not data["thumbnail_url"]:
  110. thumb = "[no thumbnail]"
  111. else:
  112. thumb = data["thumbnail_url"]
  113. if not data["title"]:
  114. title = "[no title]"
  115. else:
  116. title = data["title"]
  117. d = {"categories": ["Thumbnail", "Title"],
  118. "size":[2, 3],
  119. "data":[[thumb, title]]}
  120. table(d, False)
  121. # LICENSING INFORMATION
  122. if not data["license"]:
  123. license = "[no license]"
  124. else:
  125. license = data["license"]
  126. if not data["license_url"]:
  127. lurl = "[no license url]"
  128. else:
  129. lurl = data["license_url"]
  130. d = {"categories": ["License", "URL"],
  131. "size":[3, 2],
  132. "data":[[license, lurl]]}
  133. table(d, False)
  134. # DESCRIPTION PREVIEW
  135. d = {"categories": ["DESCRIPTION PREVIEW"],
  136. "size":[1],
  137. "data":[[data["description"].replace("\n", " ")]]}
  138. table(d, False)
  139. # Tags PREVIEW
  140. d = {"categories": ["TAGS"],
  141. "size":[1],
  142. "data":[[data["tags"]]]}
  143. table(d, False)
  144. def configure(file_path="", data=None):
  145. # This function will prepare the publication data, before sending it
  146. # to the upload() function above.
  147. # So it doesn't say "File not found" if you put nothing
  148. if not file_path:
  149. file_path = input(typing_dots("File path", give_space=True))
  150. file_path = os.path.expanduser(file_path)
  151. while not os.path.exists(file_path):
  152. center("File '"+file_path+"' not found", "bdrd")
  153. file_path = input(typing_dots("File path", give_space=True))
  154. file_path = os.path.expanduser(file_path)
  155. lbryname = ""
  156. good = "qwertyuiopasdfghjklzxcvbnm-_QWERTYUIOPASDFGHJKLZXCVBNM1234567890"
  157. for i in range(70):
  158. lbryname = lbryname + random.choice(good)
  159. center("Upload Manager of FastLBRY")
  160. if not data:
  161. data = {"name":lbryname,
  162. "bid":0.001,
  163. "file_path":file_path,
  164. "title":"",
  165. "license":"",
  166. "license_url":"",
  167. "thumbnail_url":"",
  168. "channel_id":"",
  169. "channel_name":"",
  170. "description":"",
  171. "fee_amount":0,
  172. "tags":[]
  173. }
  174. # Completer thingy
  175. complete([
  176. "file",
  177. "bid",
  178. "price",
  179. "url",
  180. "title",
  181. "license",
  182. "channel",
  183. "tags",
  184. "description",
  185. "help",
  186. "save",
  187. "load",
  188. "publish",
  189. "thumbnail"
  190. ])
  191. while True:
  192. # preview the data
  193. view_data(data)
  194. center("---type 'help' to read how it works---")
  195. plugin.run(execute=False)
  196. # input
  197. c = input(typing_dots())
  198. if not c:
  199. break
  200. # Update file_path
  201. elif c.startswith("file"):
  202. if " " in c:
  203. file_path = c[c.find(" ")+1:]
  204. else:
  205. file_path = input(typing_dots("File path", give_space=True))
  206. while not os.path.exists(file_path):
  207. center("File '"+file_path+"' not found", "bdrd")
  208. file_path = input(typing_dots("File path", give_space=True))
  209. data["file_path"] = file_path
  210. # Update the bid info
  211. elif c.startswith("bid"):
  212. if " " in c:
  213. bid = c[c.find(" ")+1:]
  214. else:
  215. bid = input(typing_dots("Bid", to_add_dots=True))
  216. while True:
  217. try:
  218. bid = float(bid)
  219. if not bid > 0.00001:
  220. 1 / 0 # Fail switch
  221. break
  222. except:
  223. center("Bid cannot be: "+str(bid), "bdrd")
  224. bid = input(typing_dots("Bid", to_add_dots=True))
  225. data["bid"] = bid
  226. # Setup a price
  227. elif c.startswith("price"):
  228. if " " in c:
  229. price = c[c.find(" ")+1:]
  230. else:
  231. price = input(typing_dots("Price", to_add_dots=True))
  232. while True:
  233. try:
  234. price = float(price)
  235. if price < 0:
  236. 1 / 0 # Fail switch
  237. break
  238. except:
  239. center("Price cannot be: "+str(price), "bdrd")
  240. price = input(typing_dots("Price", to_add_dots=True))
  241. data["fee_amount"] = price
  242. # URL for the publication
  243. elif c.startswith("url"):
  244. if " " in c:
  245. url = c[c.find(" ")+1:]
  246. else:
  247. url = input(typing_dots("LBRY URL", give_space=True, to_add_dots=True))
  248. name = ""
  249. for i in url:
  250. if i in good:
  251. name = name + i
  252. else:
  253. name = name + "-"
  254. data["name"] = name
  255. # Title
  256. elif c.startswith("title"):
  257. if " " in c:
  258. title = c[c.find(" ")+1:]
  259. else:
  260. title = input(typing_dots("Title", give_space=True, to_add_dots=True))
  261. data["title"] = title
  262. # License setting
  263. elif c == "license":
  264. data["license"], data["license_url"] = choose_license()
  265. # Channel
  266. elif c == "channel":
  267. ch, chid = channel.select("Select from where to publish.", claim_id=True)
  268. data["channel_id"] = chid
  269. data["channel_name"] = ch
  270. # Tags
  271. elif c.startswith("tags"):
  272. if " " in c:
  273. th = c[c.find(" ")+1:]
  274. else:
  275. th = input(typing_dots("Tags separated by , ", give_space=True, to_add_dots=True))
  276. data["tags"] = th.split(",")
  277. elif c.startswith("thumbnail"):
  278. if " " in c:
  279. th = c[c.find(" ")+1:]
  280. else:
  281. th = input(typing_dots("Thumbnail url", give_space=True, to_add_dots=True))
  282. data["thumbnail_url"] = th
  283. # Description
  284. elif c.startswith("description"):
  285. if " " in c:
  286. df = c[c.find(" ")+1:]
  287. try:
  288. text = open(df, "r")
  289. text = text.read()
  290. except:
  291. text = open("/tmp/fastlbrydescriptiontwriter.txt", "w")
  292. text.write("Type your description here. Don't forget to save. Then return to FastLBRY.")
  293. text.close()
  294. os.system(df+" /tmp/fastlbrydescriptiontwriter.txt")
  295. center("Press Enter when the file is ready and saved.")
  296. input()
  297. text = open("/tmp/fastlbrydescriptiontwriter.txt", "r")
  298. text = text.read()
  299. else:
  300. text = input(typing_dots("Description", give_space=True, to_add_dots=True))
  301. data["description"] = text
  302. elif c == "help":
  303. markdown.draw("help/publish.md", "Publishing Help")
  304. # SAVE / LOAD OPTIONS
  305. elif c.startswith("save"):
  306. if " " in c:
  307. pn = c[c.find(" ")+1:]
  308. else:
  309. pn = input(typing_dots("Preset's name", to_add_dots=True))
  310. # Create the preset folder is it's not there
  311. try:
  312. os.mkdir(settings.get_settings_folder()+"presets")
  313. except:
  314. pass
  315. # Write the json file
  316. with open(settings.get_settings_folder()+"presets/"+pn+'.json', 'w') as f:
  317. json.dump(data, f, indent=4, sort_keys=True)
  318. elif c.startswith("load"):
  319. if " " in c:
  320. pn = c[c.find(" ")+1:]
  321. else:
  322. pn = input(typing_dots("Preset's name", to_add_dots=True))
  323. # loading the json file
  324. try:
  325. name = data["name"]
  326. file_path = data["file_path"]
  327. with open(settings.get_settings_folder()+"presets/"+pn+'.json') as f:
  328. data = json.load(f)
  329. data["file_path"] = file_path
  330. data["name"] = name
  331. except:
  332. center("There is no '"+pn+"' preset!", "bdrd")
  333. # PUBLISHING
  334. elif c == "publish":
  335. out = upload(data)
  336. try:
  337. center("LBRY URL FULL TEXT:")
  338. print(out['outputs'][0]['permanent_url'])
  339. center("HTTPS URL FULL TEXT:")
  340. print(out['outputs'][0]['permanent_url'].replace("lbry://","https://spee.ch/"))
  341. center("Publishing is done successfully!", "bdgr")
  342. center("Confirming publication... It may take a few minutes.")
  343. except:
  344. center("Failed", "bdrd")
  345. center("================= ERROR! ================", "bdrd")
  346. try:
  347. for line in out["message"].split("\n"):
  348. center(line, "bdrd")
  349. except:
  350. print(out)
  351. center("=========================================", "bdrd")
  352. return out
  353. elif c:
  354. c = plugin.run(data, command=c)
  355. def speech_upload(file, name="", fee=0, speech=True):
  356. file = os.path.expanduser(file)
  357. if os.path.isfile(file):
  358. center("Uploading '"+file+"' to LBRY")
  359. if not name:
  360. rndname = ""
  361. else:
  362. rndname = name + "_"
  363. length = 70 - len(rndname)
  364. good = "qwertyuiopasdfghjklzxcvbnm-_QWERTYUIOPASDFGHJKLZXCVBNM1234567890"
  365. for i in range(length):
  366. rndname = rndname + random.choice(good)
  367. try:
  368. out = upload({"name":rndname,
  369. "bid":0.001,
  370. "file_path":file,
  371. "title":"",
  372. "license":"",
  373. "license_url":"",
  374. "thumbnail_url":"",
  375. "channel_id":"",
  376. "channel_name":"",
  377. "description":"",
  378. "fee_amount":fee,
  379. "tags":[]
  380. })
  381. if speech:
  382. return out['outputs'][0]['permanent_url'].replace("lbry://","https://spee.ch/")
  383. else:
  384. return out['outputs'][0]['permanent_url']
  385. except:
  386. return ""
  387. center("Failed uploading file", "bdrd")
  388. else:
  389. return file