downloader.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. import sys
  2. import time
  3. import os
  4. import shutil
  5. import subprocess
  6. import threading
  7. from instagram_private_api_extensions import live, replay
  8. from .logger import log, seperator
  9. class NoLivestreamException(Exception):
  10. pass
  11. class NoReplayException(Exception):
  12. pass
  13. def main(api_arg, record_arg, settings_arg):
  14. global api
  15. global record
  16. global broadcast
  17. global mpd_url
  18. global settings
  19. settings = settings_arg
  20. api = api_arg
  21. record = record_arg
  22. get_user_info(record)
  23. def run_script(file):
  24. try:
  25. FNULL = open(os.devnull, 'w')
  26. if sys.version.split(' ')[0].startswith('2'):
  27. subprocess.call(["python", file], stdout=FNULL, stderr=subprocess.STDOUT)
  28. else:
  29. subprocess.call(["python3", file], stdout=FNULL, stderr=subprocess.STDOUT)
  30. except OSError as e:
  31. pass
  32. def record_stream(broadcast):
  33. try:
  34. def print_status():
  35. heartbeat_info = api.broadcast_heartbeat_and_viewercount(broadcast['id'])
  36. viewers = broadcast.get('viewer_count', 0)
  37. started_mins, started_secs = divmod((int(time.time()) - broadcast['published_time']), 60)
  38. started_label = '%d minutes' % started_mins
  39. if started_secs:
  40. started_label += ' and %d seconds' % started_secs
  41. log('[I] Viewers : ' + str(int(viewers)) + " watching", "GREEN")
  42. log('[I] Airing time : ' + started_label, "GREEN")
  43. log('[I] Status : ' + heartbeat_info['broadcast_status'].title(), "GREEN")
  44. seperator("GREEN")
  45. return heartbeat_info['broadcast_status'] not in ['active', 'interrupted']
  46. mpd_url = (broadcast.get('dash_manifest')
  47. or broadcast.get('dash_abr_playback_url')
  48. or broadcast['dash_playback_url'])
  49. output_dir = settings.save_path + '{}_{}_{}_{}_live_downloads'.format(settings.current_date, record, broadcast['id'], settings.current_time)
  50. dl = live.Downloader(
  51. mpd=mpd_url,
  52. output_dir=output_dir,
  53. user_agent=api.user_agent,
  54. max_connection_error_retry=3,
  55. duplicate_etag_retry=30,
  56. callback_check=print_status,
  57. mpd_download_timeout=5,
  58. download_timeout=10)
  59. except Exception as e:
  60. log('[E] Could not start recording livestream: ' + str(e), "RED")
  61. seperator("GREEN")
  62. sys.exit(1)
  63. try:
  64. log('[I] Starting livestream recording:', "GREEN")
  65. log('[I] Username : ' + record, "GREEN")
  66. log('[I] MPD URL : ' + mpd_url, "GREEN")
  67. print_status()
  68. log('[I] Recording livestream... press [CTRL+C] to abort.', "GREEN")
  69. if (settings.run_at_start is not ""):
  70. try:
  71. thread = threading.Thread(target=run_script, args=(settings.run_at_start,))
  72. thread.daemon = True
  73. thread.start()
  74. except Exception as e:
  75. log('[W] Could not run file: ' + str(e), "YELLOW")
  76. dl.run()
  77. stitch_video(dl, broadcast)
  78. except KeyboardInterrupt:
  79. log("", "GREEN")
  80. log('[W] Download has been aborted.', "YELLOW")
  81. log("", "GREEN")
  82. if not dl.is_aborted:
  83. dl.stop()
  84. stitch_video(dl, broadcast)
  85. def stitch_video(dl, broadcast):
  86. log('[I] Stitching downloaded files into video...', "GREEN")
  87. if (settings.run_at_finish is not ""):
  88. try:
  89. thread = threading.Thread(target=run_script, args=(settings.run_at_finish,))
  90. thread.daemon = True
  91. thread.start()
  92. except Exception as e:
  93. log('[W] Could not run file: ' + str(e), "YELLOW")
  94. output_file = settings.save_path + '{}_{}_{}_{}_live.mp4'.format(settings.current_date, record, broadcast['id'], settings.current_time)
  95. try:
  96. if settings.clear_temp_files.title() == "True":
  97. dl.stitch(output_file, cleartempfiles=True)
  98. else:
  99. dl.stitch(output_file, cleartempfiles=False)
  100. log('[I] Successfully stitched downloaded files.', "GREEN")
  101. seperator("GREEN")
  102. sys.exit(0)
  103. except Exception as e:
  104. log('[E] Could not stitch downloaded files: ' + str(e), "RED")
  105. seperator("GREEN")
  106. sys.exit(1)
  107. def get_user_info(record):
  108. try:
  109. log("[I] Checking user: '"+ record + "'", "GREEN")
  110. user_res = api.username_info(record)
  111. user_id = user_res['user']['pk']
  112. except Exception as e:
  113. log('[E] Could not get user info: ' + str(e), "RED")
  114. seperator("GREEN")
  115. sys.exit(1)
  116. get_livestreams(user_id)
  117. if settings.save_replays.title() == "True":
  118. get_replays(user_id)
  119. else:
  120. log("", "BLUE")
  121. log("[I] Replay saving is disabled either with a flag or in the config file.", "BLUE")
  122. seperator("GREEN")
  123. sys.exit(0)
  124. def get_livestreams(user_id):
  125. try:
  126. log('[I] Checking for ongoing livestreams...', "GREEN")
  127. broadcast = api.user_broadcast(user_id)
  128. if (broadcast is None):
  129. raise NoLivestreamException('There are no livestreams available.')
  130. else:
  131. record_stream(broadcast)
  132. except NoLivestreamException as e:
  133. log('[W] ' + str(e), "YELLOW")
  134. except Exception as e:
  135. if (e.__class__.__name__ is not NoLivestreamException):
  136. log('[E] Could not get livestreams info: ' + str(e), "RED")
  137. seperator("GREEN")
  138. sys.exit(1)
  139. def get_replays(user_id):
  140. try:
  141. log('[I] Checking for available replays...', "GREEN")
  142. user_story_feed = api.user_story_feed(user_id)
  143. broadcasts = user_story_feed.get('post_live_item', {}).get('broadcasts', [])
  144. except Exception as e:
  145. log('[E] Could not get replay info: ' + str(e), "RED")
  146. seperator("GREEN")
  147. sys.exit(1)
  148. try:
  149. if (len(broadcasts) == 0):
  150. raise NoReplayException('There are no replays available.')
  151. else:
  152. log("[I] Available replays have been found to download, press [CTRL+C] to abort.", "GREEN")
  153. log("", "GREEN")
  154. for index, broadcast in enumerate(broadcasts):
  155. exists = False
  156. if sys.version.split(' ')[0].startswith('2'):
  157. directories = (os.walk(settings.save_path).next()[1])
  158. else:
  159. directories = (os.walk(settings.save_path).__next__()[1])
  160. for directory in directories:
  161. if (str(broadcast['id']) in directory) and ("_live_" not in directory):
  162. log("[W] Already downloaded a replay with ID '" + str(broadcast['id']) + "', skipping...", "GREEN")
  163. exists = True
  164. if exists is False:
  165. current = index + 1
  166. log("[I] Downloading replay " + str(current) + " of " + str(len(broadcasts)) + " with ID '" + str(broadcast['id']) + "'...", "GREEN")
  167. current_time = str(int(time.time()))
  168. output_dir = settings.save_path + '{}_{}_{}_{}_replay_downloads'.format(settings.current_date, record, broadcast['id'], settings.current_time)
  169. dl = replay.Downloader(
  170. mpd=broadcast['dash_manifest'],
  171. output_dir=output_dir,
  172. user_agent=api.user_agent)
  173. if settings.clear_temp_files.title() == "True":
  174. replay_saved = dl.download(settings.save_path + '{}_{}_{}_{}_replay.mp4'.format(settings.current_date, record, broadcast['id'], settings.current_time), cleartempfiles=True)
  175. else:
  176. replay_saved = dl.download(settings.save_path + '{}_{}_{}_{}_replay.mp4'.format(settings.current_date, record, broadcast['id'], settings.current_time), cleartempfiles=False)
  177. if (len(replay_saved) == 1):
  178. log("[I] Finished downloading replay " + str(current) + " of " + str(len(broadcasts)) + ".", "GREEN")
  179. log("", "GREEN")
  180. else:
  181. log("[W] No output video file was made, please merge the files manually.", "RED")
  182. log("[W] Check if ffmpeg is available by running ffmpeg in your terminal.", "RED")
  183. log("", "GREEN")
  184. log("[I] Finished downloading available replays.", "GREEN")
  185. seperator("GREEN")
  186. sys.exit(0)
  187. except NoReplayException as e:
  188. log('[W] ' + str(e), "YELLOW")
  189. seperator("GREEN")
  190. sys.exit(0)
  191. except Exception as e:
  192. log('[E] Could not save replay: ' + str(e), "RED")
  193. seperator("GREEN")
  194. sys.exit(1)
  195. except KeyboardInterrupt:
  196. log("", "GREEN")
  197. log('[W] Download has been aborted.', "YELLOW")
  198. try:
  199. shutil.rmtree(output_dir)
  200. except Exception as e:
  201. log("[E] Could not remove temp folder: " + str(e), "RED")
  202. sys.exit(1)
  203. sys.exit(0)