local_markdown.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  1. # THIS SOFTWARE IS A PART OF FASTLBRY PROJECT
  2. # THIS SPECIFIC FILE IS UNDER GNU GPLv3 or later
  3. import os
  4. import json
  5. from subprocess import *
  6. import urllib.request
  7. import urllib.parse
  8. from urllib import request, parse
  9. ################################################################################
  10. # Markdown. Or .md file format is an easy way to give your simple text documents
  11. # a bit of flare. Stuff like links, images and quotes are supported. Also bold
  12. # an italic characters.
  13. def lbrynet(method="", params={}):
  14. # First we will make an attempt to use the request module
  15. try:
  16. # To test the SDK subprocess thing I have this little switch
  17. # 1/0 # Division by zero will trigger and error in this 'try'
  18. # and will skip it, to test the other method.
  19. data = {"method":method,
  20. "params":params}
  21. # The port of the LBRY SDK could be different for each user
  22. # so here I'm trying to solve this issue
  23. sdk_url = "http://localhost:5279"
  24. try:
  25. settings = open(os.path.expanduser('~/.local/share/lbry/lbrynet/daemon_settings.yml'))
  26. for line in settings:
  27. if line.startswith("api:"):
  28. sdk_url = "http://"+line[5:]
  29. except:
  30. pass
  31. data = str(json.dumps(data))
  32. data = data.encode('utf-8')
  33. req = request.Request(sdk_url, data=data)
  34. resp = json.loads(request.urlopen(req).read())
  35. try:
  36. resp = resp["result"]
  37. except:
  38. pass
  39. return resp
  40. except Exception as e:
  41. print("Failed", e)
  42. return False
  43. def odysee_get(link):
  44. if link.startswith("lbry://"):
  45. with open("lbry.json") as json_file:
  46. lbry = json.load(json_file)
  47. newlink = link.replace("lbry://", "/lbry/").replace("#", ":")
  48. if newlink not in lbry["hosting"]:
  49. out = lbrynet("resolve",
  50. {"urls":[link]}
  51. )
  52. out = out[link]
  53. try:
  54. price = out["value"]["fee"]["amount"]
  55. except:
  56. price = 0
  57. if price != 0:
  58. return link
  59. dpath = lbrynet("get", {"uri":link, "save_file":True}).get("download_path")
  60. lbry["hosting"][newlink] = dpath
  61. if dpath:
  62. with open("lbry.json", 'w') as f:
  63. json.dump(lbry, f, indent=4)
  64. else:
  65. return link
  66. return newlink+"\n"
  67. return link
  68. def Open(md):
  69. # Spliting it for the read.
  70. md = "\n\n"+md
  71. md = md.split("\n")
  72. # First thing is I was to read the headings and convert it into a tree.
  73. tree = []
  74. indent = 1
  75. c = []
  76. skip = 0
  77. for n,line in enumerate(md):
  78. if skip > n:
  79. continue
  80. # Mentions
  81. line2 = line
  82. line = ""
  83. for word in line2.split(" "):
  84. if word.startswith("@"):
  85. word = '['+word+'](/account/'+word.replace("@", "")+')'
  86. line = line + " " + word
  87. line = line[1:]
  88. ty = "text"
  89. te = line
  90. # Here I want to simply get a type of each line. Later we going to parse
  91. # the links and other things. But first. Let's parse stuff based on
  92. # lines.
  93. if line.startswith("```"):
  94. # THREE ``` aka code block
  95. # This tag will block any other tags
  96. # untill it's untagged
  97. code = ""
  98. print("#####", n)
  99. for l in md[n+1:]:
  100. if not l.startswith("```"):
  101. code = code + l + "\n"
  102. else:
  103. skip = n + code.count("\n") + 2
  104. break
  105. print("!!!!!!!!!", skip)
  106. tree.append(["text_cm", code+"\n"])
  107. te = ""
  108. elif line.startswith("#"):
  109. # The titles of the chapter. The Headers are usually written similar
  110. # to how here in python you write comments. It's a # , space, and the
  111. # text.
  112. # The amount of hashes. ## or ### gives different sized text. Officialy
  113. # it should support up to 6 hashes. ######. But why not make it more
  114. # just in case.
  115. ty = line.count("#") # This might give bugs
  116. tree.append([ty, te+"\n"])
  117. # Now the stage 0 is over and we parsed the basic things. Now is the hard
  118. # part to parse out all the images and stuff inside them. It's going to be
  119. # done per part. And we are going to use the same technique I used for the
  120. # conversion of the legacy projects. See : studio/story.py ( in VCStudio )
  121. # We are going to itterate over each letter. And decide what to do by that
  122. newtree = []
  123. for block in tree:
  124. if block[0] == "text_cm":
  125. newtree.append(block)
  126. continue
  127. part = ""
  128. skip = 0
  129. for n, l in enumerate(block[-1]):
  130. if skip > n:
  131. continue
  132. part = part + l
  133. # Here we are going to do something if a give condition is met.
  134. # Usually I gonna do something if [part] ends with a given markdown
  135. # thing. I don't have a manual of markdown on me. So please make it
  136. # more supported. I guess. I might forget things I rarely use.
  137. # Links are made with [stuff you click on](https://example.com)
  138. # but similar to it. Images are done ![Tooltip](Image.png)
  139. # and even weirder you can put one into the other. Like
  140. # [![Tooltip](Image.png)](https://example.com)
  141. # Which going to give you a clickable image.
  142. # For this version what we are going to do is next.
  143. # If we got [![ then it's a clickable image
  144. # If we got ![ then it's just image
  145. # and if we got [ then it's a link.
  146. if part.endswith("[!["):
  147. # IMAGE LINK
  148. newtree.append([block[0], part[:-3]])
  149. tooltip = ""
  150. imageurl = ""
  151. url = ""
  152. t = False
  153. iu = False
  154. skip = n
  155. for le in block[-1][n:]: # For letters in the rest of text
  156. skip = skip + 1
  157. if le == "]":
  158. t = True
  159. elif le == ")" and t and not iu:
  160. iu = True
  161. elif le == ")" and t and iu:
  162. break
  163. elif not t:
  164. tooltip = tooltip +le
  165. elif t and not iu:
  166. imageurl = imageurl + le
  167. else:
  168. url = url+le
  169. tooltip = tooltip[tooltip.find("[")+1:]
  170. imageurl = imageurl[imageurl.find("(")+1:]
  171. url = url[url.find("(")+1:]
  172. apnd = ["image_link", imageurl, url]
  173. newtree.append(apnd)
  174. part = ""
  175. elif part.endswith("!["):
  176. # IMAGE
  177. newtree.append([block[0], part[:-2]])
  178. tooltip = ""
  179. url = ""
  180. t = False
  181. skip = n
  182. for le in block[-1][n:]: # For letters in the rest of text
  183. skip = skip + 1
  184. if le == "]":
  185. t = True
  186. elif le == ")" and t:
  187. break
  188. elif not t:
  189. tooltip = tooltip +le
  190. else:
  191. url = url+le
  192. tooltip = tooltip[tooltip.find("[")+1:]
  193. url = url[url.find("(")+1:]
  194. apnd = ["image", tooltip, url]
  195. newtree.append(apnd)
  196. part = ""
  197. elif part.endswith("[") and not block[-1][n:].startswith('[!['):
  198. # LINK
  199. newtree.append([block[0], part[:-1]])
  200. tooltip = ""
  201. url = ""
  202. t = False
  203. skip = n
  204. for le in block[-1][n:]: # For letters in the rest of text
  205. skip = skip + 1
  206. if le == "]":
  207. t = True
  208. elif le == ")" and t:
  209. break
  210. elif not t:
  211. tooltip = tooltip +le
  212. else:
  213. url = url+le
  214. tooltip = tooltip[tooltip.find("[")+1:]
  215. url = url[url.find("(")+1:]
  216. apnd = ["link", tooltip, url]
  217. newtree.append(apnd)
  218. part = ""
  219. # Now I want to deal with `, *, ** and ***. If you want to help me you
  220. # can implement other types. Such as _, __, ___ and so on. Markdown is
  221. # a very rich language. I'm going to use the cut down version I see other
  222. # people use.
  223. # BTW this is the time. Feb 28. When I switched from Gedit to GNU Emacs.
  224. # Interesting feeling using this programm. I kind a love it even tho
  225. # so many stuff in not intuitive. Like saving is not Ctrl - S but
  226. # Ctrl - X -> Ctrl - S.
  227. # Things like Alt-; to comment multiple lines at ones is HUGE. Also it
  228. # was built by programmers for programmers. So it's a very good tool.
  229. elif part.endswith("**") and not block[-1][n+2:].startswith('*'):
  230. # DOUBLE **
  231. newtree.append([block[0], part[:-2]])
  232. if block[0] == "text":
  233. block[0] = "text_b"
  234. else:
  235. block[0] = "text"
  236. part = ""
  237. elif part.endswith("*") and not block[-1][n+1:].startswith('*'):
  238. # SINGLE *
  239. newtree.append([block[0], part[:-1]])
  240. if block[0] == "text":
  241. block[0] = "text_i"
  242. else:
  243. block[0] = "text"
  244. part = ""
  245. elif part.endswith("`"):
  246. # SINGLE `
  247. newtree.append([block[0], part[:-1]])
  248. if block[0] == "text":
  249. block[0] = "text_c"
  250. else:
  251. block[0] = "text"
  252. part = ""
  253. newtree.append([block[0], part])
  254. #newtree.append(["text", "\n"*20+" [END OF DOCUMENT] "])
  255. tree = newtree
  256. return(tree)
  257. def search_convert(s):
  258. # This function convers a chapter name into a link
  259. # such links are use in notabug.org to link to chapters
  260. # for example example.com/file.md#chapter-name
  261. # With this url it will load the example.com/file.md and
  262. # then skip to the "Chapter Name" chapter.
  263. # This function transforms "Chapter Name" into "chapter-name"
  264. l = " ./\|[]{}()?!@#$%^&*`~:;'\"=,<>"
  265. s = s.lower().replace(" ","-")
  266. r = ""
  267. for i in s:
  268. if i not in l:
  269. r = r + i
  270. return r
  271. def convert(filename, isfile=True):
  272. textReturn = ""
  273. if isfile:
  274. text = open(filename)
  275. text = text.read()
  276. else:
  277. text = filename
  278. md = Open(text)
  279. close_div = False
  280. for n, i in enumerate(md):
  281. close_not_here = False
  282. if i[-1].startswith(">") or i[-1].startswith("&gt") and not close_div:
  283. i[-1] = '<div class="quote">' + i[-1].replace(">", "").replace("&gt", "")
  284. close_div = True
  285. elif close_div:
  286. i[-1] = i[-1].replace(">", "").replace("&gt", "")
  287. try:
  288. NEXT = md[n+1]
  289. except:
  290. NEXT = ["text", ""]
  291. if NEXT[-1].startswith(">") or NEXT[-1].startswith("&gt"):
  292. close_not_here = True
  293. if close_div and "\n" in i[-1] and not close_not_here:
  294. i[-1] = i[-1]+"</div>"
  295. close_div = False
  296. if type(i[0]) == str and i[0].startswith("text") and not i[0] == "text_cm":
  297. tag = ""
  298. ctag = ""
  299. for f in ["i", "b", "c"]:
  300. if f in i[0]:
  301. f.replace("c", "code").replace("q", "blockquote")
  302. tag = "<"+f+">"
  303. ctag = "</"+f+">"
  304. if i[-1].startswith("lbry://"):
  305. tag = '<a href="https://odysee.com/'+i[-1].replace("lbry://", "")[:-1]+'">'
  306. ctag = "</a>"
  307. if i[-1].startswith("http"):
  308. tag = '<a href="'+i[-1][:-1]+'">'
  309. ctag = "</a>"
  310. textReturn = textReturn + tag + i[-1] + ctag
  311. elif i[0] == "text_cm":
  312. tag = "<code>"
  313. ctag = "</code>"
  314. textReturn = textReturn + tag + i[-1] + ctag
  315. elif type(i[0]) == int:
  316. textReturn = textReturn + '\n<br><br><a href="#'+search_convert(i[-1].replace("#", "").replace("\n", "")[1:])+'"><h'+str(i[0])+' id="'+search_convert(i[-1].replace("#", "").replace("\n", "")[1:])+'">' + i[-1].replace("#", "") +"</h"+str(i[0])+"></a><br><br>"
  317. elif i[0] == "image_link":
  318. textReturn = textReturn + '\n<center><a href="'+i[-1]+'">'+'<img src="'+i[1]+'">'+"</a></center>"
  319. elif i[0] == "image":
  320. if i[1] == "audio":
  321. i[-1] = odysee_get(i[-1])
  322. textReturn = textReturn + '\n<audio controls="controls" width="20%" src="'+i[-1][:-1]+'"></audio>'
  323. elif i[1] == "video":
  324. i[-1] = i[-1].replace("lbry://", "https://player.odycdn.com/speech/")
  325. textReturn = textReturn + """\n<div class="video_frame"><video width="100%" controls>
  326. <source src=\""""+i[-1][:-1]+"""\" type="video/mp4">
  327. </video>
  328. </div>"""
  329. else:
  330. i[-1] = i[-1].replace("lbry://", "https://spee.ch/")
  331. textReturn = textReturn + '\n<center><img src="'+i[-1]+'"></center>'
  332. elif i[0] == "link":
  333. textReturn = textReturn + '<a href="'+i[-1]+'">'+i[1]+"</a>"
  334. textReturn = textReturn.replace("\n", "\n<br>")
  335. textReturn = textReturn + "\n\n<!-- Raw Version of the markdown text\n\n"
  336. textReturn = textReturn + text.replace("-->", "( somebody was trying to pentest the site here with exiting the comment early. Good job )") + "\n\n"
  337. textReturn = textReturn + " -->\n\n"
  338. return textReturn