def addmovie(self, params): ''' Add movie with default quality settings params (dict): params passed in request url params must contain either 'imdbid' or 'tmdbid' key and value Returns dict {'status': 'success', 'message': 'X added to wanted list.'} ''' if not (params.get('imdbid') or params.get('tmdbid')): return {'response': False, 'error': 'no movie id supplied'} elif (params.get('imdbid') and params.get('tmdbid')): return {'response': False, 'error': 'multiple movie ids supplied'} origin = cherrypy.request.headers.get('User-Agent', 'API') origin = 'API' if origin.startswith('Mozilla/') else origin quality = params.get('quality') or core.config.default_profile() category = params.get('category', 'Default') if params.get('imdbid'): imdbid = params['imdbid'] logging.info('API request add movie imdb {}'.format(imdbid)) movie = TheMovieDatabase._search_imdbid(imdbid) if not movie: return { 'response': False, 'error': 'Cannot find {} on TMDB'.format(imdbid) } else: movie = movie[0] movie['imdbid'] = imdbid elif params.get('tmdbid'): tmdbid = params['tmdbid'] logging.info('API request add movie tmdb {}'.format(tmdbid)) movie = TheMovieDatabase._search_tmdbid(tmdbid) if not movie: return { 'response': False, 'error': 'Cannot find {} on TMDB'.format(tmdbid) } else: movie = movie[0] movie['quality'] = quality movie['category'] = category movie['status'] = 'Waiting' movie['origin'] = origin response = Manage.add_movie(movie, full_metadata=True) if response['response'] and core.CONFIG['Search'][ 'searchafteradd'] and movie['year'] != 'N/A': threading.Thread(target=searcher._t_search_grab, args=(movie, )).start() return response
def _sync_new_movies(movies): ''' Adds new movies from rss feed movies (list): dicts of movies Checks last sync time and pulls new imdbids from feed. Checks if movies are already in library and ignores. Executes ajax.add_wanted_movie() for each new imdbid Does not return ''' existing_movies = [i['imdbid'] for i in core.sql.get_user_movies()] movies_to_add = [i for i in movies if i['imdb_id'] not in existing_movies] # do quick-add procedure for movie in movies_to_add: imdbid = movie['imdb_id'] movie = TheMovieDatabase._search_imdbid(imdbid) if not movie: logging.warning('{} not found on TMDB. Cannot add.'.format(imdbid)) continue else: movie = movie[0] logging.info('Adding movie {} {} from PopularMovies list.'.format( movie['title'], movie['imdbid'])) movie['quality'] = 'Default' movie['origin'] = 'PopularMovies' added = Manage.add_movie(movie) if added['response'] and core.CONFIG['Search'][ 'searchafteradd'] and movie['year'] != 'N/A': searcher.search(movie)
def search_movie(self, params): ''' Search indexers for specific movie params(dict): params passed in request url, must include q Returns dict ajax-style response ''' if not params.get('q'): return {'response': False, 'error': 'no query supplied'} results = TheMovieDatabase.search(params['q']) if results: Manage.add_status_to_search_movies(results) else: return { 'response': False, 'error': 'No Results found for {}'.format(params['q']) } return {'response': True, 'results': results}
def add_movie(movie, full_metadata=False): ''' Adds movie to Wanted list. movie (dict): movie info to add to database. full_metadata (bool): if data is complete and ready for write movie MUST inlcude tmdb id as data['id'] Writes data to MOVIES table. If full_metadata is False, searches tmdb for data['id'] and updates data full_metadata should only be True when passing movie as data pulled directly from a tmdbid search If Search on Add enabled, searches for movie immediately in separate thread. If Auto Grab enabled, will snatch movie if found. Returns dict ajax-style response ''' logging.info('Adding {} to library.'.format(movie.get('title'))) response = {} tmdbid = movie['id'] if not full_metadata: logging.debug( 'More information needed, searching TheMovieDB for {}'.format( tmdbid)) tmdb_data = TheMovieDatabase._search_tmdbid(tmdbid) if not tmdb_data: response['error'] = _('Unable to find {} on TMDB.').format( tmdbid) return response else: tmdb_data = tmdb_data[0] tmdb_data.pop('status') movie.update(tmdb_data) if core.sql.row_exists('MOVIES', imdbid=movie['imdbid']): logging.info('{} already exists in library.'.format( movie['title'])) response['response'] = False response['error'] = _('{} already exists in library.').format( movie['title']) return response if not movie.get('category', None) and movie.get( 'finished_file', None): movie['category'] = Metadata.get_category_from_path( (movie['finished_file'])) movie.setdefault('quality', 'Default') movie.setdefault('category', 'Default') movie.setdefault('status', 'Waiting') movie.setdefault('origin', 'Search') poster_path = movie.get('poster_path') movie = Metadata.convert_to_db(movie) if not core.sql.write('MOVIES', movie): response['response'] = False response['error'] = _('Could not write to database.') else: if poster_path: poster_url = 'http://image.tmdb.org/t/p/w300/{}'.format( poster_path) threading.Thread(target=Poster.save, args=(movie['imdbid'], poster_url)).start() response['response'] = True response['message'] = _('{} {} added to library.').format( movie['title'], movie['year']) plugins.added(movie['title'], movie['year'], movie['imdbid'], movie['quality']) return response
def update(imdbid, tmdbid=None, force_poster=True): ''' Updates metadata from TMDB imdbid (str): imdb id # tmdbid (str): or int tmdb id # <optional - default None> force_poster (bool): whether or not to always redownload poster <optional - default True> If tmdbid is None, looks in database for tmdbid using imdbid. If that fails, looks on tmdb api for imdbid If that fails returns error message If force_poster is True, the poster will be re-downloaded. If force_poster is False, the poster will only be redownloaded if the local database does not have a 'poster' filepath stored. In other words, this will only grab missing posters. Returns dict ajax-style response ''' logging.info('Updating metadata for {}'.format(imdbid)) movie = core.sql.get_movie_details('imdbid', imdbid) if force_poster: get_poster = True elif not movie.get('poster'): get_poster = True elif not os.path.isfile(os.path.join(core.PROG_PATH, movie['poster'])): get_poster = True else: logging.debug('Poster will not be redownloaded.') get_poster = False if tmdbid is None: tmdbid = movie.get('tmdbid') if not tmdbid: logging.debug( 'TMDB id not found in local database, searching TMDB for {}' .format(imdbid)) tmdb_data = TheMovieDatabase._search_imdbid(imdbid) tmdbid = tmdb_data[0].get('id') if tmdb_data else None if not tmdbid: logging.debug('Unable to find {} on TMDB.'.format(imdbid)) return { 'response': False, 'error': 'Unable to find {} on TMDB.'.format(imdbid) } new_data = TheMovieDatabase._search_tmdbid(tmdbid) if not new_data: logging.warning('Empty response from TMDB.') return else: new_data = new_data[0] new_data.pop('status') target_poster = os.path.join(Poster.folder, '{}.jpg'.format(imdbid)) if new_data.get('poster_path'): poster_path = 'http://image.tmdb.org/t/p/w300{}'.format( new_data['poster_path']) movie['poster'] = '{}.jpg'.format(movie['imdbid']) else: poster_path = None movie.update(new_data) movie = Metadata.convert_to_db(movie) core.sql.update_multiple_values('MOVIES', movie, 'imdbid', imdbid) if poster_path and get_poster: if os.path.isfile(target_poster): try: os.remove(target_poster) except FileNotFoundError: pass except Exception as e: logging.warning('Unable to remove existing poster.', exc_info=True) return { 'response': False, 'error': 'Unable to remove existing poster.' } Poster.save(imdbid, poster_path) return {'response': True, 'message': 'Metadata updated.'}
def from_file(filepath, imdbid=None): ''' Gets video metadata using hachoir.parser filepath (str): absolute path to movie file imdbid (str): imdb id # <optional - Default None> On failure can return empty dict Returns dict ''' logging.info('Gathering metadata for {}.'.format(filepath)) data = { 'title': None, 'year': None, 'resolution': None, 'rated': None, 'imdbid': imdbid, 'videocodec': None, 'audiocodec': None, 'releasegroup': None, 'source': None, 'quality': None, 'category': None, 'path': filepath, 'edition': [] } titledata = Metadata.parse_filename(filepath) data.update(titledata) filedata = Metadata.parse_media(filepath) data.update(filedata) if data.get('resolution'): if data['resolution'].upper() in ('4K', '1080P', '720P'): data['resolution'] = '{}-{}'.format(data['source'] or 'BluRay', data['resolution'].upper()) else: data['resolution'] = 'DVD-SD' if data.get('title') and not data.get('imdbid'): title_date = '{} {}'.format( data['title'], data['year']) if data.get('year') else data['title'] tmdbdata = TheMovieDatabase.search(title_date, single=True) if not tmdbdata: logging.warning( 'Unable to get data from TheMovieDB for {}'.format( data['title'])) return data tmdbdata = tmdbdata[0] tmdbid = tmdbdata.get('id') if not tmdbid: logging.warning( 'Unable to get data from TheMovieDB for {}'.format( data['imdbid'])) return data tmdbdata = tmdbdata = TheMovieDatabase._search_tmdbid(tmdbid) if tmdbdata: tmdbdata = tmdbdata[0] else: logging.warning('Unable to get data from TMDB for {}'.format( data['imdbid'])) return data data['year'] = tmdbdata['release_date'][:4] data.update(tmdbdata) if data.get('3d'): data['edition'].append('3D') data['edition'] = ' '.join(sorted(data['edition'])) return data
def sync(): ''' Syncs CSV lists from IMDB Does not return ''' movies_to_add = [] library = [i[2] for i in core.sql.quick_titles()] try: record = json.loads(core.sql.system('imdb_sync_record')) except Exception as e: record = {} for url in core.CONFIG['Search']['Watchlists']['imdbcsv']: if url[-6:] not in ('export', 'export/'): logging.warning('{} does not look like a valid imdb list'.format(url)) continue list_id = 'ls' + ''.join(filter(str.isdigit, url)) logging.info('Syncing rss IMDB watchlist {}'.format(list_id)) last_sync = datetime.strptime((record.get(list_id) or '2000-01-01'), date_format) try: csv_text = Url.open(url).text watchlist = [dict(i) for i in csv.DictReader(csv_text.splitlines())][::-1] record[list_id] = watchlist[0]['Created'] for movie in watchlist: pub_date = datetime.strptime(movie['Created'], date_format) if last_sync > pub_date: break imdbid = movie['Const'] if imdbid not in library and imdbid not in movies_to_add: logging.info('Found new watchlist movie {}'.format(movie['Title'])) movies_to_add.append(imdbid) except Exception as e: logging.warning('Unable to sync list {}'.format(list_id)) m = [] for imdbid in movies_to_add: movie = TheMovieDatabase._search_imdbid(imdbid) if not movie: logging.warning('{} not found on TheMovieDB. Cannot add.'.format(imdbid)) continue else: movie = movie[0] logging.info('Adding movie {} {} from IMDB watchlist.'.format(movie['title'], movie['imdbid'])) movie['year'] = movie['release_date'][:4] if movie.get('release_date') else 'N/A' movie['origin'] = 'IMDB' added = Manage.add_movie(movie) if added['response']: m.append((imdbid, movie['title'], movie['year'])) if core.CONFIG['Search']['searchafteradd']: for i in m: if i[2] != 'N/A': searcher.search(i[0], i[1], i[2], core.config.default_profile()) logging.info('Storing last synced date.') if core.sql.row_exists('SYSTEM', name='imdb_sync_record'): core.sql.update('SYSTEM', 'data', json.dumps(record), 'name', 'imdb_sync_record') else: core.sql.write('SYSTEM', {'data': json.dumps(record), 'name': 'imdb_sync_record'}) logging.info('IMDB sync complete.')