|
@@ -0,0 +1,172 @@
|
|
|
|
+import json
|
|
|
|
+import codecs
|
|
|
|
+import datetime
|
|
|
|
+import os.path
|
|
|
|
+import logging
|
|
|
|
+import argparse
|
|
|
|
+import json
|
|
|
|
+import codecs
|
|
|
|
+from socket import timeout, error as SocketError
|
|
|
|
+from ssl import SSLError
|
|
|
|
+from urllib2 import URLError
|
|
|
|
+from httplib import HTTPException
|
|
|
|
+
|
|
|
|
+try:
|
|
|
|
+ from instagram_private_api import (
|
|
|
|
+ Client, ClientError, ClientLoginError,
|
|
|
|
+ ClientCookieExpiredError, ClientLoginRequiredError,
|
|
|
|
+ __version__ as client_version)
|
|
|
|
+except ImportError:
|
|
|
|
+ import sys
|
|
|
|
+ sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
|
|
|
|
+ from instagram_private_api import (
|
|
|
|
+ Client, ClientError, ClientLoginError,
|
|
|
|
+ ClientCookieExpiredError, ClientLoginRequiredError,
|
|
|
|
+ __version__ as client_version)
|
|
|
|
+
|
|
|
|
+from instagram_private_api_extensions import live
|
|
|
|
+import sys, os, time, json
|
|
|
|
+
|
|
|
|
+def download():
|
|
|
|
+ try:
|
|
|
|
+ user_res = api.username_info(args.record)
|
|
|
|
+ user_id = user_res['user']['pk']
|
|
|
|
+ except Exception as e:
|
|
|
|
+ print('[E] Could not get user information, exiting . . .')
|
|
|
|
+ print('[E] ' + str(e))
|
|
|
|
+ print(seperator)
|
|
|
|
+ exit()
|
|
|
|
+
|
|
|
|
+ try:
|
|
|
|
+ print('[I] Checking broadcast for ' + args.record + ' . . .')
|
|
|
|
+ broadcast = api.user_broadcast(user_id)
|
|
|
|
+ if (broadcast is None):
|
|
|
|
+ raise Exception('No broadcast available')
|
|
|
|
+ except Exception as e:
|
|
|
|
+ print('[E] Could not get broadcast information, exiting . . .')
|
|
|
|
+ print('[E] ' + str(e))
|
|
|
|
+ print(seperator)
|
|
|
|
+ exit()
|
|
|
|
+
|
|
|
|
+ try:
|
|
|
|
+ dl = live.Downloader(
|
|
|
|
+ mpd=broadcast['dash_playback_url'],
|
|
|
|
+ output_dir='{}_output_{}/'.format(args.record, broadcast['id']),
|
|
|
|
+ user_agent=api.user_agent)
|
|
|
|
+ except Exception as e:
|
|
|
|
+ print('[E] Could not start broadcast recording, exiting . . .')
|
|
|
|
+ print('[E] ' + str(e))
|
|
|
|
+ print(seperator)
|
|
|
|
+ exit()
|
|
|
|
+
|
|
|
|
+ try:
|
|
|
|
+ print('[I] Starting broadcast recording . . .')
|
|
|
|
+ dl.run()
|
|
|
|
+ except KeyboardInterrupt:
|
|
|
|
+ print('')
|
|
|
|
+ print('[I] Aborting broadcast recording . . .')
|
|
|
|
+ if not dl.is_aborted:
|
|
|
|
+ dl.stop()
|
|
|
|
+ finally:
|
|
|
|
+ t = time.time()
|
|
|
|
+ print('[I] Stitching downloaded files into video . . .')
|
|
|
|
+ dl.stitch(args.record + "_" + str(broadcast['id']) + "_" + str(int(t)) + '.mp4')
|
|
|
|
+ print('[I] Successfully stitched downloaded files, exiting . . .')
|
|
|
|
+ print(seperator)
|
|
|
|
+ exit()
|
|
|
|
+
|
|
|
|
+def to_json(python_object):
|
|
|
|
+ if isinstance(python_object, bytes):
|
|
|
|
+ return {'__class__': 'bytes',
|
|
|
|
+ '__value__': codecs.encode(python_object, 'base64').decode()}
|
|
|
|
+ raise TypeError(repr(python_object) + ' is not JSON serializable')
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def from_json(json_object):
|
|
|
|
+ if '__class__' in json_object and json_object['__class__'] == 'bytes':
|
|
|
|
+ return codecs.decode(json_object['__value__'].encode(), 'base64')
|
|
|
|
+ return json_object
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+def onlogin_callback(api, new_settings_file):
|
|
|
|
+ cache_settings = api.settings
|
|
|
|
+ with open(new_settings_file, 'w') as outfile:
|
|
|
|
+ json.dump(cache_settings, outfile, default=to_json)
|
|
|
|
+ print('SAVED: {0!s}'.format(new_settings_file))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+if __name__ == '__main__':
|
|
|
|
+
|
|
|
|
+ logging.basicConfig()
|
|
|
|
+ logger = logging.getLogger('instagram_private_api')
|
|
|
|
+ logger.setLevel(logging.WARNING)
|
|
|
|
+
|
|
|
|
+ # Example command:
|
|
|
|
+ # python examples/savesettings_logincallback.py -u "yyy" -p "zzz" -settings "test_credentials.json"
|
|
|
|
+ parser = argparse.ArgumentParser(description='login callback and save settings demo')
|
|
|
|
+ parser.add_argument('-settings', '--settings', dest='settings_file_path', type=str, required=True)
|
|
|
|
+ parser.add_argument('-u', '--username', dest='username', type=str, required=True)
|
|
|
|
+ parser.add_argument('-p', '--password', dest='password', type=str, required=True)
|
|
|
|
+ parser.add_argument('-r', '--record', dest='record', type=str, required=True)
|
|
|
|
+ global args
|
|
|
|
+ global clear
|
|
|
|
+ global seperator
|
|
|
|
+ seperator = '=-' * 35
|
|
|
|
+ clear = lambda: os.system('clear')
|
|
|
|
+ args = parser.parse_args()
|
|
|
|
+ #clear()
|
|
|
|
+ print('PYINSTALIVE DOWNLOADER (API v{0!s})'.format(client_version))
|
|
|
|
+ print(seperator)
|
|
|
|
+
|
|
|
|
+ device_id = None
|
|
|
|
+ try:
|
|
|
|
+
|
|
|
|
+ settings_file = args.settings_file_path
|
|
|
|
+ if not os.path.isfile(settings_file):
|
|
|
|
+ # settings file does not exist
|
|
|
|
+ print('[E] Unable to find file: {0!s}'.format(settings_file))
|
|
|
|
+
|
|
|
|
+ # login new
|
|
|
|
+ api = Client(
|
|
|
|
+ args.username, args.password,
|
|
|
|
+ on_login=lambda x: onlogin_callback(x, args.settings_file_path))
|
|
|
|
+ else:
|
|
|
|
+ with open(settings_file) as file_data:
|
|
|
|
+ cached_settings = json.load(file_data, object_hook=from_json)
|
|
|
|
+ print('[I] Reusing settings: {0!s}'.format(settings_file))
|
|
|
|
+
|
|
|
|
+ device_id = cached_settings.get('device_id')
|
|
|
|
+ # reuse auth settings
|
|
|
|
+ api = Client(
|
|
|
|
+ args.username, args.password,
|
|
|
|
+ settings=cached_settings)
|
|
|
|
+
|
|
|
|
+ except (ClientCookieExpiredError, ClientLoginRequiredError) as e:
|
|
|
|
+ print('[E] ClientCookieExpiredError/ClientLoginRequiredError: {0!s}'.format(e))
|
|
|
|
+
|
|
|
|
+ # Login expired
|
|
|
|
+ # Do relogin but use default ua, keys and such
|
|
|
|
+ api = Client(
|
|
|
|
+ args.username, args.password,
|
|
|
|
+ device_id=device_id,
|
|
|
|
+ on_login=lambda x: onlogin_callback(x, args.settings_file_path))
|
|
|
|
+
|
|
|
|
+ except ClientLoginError as e:
|
|
|
|
+ print('[E] ClientLoginError {0!s}'.format(e))
|
|
|
|
+ print(seperator)
|
|
|
|
+ exit(9)
|
|
|
|
+ except ClientError as e:
|
|
|
|
+ print('[E] ClientError {0!s} (Code: {1:d}, Response: {2!s})'.format(e.msg, e.code, e.error_response))
|
|
|
|
+ print(seperator)
|
|
|
|
+ exit(9)
|
|
|
|
+ except Exception as e:
|
|
|
|
+ print('[E] Unexpected Exception: {0!s}'.format(e))
|
|
|
|
+ print(seperator)
|
|
|
|
+ exit(99)
|
|
|
|
+
|
|
|
|
+ # Show when login expires
|
|
|
|
+ cookie_expiry = api.cookie_jar.expires_earliest
|
|
|
|
+ print('[I] Cookie Expiry: {0!s}'.format(datetime.datetime.fromtimestamp(cookie_expiry).strftime('%Y-%m-%dT%H:%M:%SZ')))
|
|
|
|
+
|
|
|
|
+print('[I] Successfully logged in, starting recorder . . .')
|
|
|
|
+download()
|