# Created on: 13.01.2017
import os
-import pickle
+from shutil import rmtree
from utils import noop
+try:
+ import cPickle as pickle
+except:
+ import pickle
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
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:
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, 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
+
+ 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}))
+ self.write_strm_file(path=filename, url=build_url({'action': 'play_video', 'video_id': video_id}))
+
+ def add_show (self, title, alt_title, episodes, build_url):
+ """Adds a show to the local db, generates & persists the strm files
- 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)
+ 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'], 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, 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
+
+ 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'
filepath = os.path.join(show_dir, filename)
if os.path.exists(filepath):
return
- self.write_strm_file(path=filepath, url=build_url({'action': 'play_video', 'video_id': video_id, 'pin': pin}))
+ self.write_strm_file(path=filepath, url=build_url({'action': 'play_video', 'video_id': video_id}))
+
+ def remove_movie (self, title, year):
+ """Removes the DB entry & the strm file for the movie given
- def remove_movie(self, title, year):
+ 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)
+ 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)
+ 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:
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']: