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 sync(): ''' Syncs all enabled Trakt lists and rss lists Gets list of movies from each enabled Trakt lists Adds missing movies to library as Waiting/Default Returns bool for success/failure ''' logging.info('Syncing Trakt lists.') success = True min_score = core.CONFIG['Search']['Watchlists']['traktscore'] length = core.CONFIG['Search']['Watchlists']['traktlength'] movies = [] if core.CONFIG['Search']['Watchlists']['traktrss']: sync_rss() for k, v in core.CONFIG['Search']['Watchlists']['Traktlists'].items(): if v is False: continue movies += [ i for i in get_list(k, min_score=min_score, length=length) if i not in movies ] library = [i['imdbid'] for i in core.sql.get_user_movies()] movies = [ i for i in movies if ((i['ids']['imdb'] not in library) and (i['ids']['imdb'] != 'N/A')) ] logging.info('Found {} new movies from Trakt lists.'.format(len(movies))) for i in movies: imdbid = i['ids']['imdb'] logging.info('Adding movie {} {} from Trakt'.format( i['title'], imdbid)) added = Manage.add_movie({ 'id': i['ids']['tmdb'], 'imdbid': i['ids']['imdb'], 'title': i['title'], 'origin': 'Trakt' }) try: if added['response'] and core.CONFIG['Search'][ 'searchafteradd'] and i['year'] != 'N/A': searcher.search(imdbid, i['title'], i['year'], core.config.default_profile()) except Exception as e: logging.error('Movie {} did not get added.'.format(i['title']), exc_info=False) return success
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 complete(self, data): ''' Post-processes a complete, successful download data (dict): all gathered file information and metadata data must include the following keys: path (str): path to downloaded item. Can be file or directory guid (str): nzb guid or torrent hash downloadid (str): download id from download client All params can be empty strings if unknown In SEARCHRESULTS marks guid as Finished In MARKEDRESULTS: Creates or updates entry for guid and optional guid with status=bad In MOVIES updates finished_score and finished_date Updates MOVIES status Checks to see if we found a movie file. If not, ends here. If Renamer is enabled, renames movie file according to core.CONFIG If Mover is enabled, moves file to location in core.CONFIG, then... If Clean Up enabled, deletes path after Mover finishes. Clean Up will not execute without Mover success. Returns dict of post-processing results ''' config = core.CONFIG['Postprocessing'] # dict we will json.dump and send back to downloader result = {} result['status'] = 'incomplete' result['data'] = data result['data']['finished_date'] = str(datetime.date.today()) result['tasks'] = {} # mark guid in both results tables logging.info('Marking guid as Finished.') data['guid'] = data['guid'].lower() guid_result = {} if data['guid'] and data.get('imdbid'): if Manage.searchresults(data['guid'], 'Finished', movie_info=data): guid_result['update_SEARCHRESULTS'] = True else: guid_result['update_SEARCHRESULTS'] = False if Manage.markedresults(data['guid'], 'Finished', imdbid=data['imdbid']): guid_result['update_MARKEDRESULTS'] = True else: guid_result['update_MARKEDRESULTS'] = False # create result entry for guid result['tasks'][data['guid']] = guid_result # if we have a guid2, do it all again if data.get('guid2') and data.get('imdbid'): logging.info('Marking guid2 as Finished.') guid2_result = {} if Manage.searchresults(data['guid2'], 'Finished', movie_info=data): guid2_result['update_SEARCHRESULTS'] = True else: guid2_result['update_SEARCHRESULTS'] = False if Manage.markedresults(data['guid2'], 'Finished', imdbid=data['imdbid']): guid2_result['update_MARKEDRESULTS'] = True else: guid2_result['update_MARKEDRESULTS'] = False # create result entry for guid2 result['tasks'][data['guid2']] = guid2_result # set movie status and add finished date/score if data.get('imdbid'): if core.sql.row_exists('MOVIES', imdbid=data['imdbid']): data['category'] = core.sql.get_movie_details( 'imdbid', data['imdbid'])['category'] else: logging.info('{} not found in library, adding now.'.format( data.get('title'))) data['status'] = 'Disabled' Manage.add_movie(data) logging.info('Setting MOVIE status.') r = Manage.movie_status(data['imdbid']) db_update = { 'finished_date': result['data']['finished_date'], 'finished_score': result['data'].get('finished_score') } core.sql.update_multiple_values('MOVIES', db_update, 'imdbid', data['imdbid']) else: logging.info( 'Imdbid not supplied or found, unable to update Movie status.') r = '' result['tasks']['update_movie_status'] = r data.update(Metadata.convert_to_db(data)) # mover. sets ['finished_file'] if config['moverenabled']: result['tasks']['mover'] = {'enabled': True} response = self.mover(data) if not response: result['tasks']['mover']['response'] = False else: data['finished_file'] = response result['tasks']['mover']['response'] = True else: logging.info('Mover disabled.') data['finished_file'] = data.get('original_file') result['tasks']['mover'] = {'enabled': False} # renamer if config['renamerenabled']: result['tasks']['renamer'] = {'enabled': True} new_file_name = self.renamer(data) if new_file_name == '': result['tasks']['renamer']['response'] = False else: path = os.path.split(data['finished_file'])[0] data['finished_file'] = os.path.join(path, new_file_name) result['tasks']['renamer']['response'] = True else: logging.info('Renamer disabled.') result['tasks']['renamer'] = {'enabled': False} if data.get('imdbid') and data['imdbid'] is not 'N/A': core.sql.update('MOVIES', 'finished_file', result['data'].get('finished_file'), 'imdbid', data['imdbid']) # Delete leftover dir. Skip if file links are enabled or if mover disabled/failed if config['cleanupenabled']: result['tasks']['cleanup'] = {'enabled': True} if config['movermethod'] in ('copy', 'hardlink', 'symboliclink'): logging.info( 'File copy or linking enabled -- skipping Cleanup.') result['tasks']['cleanup']['response'] = None return result elif os.path.isfile(data['path']): logging.info( 'Download is file, not directory -- skipping Cleanup.') result['tasks']['cleanup']['response'] = None return result # fail if mover disabled or failed if config['moverenabled'] is False or result['tasks']['mover'][ 'response'] is False: logging.info( 'Mover either disabled or failed -- skipping Cleanup.') result['tasks']['cleanup']['response'] = None else: if self.cleanup(data['path']): r = True else: r = False result['tasks']['cleanup']['response'] = r else: result['tasks']['cleanup'] = {'enabled': False} # all done! result['status'] = 'finished' return result
def sync_rss(): ''' Gets list of new movies in user's rss feed(s) Returns list of movie dicts ''' try: record = json.loads(core.sql.system('trakt_sync_record')) except Exception as e: record = {} for url in core.CONFIG['Search']['Watchlists']['traktrss'].split(','): list_id = url.split('.atom')[0].split('/')[-1] last_sync = record.get(list_id) or 'Sat, 01 Jan 2000 00:00:00' last_sync = datetime.datetime.strptime(last_sync, date_format) logging.info('Syncing Trakt RSS watchlist {}. Last sync: {}'.format(list_id, last_sync)) try: feed = Url.open(url).text feed = re.sub(r'xmlns=".*?"', r'', feed) root = ET.fromstring(feed) except Exception as e: logging.error('Trakt rss request:\n{}'.format(feed), exc_info=True) continue d = root.find('updated').text[:19] do = datetime.datetime.strptime(d, trakt_date_format) record[list_id] = datetime.datetime.strftime(do, date_format) for entry in root.iter('entry'): try: pub = datetime.datetime.strptime(entry.find('published').text[:19], trakt_date_format) if last_sync >= pub: break else: t = entry.find('title').text title = ' ('.join(t.split(' (')[:-1]) year = '' for i in t.split(' (')[-1]: if i.isdigit(): year += i year = int(year) logging.info('Searching TheMovieDatabase for {} {}'.format(title, year)) movie = Manage.tmdb._search_title('{} {}'.format(title, year))[0] if movie: movie['origin'] = 'Trakt' logging.info('Found new watchlist movie {} {}'.format(title, year)) r = Manage.add_movie(movie) if r['response'] and core.CONFIG['Search']['searchafteradd'] and movie['year'] != 'N/A': searcher.search(movie) else: logging.warning('Unable to find {} {} on TheMovieDatabase'.format(title, year)) except Exception as e: logging.error('Unable to parse Trakt RSS list entry.', exc_info=True) logging.info('Storing last synced date.') if core.sql.row_exists('SYSTEM', name='trakt_sync_record'): core.sql.update('SYSTEM', 'data', json.dumps(record), 'name', 'trakt_sync_record') else: core.sql.write('SYSTEM', {'data': json.dumps(record), 'name': 'trakt_sync_record'}) logging.info('Trakt RSS sync complete.')
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.')