import json import requests from time import time from profile import TinderProfile # # References: # - Tinder API documentation (https://gist.github.com/rtt/10403467) # - pynder (https://github.com/charliewolf/pynder) # class TinderLoginError(Exception): pass class InitializationError(Exception): pass class RequestError(Exception): pass class ProcessingError(Exception): pass API_BASE = 'https://api.gotinder.com' class TinderAPI(object): def __init__(self, fb_id, fb_token): """Create a new Tinder interface.""" headers = { "Content-Type": "application/json; charset=utf-8", "User-Agent": "Tinder Android Version 6.4.1", "Host": API_BASE, "os_version": "1935", "app-version": "371", "platform": "android", "Accept-Encoding": "gzip" } self._session = requests.Session() self._session.headers.update(headers) self._auth(fb_id, fb_token) def _url(self, path): """Build a full URL to resources.""" return API_BASE + path def _auth(self, fb_id, fb_token): """Authenticate with Tinder services.""" params = { "facebook_id": fb_id, "facebook_token": fb_token } params = json.dumps(params) response = self._session.post(self._url('/auth'), data=params) response = json.loads(response.content.decode('utf-8')) if 'token' not in response: raise TinderLoginError() self._token = response['token'] self._session.headers.update({"X-Auth-Token": str(response['token'])}) def get_auth_token(self): """Provide the Tider authentication token.""" if not hasattr(self, '_token'): raise TinderInitializationError() return self._token def _request(self, method, url, data={}): """Perform a request to Tinder's services in a generic way.""" if not hasattr(self, '_token'): raise TinderInitializationError() result = self._session.request(method, self._url(url), data=json.dumps(data)) while result.status_code == 429: blocker = threading.Event() blocker.wait(0.01) result = self._session.request(method, self._url(url), data=data) if result.status_code != 200: raise RequestError(result.status_code) return result.json() def _get(self, url): """Perform a GET request.""" return self._request("get", url) def _post(self, url, data={}): """Perform a POST request.""" return self._request("post", url, data=data) def _meta(self): """Get meta information about the current Tinder user.""" return self._get("/meta") def get_remaining_likes(self): """Provide the number of remaining likes for the current Tinder user.""" meta_dct = self._meta() return meta_dct['rating']['likes_remaining'] def can_like_in(self): """Return the number of seconds before being allowed to issue likes.""" meta_dct = self._meta() if 'rate_limited_until' in meta_dct['rating']: now = int(time()) limited_until = meta_dct['rating']['rate_limited_until'] / 1000 diff = limited_until - now if diff > 0: if diff % 60 == 0: wait = diff / 60 else: wait = diff / 60 + 1 else: wait = 0 else: wait = 0 return wait def get_recommendations(self, limit=10): """Get a fresh list of Tinder profiles.""" new = [] data = self._post("/user/recs", data={"limit": limit}) for d in data['results']: if not d["_id"].startswith("tinder_rate_limited_id_"): profile = TinderProfile(d) new.append(profile) return new def get_info(self, uid): """Get information about a given Tinder user.""" data = self._get("/user/" + uid) if 'results' in data: profile = TinderProfile(data['results']) else: profile = None return profile def like(self, uid): """Like a Tinder profile.""" data = self._get('/like/%s' % uid) # {'likes_remaining': 100, 'match': False} if not(data['likes_remaining']): raise ProcessingError() def superlike(self, uid): """Like a Tinder profile.""" data = self._post('/like/%s/super' % uid) # {'match': False, 'super_likes': {'alc_remaining': 0, 'allotment': 1, 'superlike_refresh_interval': 1, 'superlike_refresh_interval_unit': 'd', 'remaining': 0, 'superlike_refresh_amount': 5, 'new_alc_remaining': 0, 'resets_at': '2017-06-20T19:54:18.027Z'}, 'status': 200} if data['status'] != 200: raise ProcessingError() def dislike(self, uid): """Dislike a Tinder profile.""" data = self._get('/pass/%s' % uid) if data['status'] != 200: raise ProcessingError()