ttsselfhoster.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. #!/usr/bin/env python3
  2. def main():
  3. import os
  4. import json
  5. import re
  6. import sys
  7. import hashlib
  8. from urllib.parse import urlparse
  9. p = parser()
  10. args = p.parse_args()
  11. if args.input_file == "-":
  12. args.input_file = "/dev/stdin"
  13. sha_input = hashlib.sha256()
  14. with open(args.input_file) as fd:
  15. js = fd.read()
  16. sha_input.update(js.encode("utf-8"))
  17. js = json.loads(js)
  18. input_info = {
  19. "sha256":sha_input.hexdigest()
  20. }
  21. if args.url:
  22. js["_ttsselfhoster"] = {
  23. "url": args.url.geturl(),
  24. "origsha256":input_info["sha256"],
  25. }
  26. if "SaveName" in js:
  27. input_info["SaveName"] = js["SaveName"]
  28. if args.output_file == None:
  29. if "SaveName" in js:
  30. args.output_file = os.path.join(args.server_dir, safe_name(js["SaveName"]) + ".json")
  31. else:
  32. args.output_file = "-"
  33. if args.output_file == "-":
  34. args.output_file = "/dev/stdout"
  35. jsgen = dict_generator(js)
  36. url_regex = re.compile("^https?://")
  37. for it in jsgen:
  38. val = it[-1]
  39. if type(val)==str and url_regex.match(val):
  40. # print(it, file=sys.stderr)
  41. if args.server_dir:
  42. sha_f = cache_file(val, args.server_dir, force=args.no_cache, input_info=input_info)
  43. # print(sha_f, file=sys.stderr)
  44. if args.url and sha_f:
  45. newurl = args.url
  46. newurl = newurl._replace(path=os.path.join(newurl.path,"blocks", sha_f))
  47. dict_set(js, it[:-1], newurl.geturl())
  48. with open(args.output_file, "w") as fd:
  49. json.dump(js, fd, indent=4)
  50. def parser():
  51. import argparse
  52. from urllib.parse import urlparse
  53. p = argparse.ArgumentParser()
  54. p.add_argument("-i","--input_file", default="-")
  55. p.add_argument("-o","--output_file", default=None)
  56. p.add_argument("-s","--server_dir", default="repo")
  57. p.add_argument("-n","--no_cache", action="store_true")
  58. p.add_argument("-u","--url", type=urlparse, default=None)
  59. return p
  60. def dict_set(dic , path, val):
  61. iter_dic = dic
  62. for p in path:
  63. last_dic = iter_dic
  64. iter_dic = iter_dic[p]
  65. last_dic[p] = val
  66. def safe_name(fname):
  67. import re
  68. fname = fname.replace(" ","_")
  69. return re.sub("[^a-zA-Z0-9_]+", "", fname)
  70. def cache_file(url, cache_dir, force=False, input_info={}):
  71. import os
  72. import hashlib
  73. import json
  74. import sys
  75. sha_url = hashlib.sha512()
  76. sha_url.update(url.encode())
  77. sha_url = sha_url.hexdigest()
  78. sha_dir = os.path.join(cache_dir, "sha")
  79. sha_file = os.path.join(sha_dir, sha_url)
  80. url_file = os.path.join(cache_dir, "urls.txt")
  81. if not os.path.isdir(sha_dir):
  82. os.makedirs(sha_dir)
  83. sha_f = None
  84. if force or (not os.path.isfile(sha_file)):
  85. sha_f = get_file(url, cache_dir, sha_file)
  86. if sha_f:
  87. with open(url_file, "a+") as fd:
  88. for line in fd.readlines():
  89. if json.loads(line)["sha_f"] == sha_f:
  90. return sha_f
  91. new_line = json.dumps({"url":url,"sha_f":sha_f,"sha_url":sha_url, "input_info":input_info})+"\n"
  92. print(new_line, file=sys.stderr)
  93. fd.write(new_line)
  94. else:
  95. print("Download Error:", url, file=sys.stderr)
  96. else:
  97. try:
  98. # print("Trying Cache:", sha_file, file=sys.stderr)
  99. sha_f = open(sha_file).read()
  100. except Exception as ex:
  101. print(ex, file=sys.stderr)
  102. sha_f = None
  103. return sha_f
  104. def get_file(url, cache_dir, sha_file):
  105. from urllib.request import urlopen
  106. from urllib.error import HTTPError
  107. import hashlib
  108. import sys
  109. import os
  110. import uuid
  111. blocks_dir = os.path.join(cache_dir,"blocks")
  112. if not os.path.isdir(blocks_dir):
  113. os.makedirs(blocks_dir)
  114. tmpfile = os.path.join(blocks_dir, uuid.uuid4().hex)
  115. sha_f = hashlib.sha512()
  116. try:
  117. with urlopen(url) as req:
  118. with open(tmpfile,"wb") as fd:
  119. BUF = True
  120. while BUF:
  121. BUF = req.read()
  122. fd.write(BUF)
  123. sha_f.update(BUF)
  124. except HTTPError as ex:
  125. print(ex, file=sys.stderr)
  126. try:
  127. os.unlink(tmpfile)
  128. os.unlink(sha_file)
  129. except:
  130. pass
  131. return None
  132. sha_f = sha_f.hexdigest()
  133. cachefile = os.path.join(blocks_dir, sha_f)
  134. os.rename(tmpfile, cachefile)
  135. with open(sha_file, "w") as fd:
  136. fd.write(sha_f)
  137. return sha_f
  138. def dict_generator(indict, pre=None):
  139. pre = pre[:] if pre else []
  140. if isinstance(indict, dict):
  141. for key, value in indict.items():
  142. if isinstance(value, dict):
  143. for d in dict_generator(value, pre + [key]):
  144. yield d
  145. elif isinstance(value, list) or isinstance(value, tuple):
  146. i = 0
  147. for v in value:
  148. for d in dict_generator(v, pre + [key,i]):
  149. yield d
  150. i += 1
  151. else:
  152. yield pre + [key, value]
  153. else:
  154. yield pre + [indict]
  155. if __name__ == "__main__":
  156. main()