2019-10-26 00:31:27 +07:00
|
|
|
import argparse
|
|
|
|
import codecs
|
|
|
|
import datetime
|
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import time
|
|
|
|
import subprocess
|
|
|
|
|
|
|
|
from dotenv import load_dotenv
|
|
|
|
from xml.dom.minidom import parseString
|
|
|
|
import urllib as urllib
|
|
|
|
import send_telegram
|
|
|
|
import time
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
import redis
|
|
|
|
|
|
|
|
|
|
|
|
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.get('__class__') == 'bytes':
|
|
|
|
return codecs.decode(json_object.get('__value__').encode(), 'base64')
|
|
|
|
return json_object
|
|
|
|
|
|
|
|
|
|
|
|
def onlogin_callback(api, setting_name):
|
|
|
|
cache_settings = api.settings
|
|
|
|
redis_client.setex(setting_name, 7776000000, json.dumps(cache_settings, default=to_json))
|
|
|
|
print('[+] New auth cookie file was made: {0!s}'.format(setting_name))
|
|
|
|
|
|
|
|
def login(username, password):
|
|
|
|
device_id = None
|
|
|
|
try:
|
|
|
|
settings_file = "credentials.json"
|
|
|
|
credential = redis_client.get('credentials')
|
|
|
|
if credential is None:
|
|
|
|
api = Client(
|
|
|
|
username, password,
|
|
|
|
on_login=lambda x: onlogin_callback(x, 'credentials'))
|
|
|
|
else:
|
|
|
|
cached_settings = json.loads(credential, object_hook=from_json)
|
|
|
|
device_id = cached_settings.get('device_id')
|
|
|
|
# reuse auth settings
|
|
|
|
api = Client(
|
|
|
|
username, password,
|
|
|
|
settings=cached_settings)
|
|
|
|
print('[+] Using cached login cookie for "' + api.authenticated_user_name + '".')
|
|
|
|
except (ClientCookieExpiredError, ClientLoginRequiredError) as e:
|
|
|
|
print('ClientCookieExpiredError/ClientLoginRequiredError: {0!s}'.format(e))
|
|
|
|
|
|
|
|
# Login expired
|
|
|
|
# Do relogin but use default ua, keys and such
|
|
|
|
api = Client(
|
|
|
|
username, password,
|
|
|
|
device_id=device_id,
|
|
|
|
on_login=lambda x: onlogin_callback(x, settings_file))
|
|
|
|
|
|
|
|
except ClientLoginError as e:
|
|
|
|
print('[!] Could not login: {:s}.\n[!] {:s}\n\n{:s}'.format(
|
|
|
|
json.loads(e.error_response).get("error_title", "Error title not available."),
|
|
|
|
json.loads(e.error_response).get("message", "Not available"), e.error_response))
|
|
|
|
print('-' * 70)
|
|
|
|
sys.exit(9)
|
|
|
|
except ClientError as e:
|
|
|
|
print('[!] Client Error: {:s}'.format(e.error_response))
|
|
|
|
print('-' * 70)
|
|
|
|
sys.exit(9)
|
|
|
|
except Exception as e:
|
|
|
|
if str(e).startswith("unsupported pickle protocol"):
|
|
|
|
print("[W] This cookie file is not compatible with Python {}.".format(sys.version.split(' ')[0][0]))
|
|
|
|
print("[W] Please delete your cookie file 'credentials.json' and try again.")
|
|
|
|
else:
|
|
|
|
print('[!] Unexpected Exception: {0!s}'.format(e))
|
|
|
|
print('-' * 70)
|
|
|
|
sys.exit(99)
|
|
|
|
|
|
|
|
print('[+] Login to "' + api.authenticated_user_name + '" OK!')
|
|
|
|
cookie_expiry = api.cookie_jar.auth_expires
|
|
|
|
print('[+] Login cookie expiry date: {0!s}'.format(
|
|
|
|
datetime.datetime.fromtimestamp(cookie_expiry).strftime('%Y-%m-%d at %I:%M:%S %p')))
|
|
|
|
|
|
|
|
return api
|
|
|
|
|
|
|
|
def like_post(post_id):
|
|
|
|
like = ig_client.post_like(post_id)
|
|
|
|
return like
|
|
|
|
|
|
|
|
def latest_post(username, user_id):
|
2019-11-03 03:24:30 +07:00
|
|
|
try:
|
|
|
|
today = datetime.date.today()
|
|
|
|
t = time.mktime(datetime.datetime.strptime(str(today), "%Y-%m-%d").timetuple())
|
|
|
|
t = int(t)
|
|
|
|
feed = ig_client.user_feed(user_id, min_timestamp=str(t))
|
|
|
|
f = open("feeds.json", "w")
|
|
|
|
f.write(json.dumps(feed))
|
|
|
|
f.close()
|
2019-10-26 00:31:27 +07:00
|
|
|
|
2019-11-03 03:24:30 +07:00
|
|
|
for post in feed['items']:
|
|
|
|
list_media = []
|
|
|
|
post_id = post['id']
|
|
|
|
pk = post['code']
|
|
|
|
k = '{}:{}:{}'.format("post", username, pk)
|
|
|
|
exist = redis_client.exists(k)
|
|
|
|
if exist == 1:
|
|
|
|
print(pk + " Exist")
|
|
|
|
continue
|
|
|
|
media_type = "photo" if post['media_type'] == 1 else "video"
|
|
|
|
if "carousel_media" in post:
|
|
|
|
carousel = True
|
|
|
|
for i, cs in enumerate(post['carousel_media'], start=1):
|
|
|
|
carousel_media_type = "photo" if cs['media_type'] == 1 else "video"
|
|
|
|
if carousel_media_type == 'photo':
|
|
|
|
list_media.append({
|
|
|
|
"caption":"Photo #{}".format(i),
|
|
|
|
"type":"photo",
|
|
|
|
"media":cs['image_versions2']['candidates'][0]['url']
|
|
|
|
})
|
|
|
|
else:
|
|
|
|
list_media.append({
|
|
|
|
"caption":"Video #{}".format(i),
|
|
|
|
"type":"video",
|
|
|
|
"media":cs['video_versions'][0]['url']
|
|
|
|
})
|
2019-10-26 00:31:27 +07:00
|
|
|
else:
|
2019-11-03 03:24:30 +07:00
|
|
|
carousel = False
|
|
|
|
if media_type == 'photo':
|
|
|
|
url_media = post['image_versions2']['candidates'][0]['url']
|
|
|
|
else:
|
|
|
|
url_media = post['video_versions'][0]['url']
|
|
|
|
post_url = "https://instagram.com/p/{}".format(pk)
|
|
|
|
caption = "[POST] from {}\n\n{}\n\nLink: {}".format(username, post['caption']['text'], post_url)
|
|
|
|
if len(caption) > 1000:
|
|
|
|
caption = caption[:1000] + '...'
|
|
|
|
|
|
|
|
like = like_post(post_id)
|
2019-10-26 00:31:27 +07:00
|
|
|
|
2019-11-03 03:24:30 +07:00
|
|
|
print(pk + " Sending...")
|
|
|
|
if carousel is True:
|
|
|
|
send_telegram.send_media_group(caption=caption, media=list_media)
|
|
|
|
else:
|
|
|
|
send_telegram.telegram_bot_send_media(fileType=media_type, url=url_media, caption=caption)
|
|
|
|
print(pk + " OK")
|
|
|
|
redis_client.setex(k, 86400, "True")
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
2019-10-26 00:31:27 +07:00
|
|
|
|
|
|
|
def latest_stories(username, user_id):
|
|
|
|
feed = ig_client.user_story_feed(user_id)
|
|
|
|
if feed['reel'] is None:
|
|
|
|
print('No Update')
|
|
|
|
return False
|
|
|
|
taken_at = True
|
|
|
|
feed_json = feed['reel']['items']
|
|
|
|
|
|
|
|
list_video = []
|
|
|
|
list_image = []
|
|
|
|
|
|
|
|
for media in feed_json:
|
|
|
|
if not taken_at:
|
|
|
|
taken_ts = None
|
|
|
|
else:
|
|
|
|
if media.get('imported_taken_at'):
|
|
|
|
taken_ts = datetime.datetime.utcfromtimestamp(media.get('imported_taken_at', "")).strftime(
|
|
|
|
'%Y-%m-%d %H:%M:%S')
|
|
|
|
else:
|
|
|
|
taken_ts = datetime.datetime.utcfromtimestamp(media.get('taken_at', "")).strftime(
|
|
|
|
'%Y-%m-%d %H:%M:%S')
|
|
|
|
|
|
|
|
is_video = 'video_versions' in media and 'image_versions2' in media
|
|
|
|
pk = media['code']
|
|
|
|
k = '{}:{}:{}:{}'.format("story", username, "video" if is_video else "photo", pk)
|
|
|
|
exist = redis_client.exists(k)
|
|
|
|
|
|
|
|
if exist == 0:
|
|
|
|
print('{} Sending...'.format(pk))
|
|
|
|
caption = "[STORY] from {}"
|
|
|
|
if is_video:
|
|
|
|
data_media = {
|
|
|
|
'url': media['video_versions'][0]['url'],
|
|
|
|
'taken': taken_ts
|
|
|
|
}
|
|
|
|
# caption = "[VIDEO] from {}"
|
|
|
|
list_video.append(data_media)
|
|
|
|
send_telegram.telegram_bot_send_media(fileType='video', url=data_media['url'], caption=caption.format(username))
|
|
|
|
else:
|
|
|
|
data_media = {
|
|
|
|
'url': media['image_versions2']['candidates'][0]['url'],
|
|
|
|
'taken': taken_ts
|
|
|
|
}
|
|
|
|
# caption = "[PHOTO] from {}"
|
|
|
|
list_image.append(data_media)
|
|
|
|
send_telegram.telegram_bot_send_media(fileType='photo', url=data_media['url'], caption=caption.format(username))
|
|
|
|
print('{} OK'.format(pk))
|
|
|
|
redis_client.setex(k, 86400, json.dumps(data_media))
|
|
|
|
else:
|
|
|
|
print(pk + ' Exists')
|
|
|
|
return feed
|
|
|
|
|
|
|
|
def download_user(user, attempt=0):
|
|
|
|
try:
|
|
|
|
if not user.isdigit():
|
|
|
|
user_res = ig_client.username_info(user)
|
|
|
|
user_id = user_res['user']['pk']
|
|
|
|
else:
|
|
|
|
user_id = user
|
|
|
|
user_info = ig_client.user_info(user_id)
|
|
|
|
if not user_info.get("user", None):
|
|
|
|
raise Exception("No user is associated with the given user id.")
|
|
|
|
else:
|
|
|
|
user = user_info.get("user").get("username")
|
|
|
|
if "feed" in sys.argv:
|
|
|
|
print("[=] Fetch POST [=]")
|
|
|
|
latest_post(user, user_id)
|
|
|
|
if "story" in sys.argv:
|
|
|
|
print("[=] Fetch STORY [=]")
|
|
|
|
latest_stories(user, user_id)
|
|
|
|
return user
|
|
|
|
except Exception as e:
|
|
|
|
print(e)
|
|
|
|
|
|
|
|
def start():
|
|
|
|
oshi = os.getenv('OSHI_USERNAME')
|
|
|
|
oshi = oshi.split(',')
|
|
|
|
print('------------------------------')
|
|
|
|
for o in oshi:
|
|
|
|
print("Oshi: "+ o)
|
|
|
|
download_user(o)
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
load_dotenv()
|
|
|
|
try:
|
|
|
|
redis_client = redis.Redis(host=os.getenv('REDIS_HOST'), port=os.getenv('REDIS_PORT'), db=os.getenv('REDIS_DB'), password=os.getenv('REDIS_PASSWORD'))
|
|
|
|
print("Connection to redis has been established...")
|
|
|
|
except Exception as e:
|
|
|
|
print("Cannot connect to redis...")
|
|
|
|
print(e)
|
|
|
|
username = os.getenv('INSTAGRAM_USER')
|
|
|
|
password = os.getenv('INSTAGRAM_PASS')
|
|
|
|
ig_client = login(username, password)
|
|
|
|
start()
|