def search_object(): basepath = path.dirname(__file__) filepath = path.abspath(path.join(basepath, "..", "..", "config_files", "config.json")) country = json.loads(open(filepath).read())["COUNTRY"] just_watch=JustWatch(country=country) return(just_watch.get_providers())
def getProviders(): with open("config/providers.json", "r") as f: providers = json.load(f) jw = JustWatch(country = "US") provider_details = jw.get_providers() for provider in provider_details: providers[str(provider['id'])] = provider with open("config/providers.json", "w") as f: json.dump(providers, f) return providers
def get_movie(title, country, content_types=['movie'], monetization_types=['flatrate']): just_watch = JustWatch(country=country) provider_details = just_watch.get_providers() results = just_watch.search_for_item(query=title, content_types=content_types) if len(results['items']) == 0: return first_movie = results['items'][0] return { 'title': first_movie['title'], 'id': get_tmdb_id(first_movie), 'offers': get_offers(first_movie, country, provider_details, monetization_types) }
def getProviderName(provider_id): just_watch = JustWatch(country='ES') provider_details = just_watch.get_providers() for provider in provider_details: if provider['id'] == provider_id: return provider['clear_name']
#! /usr/bin/env python3 import requests from bs4 import BeautifulSoup from justwatch import JustWatch import time import re jw = JustWatch(country='IN') source = jw.get_providers() sourceN = len(source) sourceL = { 8: "Netflix", 125: "Hooq", 119: "Amazon Prime Video", 122: "Disney+ Hotstar", 121: "Voot", 158: "Viu", 220: "JioCinema", 232: "Zee5", 218: "Eros Now", 2: "iTunes", 3: "Google Play", 350: "Apple TV+", 11: "MUBI", 237: "Sony Liv", 192: "YouTube", 100: "GuideDoc", 175: "Netflix Kids", 73: "Tubi TV", 124: "BookMyShow", 255: "Yupp TV",
def test_get_providers(self): just_watch = JustWatch(country='US') prov = just_watch.get_providers() self.assertIsNotNone(prov)
from justwatch import JustWatch import json just_watch = JustWatch(country='ES') provider_details = just_watch.get_providers() for provider in provider_details: results = just_watch.search_for_item(providers=[provider['short_name']]) print() print() print(provider['technical_name']) for item in results['items']: print(item['title']) # for item in results['items']: # print(item['title'])
#!/usr/bin/env python3 from justwatch import JustWatch from flask import Flask, request, jsonify from os import environ from discord_interactions import verify_key_decorator, InteractionType, InteractionResponseType from discord import Embed jw = JustWatch(country="AU") providers = {p["id"]: p for p in jw.get_providers()} app = Flask(__name__) PUBKEY = environ["JWBOT_PUBKEY"] @app.route("/", methods=["POST"]) @verify_key_decorator(PUBKEY) def route(): if not "type" in request.json: return jsonify({}) if request.json["type"] == InteractionType.PING: return jsonify({"type": InteractionResponseType.PONG}) elif request.json["type"] == InteractionType.APPLICATION_COMMAND: if request.json["data"]["name"] == "watch": kwargs = { d["name"]: d["value"] for d in request.json["data"]["options"] } filtered_count = 0 embeds = [] for count, embed in watch(**kwargs):
class Nation: def __init__(self, aCountry='DE', someProviders=["Netflix"]): self.country = aCountry self.api = JustWatch(aCountry) result = self.api.get_providers() self.providers = [ x for x in result if x['clear_name'] in someProviders ] def get_minimum_price(self, anOriginalItem): ret = [] results = self.api.search_for_item( query=anOriginalItem['original_title']) if len(results['items']) > 0: item = results['items'][0] if item['id'] == anOriginalItem['id'] and 'offers' in item: offers = item['offers'] flatrates = self._search_for_flatrate(offers) ret.extend(flatrates) if len(ret) == 0: minimum = self._search_for_lowest_price(offers) ret.extend(minimum) return ret def _search_for_flatrate(self, someOffers): ids = [i['id'] for i in self.providers] flatrates = [ x for x in someOffers if x['monetization_type'] == 'flatrate' and x['presentation_type'] != 'sd' and x['provider_id'] in ids ] flatrates = [self._add_zero_price(x) for x in flatrates] return flatrates def _add_zero_price(self, aVal): aVal['retail_price'] = 0.00 return aVal def _search_for_lowest_price(self, someOffers): rents = [ x for x in someOffers if x['monetization_type'] == 'rent' and x['presentation_type'] != 'sd' ] rents.sort(key=self._sort_price) if len(rents) > 0: lowest = rents[0]['retail_price'] rents = [x for x in rents if x['retail_price'] == lowest] return rents def _sort_price(self, aVal): return aVal['retail_price'] def get_item(self, aTitle): results = self.api.search_for_item(query=aTitle) if len(results['items']) > 0: item = results['items'][0] return item return ""
class Watchlist(object): # Init def __init__(self): # Libraries self.letterboxd = Letterboxd(LB_USERNAME, LB_PASSWORD) self.tmdb = TMDb(TMDB_API_KEY) self.justwatch = JustWatch(country=JUSTWATCH_COUNTRY) self.justwatch.locale = JUSTWATCH_LOCALE # Load cached watchlist films self.films = self.load() # Load def load(self): logger.info('Loading watchlist from cache') watchlist = {} try: f = open(WATCHLIST_CACHE, 'r', 'utf-8') watchlist = loads(f.read()) f.close() except: logger.exception('Could not load watchlist cache') logger.info('Loaded %d films from watchlist cache' % (len(watchlist))) return watchlist # Save def save(self): logger.info('Saving films to watchlist cache') try: with open(WATCHLIST_CACHE, 'w', 'utf-8') as f: f.write(dumps(self.films, indent=4, ensure_ascii=False)) except: logger.exception('Could not save watchlist cache') else: logger.info('Saved %d films to watchlist cache' % (len(self.films))) # Sync @json_request def sync(self): logger.info('Syncing watchlist') results = {'new': {}, 'removed': []} # Fetch Letterboxd watchlist logger.info('> Existing films: %d' % (len(self.films.keys()))) lb_watchlist = self.letterboxd.watchlist() logger.info('> Got %d films from Letterboxd' % (len(lb_watchlist.keys()))) logger.info('Updating watchlist') for slug, metadata in lb_watchlist.iteritems(): if slug in self.films: # Update self.films[slug]['ids']['letterboxd'] = metadata['id'] self.films[slug]['title'] = metadata['title'] # self.films[slug]['year'] = metadata['year'] else: # Create self.films[slug] = { 'ids': { 'letterboxd': metadata['id'] }, 'title': metadata['title'], # 'year': metadata['year'], } results['new'][slug] = self.films[slug] logger.info('> Added %s' % (slug)) # Find removed removed = [ f for f in self.films.keys() if f not in lb_watchlist.keys() ] for slug in removed: logger.info('> Removed %s' % (slug)) del self.films[slug] results['removed'] = removed # Save self.save() return results # Films @json_request def all_films(self): return self.films # Search TMDb @json_request def search_tmdb(self, slug): # Query title, year = self.parse_slug(slug) logger.info('> Searching TMDb, title=%s, year=%s' % (title, year)) tmdb = self.tmdb.search(title, year=year) results = [] for film in tmdb.get('results', []): year = film.get('release_date') year = int(year.split('-')[0]) if year else None overview = film.get('overview', '') overview = overview[0:200] + '...' if len( overview) > 200 else overview results.append({ 'id': film.get('id'), 'title': film.get('title'), 'year': year, 'overview': overview }) return results # Search JustWatch @json_request def search_justwatch(self, slug): # Query title, year = self.parse_slug(slug) logger.info('> Searching JustWatch, title=%s, year=%s' % (title, year)) justwatch = self.justwatch.search_for_item( **{ 'query': title, 'page_size': 10, 'release_year_from': (year - 1) if year else None, 'release_year_until': (year + 1) if year else None, }) results = [] for film in justwatch.get('items', []): if film.get('object_type') != 'movie': continue tmdb_id = None for scoring in film.get('scoring', []): if scoring['provider_type'] == 'tmdb:id': tmdb_id = scoring['value'] overview = film.get('short_description', '') overview = overview[0:200] + '...' if len( overview) > 200 else overview results.append({ 'id': film.get('id'), 'title': film.get('title'), 'original_title': film.get('original_title'), 'year': film.get('original_release_year'), 'overview': overview, 'tmdb_id': tmdb_id }) # Check if TMDb ID is available film_tmdb_id = self.films[slug].get('ids', {}).get('tmdb') if film_tmdb_id: logger.info( 'TMDb ID available (%s), retuning single result if match' % (film_tmdb_id)) for result in results: if result['tmdb_id'] == film_tmdb_id: return [result] return results # Update metadata @json_request def update_metadata(self, slug, tmdb_id): if slug not in self.films: logger.warning('Could not update "%s", not in watchlist' % (slug)) return None # Get metadata logger.info('Getting metadata for "%s" using TMDb id=%s' % (slug, tmdb_id)) details = self.tmdb.details(tmdb_id) if not details or details.get('status_code'): raise Exception('No metadata found for %s' % (slug)) # Parse TMDb details try: # Details year = details.get('release_date') year = int(year.split('-')[0]) if year else None credits = details.get('credits', {}) crew = credits.get('crew', []) metadata = { 'title': details.get('title'), 'original_title': details.get('original_title'), 'year': year, 'overview': details.get('overview'), 'genres': [g['name'] for g in details.get('genres', [])], 'runtime': details.get('runtime'), 'original_language': details.get('original_language'), 'spoken_languages': [l['name'] for l in details.get('spoken_languages', [])], 'directors': [p['name'] for p in crew if p['job'] == 'Director'], 'writers': [p['name'] for p in crew if p['job'] == 'Writer'], } # Images if details.get('backdrop_path') and not path.isfile( path.join(BACKDROPS_PATH, '%s.jpg' % (slug))): try: backdrop_url = TMDB_BACKDROP_URL % ( details.get('backdrop_path')) logger.info('Fetching backdrop for "%s", url=%s' % (slug, backdrop_url)) r = get(backdrop_url, stream=True) r.raise_for_status() with open(path.join(BACKDROPS_PATH, '%s.jpg' % (slug)), 'wb') as f: r.raw.decode_content = True copyfileobj(r.raw, f) except: logger.exception('Could not save backdrop image') else: logger.warning('No backdrop found for "%s"' % (slug)) except: logger.exception('TMDb parse error') raise Exception('Could not parse metadata for %s' % (slug)) # Update film logger.info('Updating metadata for "%s"' % (slug)) self.films[slug]['ids']['tmdb'] = details.get('id') self.films[slug]['ids']['imdb'] = details.get('imdb_id') self.films[slug]['metadata'] = metadata self.save() return metadata # Update offerings @json_request def update_offerings(self, slug, justwatch_id): if slug not in self.films: logger.warning('Could not update "%s", not in watchlist' % (slug)) return None # Get offerings logger.info('Getting offerings for "%s" using JustWatch id=%s' % (slug, justwatch_id)) try: providers = { p['id']: p['clear_name'] for p in self.justwatch.get_providers() } justwatch = self.justwatch.get_title(title_id=justwatch_id) print dumps(justwatch, indent=4) offers = justwatch.get('offers', []) justwatch_id = justwatch['id'] justwatch_url = justwatch.get('full_paths', {}).get('MOVIE_DETAIL_OVERVIEW') except: logger.exception( 'No offerings found for "%s" using JustWatch id=%s' % (slug, justwatch_id)) return {} # if not offers: # logger.error('No offerings found for "%s" using JustWatch id=%s' % (slug, justwatch_id)) # return {} # Parse JustWatch data try: # Offerings offerings = {} for offer in offers: if offer.get('provider_id') not in offerings: offerings[offer.get('provider_id')] = { 'name': providers.get(offer.get('provider_id')), 'offers': [], 'offer_types': [], } offerings[offer.get('provider_id')]['offers'].append({ 'date_created': offer.get('date_created'), 'monetization_type': offer.get('monetization_type'), 'presentation_type': offer.get('presentation_type'), # 'provider_id': offer.get('provider_id'), 'urls': offer.get('urls', {}), 'price': offer.get('retail_price'), 'currency': offer.get('currency'), }) if offer.get('monetization_type') not in offerings[offer.get( 'provider_id')]['offer_types']: offerings[offer.get('provider_id')]['offer_types'].append( offer.get('monetization_type')) # Scoring tomato_id = None scoring = {} average_score = None scores = [] for score in justwatch.get('scoring', []): if ':id' not in score['provider_type']: key = score['provider_type'].replace(':', '_') scoring[key] = score['value'] if key == 'imdb_score': scores.append(float(score['value'])) if key == 'tmdb_score': scores.append(float(score['value'])) if key == 'tomato_score': scores.append((float(score['value']) / 10)) if key == 'metacritic_score': scores.append((float(score['value']) / 10)) if score['provider_type'] == 'tomato:id': tomato_id = score['value'] # Calculate average if len(scores) > 0: average_score = (float(sum(scores)) / len(scores)) average_score = round(average_score, 2) except: logger.exception('Could not parse metadata for %s' % (slug)) return {} # Update film logger.info('Updating offerings for "%s"' % (slug)) self.films[slug]['ids']['justwatch'] = justwatch_id self.films[slug]['ids']['tomato'] = tomato_id self.films[slug]['offerings'] = offerings self.films[slug]['offerings_updated'] = time() self.films[slug]['offerings_updated_str'] = datetime.now().strftime( '%Y-%m-%d') self.films[slug]['justwatch_url'] = justwatch_url self.films[slug]['scoring'] = scoring self.films[slug]['scoring']['average'] = average_score self.save() return offerings # Offerings update @json_request def offerings_update(self): # Queue logger.info('Find films queued for offerings update') logger.info('> Max requests: %d' % (JUSTWATCH_MAX_REQUESTS)) logger.info('> Check age: %d' % (JUSTWATCH_CHECK_AGE)) queue = {} for slug, film in self.films.iteritems(): if not film.get('offerings_updated') or not film.get( 'ids', []).get('justwatch'): continue update_age = (time() - film.get('offerings_updated')) if update_age < JUSTWATCH_CHECK_AGE: continue queue[slug] = { 'slug': slug, 'justwatch_id': film.get('ids', []).get('justwatch'), 'last_update': film.get('offerings_updated'), 'update_age': update_age, 'result': {}, } if (len(queue) == JUSTWATCH_MAX_REQUESTS): break # Update for slug, film in queue.iteritems(): # Update offerings # offers = [] result = self.update_offerings( slug, film.get('justwatch_id')).get('result') # for provider_id, provider in result.iteritems(): # offers.append({ # 'name': provider.get('name'), # 'offers': provider.get('offer_types'), # }) queue[slug]['result'] = result return queue # Genres @json_request def genres(self): genres = {} for slug, film in self.films.iteritems(): if film.get('metadata', {}).get('genres'): for genre in film.get('metadata', {}).get('genres'): if genre not in genres: genres[genre] = 0 genres[genre] += 1 return genres # Providers @json_request def providers(self): return { p['id']: p['clear_name'] for p in self.justwatch.get_providers() } # Parse slug def parse_slug(self, slug): year = search(r'\-([0-9]{4}$|[0-9]{4}\-[0-9]$)', slug) year_split = year.group() if year else '---' year = year.groups(1)[0].split('-')[0] if year else None year = int(year) if year and int(year) <= (datetime.today().year + 2) else None title = slug.split(year_split)[0].replace('-', ' ') return title, year # Property: Size @property def size(self): return len(self.films)