startup.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. import argparse
  2. import configparser
  3. import os
  4. import logging
  5. import platform
  6. import subprocess
  7. try:
  8. import pil
  9. import auth
  10. import logger
  11. import helpers
  12. import downloader
  13. import assembler
  14. from constants import Constants
  15. except ImportError:
  16. from . import pil
  17. from . import auth
  18. from . import logger
  19. from . import helpers
  20. from . import downloader
  21. from . import assembler
  22. from .constants import Constants
  23. def validate_inputs(config, args, unknown_args):
  24. error_arr = []
  25. try:
  26. config.read(pil.config_path)
  27. if args.download:
  28. pil.dl_user = args.download
  29. if args.downloadfollowing:
  30. logger.banner()
  31. logger.warn("Please use either argument --download or --download-following, not both.")
  32. logger.separator()
  33. return False
  34. elif not args.clean and not args.info and not args.assemble and not args.downloadfollowing:
  35. logger.banner()
  36. logger.error("Missing --download or --download-following argument, please use either of the two.")
  37. logger.separator()
  38. return False
  39. if helpers.bool_str_parse(config.get('pyinstalive', 'log_to_file')) == "Invalid":
  40. pil.log_to_file = True
  41. error_arr.append(['log_to_file', 'True'])
  42. elif helpers.bool_str_parse(config.get('pyinstalive', 'log_to_file')):
  43. pil.log_to_file = True
  44. else:
  45. pil.log_to_file = False
  46. logger.banner()
  47. if unknown_args:
  48. pil.uargs = unknown_args
  49. logger.warn("The following unknown argument(s) were provided and will be ignored: ")
  50. logger.warn(' ' + ' '.join(unknown_args))
  51. logger.separator()
  52. pil.ig_user = config.get('pyinstalive', 'username')
  53. pil.ig_pass = config.get('pyinstalive', 'password')
  54. pil.dl_path = config.get('pyinstalive', 'download_path')
  55. pil.run_at_start = config.get('pyinstalive', 'run_at_start')
  56. pil.run_at_finish = config.get('pyinstalive', 'run_at_finish')
  57. pil.ffmpeg_path = config.get('pyinstalive', 'ffmpeg_path')
  58. pil.args = args
  59. pil.config = config
  60. if args.configpath:
  61. pil.config_path = args.configpath
  62. if not os.path.isfile(pil.config_path):
  63. pil.config_path = os.path.join(os.getcwd(), "pyinstalive.ini")
  64. logger.warn("Custom config path is invalid, falling back to default path: {:s}".format(pil.config_path))
  65. logger.separator()
  66. if args.dlpath:
  67. pil.dl_path = args.dlpath
  68. if helpers.bool_str_parse(config.get('pyinstalive', 'show_cookie_expiry')) == "Invalid":
  69. pil.show_cookie_expiry = False
  70. error_arr.append(['show_cookie_expiry', 'False'])
  71. elif helpers.bool_str_parse(config.get('pyinstalive', 'show_cookie_expiry')):
  72. pil.show_cookie_expiry = True
  73. else:
  74. pil.show_cookie_expiry = False
  75. if helpers.bool_str_parse(config.get('pyinstalive', 'use_locks')) == "Invalid":
  76. pil.use_locks = False
  77. error_arr.append(['use_locks', 'False'])
  78. elif helpers.bool_str_parse(config.get('pyinstalive', 'use_locks')):
  79. pil.use_locks = True
  80. else:
  81. pil.use_locks = False
  82. if helpers.bool_str_parse(config.get('pyinstalive', 'clear_temp_files')) == "Invalid":
  83. pil.clear_temp_files = False
  84. error_arr.append(['clear_temp_files', 'False'])
  85. elif helpers.bool_str_parse(config.get('pyinstalive', 'clear_temp_files')):
  86. pil.clear_temp_files = True
  87. else:
  88. pil.clear_temp_files = False
  89. if not args.nolives and helpers.bool_str_parse(config.get('pyinstalive', 'download_lives')) == "Invalid":
  90. pil.dl_lives = True
  91. error_arr.append(['download_lives', 'True'])
  92. elif helpers.bool_str_parse(config.get('pyinstalive', 'download_lives')):
  93. pil.dl_lives = True
  94. else:
  95. pil.dl_lives = False
  96. if not args.noreplays and helpers.bool_str_parse(config.get('pyinstalive', 'download_replays')) == "Invalid":
  97. pil.dl_replays = True
  98. error_arr.append(['download_replays', 'True'])
  99. elif helpers.bool_str_parse(config.get('pyinstalive', 'download_replays')):
  100. pil.dl_replays = True
  101. else:
  102. pil.dl_replays = False
  103. if helpers.bool_str_parse(config.get('pyinstalive', 'download_comments')) == "Invalid":
  104. pil.dl_comments = True
  105. error_arr.append(['download_comments', 'True'])
  106. elif helpers.bool_str_parse(config.get('pyinstalive', 'download_comments')):
  107. pil.dl_comments = True
  108. else:
  109. pil.dl_comments = False
  110. if args.nolives:
  111. pil.dl_lives = False
  112. if args.noreplays:
  113. pil.dl_replays = False
  114. if not pil.dl_lives and not pil.dl_replays:
  115. logger.error("You have disabled both livestream and replay downloading.")
  116. logger.error("Please enable at least one of them and try again.")
  117. logger.separator()
  118. return False
  119. if pil.ffmpeg_path:
  120. if not os.path.isfile(pil.ffmpeg_path):
  121. pil.ffmpeg_path = None
  122. cmd = "where" if platform.system() == "Windows" else "which"
  123. logger.warn("Custom ffmpeg binary path is invalid, falling back to default path: {:s}".format(
  124. subprocess.check_output([cmd, 'ffmpeg']).decode('UTF-8').rstrip()))
  125. else:
  126. logger.binfo("Overriding ffmpeg binary path: {:s}".format(pil.ffmpeg_path))
  127. if not pil.ig_user or not len(pil.ig_user):
  128. raise Exception("Invalid value for 'username'. This value is required.")
  129. if not pil.ig_pass or not len(pil.ig_pass):
  130. raise Exception("Invalid value for 'password'. This value is required.")
  131. if not pil.dl_path.endswith('/'):
  132. pil.dl_path = pil.dl_path + '/'
  133. if not pil.dl_path or not os.path.exists(pil.dl_path):
  134. pil.dl_path = os.getcwd()
  135. if not args.dlpath:
  136. error_arr.append(['download_path', os.getcwd()])
  137. else:
  138. logger.warn("Custom config path is invalid, falling back to default path: {:s}".format(pil.dl_path))
  139. logger.separator()
  140. if error_arr:
  141. for error in error_arr:
  142. logger.warn("Invalid value for '{:s}'. Using default value: {:s}".format(error[0], error[1]))
  143. logger.separator()
  144. if args.info:
  145. helpers.show_info()
  146. return False
  147. elif args.clean:
  148. helpers.clean_download_dir()
  149. return False
  150. elif args.assemble:
  151. pil.assemble_arg = args.assemble
  152. assembler.assemble()
  153. return False
  154. return True
  155. except Exception as e:
  156. logger.error("An error occurred: {:s}".format(str(e)))
  157. logger.error("Make sure the config file and given arguments are valid and try again.")
  158. logger.separator()
  159. return False
  160. def run():
  161. pil.initialize()
  162. logging.disable(logging.CRITICAL)
  163. config = configparser.ConfigParser()
  164. parser = argparse.ArgumentParser(
  165. description="You are running PyInstaLive {:s} using Python {:s}".format(Constants.SCRIPT_VER,
  166. Constants.PYTHON_VER))
  167. parser.add_argument('-u', '--username', dest='username', type=str, required=False,
  168. help="Instagram username to login with.")
  169. parser.add_argument('-p', '--password', dest='password', type=str, required=False,
  170. help="Instagram password to login with.")
  171. parser.add_argument('-d', '--download', dest='download', type=str, required=False,
  172. help="The username of the user whose livestream or replay you want to save.")
  173. parser.add_argument('-i', '--info', dest='info', action='store_true', help="View information about PyInstaLive.")
  174. parser.add_argument('-nr', '--no-replays', dest='noreplays', action='store_true',
  175. help="When used, do not check for any available replays.")
  176. parser.add_argument('-nl', '--no-lives', dest='nolives', action='store_true',
  177. help="When used, do not check for any available livestreams.")
  178. parser.add_argument('-cl', '--clean', dest='clean', action='store_true',
  179. help="PyInstaLive will clean the current download folder of all leftover files.")
  180. parser.add_argument('-cp', '--config-path', dest='configpath', type=str, required=False,
  181. help="Path to a PyInstaLive configuration file.")
  182. parser.add_argument('-dp', '--download-path', dest='dlpath', type=str, required=False,
  183. help="Path to folder where PyInstaLive should save livestreams and replays.")
  184. parser.add_argument('-as', '--assemble', dest='assemble', type=str, required=False,
  185. help="Path to json file required by the assembler to generate a video file from the segments.")
  186. parser.add_argument('-df', '--download-following', dest='downloadfollowing', action='store_true',
  187. help="PyInstaLive will check for available livestreams and replays from users the account "
  188. "used to login follows.")
  189. # Workaround to 'disable' argument abbreviations
  190. parser.add_argument('--usernamx', help=argparse.SUPPRESS, metavar='IGNORE')
  191. parser.add_argument('--passworx', help=argparse.SUPPRESS, metavar='IGNORE')
  192. parser.add_argument('--infx', help=argparse.SUPPRESS, metavar='IGNORE')
  193. parser.add_argument('--noreplayx', help=argparse.SUPPRESS, metavar='IGNORE')
  194. parser.add_argument('--cleax', help=argparse.SUPPRESS, metavar='IGNORE')
  195. parser.add_argument('--downloadfollowinx', help=argparse.SUPPRESS, metavar='IGNORE')
  196. parser.add_argument('--configpatx', help=argparse.SUPPRESS, metavar='IGNORE')
  197. parser.add_argument('--confix', help=argparse.SUPPRESS, metavar='IGNORE')
  198. parser.add_argument('-cx', help=argparse.SUPPRESS, metavar='IGNORE')
  199. parser.add_argument('-nx', help=argparse.SUPPRESS, metavar='IGNORE')
  200. parser.add_argument('-dx', help=argparse.SUPPRESS, metavar='IGNORE')
  201. args, unknown_args = parser.parse_known_args() # Parse arguments
  202. if not os.path.exists(pil.config_path): # Create new config if it doesn't exist
  203. logger.banner()
  204. helpers.new_config()
  205. return
  206. if validate_inputs(config, args, unknown_args):
  207. if not args.username and not args.password:
  208. pil.ig_api = auth.authenticate(username=pil.ig_user, password=pil.ig_pass)
  209. elif (args.username and not args.password) or (args.password and not args.username):
  210. logger.warn("Missing --username or --password argument. Falling back to config file.")
  211. logger.separator()
  212. pil.ig_api = auth.authenticate(username=pil.ig_user, password=pil.ig_pass)
  213. elif args.username and args.password:
  214. pil.ig_api = auth.authenticate(username=args.username, password=args.password, force_use_login_args=True)
  215. if pil.ig_api:
  216. downloader.start()