#!/usr/bin/python3 """ Simple script that extracts information from Télé 7 jours and TMDB to help choosing the movies you want to record with your Freebox Todo : * Scrape beginning and end time * Schedule recordings on Freebox using the FB API https://dev.freebox.fr/sdk/os/pvr/#pvr-programmed-records * Display conflicts if any """ import datetime import json import logging import requests import textwrap import tmdbsimple from pyfbx.pyfbx import Fbx from bs4 import BeautifulSoup from collections import deque class Movie: def __init__(self): self.day = '' self.title = '' self.genre = '' self.channel = '' self.rating = '' self.original_title = '' self.overview = '' self.good = False self.tmdb_id = '' self.url = '' self.user_selected = False def __str__(self): return '{}: {} - {} ({})\n TMDB: {} - {}\n @ {}\n {}'.format( 'Today' if self.day == '' else self.day, self.title, self.genre, self.channel, self.rating, self.original_title, self.url, self.overview ) def __repr__(self): return "Movie <{} (D:{} — Ch:{} – R:{})>".format( self.title, 'Today' if self.day == '' else self.day, self.channel, self.rating ) class TVGuideScraper: TV_GUIDE_URL = 'https://www.programme-television.org/{}?bouquet=free' def findAllMovies(): movies = [] days = deque(['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche']) offset = datetime.datetime.today().weekday() days.rotate(-1-offset) days.appendleft('') for day in days: movies += TVGuideScraper._getMovies(day) logging.info('Found the following movies: {}'.format(movies)) return movies @staticmethod def _getMovies(day=''): logging.info('Connecting to {}'.format(TVGuideScraper.TV_GUIDE_URL)) r = requests.get(TVGuideScraper.TV_GUIDE_URL.format(day)) r.raise_for_status() html = BeautifulSoup(r.text, 'html.parser') movies = [] for channel in html.select('.bloc_cnt'): if len(channel.select('em')): for movietag in channel.find_all(TVGuideScraper._tag_is_film): movie = Movie() movie.title = \ movietag.select('.texte_titre a')[0]['title'] movie.genre = movietag.select('.texte_cat a')[0].string movie.channel = channel.select('em')[0]\ .string.replace('Programme ', '') movie.day = day.title() logging.info('Found movie: {0!r}'.format(movie)) movies.append(movie) return movies @staticmethod def _tag_is_film(tag): """ Helper to check if a tag is a film """ return ( tag.has_attr('data-nature') and tag['data-nature'] == 'films-telefilms' ) class FreeboxMoviePlanner: def __init__(self, movies): logging.info('Opening config file: config.json') with open('config.json') as config_file: self.config = json.load(config_file) tmdbsimple.API_KEY = self.config['tmdb-api'] self.movies = movies logging.info('Opening Freebox session') self.freebox = Fbx() self.freebox.mksession( app_id='FreeboxMoviePlanner', token=self.config['freebox-session-token'] ) self.getListOfAvailableChannels() self.excludeUnavailableChannels() self.findMoviesOnTMDB() self.excludeBadRatings() def __repr__(self): result = 'FreeboxMoviePlanner = self.config['minimum-rating'] movie.url = 'https://www.themoviedb.org/movie/{}?language={}' \ .format(movie.tmdb_id, self.config['tmdb-language']) def _findMovieOnTMDB(self, movie): logging.info("Searching for '{}' on TMDB".format(movie)) search = tmdbsimple.Search() search.movie(query=movie, language=self.config['tmdb-language']) if len(search.results): logging.info("Found '{}'".format( search.results[0]['title'] )) return search.results[0] else: logging.warning("'{}' not found on TMDB!".format(movie)) return [] def excludeBadRatings(self): logging.info('Dropping novies with bad ratings: {}'.format( [m for m in self.movies if not m.good] )) self.movies = [m for m in self.movies if m.good] logging.info('Kept {}'.format(self.movies)) def excludeUnavailableChannels(self): logging.info('Dropping movies on unavailable channels: {}'.format( [m for m in self.movies if m.channel not in self.channels] )) self.movies = [m for m in self.movies if m.channel in self.channels] logging.info('Kept {}'.format(self.movies)) def excludeNotSelected(self): self.movies = [m for m in self.movies if m.user_selected] if __name__ == '__main__': logging.basicConfig( level=logging.INFO, format=' %(asctime)s - %(levelname)s - %(message)s' ) fmp = FreeboxMoviePlanner(TVGuideScraper.findAllMovies()) fmp.askForUserSelection() fmp.excludeNotSelected() print('\n====== Selected ======\n') fmp.printAllMovies()