def withStatus(self, status, types=None, with_doc=True): db = get_db() if types and not isinstance(types, (list, tuple)): types = [types] status = list(status if isinstance(status, (list, tuple)) else [status]) for s in status: for ms in db.get_many('media_status', s): if with_doc: try: doc = db.get('id', ms['_id']) if types and doc.get('type') not in types: continue yield doc except (RecordDeleted, RecordNotFound): log.debug('Record not found, skipping: %s', ms['_id']) except (ValueError, EOFError): fire_event('database.delete_corrupted', ms.get('_id'), traceback_error=traceback.format_exc(0)) else: yield ms
def updateReleaseDate(self, media_id): """ Update release_date (eta) info only @param media_id: document id @return: dict, with dates dvd, theater, bluray, expires """ try: db = get_db() media = db.get('id', media_id) if not media.get('info'): media = self.update(media_id) dates = media.get('info', {}).get('release_date') else: dates = media.get('info').get('release_date') if dates and (dates.get('expires', 0) < time.time() or dates.get('expires', 0) > time.time() + (604800 * 4)) or not dates: dates = fireEvent('movie.info.release_date', identifier = getIdentifier(media), merge = True) media['info'].update({'release_date': dates}) db.update(media) return dates except: log.error('Failed updating release dates: %s', traceback.format_exc()) return {}
def delete(self, id = None, **kwargs): try: db = get_db() success = False message = '' try: c = db.get('id', id) db.delete(c) # Force defaults on all empty category movies self.removeFromMovie(id) success = True except: message = log.error('Failed deleting category: %s', traceback.format_exc()) return { 'success': success, 'message': message } except: log.error('Failed: %s', traceback.format_exc()) return { 'success': False }
def get(self, media_id): db = get_db() imdb_id = getImdb(str(media_id)) media = None if imdb_id: media = db.get('media', 'imdb-%s' % imdb_id, with_doc=True)['doc'] else: media = db.get('id', media_id) if media: # Attach category try: media['category'] = db.get('id', media.get('category_id')) except: pass media['releases'] = fireEvent('release.for_media', media['_id'], single=True) return media
def manualDownload(self, id = None, **kwargs): db = get_db() try: release = db.get('id', id) item = release['info'] movie = db.get('id', release['media_id']) fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Snatching "%s"' % item['name']) # Get matching provider provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True) if item.get('protocol') != 'torrent_magnet': item['download'] = provider.loginDownload if provider.urls.get('login') else provider.download success = self.download(data = item, media = movie, manual = True) if success: fireEvent('notify.frontend', type = 'release.manual_download', data = True, message = 'Successfully snatched "%s"' % item['name']) return { 'success': success == True } except: log.error('Couldn\'t find release with id: %s: %s', (id, traceback.format_exc())) return { 'success': False }
def clean(self, release_id): try: db = get_db() rel = db.get('id', release_id) raw_files = rel.get('files') if len(raw_files) == 0: self.delete(rel['_id']) else: files = {} for file_type in raw_files: for release_file in raw_files.get(file_type, []): if os.path.isfile(sp(release_file)): if file_type not in files: files[file_type] = [] files[file_type].append(release_file) rel['files'] = files db.update(rel) return True except: log.error('Failed: %s', traceback.format_exc()) return False
def forceDefaults(self): db = get_db() # Fill qualities and profiles if they are empty somehow.. if db.count(db.all, "profile") == 0: if db.count(db.all, "quality") == 0: fireEvent("quality.fill", single=True) self.fill() # Get all active movies without profile try: medias = fireEvent("media.with_status", "active", single=True) profile_ids = [x.get("_id") for x in self.all()] default_id = profile_ids[0] for media in medias: if media.get("profile_id") not in profile_ids: media["profile_id"] = default_id db.update(media) except: log.error("Failed: %s", traceback.format_exc())
def get(self, media_id): try: db = get_db() imdb_id = getImdb(str(media_id)) if imdb_id: media = db.get('media', 'imdb-%s' % imdb_id, with_doc = True)['doc'] else: media = db.get('id', media_id) if media: # Attach category try: media['category'] = db.get('id', media.get('category_id')) except: pass media['releases'] = fireEvent('release.for_media', media['_id'], single = True) return media except (RecordNotFound, RecordDeleted): log.error('Media with id "%s" not found', media_id) except: raise
def notify(self, message = '', data = None, listener = None): if not data: data = {} try: db = get_db() data['notification_type'] = listener if listener else 'unknown' n = { '_t': 'notification', 'time': int(time.time()), 'message': toUnicode(message) } if data.get('sticky'): n['sticky'] = True if data.get('important'): n['important'] = True db.insert(n) self.frontend(type = listener, data = n) return True except: log.error('Failed notify: %s', traceback.format_exc())
def withStatus(self, status, types = None, with_doc = True): db = get_db() if types and not isinstance(types, (list, tuple)): types = [types] status = list(status if isinstance(status, (list, tuple)) else [status]) for s in status: for ms in db.get_many('media_status', s): if with_doc: try: doc = db.get('id', ms['_id']) if types and doc.get('type') not in types: continue yield doc except (RecordDeleted, RecordNotFound): log.debug('Record not found, skipping: %s', ms['_id']) except (ValueError, EOFError): fireEvent('database.delete_corrupted', ms.get('_id'), traceback_error = traceback.format_exc(0)) else: yield ms
def restatus(self, media_id): try: db = get_db() m = db.get('id', media_id) previous_status = m['status'] log.debug('Changing status for %s', getTitle(m)) if not m['profile_id']: m['status'] = 'done' else: move_to_wanted = True profile = db.get('id', m['profile_id']) media_releases = fireEvent('release.for_media', m['_id'], single = True) for q_identifier in profile['qualities']: index = profile['qualities'].index(q_identifier) for release in media_releases: if q_identifier == release['quality'] and (release.get('status') == 'done' and profile['finish'][index]): move_to_wanted = False m['status'] = 'active' if move_to_wanted else 'done' # Only update when status has changed if previous_status != m['status']: db.update(m) return True except: log.error('Failed restatus: %s', traceback.format_exc())
def get(self, media_id): try: db = get_db() imdb_id = getImdb(str(media_id)) if imdb_id: media = db.get("media", "imdb-%s" % imdb_id, with_doc=True)["doc"] else: media = db.get("id", media_id) if media: # Attach category try: media["category"] = db.get("id", media.get("category_id")) except: pass media["releases"] = fireEvent("release.for_media", media["_id"], single=True) return media except (RecordNotFound, RecordDeleted): log.error('Media with id "%s" not found', media_id) except: raise
def notify(self, message='', data=None, listener=None): if not data: data = {} try: db = get_db() data['notification_type'] = listener if listener else 'unknown' n = { '_t': 'notification', 'time': int(time.time()), 'message': toUnicode(message) } if data.get('sticky'): n['sticky'] = True if data.get('important'): n['important'] = True db.insert(n) self.frontend(type=listener, data=n) return True except: log.error('Failed notify: %s', traceback.format_exc())
def notify(self, message='', data=None, listener=None): if not data: data = {} n = { '_t': 'notification', 'time': int(time.time()), } try: db = get_db() n['message'] = to_unicode(message) if data.get('sticky'): n['sticky'] = True if data.get('important'): n['important'] = True db.insert(n) self.frontend(type=listener, data=n) return True except: log.error('Failed notify "%s": %s', (n, traceback.format_exc()))
def cleanDone(self): log.debug('Removing releases from dashboard') now = time.time() week = 604800 db = get_db() # Get (and remove) parentless releases releases = db.all('release', with_doc=True) media_exist = [] for release in releases: if release.get('key') in media_exist: continue try: db.get('id', release.get('key')) media_exist.append(release.get('key')) try: if release['doc'].get('status') == 'ignore': release['doc']['status'] = 'ignored' db.update(release['doc']) except: log.error('Failed fixing mis-status tag: %s', traceback.format_exc()) except RecordDeleted: db.delete(release['doc']) log.debug('Deleted orphaned release: %s', release['doc']) except: log.debug('Failed cleaning up orphaned releases: %s', traceback.format_exc()) del media_exist # get movies last_edit more than a week ago medias = fireEvent('media.with_status', ['done', 'active'], single=True) for media in medias: if media.get('last_edit', 0) > (now - week): continue for rel in fireEvent('release.for_media', media['_id'], single=True): # Remove all available releases if rel['status'] in ['available']: self.delete(rel['_id']) # Set all snatched and downloaded releases to ignored to make sure they are ignored when re-adding the media elif rel['status'] in ['snatched', 'downloaded']: self.updateStatus(rel['_id'], status='ignored') if 'recent' in media.get('tags', []): fireEvent('media.untag', media.get('_id'), 'recent', single=True)
def get(self, media_id): try: db = get_db() imdb_id = get_imdb(str(media_id)) if imdb_id: media = db.get('media', 'imdb-%s' % imdb_id, with_doc=True)['doc'] else: media = db.get('id', media_id) if media: # Attach category try: media['category'] = db.get('id', media.get('category_id')) except: pass media['releases'] = fire_event('release.for_media', media['_id'], single=True) return media except (RecordNotFound, RecordDeleted): log.error('Media with id "%s" not found', media_id) except: raise
def updateSuggestionCache(self, ignore_imdb = None, limit = 6, ignored = None, seen = None): # Combine with previous suggestion_cache cached_suggestion = self.getCache('suggestion_cached') or [] new_suggestions = [] ignored = [] if not ignored else ignored seen = [] if not seen else seen if ignore_imdb: suggested_imdbs = [] for cs in cached_suggestion: if cs.get('imdb') != ignore_imdb and cs.get('imdb') not in suggested_imdbs: suggested_imdbs.append(cs.get('imdb')) new_suggestions.append(cs) # Get new results and add them if len(new_suggestions) - 1 < limit: db = get_db() active_movies = fireEvent('media.with_status', ['active', 'done'], single = True) movies = [getIdentifier(x) for x in active_movies] movies.extend(seen) ignored.extend([x.get('imdb') for x in cached_suggestion]) suggestions = fireEvent('movie.suggest', movies = movies, ignore = removeDuplicate(ignored), single = True) if suggestions: new_suggestions.extend(suggestions) self.setCache('suggestion_cached', new_suggestions, timeout = 3024000) return new_suggestions
def forMedia(self, media_id): db = get_db() raw_releases = db.get_many('release', media_id) releases = [] for r in raw_releases: try: doc = db.get('id', r.get('_id')) releases.append(doc) except RecordDeleted: pass except (ValueError, EOFError): fire_event('database.delete_corrupted', r.get('_id'), traceback_error=traceback.format_exc(0)) releases = sorted(releases, key=lambda k: k.get('info', {}).get('score', 0), reverse=True) # Sort based on preferred search method download_preference = self.conf('preferred_method', section='searcher') if download_preference != 'both': releases = sorted( releases, key=lambda k: k.get('info', {}).get('protocol', '')[:3], reverse=(download_preference == 'torrent')) return releases or []
def updateStatus(self, release_id, status = None): if not status: return False try: db = get_db() rel = db.get('id', release_id) if rel and rel.get('status') != status: release_name = None if rel.get('files'): for file_type in rel.get('files', {}): if file_type == 'movie': for release_file in rel['files'][file_type]: release_name = os.path.basename(release_file) break if not release_name and rel.get('info'): release_name = rel['info'].get('name') #update status in Db log.debug('Marking release %s as %s', (release_name, status)) rel['status'] = status rel['last_edit'] = int(time.time()) db.update(rel) #Update all movie info as there is no release update function fireEvent('notify.frontend', type = 'release.update_status', data = rel) return True except: log.error('Failed: %s', traceback.format_exc()) return False
def updateReleaseDate(self, media_id): """ Update release_date (eta) info only @param media_id: document id @return: dict, with dates dvd, theater, bluray, expires """ try: db = get_db() media = db.get("id", media_id) if not media.get("info"): media = self.update(media_id) dates = media.get("info", {}).get("release_date") else: dates = media.get("info").get("release_date") if ( dates and (dates.get("expires", 0) < time.time() or dates.get("expires", 0) > time.time() + (604800 * 4)) or not dates ): dates = fireEvent("movie.info.release_date", identifier=getIdentifier(media), merge=True) media["info"].update({"release_date": dates}) db.update(media) return dates except: log.error("Failed updating release dates: %s", traceback.format_exc()) return {}
def fill(self): try: db = get_db() order = 0 for q in self.qualities: db.insert({ '_t': 'quality', 'order': order, 'identifier': q.get('identifier'), 'size_min': tryInt(q.get('size')[0]), 'size_max': tryInt(q.get('size')[1]), }) log.info('Creating profile: %s', q.get('label')) db.insert({ '_t': 'profile', 'order': order + 20, # Make sure it goes behind other profiles 'core': True, 'qualities': [q.get('identifier')], 'label': toUnicode(q.get('label')), 'finish': [True], 'wait_for': [0], }) order += 1 return True except: log.error('Failed: %s', traceback.format_exc()) return False
def createFromSearch(self, search_results, media, quality): try: db = get_db() found_releases = [] is_3d = False try: is_3d = quality['custom']['3d'] except: pass for rel in search_results: rel_identifier = md5(rel['url']) found_releases.append(rel_identifier) release = { '_t': 'release', 'identifier': rel_identifier, 'media_id': media.get('_id'), 'quality': quality.get('identifier'), 'is_3d': is_3d, 'status': rel.get('status', 'available'), 'last_edit': int(time.time()), 'info': {} } # Add downloader info if provided try: release['download_info'] = rel['download_info'] del rel['download_info'] except: pass try: rls = db.get('release_identifier', rel_identifier, with_doc = True)['doc'] except: rls = db.insert(release) rls.update(release) # Update info, but filter out functions for info in rel: try: if not isinstance(rel[info], (str, unicode, int, long, float)): continue rls['info'][info] = toUnicode(rel[info]) if isinstance(rel[info], (str, unicode)) else rel[info] except: log.debug('Couldn\'t add %s to ReleaseInfo: %s', (info, traceback.format_exc())) db.update(rls) # Update release in search_results rel['status'] = rls.get('status') return found_releases except: log.error('Failed: %s', traceback.format_exc()) return []
def delete(self, id = None, **kwargs): try: db = get_db() success = False message = '' try: p = db.get('id', id) db.delete(p) # Force defaults on all empty profile movies self.forceDefaults() success = True except Exception as e: message = log.error('Failed deleting Profile: %s', e) return { 'success': success, 'message': message } except: log.error('Failed: %s', traceback.format_exc()) return { 'success': False }
def forceDefaults(self): db = get_db() # Fill qualities and profiles if they are empty somehow.. if db.count(db.all, 'profile') == 0: if db.count(db.all, 'quality') == 0: fireEvent('quality.fill', single = True) self.fill() # Get all active movies without profile try: medias = fireEvent('media.with_status', 'active', single = True) profile_ids = [x.get('_id') for x in self.all()] default_id = profile_ids[0] for media in medias: if media.get('profile_id') not in profile_ids: media['profile_id'] = default_id db.update(media) except: log.error('Failed: %s', traceback.format_exc())
def updateStatus(self, release_id, status=None): if not status: return False try: db = get_db() rel = db.get('id', release_id) if rel and rel.get('status') != status: release_name = rel['info'].get('name') if rel.get('files'): for file_type in rel.get('files', {}): if file_type == 'movie': for release_file in rel['files'][file_type]: release_name = os.path.basename(release_file) break #update status in Db log.debug('Marking release %s as %s', (release_name, status)) rel['status'] = status rel['last_edit'] = int(time.time()) db.update(rel) #Update all movie info as there is no release update function fireEvent('notify.frontend', type='release.update_status', data=rel) return True except: log.error('Failed: %s', traceback.format_exc()) return False
def forceDefaults(self): db = get_db() # Fill qualities and profiles if they are empty somehow.. if db.count(db.all, 'profile') == 0: if db.count(db.all, 'quality') == 0: fireEvent('quality.fill', single=True) self.fill() # Get all active movies without profile try: medias = fireEvent('media.with_status', 'active', single=True) profile_ids = [x.get('_id') for x in self.all()] default_id = profile_ids[0] for media in medias: if media.get('profile_id') not in profile_ids: media['profile_id'] = default_id db.update(media) except: log.error('Failed: %s', traceback.format_exc())
def forMedia(self, media_id): db = get_db() raw_releases = db.get_many('release', media_id) releases = [] for r in raw_releases: try: doc = db.get('id', r.get('_id')) releases.append(doc) except RecordDeleted: pass releases = sorted(releases, key=lambda k: k.get('info', {}).get('score', 0), reverse=True) # Sort based on preferred search method download_preference = self.conf('preferred_method', section='searcher') if download_preference != 'both': releases = sorted( releases, key=lambda k: k.get('info', {}).get('protocol', '')[:3], reverse=(download_preference == 'torrent')) return releases
def getDB(self): if not self.db: from couchpotato import get_db self.db = get_db() return self.db
def treeView(self, media_id, **kwargs): db = get_db() media = db.get('id', media_id) return { 'result': fireEvent('library.tree', media, single = True) }
def save(self, **kwargs): try: db = get_db() category = { '_t': 'category', 'order': kwargs.get('order', 999), 'label': toUnicode(kwargs.get('label', '')), 'ignored': toUnicode(kwargs.get('ignored', '')), 'preferred': toUnicode(kwargs.get('preferred', '')), 'required': toUnicode(kwargs.get('required', '')), 'destination': toUnicode(kwargs.get('destination', '')), } try: c = db.get('id', kwargs.get('id')) category['order'] = c.get('order', category['order']) c.update(category) db.update(c) except: c = db.insert(category) c.update(category) return {'success': True, 'category': c} except: log.error('Failed: %s', traceback.format_exc()) return {'success': False, 'category': None}
def delete(self, media_id, delete_from=None): try: db = get_db() media = db.get('id', media_id) if media: deleted = False media_releases = fireEvent('release.for_media', media['_id'], single=True) if delete_from == 'all': # Delete connected releases for release in media_releases: db.delete(release) db.delete(media) deleted = True else: total_releases = len(media_releases) total_deleted = 0 new_media_status = None for release in media_releases: if delete_from in ['wanted', 'snatched', 'late']: if release.get('status') != 'done': db.delete(release) total_deleted += 1 new_media_status = 'done' elif delete_from == 'manage': if release.get('status') == 'done': db.delete(release) total_deleted += 1 if (total_releases == total_deleted and media['status'] != 'active') or ( delete_from == 'wanted' and media['status'] == 'active') or (not new_media_status and delete_from == 'late'): db.delete(media) deleted = True elif new_media_status: media['status'] = new_media_status db.update(media) else: fireEvent('media.restatus', media.get('_id'), single=True) if deleted: fireEvent('notify.frontend', type='media.deleted', data=media) except: log.error('Failed deleting media: %s', traceback.format_exc()) return True
def updateReleaseDate(self, media_id): """ Update release_date (eta) info only @param media_id: document id @return: dict, with dates dvd, theater, bluray, expires """ try: db = get_db() media = db.get('id', media_id) if not media.get('info'): media = self.update(media_id) dates = media.get('info', {}).get('release_date') else: dates = media.get('info').get('release_date') if dates and (dates.get('expires', 0) < time.time() or dates.get('expires', 0) > time.time() + (604800 * 4)) or not dates: dates = fireEvent('movie.info.release_date', identifier=getIdentifier(media), merge=True) media['info'].update({'release_date': dates}) db.update(media) # Workaround for a bug in https://api.couchpota.to/eta/<imdbid> # CP uses this API to retrieve movie release dates. The API always returns # "{dvd":0,"theater":0,"bluray":false,"expires":<some-bogus-time-about-11-days-in-the future>} # Because of this, CP will never auto-snatch movies because it can't establish a valid ETA # This workaround tries to extract a valid release-date from the 'released' field of the media info # which seems to be valid but seems to vary in format. # If it fails to convert the date, it uses the expires value. if dates['theater'] == 0: released = media.get('info').get('released') formats = ['%d %b %Y', '%Y-%m-%d'] for format in formats: try: dates['theater'] = int( time.mktime( datetime.strptime(released, format).timetuple())) log.info('Extracted release date for "%s" from "%s"', (media['title'], released)) except ValueError: continue if dates['theater'] == 0: dates['theater'] = dates['expires'] log.info('Using expired date as release date for "%s": %d', (media['title'], dates['expires'])) return dates except: log.error('Failed updating release dates: %s', traceback.format_exc()) return {}
def restatus(self, media_id, tag_recent=True, allowed_restatus=None): try: db = get_db() m = db.get('id', media_id) previous_status = m['status'] log.debug('Changing status for %s', get_title(m)) if not m['profile_id']: m['status'] = 'done' else: m['status'] = 'active' try: profile = db.get('id', m['profile_id']) media_releases = fire_event('release.for_media', m['_id'], single=True) done_releases = [ release for release in media_releases if release.get('status') == 'done' ] if done_releases: # Check if we are finished with the media for release in done_releases: if fire_event('quality.isfinish', { 'identifier': release['quality'], 'is_3d': release.get('is_3d', False) }, profile, timedelta(seconds=time.time() - release['last_edit']).days, single=True): m['status'] = 'done' break elif previous_status == 'done': m['status'] = 'done' except RecordNotFound: log.debug('Failed restatus, keeping previous: %s', traceback.format_exc()) m['status'] = previous_status # Only update when status has changed if previous_status != m['status'] and ( not allowed_restatus or m['status'] in allowed_restatus): db.update(m) # Tag media as recent if tag_recent: self.tag(media_id, 'recent', update_edited=True) return m['status'] except: log.error('Failed restatus: %s', traceback.format_exc())
def fill(self): try: db = get_db() profiles = [{ 'label': 'Best', 'qualities': ['720p', '1080p', 'brrip', 'dvdrip'] }, { 'label': 'HD', 'qualities': ['720p', '1080p'] }, { 'label': 'SD', 'qualities': ['dvdrip', 'dvdr'] }, { 'label': 'Prefer 3D HD', 'qualities': ['1080p', '720p', '720p', '1080p'], '3d': [True, True] }, { 'label': '3D HD', 'qualities': ['1080p', '720p'], '3d': [True, True] }, { 'label': 'UHD 4K', 'qualities': ['720p', '1080p', '2160p'] }] # Create default quality profile order = 0 for profile in profiles: log.info('Creating default profile: %s', profile.get('label')) pro = { '_t': 'profile', 'label': toUnicode(profile.get('label')), 'order': order, 'qualities': profile.get('qualities'), 'minimum_score': 1, 'finish': [], 'wait_for': [], 'stop_after': [], '3d': [] } threed = profile.get('3d', []) for q in profile.get('qualities'): pro['finish'].append(True) pro['wait_for'].append(0) pro['stop_after'].append(0) pro['3d'].append(threed.pop() if threed else False) db.insert(pro) order += 1 return True except: log.error('Failed: %s', traceback.format_exc()) return False
def clean(self): try: db = get_db() for n in db.all('notification', with_doc = True): if n['doc'].get('time', 0) <= (int(time.time()) - 2419200): db.delete(n['doc']) except: log.error('Failed cleaning notification: %s', traceback.format_exc())
def clean(self): try: db = get_db() for n in db.all("notification", with_doc=True): if n["doc"].get("time", 0) <= (int(time.time()) - 2419200): db.delete(n["doc"]) except: log.error("Failed cleaning notification: %s", traceback.format_exc())
def root(self, media): db = get_db() cur = media while cur and cur.get('parent_id'): cur = db.get('id', cur['parent_id']) return cur
def update(self, media_id = None, identifier = None, default_title = None, extended = False): """ Update movie information inside media['doc']['info'] @param media_id: document id @param default_title: default title, if empty, use first one or existing one @param extended: update with extended info (parses more info, actors, images from some info providers) @return: dict, with media """ if self.shuttingDown(): return lock_key = 'media.get.%s' % media_id if media_id else identifier self.acquireLock(lock_key) media = {} try: db = get_db() if media_id: media = db.get('id', media_id) else: media = db.get('media', 'imdb-%s' % identifier, with_doc = True)['doc'] info = fireEvent('movie.info', merge = True, extended = extended, identifier = getIdentifier(media)) # Don't need those here try: del info['in_wanted'] except: pass try: del info['in_library'] except: pass if not info or len(info) == 0: log.error('Could not update, no movie info to work with: %s', identifier) return False # Update basic info media['info'] = info titles = info.get('titles', []) log.debug('Adding titles: %s', titles) # Define default title if default_title or media.get('title') == 'UNKNOWN' or len(media.get('title', '')) == 0: media['title'] = self.getDefaultTitle(info, default_title) # Files image_urls = info.get('images', []) self.getPoster(media, image_urls) db.update(media) except: log.error('Failed update media: %s', traceback.format_exc()) self.releaseLock(lock_key) return media
def update(self, media_id = None, identifier = None, default_title = None, extended = False): """ Update movie information inside media['doc']['info'] @param media_id: document id @param default_title: default title, if empty, use first one or existing one @param extended: update with extended info (parses more info, actors, images from some info providers) @return: dict, with media """ if self.shuttingDown(): return lock_key = 'media.get.%s' % media_id if media_id else identifier self.acquireLock(lock_key) media = {} try: db = get_db() if media_id: media = db.get('id', media_id) else: media = db.get('media', 'imdb-%s' % identifier, with_doc = True)['doc'] info = fire_event('movie.info', merge=True, extended=extended, identifier=get_identifier(media)) # Don't need those here try: del info['in_wanted'] except: pass try: del info['in_library'] except: pass if not info or len(info) == 0: log.error('Could not update, no movie info to work with: %s', identifier) return False # Update basic info media['info'] = info titles = info.get('titles', []) log.debug('Adding titles: %s', titles) # Define default title if default_title or media.get('title') == 'UNKNOWN' or len(media.get('title', '')) == 0: media['title'] = self.getDefaultTitle(info, default_title) # Files image_urls = info.get('images', []) self.getPoster(media, image_urls) db.update(media) except: log.error('Failed update media: %s', traceback.format_exc()) self.releaseLock(lock_key) return media
def availableChars(self, types=None, status=None, release_status=None): db = get_db() # Make a list from string if status and not isinstance(status, (list, tuple)): status = [status] if release_status and not isinstance(release_status, (list, tuple)): release_status = [release_status] if types and not isinstance(types, (list, tuple)): types = [types] # query media ids if types: all_media_ids = set() for media_type in types: all_media_ids = all_media_ids.union( set([ x['_id'] for x in db.get_many('media_by_type', media_type) ])) else: all_media_ids = set([x['_id'] for x in db.all('media')]) media_ids = all_media_ids filter_by = {} # Filter on movie status if status and len(status) > 0: filter_by['media_status'] = set() for media_status in fire_event('media.with_status', status, with_doc=False, single=True): filter_by['media_status'].add(media_status.get('_id')) # Filter on release status if release_status and len(release_status) > 0: filter_by['release_status'] = set() for release_status in fire_event('release.with_status', release_status, with_doc=False, single=True): filter_by['release_status'].add(release_status.get('media_id')) # Filter by combining ids for x in filter_by: media_ids = [n for n in media_ids if n in filter_by[x]] chars = set() for x in db.all('media_startswith'): if x['_id'] in media_ids: chars.add(x['key']) if len(chars) == 27: break return list(chars)
def onComplete(): try: db = get_db() media = fireEvent('media.get', media_id, single = True) event_name = '%s.searcher.single' % media.get('type') fireEventAsync(event_name, media, on_complete = self.createNotifyFront(media_id)) except: log.error('Failed creating onComplete: %s', traceback.format_exc())
def delete(self, media_id, delete_from = None): try: db = get_db() media = db.get('id', media_id) if media: deleted = False media_releases = fireEvent('release.for_media', media['_id'], single = True) if delete_from == 'all': # Delete connected releases for release in media_releases: db.delete(release) db.delete(media) deleted = True else: total_releases = len(media_releases) total_deleted = 0 new_media_status = None for release in media_releases: if delete_from in ['wanted', 'snatched', 'late']: if release.get('status') != 'done': db.delete(release) total_deleted += 1 new_media_status = 'done' elif delete_from == 'manage': if release.get('status') == 'done' or media.get('status') == 'done': db.delete(release) total_deleted += 1 if (total_releases == total_deleted) or (total_releases == 0 and not new_media_status) or (not new_media_status and delete_from == 'late'): db.delete(media) deleted = True elif new_media_status: media['status'] = new_media_status # Remove profile (no use for in manage) if new_media_status == 'done': media['profile_id'] = None db.update(media) fireEvent('media.untag', media['_id'], 'recent', single = True) else: fireEvent('media.restatus', media.get('_id'), single = True) if deleted: fireEvent('notify.frontend', type = 'media.deleted', data = media) except: log.error('Failed deleting media: %s', traceback.format_exc()) return True
def withStatus(self, status, with_doc = True): db = get_db() status = list(status if isinstance(status, (list, tuple)) else [status]) for s in status: for ms in db.get_many('media_status', s, with_doc = with_doc): yield ms['doc'] if with_doc else ms
def automationView(self, force_update=False, **kwargs): db = get_db() charts = fire_event('automation.get_chart_list', merge=True) ignored = split_string(Env.prop('charts_ignore', default='')) # Create a list the movie/list.js can use for chart in charts: medias = [] for media in chart.get('list', []): identifier = media.get('imdb') if identifier in ignored: continue try: try: in_library = db.get('media', 'imdb-%s' % identifier) if in_library: continue except RecordNotFound: pass except: pass # Cache poster posters = media.get('images', {}).get('poster', []) poster = [x for x in posters if 'tmdb' in x] posters = poster if len(poster) > 0 else posters cached_poster = fire_event( 'file.download', url=posters[0], single=True) if len(posters) > 0 else False files = { 'image_poster': [cached_poster] } if cached_poster else {} medias.append({ 'status': 'chart', 'title': get_title(media), 'type': 'movie', 'info': media, 'files': files, 'identifiers': { 'imdb': identifier } }) chart['list'] = medias return { 'success': True, 'count': len(charts), 'charts': charts, 'ignored': ignored, }
def delete(self, media_id, delete_from=None): try: db = get_db() media = db.get("id", media_id) if media: deleted = False media_releases = fireEvent("release.for_media", media["_id"], single=True) if delete_from == "all": # Delete connected releases for release in media_releases: db.delete(release) db.delete(media) deleted = True else: total_releases = len(media_releases) total_deleted = 0 new_media_status = None for release in media_releases: if delete_from in ["wanted", "snatched", "late"]: if release.get("status") != "done": db.delete(release) total_deleted += 1 new_media_status = "done" elif delete_from == "manage": if release.get("status") == "done" or media.get("status") == "done": db.delete(release) total_deleted += 1 if ( (total_releases == total_deleted) or (total_releases == 0 and not new_media_status) or (not new_media_status and delete_from == "late") ): db.delete(media) deleted = True elif new_media_status: media["status"] = new_media_status db.update(media) fireEvent("media.untag", media["_id"], "recent", single=True) else: fireEvent("media.restatus", media.get("_id"), single=True) if deleted: fireEvent("notify.frontend", type="media.deleted", data=media) except: log.error("Failed deleting media: %s", traceback.format_exc()) return True
def single(self, identifier = ''): db = get_db() quality_dict = {} quality = db.get('quality', identifier, with_doc = True)['doc'] if quality: quality_dict = mergeDicts(self.getQuality(quality['identifier']), quality) return quality_dict
def databaseSetup(self): from couchpotato import get_db db = get_db() try: db.add_index(PropertyIndex(db.path, 'property')) except: self.log.debug('Index for properties already exists') db.edit_index(PropertyIndex(db.path, 'property'))
def withStatus(self, status, with_doc=True): db = get_db() status = list(status if isinstance(status, (list, tuple)) else [status]) for s in status: for ms in db.get_many('release_status', s, with_doc=with_doc): yield ms['doc'] if with_doc else ms
def cleanupFaults(self): medias = fireEvent('media.with_status', 'ignored', single = True) or [] db = get_db() for media in medias: try: media['status'] = 'done' db.update(media) except: pass