helpers.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  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 not pil.broadcast_downloader.is_aborted:
  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. time.sleep(2.5)
  74. except Exception as e:
  75. logger.warn(str(e))
  76. def clean_download_dir():
  77. dir_delcount = 0
  78. file_delcount = 0
  79. error_count = 0
  80. lock_count = 0
  81. try:
  82. logger.info('Cleaning up temporary files and folders.')
  83. if Constants.PYTHON_VER[0] == "2":
  84. directories = (os.walk(pil.dl_path).next()[1])
  85. files = (os.walk(pil.dl_path).next()[2])
  86. else:
  87. directories = (os.walk(pil.dl_path).__next__()[1])
  88. files = (os.walk(pil.dl_path).__next__()[2])
  89. for directory in directories:
  90. if directory.endswith('_downloads'):
  91. if not any(filename.endswith('.lock') for filename in
  92. os.listdir(os.path.join(pil.dl_path, directory))):
  93. try:
  94. shutil.rmtree(os.path.join(pil.dl_path, directory))
  95. dir_delcount += 1
  96. except Exception as e:
  97. logger.error("Could not remove folder: {:s}".format(str(e)))
  98. error_count += 1
  99. else:
  100. lock_count += 1
  101. logger.separator()
  102. for file in files:
  103. if file.endswith('_downloads.json'):
  104. if not any(filename.endswith('.lock') for filename in
  105. os.listdir(os.path.join(pil.dl_path))):
  106. try:
  107. os.remove(os.path.join(pil.dl_path, file))
  108. file_delcount += 1
  109. except Exception as e:
  110. logger.error("Could not remove file: {:s}".format(str(e)))
  111. error_count += 1
  112. else:
  113. lock_count += 1
  114. if dir_delcount == 0 and file_delcount == 0 and error_count == 0 and lock_count == 0:
  115. logger.info('The cleanup has finished. No items were removed.')
  116. logger.separator()
  117. return
  118. logger.info('The cleanup has finished.')
  119. logger.info('Folders removed: {:d}'.format(dir_delcount))
  120. logger.info('Files removed: {:d}'.format(file_delcount))
  121. logger.info('Locked items: {:d}'.format(lock_count))
  122. logger.info('Errors: {:d}'.format(error_count))
  123. logger.separator()
  124. except KeyboardInterrupt as e:
  125. logger.separator()
  126. logger.warn("The cleanup has been aborted.")
  127. if dir_delcount == 0 and file_delcount == 0 and error_count == 0 and lock_count == 0:
  128. logger.info('No items were removed.')
  129. logger.separator()
  130. return
  131. logger.info('Folders removed: {:d}'.format(dir_delcount))
  132. logger.info('Files removed: {:d}'.format(file_delcount))
  133. logger.info('Locked items : {:d}'.format(lock_count))
  134. logger.info('Errors: {:d}'.format(error_count))
  135. logger.separator()
  136. def show_info():
  137. cookie_files = []
  138. cookie_from_config = ''
  139. try:
  140. for file in os.listdir(os.getcwd()):
  141. if file.endswith(".json"):
  142. with open(file) as data_file:
  143. try:
  144. json_data = json.load(data_file)
  145. if json_data.get('created_ts'):
  146. cookie_files.append(file)
  147. except Exception as e:
  148. pass
  149. if pil.ig_user == file.replace(".json", ''):
  150. cookie_from_config = file
  151. except Exception as e:
  152. logger.warn("Could not check for cookie files: {:s}".format(str(e)))
  153. logger.whiteline()
  154. logger.info("To see all the available arguments, use the -h argument.")
  155. logger.whiteline()
  156. logger.info("PyInstaLive version: {:s}".format(Constants.SCRIPT_VER))
  157. logger.info("Python version: {:s}".format(Constants.PYTHON_VER))
  158. if not command_exists("ffmpeg"):
  159. logger.error("FFmpeg framework: Not found")
  160. else:
  161. logger.info("FFmpeg framework: Available")
  162. if len(cookie_from_config) > 0:
  163. logger.info("Cookie files: {:s} ({:s} matches config user)".format(str(len(cookie_files)),
  164. cookie_from_config))
  165. elif len(cookie_files) > 0:
  166. logger.info("Cookie files: {:s}".format(str(len(cookie_files))))
  167. else:
  168. logger.warn("Cookie files: None found")
  169. logger.info("CLI supports color: {:s}".format("No" if not logger.supports_color() else "Yes"))
  170. logger.info(
  171. "Command to run at start: {:s}".format("None" if not pil.run_at_start else pil.run_at_start))
  172. logger.info(
  173. "Command to run at finish: {:s}".format("None" if not pil.run_at_finish else pil.run_at_finish))
  174. if os.path.exists(pil.config_path):
  175. logger.info("Config file contents:")
  176. logger.whiteline()
  177. with open(pil.config_path) as f:
  178. for line in f:
  179. logger.plain(" {:s}".format(line.rstrip()))
  180. else:
  181. logger.error("Config file: Not found")
  182. logger.whiteline()
  183. logger.info("End of PyInstaLive information screen.")
  184. logger.separator()
  185. def new_config():
  186. try:
  187. if os.path.exists(pil.config_path):
  188. logger.info("A configuration file is already present:")
  189. logger.whiteline()
  190. with open(pil.config_path) as f:
  191. for line in f:
  192. logger.plain(" {:s}".format(line.rstrip()))
  193. logger.whiteline()
  194. logger.info("To create a default config file, delete 'pyinstalive.ini' and run this script again.")
  195. logger.separator()
  196. else:
  197. try:
  198. logger.warn("Could not find configuration file, creating a default one.")
  199. config_file = open(pil.config_path, "w")
  200. config_file.write(Constants.CONFIG_TEMPLATE.format(os.getcwd()).strip())
  201. config_file.close()
  202. logger.warn("Edit the created 'pyinstalive.ini' file and run this script again.")
  203. logger.separator()
  204. return
  205. except Exception as e:
  206. logger.error("Could not create default config file: {:s}".format(str(e)))
  207. logger.warn("You must manually create and edit it with the following template: ")
  208. logger.whiteline()
  209. for line in Constants.CONFIG_TEMPLATE.strip().splitlines():
  210. logger.plain(" {:s}".format(line.rstrip()))
  211. logger.whiteline()
  212. logger.warn("Save it as 'pyinstalive.ini' and run this script again.")
  213. logger.separator()
  214. except Exception as e:
  215. logger.error("An error occurred: {:s}".format(str(e)))
  216. logger.warn(
  217. "If you don't have a configuration file, manually create and edit one with the following template:")
  218. logger.whiteline()
  219. logger.plain(Constants.CONFIG_TEMPLATE)
  220. logger.whiteline()
  221. logger.warn("Save it as 'pyinstalive.ini' and run this script again.")
  222. logger.separator()
  223. def create_lock_user():
  224. try:
  225. if not os.path.isfile(os.path.join(pil.dl_path, pil.dl_user + '.lock')):
  226. if pil.use_locks:
  227. open(os.path.join(pil.dl_path, pil.dl_user + '.lock'), 'a').close()
  228. return True
  229. else:
  230. return False
  231. except Exception as e:
  232. logger.warn("Lock file could not be created. Be careful when running multiple downloads concurrently!")
  233. return True
  234. def create_lock_folder():
  235. try:
  236. if not os.path.isfile(os.path.join(pil.live_folder_path, 'folder.lock')):
  237. if pil.use_locks:
  238. open(os.path.join(pil.live_folder_path, 'folder.lock'), 'a').close()
  239. return True
  240. else:
  241. return False
  242. except Exception as e:
  243. logger.warn("Lock file could not be created. Be careful when running multiple downloads concurrently!")
  244. return True
  245. def remove_lock():
  246. download_folder_lock = os.path.join(pil.dl_path, pil.dl_user + '.lock')
  247. temp_folder_lock = os.path.join(pil.live_folder_path, 'folder.lock')
  248. lock_paths = [download_folder_lock, temp_folder_lock]
  249. for lock in lock_paths:
  250. try:
  251. os.remove(lock)
  252. except Exception:
  253. pass
  254. def remove_temp_folder():
  255. try:
  256. shutil.rmtree(pil.live_folder_path)
  257. except Exception as e:
  258. logger.error("Could not remove segment folder: {:s}".format(str(e)))
  259. def download_folder_has_lockfile():
  260. return os.path.isfile(os.path.join(pil.dl_path, pil.dl_user + '.lock'))