コード例 #1
0
def getJustWatch(title, jw_id, rt_score, streams, jw = None):
    if jw == None:
        jw = JustWatch(country = 'US')
    sel = 'n'
    ## JustWatch breaks if you bombard it too much, so use a VPN
    while True:
        try:
            res = jw.get_title(title_id = int(jw_id))
        except Exception as e:
            if e.response.status_code == 500:
                print("No match found for this JustWatch ID {}.".format(jw_id))
                return jw_id, rt_score, streams
            if e.response.status_code == 404:
                print("No match found for this JustWatch ID {}.".format(jw_id))
                return jw_id, rt_score, streams
            print(e.response.status_code)
            print("JustWatch not reached. Try again...")
            print("** Rate Limit was likely exceeded. Please use VPN. **")
            nada = input("Press [enter] to continue once VPN is turned on.")
            continue
        else:
            print("* MATCHED JustWatch")
            break
    if 'error' in res:
        print("No match found for this JustWatch ID {}.".format(jw_id))
        return jw_id, rt_score, streams
    jw_id, year, desc, runtime, rt_score, streams = parseJustWatch(res)
    return jw_id, rt_score, streams
コード例 #2
0
def findJustWatch(title, jw = None, jw_genres = None, imdb_id = None, tmdb_id = None):
    if jw == None:
        jw = JustWatch(country = 'US')
    if jw_genres is None:
        jw_genres = jw.get_genres()
    sel = 'n'
    jw_id = np.nan
    year = np.nan
    desc = None
    runtime = np.nan
    rt_score = np.nan
    gs = []
    streams = []
    jw_title = None
    res = jw.search_for_item(query = title)
    while sel != 'y' and 'total_results' in res and res['total_results'] > 0:
        for r in res['items']:
            if 'scoring' in r:
                provs = pd.DataFrame(r['scoring'])
                if (imdb_id != None and len(provs.value[provs.provider_type == 'imdb:id'].values) != 0):
                    if provs.value[provs.provider_type == 'imdb:id'].values != imdb_id:
                        next
                if (tmdb_id != None and len(provs.value[provs.provider_type == 'tmdb:id'].values) != 0):
                    if provs.value[provs.provider_type == 'tmdb:id'].values != tmdb_id:
                        next
                jw_title = unidecode(r['title']).replace(',', '')
                if jw_title is not None and title is not None:
                    if jw_title.lower() == title.lower():
                        sel = 'y'
                    elif title.lower() in jw_title.lower() or jw_title.lower() in title.lower():
                        sel = input(
                            "Matching '{}' with JustWatch '{}' ({})... OK? [y or n] ".format(title, jw_title, r['id'])
                        ).lower()
                if sel == 'y':
                    jw_id, year, desc, runtime, rt_score, streams = parseJustWatch(r)
                    break
                else:
                    print("Trying again...")
        break
    if sel != 'y':
        print("Unable to find match in JustWatch for '{}'".format(title))
        jw_id = tryFloat(input("What is the JustWatch ID?  "), get = True)
        if jw_id == '':
            jw_id = np.nan
        rt_score = tryFloat(input("What is the Rotten Tomatoes score?  "), get = True)
        if rt_score == '':
            rt_score = np.nan
        user_streams = input("On which services is it streaming? (separated by commas)  ")
        if user_streams != '':
            streams = [x.strip() for x in user_streams.split(',')]
        jw_title = None
    else:
        print("* MATCHED JustWatch")

    ## get genres
    if not np.isnan(jw_id):
        full_res = jw.get_title(title_id = int(jw_id))
        gs = parseGenres(full_res['genre_ids'], jw_genres) if 'genre_ids' in full_res.keys() else []

    return jw_id, year, desc, runtime, rt_score, gs, streams, jw_title
コード例 #3
0
ファイル: main.py プロジェクト: vinaywadhwa/justwatch-alfred
def main(wf):
    from justwatch import JustWatch
    parser = argparse.ArgumentParser()
    parser.add_argument('-s', '--search_keyword')
    parser.add_argument('-t', '--title_id')
    parser.add_argument('-i', '--input_locale')

    args = parser.parse_args()

    search_keyword = args.search_keyword
    title_id = args.title_id
    constants.LOCALE = args.input_locale

    just_watch = JustWatch(country=constants.LOCALE)
    providers = Providers(just_watch)
    t = thumbs()
    if search_keyword is not None:
        media_items = MediaItems(just_watch, sys.argv[len(sys.argv) - 1],
                                 providers).get_alfred_json_list()
        should_rerun = process_thumbnails_search(t, media_items)
        wf.logger.error("should_rerun = %s" % should_rerun)
        show_results_search(media_items, should_rerun)
    elif title_id is not None:
        title_id, content_type = parse_title_id(title_id)
        media_item = MediaItem(
            just_watch.get_title(title_id=title_id, content_type=content_type),
            providers)
        should_rerun = process_thumbnails_providers(t, media_item)
        show_results_providers(media_item, should_rerun)
    else:
        pass

    t.save_queue()
    if t.has_queue:
        if not is_running('generate_thumbnails'):
            run_in_background(
                'generate_thumbnails',
                ['/usr/bin/python3',
                 wf.workflowfile('thumbnails.py')])
コード例 #4
0
ファイル: tests.py プロジェクト: patrick-wraws/JustWatchAPI
 def test_get_title(self):
     the_matrix_title_id = '10'
     just_watch = JustWatch()
     titles = just_watch.get_title(the_matrix_title_id)
     self.assertIsNotNone(titles)
     self.assertGreater(len(titles), 0)
コード例 #5
0
            }},
            page_size=pageSize)

        for item in page['items']:
            peliculas.append(item['id'])

        print('Página ' + str(count) + '/' + str(totalPages))

        count += 1

    count = 0

    while (count < len(peliculas)):

        try:
            movie = just_watch.get_title(title_id=peliculas[count])

            # print(json.dumps(movie, indent=4, sort_keys=True))

            if ((movie['object_type'] == 'movie') & ("offers" in movie)):

                name = movie['title'] + ' (' + str(
                    movie['original_release_year']) + ')'

                genresId = movie['genre_ids']

                i = 0
                genres = []

                for id in genresId:
                    genres.append(GenreIdToGenero(id))
コード例 #6
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)