X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=resources%2Flib%2FLibrary.py;fp=resources%2Flib%2FLibrary.py;h=8c1d841217d786f23ae27af9abcd8fe9e7b62c74;hb=b0976bc1b439d881585d37a79e3ea60fbeefa306;hp=e7e4f5be2307863f1b6d1069b8e6847dc65552fe;hpb=07c987a9bb20d1766404669fa945b98764b45c97;p=plugin.video.netflix.git diff --git a/resources/lib/Library.py b/resources/lib/Library.py index e7e4f5b..8c1d841 100644 --- a/resources/lib/Library.py +++ b/resources/lib/Library.py @@ -4,25 +4,30 @@ # Created on: 13.01.2017 import os -import pickle +import shutil +try: + import cPickle as pickle +except: + import pickle from utils import noop class Library: - """Exports Netflix shows & movies to a local library folder (Not yet ready)""" + """Exports Netflix shows & movies to a local library folder""" series_label = 'shows' + """str: Label to identify shows""" + movies_label = 'movies' - db_filename = 'lib.ndb' + """str: Label to identify movies""" + db_filename = 'lib.ndb' + """str: (File)Name of the store for the database dump that contains all shows/movies added to the library""" - def __init__ (self, base_url, root_folder, library_settings, log_fn=noop): + def __init__ (self, root_folder, library_settings, log_fn=noop): """Takes the instances & configuration options needed to drive the plugin Parameters ---------- - base_url : :obj:`str` - Plugin base url - root_folder : :obj:`str` Cookie location @@ -35,44 +40,71 @@ class Library: log_fn : :obj:`fn` optional log function """ - self.base_url = base_url self.base_data_path = root_folder self.enable_custom_library_folder = library_settings['enablelibraryfolder'] self.custom_library_folder = library_settings['customlibraryfolder'] - self.log = log_fn self.db_filepath = os.path.join(self.base_data_path, self.db_filename) + self.log = log_fn # check for local library folder & set up the paths - if self.enable_custom_library_folder != 'true': - self.movie_path = os.path.join(self.base_data_path, self.series_label) - self.tvshow_path = os.path.join(self.base_data_path, self.movies_label) - else: - self.movie_path = os.path.join(self.custom_library_folder, self.movies_label) - self.tvshow_path = os.path.join(self.custom_library_folder, self.series_label) + lib_path = self.base_data_path if self.enable_custom_library_folder != 'true' else self.custom_library_folder + self.movie_path = os.path.join(lib_path, self.movies_label) + self.tvshow_path = os.path.join(lib_path, self.series_label) + # check if we need to setup the base folder structure & do so if needed self.setup_local_netflix_library(source={ self.movies_label: self.movie_path, self.series_label: self.tvshow_path }) + # load the local db self.db = self._load_local_db(filename=self.db_filepath) def setup_local_netflix_library (self, source): + """Sets up the basic directories + + Parameters + ---------- + source : :obj:`dict` of :obj:`str` + Dicitionary with directories to be created + """ for label in source: if not os.path.exists(source[label]): os.makedirs(source[label]) def write_strm_file(self, path, url): + """Writes the stream file that Kodi can use to integrate it into the DB + + Parameters + ---------- + path : :obj:`str` + Filepath of the file to be created + + url : :obj:`str` + Stream url + """ with open(path, 'w+') as f: f.write(url) f.close() def _load_local_db (self, filename): + """Loads the local db file and parses it, creates one if not existent + + Parameters + ---------- + filename : :obj:`str` + Filepath of db file + + Returns + ------- + :obj:`dict` + Parsed contents of the db file + """ # if the db doesn't exist, create it if not os.path.isfile(filename): data = {self.movies_label: {}, self.series_label: {}} self.log('Setup local library DB') - self._update_local_db(filename=filename, data=data) + self._update_local_db(filename=filename, db=data) return data with open(filename) as f: @@ -82,75 +114,216 @@ class Library: else: return {} - def _update_local_db (self, filename, data): + def _update_local_db (self, filename, db): + """Updates the local db file with new data + + Parameters + ---------- + filename : :obj:`str` + Filepath of db file + + db : :obj:`dict` + Database contents + + Returns + ------- + bool + Update has been successfully executed + """ if not os.path.isdir(os.path.dirname(filename)): return False with open(filename, 'w') as f: f.truncate() - pickle.dump(data, f) + pickle.dump(db, f) return True def movie_exists (self, title, year): + """Checks if a movie is already present in the local DB + + Parameters + ---------- + title : :obj:`str` + Title of the movie + + year : :obj:`int` + Release year of the movie + + Returns + ------- + bool + Movie exists in DB + """ movie_meta = '%s (%d)' % (title, year) return movie_meta in self.db[self.movies_label] - def show_exists (self, title, year): - show_meta = '%s (%d)' % (title, year) + def show_exists (self, title): + """Checks if a show is present in the local DB + + Parameters + ---------- + title : :obj:`str` + Title of the show + + Returns + ------- + bool + Show exists in DB + """ + show_meta = '%s' % (title) return show_meta in self.db[self.series_label] - def season_exists (self, title, year, season): - if self.show_exists() == False: + def season_exists (self, title, season): + """Checks if a season is present in the local DB + + Parameters + ---------- + title : :obj:`str` + Title of the show + + season : :obj:`int` + Season sequence number + + Returns + ------- + bool + Season of show exists in DB + """ + if self.show_exists(title) == False: return False - show_meta = '%s (%d)' % (title, year) - show_entry = self.db[self.series_label][show_meta] + show_entry = self.db[self.series_label][title] return season in show_entry['seasons'] - def episode_exists (self, title, year, season, episode): - if self.show_exists() == False: + def episode_exists (self, title, season, episode): + """Checks if an episode if a show is present in the local DB + + Parameters + ---------- + title : :obj:`str` + Title of the show + + season : :obj:`int` + Season sequence number + + episode : :obj:`int` + Episode sequence number + + Returns + ------- + bool + Episode of show exists in DB + """ + if self.show_exists(title) == False: return False - show_meta = '%s (%d)' % (title, year) - show_entry = self.db[self.series_label][show_meta] + show_entry = self.db[self.series_label][title] episode_entry = 'S%02dE%02d' % (season, episode) return episode_entry in show_entry['episodes'] - def add_movie(self, title, year, video_id, pin, build_url): + def add_movie (self, title, alt_title, year, video_id, pin, build_url): + """Adds a movie to the local db, generates & persists the strm file + + Parameters + ---------- + title : :obj:`str` + Title of the show + + alt_title : :obj:`str` + Alternative title given by the user + + year : :obj:`int` + Release year of the show + + video_id : :obj:`str` + ID of the video to be played + + pin : bool + Needs adult pin + + build_url : :obj:`fn` + Function to generate the stream url + """ + movie_meta = '%s (%d)' % (title, year) - dirname = os.path.join(self.movie_path, movie_meta) + folder = alt_title + dirname = os.path.join(self.movie_path, folder) filename = os.path.join(dirname, movie_meta + '.strm') if os.path.exists(filename): return if not os.path.exists(dirname): os.makedirs(dirname) if self.movie_exists(title=title, year=year) == False: - self.db[self.movies_label][movie_meta] = True + self.db[self.movies_label][movie_meta] = {'alt_title': alt_title} self._update_local_db(filename=self.db_filepath, db=self.db) self.write_strm_file(path=filename, url=build_url({'action': 'play_video', 'video_id': video_id, 'pin': pin})) - def add_show(self, title, year, episodes, build_url): - show_meta = '%s (%d)' % (title, year) - show_dir = os.path.join(self.tvshow_path, show_meta) + def add_show (self, title, alt_title, episodes, build_url): + """Adds a show to the local db, generates & persists the strm files + + Note: Can also used to store complete seasons or single episodes, it all depends on + what is present in the episodes dictionary + + Parameters + ---------- + title : :obj:`str` + Title of the show + + alt_title : :obj:`str` + Alternative title given by the user + + episodes : :obj:`dict` of :obj:`dict` + Episodes that need to be added + + build_url : :obj:`fn` + Function to generate the stream url + """ + show_meta = '%s' % (title) + folder = alt_title + show_dir = os.path.join(self.tvshow_path, folder) if not os.path.exists(show_dir): os.makedirs(show_dir) - if self.show_exists(title, year) == False: - self.db[self.series_label][show_meta] = {'seasons': [], 'episodes': []} - for episode_id in episodes: - episode = episodes[episode_id] - self._add_episode(show_dir=show_dir, show_meta=show_meta, title=title, year=year, season=episode['season'], episode=episode['idx'], video_id=episode['id'], pin=episode['pin'], build_url=build_url) + if self.show_exists(title) == False: + self.db[self.series_label][show_meta] = {'seasons': [], 'episodes': [], 'alt_title': alt_title} + for episode in episodes: + self._add_episode(show_dir=show_dir, title=title, season=episode['season'], episode=episode['episode'], video_id=episode['id'], pin=episode['pin'], build_url=build_url) self._update_local_db(filename=self.db_filepath, db=self.db) return show_dir - def _add_episode(self, title, year, show_dir, show_meta, season, episode, video_id, pin, build_url): + def _add_episode (self, title, show_dir, season, episode, video_id, pin, build_url): + """Adds a single episode to the local DB, generates & persists the strm file + + Parameters + ---------- + title : :obj:`str` + Title of the show + + show_dir : :obj:`str` + Directory that holds the stream files for that show + + season : :obj:`int` + Season sequence number + + episode : :obj:`int` + Episode sequence number + + video_id : :obj:`str` + ID of the video to be played + + pin : bool + Needs adult pin + + build_url : :obj:`fn` + Function to generate the stream url + """ season = int(season) episode = int(episode) # add season - if self.season_exists(title=title, year=year, season=season) == False: - self.db[self.series_label][show_meta]['seasons'].append(season) + if self.season_exists(title=title, season=season) == False: + self.db[self.series_label][title]['seasons'].append(season) # add episode episode_meta = 'S%02dE%02d' % (season, episode) - if self.episode_exists(title=title, year=year, season=season, episode=episode) == False: - self.db[self.series_label][show_meta]['episodes'].append(episode_meta) + if self.episode_exists(title=title, season=season, episode=episode) == False: + self.db[self.series_label][title]['episodes'].append(episode_meta) # create strm file filename = episode_meta + '.strm' @@ -159,36 +332,79 @@ class Library: return self.write_strm_file(path=filepath, url=build_url({'action': 'play_video', 'video_id': video_id, 'pin': pin})) - def remove_movie(self, title, year): + def remove_movie (self, title, year): + """Removes the DB entry & the strm file for the movie given + + Parameters + ---------- + title : :obj:`str` + Title of the movie + + year : :obj:`int` + Release year of the movie + + Returns + ------- + bool + Delete successfull + """ movie_meta = '%s (%d)' % (title, year) + folder = self.db[self.movies_label][movie_meta]['alt_title'] del self.db[self.movies_label][movie_meta] self._update_local_db(filename=self.db_filepath, db=self.db) - dirname = os.path.join(self.movie_path, movie_meta) + dirname = os.path.join(self.movie_path, folder) if os.path.exists(dirname): - os.rmtree(dirname) + shutil.rmtree(dirname) return True return False - def remove_show(self, title, year): - show_meta = '%s (%d)' % (title, year) - del self.db[self.series_label][show_meta] + def remove_show (self, title): + """Removes the DB entry & the strm files for the show given + + Parameters + ---------- + title : :obj:`str` + Title of the show + + Returns + ------- + bool + Delete successfull + """ + folder = self.db[self.series_label][title]['alt_title'] + del self.db[self.series_label][title] self._update_local_db(filename=self.db_filepath, db=self.db) - show_dir = os.path.join(self.tvshow_path, show_meta) + show_dir = os.path.join(self.tvshow_path, folder) if os.path.exists(show_dir): - os.rmtree(show_dir) + shutil.rmtree(show_dir) return True return False - def remove_season(self, title, year, season): + def remove_season (self, title, season): + """Removes the DB entry & the strm files for a season of a show given + + Parameters + ---------- + title : :obj:`str` + Title of the show + + season : :obj:`int` + Season sequence number + + Returns + ------- + bool + Delete successfull + """ season = int(season) season_list = [] episodes_list = [] - show_meta = '%s (%d)' % (title, year) + show_meta = '%s' % (title) for season_entry in self.db[self.series_label][show_meta]['seasons']: if season_entry != season: season_list.append(season_entry) self.db[self.series_label][show_meta]['seasons'] = season_list - show_dir = os.path.join(self.tvshow_path, show_meta) + show_dir = os.path.join(self.tvshow_path, self.db[self.series_label][show_meta]['alt_title']) if os.path.exists(show_dir): show_files = [f for f in os.listdir(show_dir) if os.path.isfile(os.path.join(show_dir, f))] for filename in show_files: @@ -200,11 +416,29 @@ class Library: self._update_local_db(filename=self.db_filepath, db=self.db) return True - def remove_episode(self, title, year, season, episode): + def remove_episode (self, title, season, episode): + """Removes the DB entry & the strm files for an episode of a show given + + Parameters + ---------- + title : :obj:`str` + Title of the show + + season : :obj:`int` + Season sequence number + + episode : :obj:`int` + Episode sequence number + + Returns + ------- + bool + Delete successfull + """ episodes_list = [] - show_meta = '%s (%d)' % (title, year) + show_meta = '%s' % (title) episode_meta = 'S%02dE%02d' % (season, episode) - show_dir = os.path.join(self.tvshow_path, show_meta) + show_dir = os.path.join(self.tvshow_path, self.db[self.series_label][show_meta]['alt_title']) if os.path.exists(os.path.join(show_dir, episode_meta + '.strm')): os.remove(os.path.join(show_dir, episode_meta + '.strm')) for episode_entry in self.db[self.series_label][show_meta]['episodes']: