downloader.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647
  1. import os
  2. import shutil
  3. import subprocess
  4. import sys
  5. import threading
  6. import time
  7. import shlex
  8. import json
  9. from xml.dom.minidom import parse, parseString
  10. from instagram_private_api import ClientConnectionError
  11. from instagram_private_api import ClientError
  12. from instagram_private_api import ClientThrottledError
  13. from instagram_private_api_extensions import live
  14. from instagram_private_api_extensions import replay
  15. from .comments import CommentsDownloader
  16. from .logger import log_seperator, supports_color, log_info_blue, log_info_green, log_warn, log_error, log_whiteline, log_plain
  17. def start_single(instagram_api_arg, download_arg, settings_arg):
  18. global instagram_api
  19. global user_to_download
  20. global broadcast
  21. global settings
  22. settings = settings_arg
  23. instagram_api = instagram_api_arg
  24. user_to_download = download_arg
  25. try:
  26. if not os.path.isfile(os.path.join(settings.save_path, user_to_download + '.lock')):
  27. if settings.use_locks.title() == "True":
  28. open(os.path.join(settings.save_path, user_to_download + '.lock'), 'a').close()
  29. else:
  30. log_warn("Lock file is already present for this user, there is probably another download ongoing!")
  31. log_warn("If this is not the case, manually delete the file '{:s}' and try again.".format(user_to_download + '.lock'))
  32. log_seperator()
  33. sys.exit(1)
  34. except Exception:
  35. log_warn("Lock file could not be created. Downloads started from -df might cause problems!")
  36. get_user_info(user_to_download)
  37. def start_multiple(instagram_api_arg, settings_arg, proc_arg, initialargs_arg):
  38. try:
  39. log_info_green("Checking following users for any livestreams or replays...")
  40. broadcast_f_list = instagram_api_arg.reels_tray()
  41. usernames_available = []
  42. if broadcast_f_list['broadcasts']:
  43. for broadcast_f in broadcast_f_list['broadcasts']:
  44. username = broadcast_f['broadcast_owner']['username']
  45. if username not in usernames_available:
  46. usernames_available.append(username)
  47. if broadcast_f_list.get('post_live', {}).get('post_live_items', []):
  48. for broadcast_r in broadcast_f_list.get('post_live', {}).get('post_live_items', []):
  49. for broadcast_f in broadcast_r.get("broadcasts", []):
  50. username = broadcast_f['broadcast_owner']['username']
  51. if username not in usernames_available:
  52. usernames_available.append(username)
  53. log_seperator()
  54. if usernames_available:
  55. log_info_green("The following users have available livestreams or replays:")
  56. log_info_green(', '.join(usernames_available))
  57. log_seperator()
  58. for user in usernames_available:
  59. try:
  60. if os.path.isfile(os.path.join(settings_arg.save_path, user + '.lock')):
  61. log_warn("Lock file is already present for '{:s}', there is probably another download ongoing!".format(user))
  62. log_warn("If this is not the case, manually delete the file '{:s}' and try again.".format(user + '.lock'))
  63. else:
  64. log_info_green("Launching daemon process for '{:s}'...".format(user))
  65. if not initialargs_arg.savepath and not initialargs_arg.configpath:
  66. start_result = run_command("{:s} -d {:s}".format(proc_arg, user))
  67. elif initialargs_arg.savepath and initialargs_arg.configpath:
  68. start_result = run_command("{:s} -d {:s} -cp '{:s}' -sp '{:s}'".format(proc_arg, user, settings_arg.custom_config_path, settings_arg.save_path))
  69. elif initialargs_arg.savepath:
  70. start_result = run_command("{:s} -d {:s} -sp '{:s}'".format(proc_arg, user, settings_arg.save_path))
  71. elif initialargs_arg.configpath:
  72. start_result = run_command("{:s} -d {:s} -cp '{:s}'".format(proc_arg, user, settings_arg.custom_config_path))
  73. if start_result:
  74. log_info_green("Could not start processs: {:s}".format(str(start_result)))
  75. else:
  76. log_info_green("Process started successfully.")
  77. log_seperator()
  78. time.sleep(2)
  79. except Exception as e:
  80. log_error("Could not start processs: {:s}".format(str(e)))
  81. except KeyboardInterrupt:
  82. log_info_blue('The process launching has been aborted by the user.')
  83. log_seperator()
  84. sys.exit(0)
  85. else:
  86. log_info_green("There are currently no available livestreams or replays.")
  87. log_seperator()
  88. sys.exit(0)
  89. except Exception as e:
  90. log_error("Could not finish checking following users: {:s}".format(str(e)))
  91. sys.exit(1)
  92. except KeyboardInterrupt:
  93. log_seperator()
  94. log_info_blue('The checking process has been aborted by the user.')
  95. log_seperator()
  96. sys.exit(0)
  97. def run_command(command):
  98. try:
  99. FNULL = open(os.devnull, 'w')
  100. subprocess.Popen(shlex.split(command), stdout=FNULL, stderr=subprocess.STDOUT)
  101. return False
  102. except Exception as e:
  103. return str(e)
  104. def get_stream_duration(compare_time, broadcast=None):
  105. try:
  106. had_wrong_time = False
  107. if broadcast:
  108. if (int(time.time()) < int(compare_time)):
  109. had_wrong_time = True
  110. corrected_compare_time = int(compare_time) - 5
  111. download_time = int(time.time()) - int(corrected_compare_time)
  112. else:
  113. download_time = int(time.time()) - int(compare_time)
  114. stream_time = int(time.time()) - int(broadcast.get('published_time'))
  115. stream_started_mins, stream_started_secs = divmod(stream_time - download_time, 60)
  116. else:
  117. if (int(time.time()) < int(compare_time)):
  118. had_wrong_time = True
  119. corrected_compare_time = int(compare_time) - 5
  120. stream_started_mins, stream_started_secs = divmod((int(time.time()) - int(corrected_compare_time)), 60)
  121. else:
  122. stream_started_mins, stream_started_secs = divmod((int(time.time()) - int(compare_time)), 60)
  123. stream_duration_str = '%d minutes' % stream_started_mins
  124. if stream_started_secs:
  125. stream_duration_str += ' and %d seconds' % stream_started_secs
  126. if had_wrong_time:
  127. return "{:s} (corrected)".format(stream_duration_str)
  128. else:
  129. return stream_duration_str
  130. except Exception as e:
  131. return "Not available"
  132. def download_livestream(broadcast):
  133. try:
  134. def print_status(sep=True):
  135. heartbeat_info = instagram_api.broadcast_heartbeat_and_viewercount(broadcast.get('id'))
  136. viewers = broadcast.get('viewer_count', 0)
  137. if sep:
  138. log_seperator()
  139. log_info_green('Viewers : {:s} watching'.format(str(int(viewers))))
  140. log_info_green('Airing time : {:s}'.format(get_stream_duration(broadcast.get('published_time'))))
  141. log_info_green('Status : {:s}'.format(heartbeat_info.get('broadcast_status').title()))
  142. return heartbeat_info.get('broadcast_status') not in ['active', 'interrupted']
  143. mpd_url = (broadcast.get('dash_manifest')
  144. or broadcast.get('dash_abr_playback_url')
  145. or broadcast.get('dash_playback_url'))
  146. output_dir = '{}{}_{}_{}_{}_live_downloads'.format(settings.save_path, settings.current_date, user_to_download, broadcast.get('id'), settings.current_time)
  147. broadcast_downloader = live.Downloader(
  148. mpd=mpd_url,
  149. output_dir=output_dir,
  150. user_agent=instagram_api.user_agent,
  151. max_connection_error_retry=3,
  152. duplicate_etag_retry=30,
  153. callback_check=print_status,
  154. mpd_download_timeout=3,
  155. download_timeout=3,
  156. ffmpeg_binary=settings.ffmpeg_path)
  157. except Exception as e:
  158. log_error('Could not start downloading livestream: {:s}'.format(str(e)))
  159. log_seperator()
  160. try:
  161. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  162. except Exception:
  163. pass
  164. sys.exit(1)
  165. try:
  166. log_info_green('Livestream found, beginning download...')
  167. broadcast_owner = broadcast.get('broadcast_owner', {}).get('username')
  168. try:
  169. broadcast_guest = broadcast.get('cobroadcasters', {})[0].get('username')
  170. except Exception:
  171. broadcast_guest = None
  172. if (broadcast_owner != user_to_download):
  173. log_info_blue('This livestream is a dual-live, the owner is "{}".'.format(broadcast_owner))
  174. broadcast_guest = None
  175. if broadcast_guest:
  176. log_info_blue('This livestream is a dual-live, the current guest is "{}".'.format(broadcast_guest))
  177. log_seperator()
  178. log_info_green('Username : {:s}'.format(user_to_download))
  179. print_status(False)
  180. log_info_green('MPD URL : {:s}'.format(mpd_url))
  181. log_seperator()
  182. if settings.use_locks.title() == "True":
  183. open(os.path.join(output_dir, 'folder.lock'), 'a').close()
  184. log_info_green('Downloading livestream... press [CTRL+C] to abort.')
  185. if (settings.run_at_start is not "None"):
  186. try:
  187. thread = threading.Thread(target=run_command, args=(settings.run_at_start,))
  188. thread.daemon = True
  189. thread.start()
  190. log_info_green("Command executed: \033[94m{:s}".format(settings.run_at_start))
  191. except Exception as e:
  192. log_warn('Could not execute command: {:s}'.format(str(e)))
  193. comment_thread_worker = None
  194. if settings.save_comments.title() == "True":
  195. try:
  196. comments_json_file = os.path.join(output_dir, '{}_{}_{}_{}_live_comments.json'.format(settings.current_date, user_to_download, broadcast.get('id'), settings.current_time))
  197. comment_thread_worker = threading.Thread(target=get_live_comments, args=(instagram_api, broadcast, comments_json_file, broadcast_downloader,))
  198. comment_thread_worker.start()
  199. except Exception as e:
  200. log_error('An error occurred while downloading comments: {:s}'.format(str(e)))
  201. broadcast_downloader.run()
  202. log_seperator()
  203. log_info_green('Download duration : {}'.format(get_stream_duration(int(settings.current_time))))
  204. log_info_green('Stream duration : {}'.format(get_stream_duration(broadcast.get('published_time'))))
  205. log_info_green('Missing (approx.) : {}'.format(get_stream_duration(int(settings.current_time), broadcast)))
  206. log_seperator()
  207. stitch_video(broadcast_downloader, broadcast, comment_thread_worker)
  208. except KeyboardInterrupt:
  209. log_seperator()
  210. log_info_blue('The download has been aborted by the user.')
  211. log_seperator()
  212. log_info_green('Download duration : {}'.format(get_stream_duration(int(settings.current_time))))
  213. log_info_green('Stream duration : {}'.format(get_stream_duration(broadcast.get('published_time'))))
  214. log_info_green('Missing (approx.) : {}'.format(get_stream_duration(int(settings.current_time), broadcast)))
  215. log_seperator()
  216. if not broadcast_downloader.is_aborted:
  217. broadcast_downloader.stop()
  218. stitch_video(broadcast_downloader, broadcast, comment_thread_worker)
  219. except Exception as e:
  220. log_error("Could not download livestream: {:s}".format(str(e)))
  221. try:
  222. os.remove(os.path.join(output_dir, 'folder.lock'))
  223. except Exception:
  224. pass
  225. try:
  226. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  227. except Exception:
  228. pass
  229. def stitch_video(broadcast_downloader, broadcast, comment_thread_worker):
  230. try:
  231. live_mp4_file = '{}{}_{}_{}_{}_live.mp4'.format(settings.save_path, settings.current_date, user_to_download, broadcast.get('id'), settings.current_time)
  232. live_folder_path = "{:s}_downloads".format(live_mp4_file.split('.mp4')[0])
  233. if comment_thread_worker and comment_thread_worker.is_alive():
  234. log_info_green("Waiting for comment downloader to end cycle...")
  235. comment_thread_worker.join()
  236. if (settings.run_at_finish is not "None"):
  237. try:
  238. thread = threading.Thread(target=run_command, args=(settings.run_at_finish,))
  239. thread.daemon = True
  240. thread.start()
  241. log_info_green("Command executed: \033[94m{:s}".format(settings.run_at_finish))
  242. except Exception as e:
  243. log_warn('Could not execute command: {:s}'.format(str(e)))
  244. log_info_green('Stitching downloaded files into video...')
  245. try:
  246. if settings.clear_temp_files.title() == "True":
  247. broadcast_downloader.stitch(live_mp4_file, cleartempfiles=True)
  248. else:
  249. broadcast_downloader.stitch(live_mp4_file, cleartempfiles=False)
  250. log_info_green('Successfully stitched downloaded files into video.')
  251. try:
  252. os.remove(os.path.join(live_folder_path, 'folder.lock'))
  253. except Exception:
  254. pass
  255. try:
  256. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  257. except Exception:
  258. pass
  259. if settings.clear_temp_files.title() == "True":
  260. try:
  261. shutil.rmtree(live_folder_path)
  262. except Exception as e:
  263. log_error("Could not remove temp folder: {:s}".format(str(e)))
  264. log_seperator()
  265. sys.exit(0)
  266. except ValueError as e:
  267. log_error('Could not stitch downloaded files: {:s}'.format(str(e)))
  268. log_error('Likely the download duration was too short and no temp files were saved.')
  269. log_seperator()
  270. try:
  271. os.remove(os.path.join(live_folder_path, 'folder.lock'))
  272. except Exception:
  273. pass
  274. try:
  275. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  276. except Exception:
  277. pass
  278. sys.exit(1)
  279. except Exception as e:
  280. log_error('Could not stitch downloaded files: {:s}'.format(str(e)))
  281. log_seperator()
  282. try:
  283. os.remove(os.path.join(live_folder_path, 'folder.lock'))
  284. except Exception:
  285. pass
  286. try:
  287. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  288. except Exception:
  289. pass
  290. sys.exit(1)
  291. except KeyboardInterrupt:
  292. log_info_blue('Aborted stitching process, no video was created.')
  293. log_seperator()
  294. try:
  295. os.remove(os.path.join(live_folder_path, 'folder.lock'))
  296. except Exception:
  297. pass
  298. try:
  299. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  300. except Exception:
  301. pass
  302. sys.exit(0)
  303. def get_user_info(user_to_download):
  304. is_user_id = False
  305. try:
  306. user_id = int(user_to_download)
  307. is_user_id = True
  308. except ValueError:
  309. user_id = user_to_download
  310. try:
  311. user_res = instagram_api.username_info(user_to_download)
  312. user_id = user_res.get('user', {}).get('pk')
  313. except ClientConnectionError as cce:
  314. log_error('Could not get user info for "{:s}": {:d} {:s}'.format(user_to_download, cce.code, str(cce)))
  315. if "getaddrinfo failed" in str(cce):
  316. log_error('Could not resolve host, check your internet connection.')
  317. if "timed out" in str(cce):
  318. log_error('The connection timed out, check your internet connection.')
  319. log_seperator()
  320. try:
  321. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  322. except Exception:
  323. pass
  324. sys.exit(1)
  325. except ClientThrottledError as cte:
  326. log_error('Could not get user info for "{:s}": {:d} {:s}.'.format(user_to_download, cte.code, str(cte)))
  327. log_error('You are making too many requests at this time.')
  328. log_seperator()
  329. try:
  330. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  331. except Exception:
  332. pass
  333. sys.exit(1)
  334. except ClientError as ce:
  335. log_error('Could not get user info for "{:s}": {:d} {:s}'.format(user_to_download, ce.code, str(ce)))
  336. if ("Not Found") in str(ce):
  337. log_error('The specified user does not exist.')
  338. log_seperator()
  339. try:
  340. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  341. except Exception:
  342. pass
  343. sys.exit(1)
  344. except Exception as e:
  345. log_error('Could not get user info for "{:s}": {:s}'.format(user_to_download, str(e)))
  346. log_seperator()
  347. try:
  348. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  349. except Exception:
  350. pass
  351. sys.exit(1)
  352. except KeyboardInterrupt:
  353. log_info_blue('Aborted getting user info for "{:s}", exiting...'.format(user_to_download))
  354. log_seperator()
  355. try:
  356. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  357. except Exception:
  358. pass
  359. sys.exit(0)
  360. if is_user_id:
  361. log_info_green('Getting info for "{:s}" successful. (assumed input is Id)'.format(user_to_download))
  362. else:
  363. log_info_green('Getting info for "{:s}" successful.'.format(user_to_download))
  364. get_broadcasts_info(user_id)
  365. def get_broadcasts_info(user_id):
  366. try:
  367. log_seperator()
  368. log_info_green('Checking for livestreams and replays...')
  369. log_seperator()
  370. broadcasts = instagram_api.user_story_feed(user_id)
  371. livestream = broadcasts.get('broadcast')
  372. replays = broadcasts.get('post_live_item', {}).get('broadcasts', [])
  373. if settings.save_lives.title() == "True":
  374. if livestream:
  375. download_livestream(livestream)
  376. else:
  377. log_info_green('There are no available livestreams.')
  378. else:
  379. log_info_blue("Livestream saving is disabled either with an argument or in the config file.")
  380. if settings.save_replays.title() == "True":
  381. if replays:
  382. log_seperator()
  383. log_info_green('Replays found, beginning download...')
  384. log_seperator()
  385. download_replays(replays)
  386. else:
  387. log_info_green('There are no available replays.')
  388. else:
  389. log_seperator()
  390. log_info_blue("Replay saving is disabled either with an argument or in the config file.")
  391. log_seperator()
  392. try:
  393. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  394. except Exception:
  395. pass
  396. except Exception as e:
  397. log_error('Could not finish checking: {:s}'.format(str(e)))
  398. if "timed out" in str(e):
  399. log_error('The connection timed out, check your internet connection.')
  400. log_seperator()
  401. try:
  402. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  403. except Exception:
  404. pass
  405. sys.exit(1)
  406. except KeyboardInterrupt:
  407. log_info_blue('Aborted checking for livestreams and replays, exiting...'.format(user_to_download))
  408. log_seperator()
  409. try:
  410. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  411. except Exception:
  412. pass
  413. sys.exit(1)
  414. except ClientThrottledError as cte:
  415. log_error('Could not check because you are making too many requests at this time.')
  416. log_seperator()
  417. try:
  418. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  419. except Exception:
  420. pass
  421. sys.exit(1)
  422. def download_replays(broadcasts):
  423. try:
  424. try:
  425. log_info_green('Amount of replays : {:s}'.format(str(len(broadcasts))))
  426. for replay_index, broadcast in enumerate(broadcasts):
  427. bc_dash_manifest = parseString(broadcast.get('dash_manifest')).getElementsByTagName('Period')
  428. bc_duration_raw = bc_dash_manifest[0].getAttribute("duration")
  429. bc_hours = (bc_duration_raw.split("PT"))[1].split("H")[0]
  430. bc_minutes = (bc_duration_raw.split("H"))[1].split("M")[0]
  431. bc_seconds = ((bc_duration_raw.split("M"))[1].split("S")[0]).split('.')[0]
  432. log_info_green('Replay {:s} duration : {:s} minutes and {:s} seconds'.format(str(replay_index + 1), bc_minutes, bc_seconds))
  433. except Exception as e:
  434. log_warn("An error occurred while getting replay duration information: {:s}".format(str(e)))
  435. log_seperator()
  436. log_info_green("Downloading replays... press [CTRL+C] to abort.")
  437. log_seperator()
  438. for replay_index, broadcast in enumerate(broadcasts):
  439. exists = False
  440. if sys.version.split(' ')[0].startswith('2'):
  441. directories = (os.walk(settings.save_path).next()[1])
  442. else:
  443. directories = (os.walk(settings.save_path).__next__()[1])
  444. for directory in directories:
  445. if (str(broadcast.get('id')) in directory) and ("_live_" not in directory):
  446. log_info_blue("Already downloaded a replay with ID '{:s}'.".format(str(broadcast.get('id'))))
  447. exists = True
  448. if not exists:
  449. current = replay_index + 1
  450. log_info_green("Downloading replay {:s} of {:s} with ID '{:s}'...".format(str(current), str(len(broadcasts)), str(broadcast.get('id'))))
  451. current_time = str(int(time.time()))
  452. output_dir = '{}{}_{}_{}_{}_replay_downloads'.format(settings.save_path, settings.current_date, user_to_download, broadcast.get('id'), settings.current_time)
  453. broadcast_downloader = replay.Downloader(
  454. mpd=broadcast.get('dash_manifest'),
  455. output_dir=output_dir,
  456. user_agent=instagram_api.user_agent,
  457. ffmpeg_binary=settings.ffmpeg_path)
  458. if settings.use_locks.title() == "True":
  459. open(os.path.join(output_dir, 'folder.lock'), 'a').close()
  460. replay_mp4_file = '{}{}_{}_{}_{}_replay.mp4'.format(settings.save_path, settings.current_date, user_to_download, broadcast.get('id'), settings.current_time)
  461. replay_json_file = os.path.join(output_dir, '{}_{}_{}_{}_replay_comments.json'.format(settings.current_date, user_to_download, broadcast.get('id'), settings.current_time))
  462. if settings.clear_temp_files.title() == "True":
  463. replay_saved = broadcast_downloader.download(replay_mp4_file, cleartempfiles=True)
  464. else:
  465. replay_saved = broadcast_downloader.download(replay_mp4_file, cleartempfiles=False)
  466. if settings.save_comments.title() == "True":
  467. log_info_green("Downloading replay comments...")
  468. try:
  469. get_replay_comments(instagram_api, broadcast, replay_json_file, broadcast_downloader)
  470. except Exception as e:
  471. log_error('An error occurred while downloading comments: {:s}'.format(str(e)))
  472. if (len(replay_saved) == 1):
  473. log_info_green("Finished downloading replay {:s} of {:s}.".format(str(current), str(len(broadcasts))))
  474. try:
  475. os.remove(os.path.join(output_dir, 'folder.lock'))
  476. except Exception:
  477. pass
  478. if (current != len(broadcasts)):
  479. log_seperator()
  480. else:
  481. log_warn("No output video file was made, please merge the files manually if possible.")
  482. log_warn("Check if ffmpeg is available by running ffmpeg in your terminal/cmd prompt.")
  483. log_whiteline()
  484. log_seperator()
  485. log_info_green("Finished downloading all available replays.")
  486. log_seperator()
  487. try:
  488. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  489. except Exception:
  490. pass
  491. sys.exit(0)
  492. except Exception as e:
  493. log_error('Could not save replay: {:s}'.format(str(e)))
  494. log_seperator()
  495. try:
  496. os.remove(os.path.join(output_dir, 'folder.lock'))
  497. except Exception:
  498. pass
  499. try:
  500. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  501. except Exception:
  502. pass
  503. sys.exit(1)
  504. except KeyboardInterrupt:
  505. log_seperator()
  506. log_info_blue('The download has been aborted by the user, exiting...')
  507. log_seperator()
  508. try:
  509. shutil.rmtree(output_dir)
  510. except Exception as e:
  511. log_error("Could not remove temp folder: {:s}".format(str(e)))
  512. sys.exit(1)
  513. try:
  514. os.remove(os.path.join(settings.save_path, user_to_download + '.lock'))
  515. except Exception:
  516. pass
  517. sys.exit(0)
  518. def get_replay_comments(instagram_api, broadcast, comments_json_file, broadcast_downloader):
  519. try:
  520. comments_downloader = CommentsDownloader(
  521. api=instagram_api, broadcast=broadcast, destination_file=comments_json_file)
  522. comments_downloader.get_replay()
  523. try:
  524. if comments_downloader.comments:
  525. comments_log_file = comments_json_file.replace('.json', '.log')
  526. comment_errors, total_comments = CommentsDownloader.generate_log(
  527. comments_downloader.comments, broadcast.get('published_time'), comments_log_file,
  528. comments_delay=0)
  529. if total_comments == 1:
  530. log_info_green("Successfully saved 1 comment to logfile.")
  531. log_seperator()
  532. return True
  533. else:
  534. if comment_errors:
  535. log_warn("Successfully saved {:s} comments to logfile but {:s} comments are (partially) missing.".format(str(total_comments), str(comment_errors)))
  536. else:
  537. log_info_green("Successfully saved {:s} comments to logfile.".format(str(total_comments)))
  538. log_seperator()
  539. return True
  540. else:
  541. log_info_green("There are no available comments to save.")
  542. return False
  543. except Exception as e:
  544. log_error('Could not save comments to logfile: {:s}'.format(str(e)))
  545. return False
  546. except KeyboardInterrupt as e:
  547. log_info_blue("Downloading replay comments has been aborted.")
  548. return False
  549. def get_live_comments(instagram_api, broadcast, comments_json_file, broadcast_downloader):
  550. try:
  551. comments_downloader = CommentsDownloader(
  552. api=instagram_api, broadcast=broadcast, destination_file=comments_json_file)
  553. first_comment_created_at = 0
  554. try:
  555. while not broadcast_downloader.is_aborted:
  556. if 'initial_buffered_duration' not in broadcast and broadcast_downloader.initial_buffered_duration:
  557. broadcast['initial_buffered_duration'] = broadcast_downloader.initial_buffered_duration
  558. comments_downloader.broadcast = broadcast
  559. first_comment_created_at = comments_downloader.get_live(first_comment_created_at)
  560. except ClientError as e:
  561. if not 'media has been deleted' in e.error_response:
  562. log_warn("Comment collection ClientError: %d %s" % (e.code, e.error_response))
  563. try:
  564. if comments_downloader.comments:
  565. comments_downloader.save()
  566. comments_log_file = comments_json_file.replace('.json', '.log')
  567. comment_errors, total_comments = CommentsDownloader.generate_log(
  568. comments_downloader.comments, settings.current_time, comments_log_file,
  569. comments_delay=broadcast_downloader.initial_buffered_duration)
  570. if len(comments_downloader.comments) == 1:
  571. log_info_green("Successfully saved 1 comment to logfile.")
  572. log_seperator()
  573. return True
  574. else:
  575. if comment_errors:
  576. log_warn("Successfully saved {:s} comments to logfile but {:s} comments are (partially) missing.".format(str(total_comments), str(comment_errors)))
  577. else:
  578. log_info_green("Successfully saved {:s} comments to logfile.".format(str(total_comments)))
  579. log_seperator()
  580. return True
  581. else:
  582. log_info_green("There are no available comments to save.")
  583. return False
  584. log_seperator()
  585. except Exception as e:
  586. log_error('Could not save comments to logfile: {:s}'.format(str(e)))
  587. return False
  588. except KeyboardInterrupt as e:
  589. log_info_blue("Downloading livestream comments has been aborted.")
  590. return False