helpers.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. import time
  2. import subprocess
  3. import os
  4. import shutil
  5. import json
  6. import shlex
  7. import sys
  8. try:
  9. import pil
  10. import helpers
  11. import logger
  12. from constants import Constants
  13. except ImportError:
  14. from . import pil
  15. from . import helpers
  16. from . import logger
  17. from .constants import Constants
  18. def strdatetime():
  19. return time.strftime('%m-%d-%Y %I:%M:%S %p')
  20. def strtime():
  21. return time.strftime('%I:%M:%S %p')
  22. def strdate():
  23. return time.strftime('%m-%d-%Y')
  24. def strepochtime():
  25. return str(int(time.time()))
  26. def strdatetime_compat():
  27. return time.strftime('%Y%m%d')
  28. def command_exists(command):
  29. try:
  30. fnull = open(os.devnull, 'w')
  31. subprocess.call([command], stdout=fnull, stderr=subprocess.STDOUT)
  32. return True
  33. except OSError:
  34. return False
  35. def run_command(command):
  36. try:
  37. fnull = open(os.devnull, 'w')
  38. subprocess.Popen(shlex.split(command), stdout=fnull, stderr=sys.stdout)
  39. return False
  40. except Exception as e:
  41. return str(e)
  42. def bool_str_parse(bool_str):
  43. if bool_str.lower() in ["true", "yes", "y", "1"]:
  44. return True
  45. elif bool_str.lower() in ["false", "no", "n", "0"]:
  46. return False
  47. else:
  48. return "Invalid"
  49. def check_if_guesting():
  50. try:
  51. broadcast_guest = pil.livestream_obj.get('cobroadcasters', {})[0].get('username')
  52. except Exception:
  53. broadcast_guest = None
  54. print(broadcast_guest)
  55. if broadcast_guest and not pil.has_guest:
  56. logger.binfo('The livestream owner has started guesting "{}".'.format(broadcast_guest))
  57. pil.has_guest = broadcast_guest
  58. if not broadcast_guest and pil.has_guest:
  59. logger.binfo('The livestream owner has stopped guesting "{}".'.format(broadcast_guest))
  60. pil.has_guest = None
  61. def generate_json_segments():
  62. while True:
  63. pil.livestream_obj['delay'] = (int(pil.epochtime) - pil.livestream_obj['published_time'])
  64. if 'initial_buffered_duration' not in pil.livestream_obj and pil.broadcast_downloader.initial_buffered_duration:
  65. pil.livestream_obj['initial_buffered_duration'] = pil.broadcast_downloader.initial_buffered_duration
  66. pil.livestream_obj['segments'] = pil.broadcast_downloader.segment_meta
  67. try:
  68. with open(pil.live_folder_path + ".json", 'w') as json_file:
  69. json.dump(pil.livestream_obj, json_file, indent=2)
  70. if not pil.broadcast_downloader.stream_id:
  71. pil.broadcast_downloader.stream_id = pil.livestream_obj['id']
  72. #check_if_guesting()
  73. if pil.kill_segment_thread:
  74. break
  75. else:
  76. time.sleep(2.5)
  77. except Exception as e:
  78. logger.warn(str(e))
  79. def clean_download_dir():
  80. dir_delcount = 0
  81. file_delcount = 0
  82. error_count = 0
  83. lock_count = 0
  84. try:
  85. logger.info('Cleaning up temporary files and folders.')
  86. if Constants.PYTHON_VER[0] == "2":
  87. directories = (os.walk(pil.dl_path).next()[1])
  88. files = (os.walk(pil.dl_path).next()[2])
  89. else:
  90. directories = (os.walk(pil.dl_path).__next__()[1])
  91. files = (os.walk(pil.dl_path).__next__()[2])
  92. for directory in directories:
  93. if directory.endswith('_downloads'):
  94. if not any(filename.endswith('.lock') for filename in
  95. os.listdir(os.path.join(pil.dl_path, directory))):
  96. try:
  97. shutil.rmtree(os.path.join(pil.dl_path, directory))
  98. dir_delcount += 1
  99. except Exception as e:
  100. logger.error("Could not remove folder: {:s}".format(str(e)))
  101. error_count += 1
  102. else:
  103. lock_count += 1
  104. logger.separator()
  105. for file in files:
  106. if file.endswith('_downloads.json'):
  107. if not any(filename.endswith('.lock') for filename in
  108. os.listdir(os.path.join(pil.dl_path))):
  109. try:
  110. os.remove(os.path.join(pil.dl_path, file))
  111. file_delcount += 1
  112. except Exception as e:
  113. logger.error("Could not remove file: {:s}".format(str(e)))
  114. error_count += 1
  115. else:
  116. lock_count += 1
  117. if dir_delcount == 0 and file_delcount == 0 and error_count == 0 and lock_count == 0:
  118. logger.info('The cleanup has finished. No items were removed.')
  119. logger.separator()
  120. return
  121. logger.info('The cleanup has finished.')
  122. logger.info('Folders removed: {:d}'.format(dir_delcount))
  123. logger.info('Files removed: {:d}'.format(file_delcount))
  124. logger.info('Locked items: {:d}'.format(lock_count))
  125. logger.info('Errors: {:d}'.format(error_count))
  126. logger.separator()
  127. except KeyboardInterrupt as e:
  128. logger.separator()
  129. logger.warn("The cleanup has been aborted.")
  130. if dir_delcount == 0 and file_delcount == 0 and error_count == 0 and lock_count == 0:
  131. logger.info('No items were removed.')
  132. logger.separator()
  133. return
  134. logger.info('Folders removed: {:d}'.format(dir_delcount))
  135. logger.info('Files removed: {:d}'.format(file_delcount))
  136. logger.info('Locked items : {:d}'.format(lock_count))
  137. logger.info('Errors: {:d}'.format(error_count))
  138. logger.separator()
  139. def show_info():
  140. cookie_files = []
  141. cookie_from_config = ''
  142. try:
  143. for file in os.listdir(os.getcwd()):
  144. if file.endswith(".json"):
  145. with open(file) as data_file:
  146. try:
  147. json_data = json.load(data_file)
  148. if json_data.get('created_ts'):
  149. cookie_files.append(file)
  150. except Exception as e:
  151. pass
  152. if pil.ig_user == file.replace(".json", ''):
  153. cookie_from_config = file
  154. except Exception as e:
  155. logger.warn("Could not check for cookie files: {:s}".format(str(e)))
  156. logger.whiteline()
  157. logger.info("To see all the available arguments, use the -h argument.")
  158. logger.whiteline()
  159. logger.info("PyInstaLive version: {:s}".format(Constants.SCRIPT_VER))
  160. logger.info("Python version: {:s}".format(Constants.PYTHON_VER))
  161. if not command_exists("ffmpeg"):
  162. logger.error("FFmpeg framework: Not found")
  163. else:
  164. logger.info("FFmpeg framework: Available")
  165. if len(cookie_from_config) > 0:
  166. logger.info("Cookie files: {:s} ({:s} matches config user)".format(str(len(cookie_files)),
  167. cookie_from_config))
  168. elif len(cookie_files) > 0:
  169. logger.info("Cookie files: {:s}".format(str(len(cookie_files))))
  170. else:
  171. logger.warn("Cookie files: None found")
  172. logger.info("CLI supports color: {:s}".format("No" if not logger.supports_color() else "Yes"))
  173. logger.info(
  174. "Command to run at start: {:s}".format("None" if not pil.run_at_start else pil.run_at_start))
  175. logger.info(
  176. "Command to run at finish: {:s}".format("None" if not pil.run_at_finish else pil.run_at_finish))
  177. if os.path.exists(pil.config_path):
  178. logger.info("Config file contents:")
  179. logger.whiteline()
  180. with open(pil.config_path) as f:
  181. for line in f:
  182. logger.plain(" {:s}".format(line.rstrip()))
  183. else:
  184. logger.error("Config file: Not found")
  185. logger.whiteline()
  186. logger.info("End of PyInstaLive information screen.")
  187. logger.separator()
  188. def new_config():
  189. try:
  190. if os.path.exists(pil.config_path):
  191. logger.info("A configuration file is already present:")
  192. logger.whiteline()
  193. with open(pil.config_path) as f:
  194. for line in f:
  195. logger.plain(" {:s}".format(line.rstrip()))
  196. logger.whiteline()
  197. logger.info("To create a default config file, delete 'pyinstalive.ini' and run this script again.")
  198. logger.separator()
  199. else:
  200. try:
  201. logger.warn("Could not find configuration file, creating a default one.")
  202. config_file = open(pil.config_path, "w")
  203. config_file.write(Constants.CONFIG_TEMPLATE.format(os.getcwd()).strip())
  204. config_file.close()
  205. logger.warn("Edit the created 'pyinstalive.ini' file and run this script again.")
  206. logger.separator()
  207. return
  208. except Exception as e:
  209. logger.error("Could not create default config file: {:s}".format(str(e)))
  210. logger.warn("You must manually create and edit it with the following template: ")
  211. logger.whiteline()
  212. for line in Constants.CONFIG_TEMPLATE.strip().splitlines():
  213. logger.plain(" {:s}".format(line.rstrip()))
  214. logger.whiteline()
  215. logger.warn("Save it as 'pyinstalive.ini' and run this script again.")
  216. logger.separator()
  217. except Exception as e:
  218. logger.error("An error occurred: {:s}".format(str(e)))
  219. logger.warn(
  220. "If you don't have a configuration file, manually create and edit one with the following template:")
  221. logger.whiteline()
  222. logger.plain(Constants.CONFIG_TEMPLATE)
  223. logger.whiteline()
  224. logger.warn("Save it as 'pyinstalive.ini' and run this script again.")
  225. logger.separator()
  226. def create_lock_user():
  227. try:
  228. if not os.path.isfile(os.path.join(pil.dl_path, pil.dl_user + '.lock')):
  229. if pil.use_locks:
  230. open(os.path.join(pil.dl_path, pil.dl_user + '.lock'), 'a').close()
  231. return True
  232. else:
  233. return False
  234. except Exception:
  235. logger.warn("Lock file could not be created. Be careful when running multiple downloads concurrently!")
  236. return True
  237. def create_lock_folder():
  238. try:
  239. if not os.path.isfile(os.path.join(pil.live_folder_path, 'folder.lock')):
  240. if pil.use_locks:
  241. open(os.path.join(pil.live_folder_path, 'folder.lock'), 'a').close()
  242. return True
  243. else:
  244. return False
  245. except Exception:
  246. logger.warn("Lock file could not be created. Be careful when running multiple downloads concurrently!")
  247. return True
  248. def remove_lock():
  249. download_folder_lock = os.path.join(pil.dl_path, pil.dl_user + '.lock')
  250. temp_folder_lock = os.path.join(pil.live_folder_path, 'folder.lock')
  251. lock_paths = [download_folder_lock, temp_folder_lock]
  252. for lock in lock_paths:
  253. try:
  254. os.remove(lock)
  255. except Exception:
  256. pass
  257. def remove_temp_folder():
  258. try:
  259. shutil.rmtree(pil.live_folder_path)
  260. except Exception as e:
  261. logger.error("Could not remove segment folder: {:s}".format(str(e)))
  262. def download_folder_has_lockfile():
  263. return os.path.isfile(os.path.join(pil.dl_path, pil.dl_user + '.lock'))
  264. def winbuild_path():
  265. if getattr(sys, 'frozen', False):
  266. return sys.executable
  267. elif __file__:
  268. return None