Ejemplo n.º 1
0
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())
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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)
    }
Ejemplo n.º 4
0
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']
Ejemplo n.º 5
0
#! /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",
Ejemplo n.º 6
0
 def test_get_providers(self):
     just_watch = JustWatch(country='US')
     prov = just_watch.get_providers()
     self.assertIsNotNone(prov)
Ejemplo n.º 7
0
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'])
Ejemplo n.º 8
0
#!/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):
Ejemplo n.º 9
0
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 ""
Ejemplo n.º 10
0
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)