# Maps Instagram media type to ActivityStreams objectType. OBJECT_TYPES = {'image': 'photo', 'video': 'video'} API_USER_URL = 'https://api.instagram.com/v1/users/%s' API_USER_MEDIA_URL = 'https://api.instagram.com/v1/users/%s/media/recent' API_USER_FEED_URL = 'https://api.instagram.com/v1/users/self/feed' API_USER_LIKES_URL = 'https://api.instagram.com/v1/users/%s/media/liked' API_MEDIA_URL = 'https://api.instagram.com/v1/media/%s' API_MEDIA_SEARCH_URL = 'https://api.instagram.com/v1/tags/%s/media/recent' API_MEDIA_SHORTCODE_URL = 'https://api.instagram.com/v1/media/shortcode/%s' API_MEDIA_POPULAR_URL = 'https://api.instagram.com/v1/media/popular' API_MEDIA_LIKES_URL = 'https://api.instagram.com/v1/media/%s/likes' API_COMMENT_URL = 'https://api.instagram.com/v1/media/%s/comments' HTML_BASE_URL = util.read( 'instagram_scrape_base') or 'https://www.instagram.com/' HTML_MEDIA = HTML_BASE_URL + 'p/%s/' HTML_PROFILE = HTML_BASE_URL + '%s/' HTML_PRELOAD_RE = re.compile( r'^/graphql/query/\?query_hash=[^&]*&(amp;)?variables=(%7B%7D|{})$') # the query hash here comes (i think) from inside a .js file served by IG, so # we'd have to fetch and scrape that to get it dynamically. not worth it yet. HTML_LIKES_URL = HTML_BASE_URL + 'graphql/query/?query_hash=d5d763b1e2acf209d62d22d184488e57&variables={"shortcode":"%s","include_reel":false,"first":100}' HTML_DATA_RE = re.compile( r""" <script\ type="text/javascript"> window\.(_sharedData\ =|__additionalDataLoaded\('[^']+',)\ * (.+?) \)?;</script>""", re.VERBOSE) HTML_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:82.0) Gecko/20100101 Firefox/82.0'
from oauth_dropins.webutil.util import json_dumps, json_loads CACHE_EXPIRATION = timedelta(minutes=10) # See https://www.cloudimage.io/ IMAGE_PROXY_URL_BASE = 'https://aujtzahimq.cloudimg.io/v7/' # https://dash.cloudflare.com/dcc4dadb279e9e9e69e9e84ec82d9303/workers/view/caching-proxy VIDEO_PROXY_URL_BASE = 'https://caching-proxy.snarfed.workers.dev/' # Flask app app = Flask('instagram-atom') app.template_folder = './templates' app.config.from_mapping( ENV='development' if appengine_info.DEBUG else 'production', CACHE_TYPE='SimpleCache', SECRET_KEY=util.read('flask_secret_key'), ) app.after_request(flask_util.default_modern_headers) app.register_error_handler(Exception, flask_util.handle_exception) flask_gae_static.init_app(app) app.wsgi_app = flask_util.ndb_context_middleware( app.wsgi_app, client=appengine_config.ndb_client) cache = Cache(app) class Feed(models.StringIdModel): """An HTML feed uploaded by the browser extension, converted to AS1. Key is token generated by browser extension. """
"""Cron jobs. Currently just nightly CircleCI build.""" import requests import webapp2 from oauth_dropins.webutil import util CIRCLECI_TOKEN = util.read('circleci_token') class BuildCircle(webapp2.RequestHandler): def get(self): resp = requests.post( 'https://circleci.com/api/v1.1/project/github/snarfed/granary/tree/master?circle-token=%s' % CIRCLECI_TOKEN) resp.raise_for_status()
""" import logging import os import sys import unittest from oauth_dropins.webutil import util from oauth_dropins import twitter_auth from granary import twitter from models import TWITTER_SCRAPE_HEADERS logger = logging.getLogger(__name__) twitter_auth.TWITTER_APP_KEY = (os.getenv('TWITTER_LIVE_TEST_APP_KEY') or util.read('twitter_live_test_app_key')) assert twitter_auth.TWITTER_APP_KEY twitter_auth.TWITTER_APP_SECRET = (os.getenv('TWITTER_LIVE_TEST_APP_SECRET') or util.read('twitter_live_test_app_secret')) assert twitter_auth.TWITTER_APP_SECRET TOKEN_KEY = (os.getenv('TWITTER_ACCESS_TOKEN_KEY') or util.read('twitter_access_token_key')) assert TOKEN_KEY TOKEN_SECRET = (os.getenv('TWITTER_ACCESS_TOKEN_SECRET') or util.read('twitter_access_token_secret')) assert TOKEN_SECRET TWEET_ID = '1270018109630369797' class TwitterLiveTest(unittest.TestCase):