diff --git a/couchpotato/core/media/movie/_base/main.py b/couchpotato/core/media/movie/_base/main.py index 8a88440c..d26936f1 100644 --- a/couchpotato/core/media/movie/_base/main.py +++ b/couchpotato/core/media/movie/_base/main.py @@ -259,10 +259,11 @@ class MovieBase(MovieTypeBase): results = q.all() for movie in results: - char = movie.library.titles[0].simple_title[0] - char = char if char in ascii_lowercase else '#' - if char not in chars: - chars += str(char) + if movie.library.titles: + char = movie.library.titles[0].simple_title[0] + char = char if char in ascii_lowercase else '#' + if char not in chars: + chars += str(char) db.expire_all() return ''.join(sorted(chars, key = str.lower)) diff --git a/couchpotato/core/media/show/_base/main.py b/couchpotato/core/media/show/_base/main.py index d7e0985a..e8afdc32 100644 --- a/couchpotato/core/media/show/_base/main.py +++ b/couchpotato/core/media/show/_base/main.py @@ -83,6 +83,7 @@ class ShowBase(MediaBase): 'movie': movie_dict, } + # XXX: Remove function and reference to it! def debug(self, identifier): """ XXX: This is only a hook for a breakpoint so we can test database stuff easily @@ -155,7 +156,7 @@ class ShowBase(MediaBase): episode['parent_identifier'] = season['identifier'] self.addToDatabase(params=episode, type = "episode") - self.debug(str(identifier)) # XXX: Remove TODO: Add Show(extend Library) convience options for db seasching + #self.debug(str(identifier)) # XXX: Remove DEBUG only return parent def addToDatabase(self, params = {}, type="show", force_readd = True, search_after = True, update_library = False, status_id = None): diff --git a/couchpotato/core/media/show/library/episode/main.py b/couchpotato/core/media/show/library/episode/main.py index 3d2323db..89da43d0 100644 --- a/couchpotato/core/media/show/library/episode/main.py +++ b/couchpotato/core/media/show/library/episode/main.py @@ -2,8 +2,9 @@ from couchpotato import get_session from couchpotato.core.event import addEvent, fireEventAsync, fireEvent from couchpotato.core.helpers.encoding import toUnicode, simplifyString from couchpotato.core.logger import CPLog -from couchpotato.core.settings.model import Library, LibraryTitle, File +from couchpotato.core.settings.model import EpisodeLibrary, SeasonLibrary, LibraryTitle, File from couchpotato.core.media._base.library import LibraryBase +from couchpotato.core.helpers.variable import tryInt from string import ascii_letters import time import traceback @@ -29,12 +30,12 @@ class EpisodeLibraryPlugin(LibraryBase): parent = None if parent_identifier: - parent = db.query(Library).filter_by(primary_provider = primary_provider, identifier = attrs.get('parent_identifier')).first() + parent = db.query(SeasonLibrary).filter_by(primary_provider = primary_provider, identifier = attrs.get('parent_identifier')).first() - l = db.query(Library).filter_by(type = type, identifier = attrs.get('identifier')).first() + l = db.query(EpisodeLibrary).filter_by(type = type, identifier = attrs.get('identifier')).first() if not l: status = fireEvent('status.get', 'needs_update', single = True) - l = Library( + l = EpisodeLibrary( type = type, primary_provider = primary_provider, year = attrs.get('year'), @@ -72,7 +73,7 @@ class EpisodeLibraryPlugin(LibraryBase): return db = get_session() - library = db.query(Library).filter_by(identifier = identifier).first() + library = db.query(EpisodeLibrary).filter_by(identifier = identifier).first() done_status = fireEvent('status.get', 'done', single = True) if library: @@ -82,7 +83,7 @@ class EpisodeLibraryPlugin(LibraryBase): # XXX: Fix to be pretty parent_identifier = None - if library.parent: + if library.parent is not None: parent_identifier = library.parent.identifier if library.status_id == done_status.get('id') and not force: @@ -111,6 +112,8 @@ class EpisodeLibraryPlugin(LibraryBase): library.tagline = toUnicode(info.get('tagline', '')) library.year = info.get('year', 0) library.status_id = done_status.get('id') + library.season_number = tryInt(info.get('seasonnumber', None)) + library.episode_number = tryInt(info.get('episodenumber', None)) library.info.update(info) db.commit() @@ -162,7 +165,7 @@ class EpisodeLibraryPlugin(LibraryBase): def updateReleaseDate(self, identifier): db = get_session() - library = db.query(Library).filter_by(identifier = identifier).first() + library = db.query(EpisodeLibrary).filter_by(identifier = identifier).first() if not library.info: library_dict = self.update(identifier, force = True) diff --git a/couchpotato/core/media/show/library/season/main.py b/couchpotato/core/media/show/library/season/main.py index 331adaf7..e8abf762 100644 --- a/couchpotato/core/media/show/library/season/main.py +++ b/couchpotato/core/media/show/library/season/main.py @@ -2,8 +2,9 @@ from couchpotato import get_session from couchpotato.core.event import addEvent, fireEventAsync, fireEvent from couchpotato.core.helpers.encoding import toUnicode, simplifyString from couchpotato.core.logger import CPLog -from couchpotato.core.settings.model import Library, LibraryTitle, File +from couchpotato.core.settings.model import SeasonLibrary, ShowLibrary, LibraryTitle, File from couchpotato.core.media._base.library import LibraryBase +from couchpotato.core.helpers.variable import tryInt from string import ascii_letters import time import traceback @@ -29,12 +30,12 @@ class SeasonLibraryPlugin(LibraryBase): parent = None if parent_identifier: - parent = db.query(Library).filter_by(primary_provider = primary_provider, identifier = attrs.get('parent_identifier')).first() + parent = db.query(ShowLibrary).filter_by(primary_provider = primary_provider, identifier = attrs.get('parent_identifier')).first() - l = db.query(Library).filter_by(type = type, identifier = attrs.get('identifier')).first() + l = db.query(SeasonLibrary).filter_by(type = type, identifier = attrs.get('identifier')).first() if not l: status = fireEvent('status.get', 'needs_update', single = True) - l = Library( + l = SeasonLibrary( type = type, primary_provider = primary_provider, year = attrs.get('year'), @@ -72,7 +73,7 @@ class SeasonLibraryPlugin(LibraryBase): return db = get_session() - library = db.query(Library).filter_by(identifier = identifier).first() + library = db.query(SeasonLibrary).filter_by(identifier = identifier).first() done_status = fireEvent('status.get', 'done', single = True) if library: @@ -82,7 +83,7 @@ class SeasonLibraryPlugin(LibraryBase): # XXX: Fix to be pretty parent_identifier = None - if library.parent: + if library.parent is not None: parent_identifier = library.parent.identifier if library.status_id == done_status.get('id') and not force: @@ -107,6 +108,7 @@ class SeasonLibraryPlugin(LibraryBase): library.tagline = toUnicode(info.get('tagline', '')) library.year = info.get('year', 0) library.status_id = done_status.get('id') + library.season_number = tryInt(info.get('seasonnumber', None)) library.info.update(info) db.commit() @@ -160,7 +162,7 @@ class SeasonLibraryPlugin(LibraryBase): def updateReleaseDate(self, identifier): db = get_session() - library = db.query(Library).filter_by(identifier = identifier).first() + library = db.query(SeasonLibrary).filter_by(identifier = identifier).first() if not library.info: library_dict = self.update(identifier, force = True) diff --git a/couchpotato/core/media/show/library/show/main.py b/couchpotato/core/media/show/library/show/main.py index df39ff8a..30079658 100644 --- a/couchpotato/core/media/show/library/show/main.py +++ b/couchpotato/core/media/show/library/show/main.py @@ -2,7 +2,7 @@ from couchpotato import get_session from couchpotato.core.event import addEvent, fireEventAsync, fireEvent from couchpotato.core.helpers.encoding import toUnicode, simplifyString from couchpotato.core.logger import CPLog -from couchpotato.core.settings.model import Library, LibraryTitle, File +from couchpotato.core.settings.model import ShowLibrary, LibraryTitle, File from couchpotato.core.media._base.library import LibraryBase from string import ascii_letters import time @@ -26,10 +26,10 @@ class ShowLibraryPlugin(LibraryBase): db = get_session() - l = db.query(Library).filter_by(type = type, identifier = attrs.get('identifier')).first() + l = db.query(ShowLibrary).filter_by(type = type, identifier = attrs.get('identifier')).first() if not l: status = fireEvent('status.get', 'needs_update', single = True) - l = Library( + l = ShowLibrary( type = type, primary_provider = primary_provider, year = attrs.get('year'), @@ -67,7 +67,7 @@ class ShowLibraryPlugin(LibraryBase): return db = get_session() - library = db.query(Library).filter_by(identifier = identifier).first() + library = db.query(ShowLibrary).filter_by(identifier = identifier).first() done_status = fireEvent('status.get', 'done', single = True) if library: @@ -93,7 +93,15 @@ class ShowLibraryPlugin(LibraryBase): library.tagline = toUnicode(info.get('tagline', '')) library.year = info.get('year', 0) library.status_id = done_status.get('id') + #-------------------------------------------------------------------------------------------------- + # XXX: TODO: implement logic to get proper values + library.airs_dayofweek = int(0) + library.airs_time = int(0) + library.last_updated = int(0) + library.show_status = toUnicode(info.get('status', '').lower()) + #-------------------------------------------------------------------------------------------------- library.info.update(info) + db.commit() # Titles @@ -144,7 +152,7 @@ class ShowLibraryPlugin(LibraryBase): def updateReleaseDate(self, identifier): db = get_session() - library = db.query(Library).filter_by(identifier = identifier).first() + library = db.query(ShowLibrary).filter_by(identifier = identifier).first() if not library.info: library_dict = self.update(identifier, force = True) diff --git a/couchpotato/core/settings/model.py b/couchpotato/core/settings/model.py index 16c0190a..0213a428 100644 --- a/couchpotato/core/settings/model.py +++ b/couchpotato/core/settings/model.py @@ -6,6 +6,8 @@ from elixir.relationships import ManyToMany, OneToMany, ManyToOne from sqlalchemy.ext.mutable import Mutable from sqlalchemy.types import Integer, Unicode, UnicodeText, Boolean, String, \ TypeDecorator, Float, BLOB +from UserDict import DictMixin +from collections import OrderedDict import json import time @@ -71,12 +73,13 @@ class MutableDict(Mutable, dict): MutableDict.associate_with(JsonType) + class Movie(Entity): """Movie Resource a movie could have multiple releases The files belonging to the movie object are global for the whole movie such as trailers, nfo, thumbnails""" - type = Field(String(10), default="movie", index=True) + type = Field(String(10), default = "movie", index = True) last_edit = Field(Integer, default = lambda: int(time.time()), index = True) library = ManyToOne('Library', cascade = 'delete, delete-orphan', single_parent = True) @@ -89,10 +92,11 @@ class Movie(Entity): class Library(Entity): """""" + using_options(inheritance = 'multi') # For Movies, CPS uses three: omdbapi (no prio !?), tmdb (prio 2) and couchpotatoapi (prio 1) - type = Field(String(10), default="movie", index=True) - primary_provider = Field(String(10), default="imdb", index=True) + type = Field(String(10), default = "movie", index = True) + primary_provider = Field(String(10), default = "imdb", index = True) year = Field(Integer) identifier = Field(String(40), index = True) @@ -109,6 +113,85 @@ class Library(Entity): children = OneToMany('Library') +class ShowLibrary(Library, DictMixin): + using_options(inheritance = 'multi') + + last_updated = Field(Integer, index = True) + show_status = Field(String(10), index = True) + airs_dayofweek = Field(Integer, index = True) + airs_time = Field(Integer, index = True) + + def getSeasons(self): + data = OrderedDict() + for c in self.children: + data[c.season_number] = c + return data + + def getEpisodes(self, season_number): + data = OrderedDict() + for c in self.children[season_number].children: + data[c.episode_number] = c + return data + + # Read access to season by number: library[1] for season 1 + data = {} + def __getitem__(self, key): + if not self.data: + self.setData() + if key in self.data: + return self.data[key] + if hasattr(self.__class__, "__missing__"): + return self.__class__.__missing__(self, key) + raise KeyError(key) + def get(self, key, failobj = None): + if key not in self: + return failobj + return self[key] + def keys(self): return self.data.keys() + def setData(self): + for c in self.children: + self.data[c.season_number] = c + + +class SeasonLibrary(Library, DictMixin): + using_options(inheritance = 'multi') + + season_number = Field(Integer, index = True) + last_updated = Field(Integer, index = True) + + def getEpisodes(self): + data = OrderedDict() + for c in self.children: + data[c.episode_number] = c + return data + + # Read access episode by number: library[1][4] for season 1, episode 4 + data = {} + def __getitem__(self, key): + if not self.data: + self.setData() + if key in self.data: + return self.data[key] + if hasattr(self.__class__, "__missing__"): + return self.__class__.__missing__(self, key) + raise KeyError(key) + def get(self, key, failobj = None): + if key not in self: + return failobj + return self[key] + def keys(self): return self.data.keys() + def setData(self): + for c in self.children: + self.data[c.episode_number] = c + + +class EpisodeLibrary(Library): + using_options(inheritance = 'multi') + + season_number = Field(Integer, index = True) + episode_number = Field(Integer, index = True) + + class LibraryTitle(Entity): """""" using_options(order_by = '-default')