Rewire llibrary sync, part 4
This commit is contained in:
parent
35a25a7f15
commit
23dada9fe5
12 changed files with 613 additions and 263 deletions
|
@ -1,6 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
from .movies import Movie
|
||||
from .tvshows import Show, Season, Episode
|
||||
|
||||
# Note: always use same order of URL arguments, NOT urlencode:
|
||||
|
|
249
resources/lib/itemtypes/movies.py
Normal file
249
resources/lib/itemtypes/movies.py
Normal file
|
@ -0,0 +1,249 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
from logging import getLogger
|
||||
|
||||
from .common import ItemBase
|
||||
from ..plex_api import API
|
||||
from .. import state, variables as v, plex_functions as PF
|
||||
|
||||
LOG = getLogger('PLEX.movies')
|
||||
|
||||
|
||||
class Movie(ItemBase):
|
||||
"""
|
||||
Used for plex library-type movies
|
||||
"""
|
||||
def add_update(self, xml, section_name=None, section_id=None,
|
||||
children=None):
|
||||
"""
|
||||
Process single movie
|
||||
"""
|
||||
api = API(xml)
|
||||
update_item = True
|
||||
plex_id = api.plex_id()
|
||||
LOG.debug('Adding movie with plex_id %s', plex_id)
|
||||
# Cannot parse XML, abort
|
||||
if not plex_id:
|
||||
LOG.error('Cannot parse XML data for movie: %s', xml.attrib)
|
||||
return
|
||||
movie = self.plex_db.getItem_byId(plex_id)
|
||||
try:
|
||||
kodi_id = movie[0]
|
||||
old_kodi_fileid = movie[1]
|
||||
kodi_pathid = movie[2]
|
||||
except TypeError:
|
||||
update_item = False
|
||||
self.kodicursor.execute('SELECT COALESCE(MAX(idMovie), 0) FROM movie')
|
||||
kodi_id = self.kodicursor.fetchone()[0] + 1
|
||||
else:
|
||||
# Verification the item is still in Kodi
|
||||
self.kodicursor.execute('SELECT idMovie FROM movie WHERE idMovie = ? LIMIT 1',
|
||||
(kodi_id, ))
|
||||
try:
|
||||
self.kodicursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# item is not found, let's recreate it.
|
||||
update_item = False
|
||||
LOG.info("kodi_id: %s missing from Kodi, repairing the entry.",
|
||||
kodi_id)
|
||||
|
||||
userdata = api.userdata()
|
||||
playcount = userdata['PlayCount']
|
||||
dateplayed = userdata['LastPlayedDate']
|
||||
resume = userdata['Resume']
|
||||
runtime = userdata['Runtime']
|
||||
rating = userdata['Rating']
|
||||
|
||||
title = api.title()
|
||||
people = api.people()
|
||||
genres = api.genre_list()
|
||||
collections = api.collection_list()
|
||||
countries = api.country_list()
|
||||
studios = api.music_studio_list()
|
||||
|
||||
# GET THE FILE AND PATH #####
|
||||
do_indirect = not state.DIRECT_PATHS
|
||||
if state.DIRECT_PATHS:
|
||||
# Direct paths is set the Kodi way
|
||||
playurl = api.file_path(force_first_media=True)
|
||||
if playurl is None:
|
||||
# Something went wrong, trying to use non-direct paths
|
||||
do_indirect = True
|
||||
else:
|
||||
playurl = api.validate_playurl(playurl, api.plex_type())
|
||||
if playurl is None:
|
||||
return False
|
||||
if '\\' in playurl:
|
||||
# Local path
|
||||
filename = playurl.rsplit("\\", 1)[1]
|
||||
else:
|
||||
# Network share
|
||||
filename = playurl.rsplit("/", 1)[1]
|
||||
path = playurl.replace(filename, "")
|
||||
kodi_pathid = self.kodi_db.add_video_path(path,
|
||||
content='movies',
|
||||
scraper='metadata.local')
|
||||
if do_indirect:
|
||||
# Set plugin path and media flags using real filename
|
||||
filename = api.file_name(force_first_media=True)
|
||||
path = 'plugin://%s.movies/' % v.ADDON_ID
|
||||
filename = ('%s?plex_id=%s&plex_type=%s&mode=play&filename=%s'
|
||||
% (path, plex_id, v.PLEX_TYPE_MOVIE, filename))
|
||||
playurl = filename
|
||||
kodi_pathid = self.kodi_db.get_path(path)
|
||||
|
||||
file_id = self.kodi_db.add_file(filename,
|
||||
kodi_pathid,
|
||||
api.date_created())
|
||||
|
||||
if update_item:
|
||||
LOG.info('UPDATE movie plex_id: %s - Title: %s',
|
||||
plex_id, api.title())
|
||||
if file_id != old_kodi_fileid:
|
||||
self.kodi_db.remove_file(old_kodi_fileid)
|
||||
rating_id = self.kodi_db.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodi_db.update_ratings(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
"default",
|
||||
rating,
|
||||
api.votecount(),
|
||||
rating_id)
|
||||
# update new uniqueid Kodi 17
|
||||
if api.provider('imdb') is not None:
|
||||
uniqueid = self.kodi_db.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodi_db.update_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.provider('imdb'),
|
||||
"imdb",
|
||||
uniqueid)
|
||||
else:
|
||||
self.kodi_db.remove_uniqueid(kodi_id, v.KODI_TYPE_MOVIE)
|
||||
uniqueid = -1
|
||||
else:
|
||||
LOG.info("ADD movie plex_id: %s - Title: %s", plex_id, title)
|
||||
rating_id = self.kodi_db.get_ratingid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodi_db.add_ratings(rating_id,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
"default",
|
||||
rating,
|
||||
api.votecount())
|
||||
if api.provider('imdb') is not None:
|
||||
uniqueid = self.kodi_db.get_uniqueid(kodi_id,
|
||||
v.KODI_TYPE_MOVIE)
|
||||
self.kodi_db.add_uniqueid(uniqueid,
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.provider('imdb'),
|
||||
"imdb")
|
||||
else:
|
||||
uniqueid = -1
|
||||
|
||||
# Update Kodi's main entry
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO movie(idMovie, idFile, c00, c01, c02, c03,
|
||||
c04, c05, c06, c07, c09, c10, c11, c12, c14, c15, c16,
|
||||
c18, c19, c21, c22, c23, premiered, userrating)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,
|
||||
?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.kodicursor.execute(
|
||||
query,
|
||||
(kodi_id, file_id, title, api.plot(), api.shortplot(),
|
||||
api.tagline(), api.votecount(), rating_id,
|
||||
api.list_to_string(people['Writer']), api.year(),
|
||||
uniqueid, api.sorttitle(), runtime, api.content_rating(),
|
||||
api.list_to_string(genres), api.list_to_string(people['Director']),
|
||||
title, api.list_to_string(studios), api.trailer(),
|
||||
api.list_to_string(countries), playurl, kodi_pathid,
|
||||
api.premiere_date(), userdata['UserRating']))
|
||||
|
||||
self.kodi_db.modify_countries(kodi_id, v.KODI_TYPE_MOVIE, countries)
|
||||
self.kodi_db.modify_people(kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
api.people_list())
|
||||
self.kodi_db.modify_genres(kodi_id, v.KODI_TYPE_MOVIE, genres)
|
||||
self.artwork.modify_artwork(api.artwork(),
|
||||
kodi_id,
|
||||
v.KODI_TYPE_MOVIE,
|
||||
self.kodicursor)
|
||||
self.kodi_db.modify_streams(file_id, api.mediastreams(), runtime)
|
||||
self.kodi_db.modify_studios(kodi_id, v.KODI_TYPE_MOVIE, studios)
|
||||
tags = [section_name]
|
||||
if collections:
|
||||
collections_match = api.collections_match()
|
||||
for plex_set_id, set_name in collections:
|
||||
tags.append(set_name)
|
||||
# Add any sets from Plex collection tags
|
||||
kodi_set_id = self.kodi_db.create_collection(set_name)
|
||||
self.kodi_db.assign_collection(kodi_set_id, kodi_id)
|
||||
for index, plex_id in collections_match:
|
||||
# Get Plex artwork for collections - a pain
|
||||
if index == plex_set_id:
|
||||
set_xml = PF.GetPlexMetadata(plex_id)
|
||||
try:
|
||||
set_xml.attrib
|
||||
except AttributeError:
|
||||
LOG.error('Could not get set metadata %s', plex_id)
|
||||
continue
|
||||
set_api = API(set_xml[0])
|
||||
self.artwork.modify_artwork(set_api.artwork(),
|
||||
kodi_set_id,
|
||||
v.KODI_TYPE_SET,
|
||||
self.kodicursor)
|
||||
break
|
||||
self.kodi_db.modify_tags(kodi_id, v.KODI_TYPE_MOVIE, tags)
|
||||
# Process playstate
|
||||
self.kodi_db.set_resume(file_id,
|
||||
resume,
|
||||
runtime,
|
||||
playcount,
|
||||
dateplayed,
|
||||
v.PLEX_TYPE_MOVIE)
|
||||
self.plex_db.add_movie(plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
kodi_id=kodi_id,
|
||||
kodi_fileid=file_id,
|
||||
kodi_pathid=kodi_pathid,
|
||||
last_sync=self.last_sync)
|
||||
|
||||
def remove(self, plex_id):
|
||||
"""
|
||||
Remove a movie with all references and all orphaned associated entries
|
||||
from the Kodi DB
|
||||
"""
|
||||
movie = self.plex_db.movie(plex_id)
|
||||
try:
|
||||
kodi_id = movie[3]
|
||||
file_id = movie[4]
|
||||
kodi_type = v.KODI_TYPE_MOVIE
|
||||
LOG.debug('Removing movie with plex_id %s, kodi_id: %s',
|
||||
plex_id, kodi_id)
|
||||
except TypeError:
|
||||
LOG.error('Movie with plex_id %s not found - cannot delete',
|
||||
plex_id)
|
||||
return
|
||||
# Remove the plex reference
|
||||
self.plex_db.remove(plex_id, v.PLEX_TYPE_MOVIE)
|
||||
# Remove artwork
|
||||
self.artwork.delete_artwork(kodi_id, kodi_type, self.self.kodicursor)
|
||||
set_id = self.kodi_db.get_set_id(kodi_id)
|
||||
self.kodi_db.modify_countries(kodi_id, kodi_type)
|
||||
self.kodi_db.modify_people(kodi_id, kodi_type)
|
||||
self.kodi_db.modify_genres(kodi_id, kodi_type)
|
||||
self.kodi_db.modify_studios(kodi_id, kodi_type)
|
||||
self.kodi_db.modify_tags(kodi_id, kodi_type)
|
||||
# Delete kodi movie and file
|
||||
self.kodi_db.remove_file(file_id)
|
||||
self.self.kodicursor.execute('DELETE FROM movie WHERE idMovie = ?',
|
||||
(kodi_id,))
|
||||
if set_id:
|
||||
self.kodi_db.delete_possibly_empty_set(set_id)
|
||||
self.kodi_db.remove_uniqueid(kodi_id, kodi_type)
|
||||
self.kodi_db.remove_ratings(kodi_id, kodi_type)
|
||||
LOG.debug('Deleted movie %s from kodi database', plex_id)
|
|
@ -203,8 +203,8 @@ class Show(ItemBase, TvShowMixin):
|
|||
toppathid = None
|
||||
|
||||
kodi_pathid = self.kodi_db.add_video_path(path,
|
||||
date_added=api.date_created(),
|
||||
id_parent_path=toppathid)
|
||||
date_added=api.date_created(),
|
||||
id_parent_path=toppathid)
|
||||
# UPDATE THE TVSHOW #####
|
||||
if update_item:
|
||||
LOG.info("UPDATE tvshow plex_id: %s - Title: %s",
|
||||
|
@ -248,8 +248,6 @@ class Show(ItemBase, TvShowMixin):
|
|||
# Link the path
|
||||
query = "INSERT INTO tvshowlinkpath(idShow, idPath) values (?, ?)"
|
||||
self.kodicursor.execute(query, (kodi_id, kodi_pathid))
|
||||
# Create the reference in plex table
|
||||
|
||||
rating_id = self.kodi_db.get_ratingid(kodi_id, v.KODI_TYPE_SHOW)
|
||||
self.kodi_db.add_ratings(rating_id,
|
||||
kodi_id,
|
||||
|
@ -293,13 +291,12 @@ class Show(ItemBase, TvShowMixin):
|
|||
tags = [section_name]
|
||||
tags.extend([i for _, i in api.collection_list()])
|
||||
self.kodi_db.modify_tags(kodi_id, v.KODI_TYPE_SHOW, tags)
|
||||
self.plex_db.add_reference(plex_type=v.PLEX_TYPE_SHOW,
|
||||
plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
kodi_id=kodi_id,
|
||||
kodi_pathid=kodi_pathid,
|
||||
last_sync=self.last_sync)
|
||||
self.plex_db.add_show(plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
kodi_id=kodi_id,
|
||||
kodi_pathid=kodi_pathid,
|
||||
last_sync=self.last_sync)
|
||||
|
||||
|
||||
class Season(ItemBase, TvShowMixin):
|
||||
|
@ -328,14 +325,13 @@ class Season(ItemBase, TvShowMixin):
|
|||
kodi_id,
|
||||
v.KODI_TYPE_SEASON,
|
||||
self.kodicursor)
|
||||
self.plex_db.add_reference(plex_type=v.PLEX_TYPE_SEASON,
|
||||
plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
show_id=show_id,
|
||||
parent_id=parent_id,
|
||||
kodi_id=kodi_id,
|
||||
last_sync=self.last_sync)
|
||||
self.plex_db.add_season(plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
show_id=show_id,
|
||||
parent_id=parent_id,
|
||||
kodi_id=kodi_id,
|
||||
last_sync=self.last_sync)
|
||||
|
||||
|
||||
class Episode(ItemBase, TvShowMixin):
|
||||
|
@ -535,15 +531,14 @@ class Episode(ItemBase, TvShowMixin):
|
|||
userdata['PlayCount'],
|
||||
userdata['LastPlayedDate'],
|
||||
None) # Do send None - 2nd entry
|
||||
self.plex_db.add_reference(plex_type=v.PLEX_TYPE_EPISODE,
|
||||
plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
show_id=show_id,
|
||||
grandparent_id=grandparent_id,
|
||||
season_id=season_id,
|
||||
parent_id=parent_id,
|
||||
kodi_id=kodi_id,
|
||||
kodi_fileid=kodi_fileid,
|
||||
kodi_pathid=kodi_pathid,
|
||||
last_sync=self.last_sync)
|
||||
self.plex_db.add_episode(plex_id=plex_id,
|
||||
checksum=api.checksum(),
|
||||
section_id=section_id,
|
||||
show_id=show_id,
|
||||
grandparent_id=grandparent_id,
|
||||
season_id=season_id,
|
||||
parent_id=parent_id,
|
||||
kodi_id=kodi_id,
|
||||
kodi_fileid=kodi_fileid,
|
||||
kodi_pathid=kodi_pathid,
|
||||
last_sync=self.last_sync)
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
# Dummy file to make this directory a package.
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
from .full_sync import start, PLAYLIST_SYNC_ENABLED
|
||||
|
|
|
@ -4,21 +4,25 @@ from __future__ import absolute_import, division, unicode_literals
|
|||
from logging import getLogger
|
||||
import time
|
||||
|
||||
from . import common, process_metadata, sections
|
||||
from .get_metadata import GetMetadataTask
|
||||
from .. import utils, backgroundthread, playlists, variables as v, state
|
||||
from . import common, process_metadata, sections
|
||||
from .. import utils, backgroundthread, variables as v, state
|
||||
from .. import plex_functions as PF, itemtypes
|
||||
from ..plex_db import PlexDB
|
||||
|
||||
|
||||
if (v.PLATFORM != 'Microsoft UWP' and
|
||||
utils.settings('enablePlaylistSync') == 'true'):
|
||||
# Xbox cannot use watchdog, a dependency for PKC playlist features
|
||||
from .. import playlists
|
||||
PLAYLIST_SYNC_ENABLED = True
|
||||
else:
|
||||
PLAYLIST_SYNC_ENABLED = False
|
||||
|
||||
|
||||
LOG = getLogger('PLEX.library_sync.full_sync')
|
||||
|
||||
|
||||
def start(repair, callback):
|
||||
"""
|
||||
"""
|
||||
# backgroundthread.BGThreader.addTask(FullSync().setup(repair, callback))
|
||||
FullSync(repair, callback).start()
|
||||
|
||||
|
||||
class FullSync(backgroundthread.KillableThread, common.libsync_mixin):
|
||||
def __init__(self, repair, callback):
|
||||
"""
|
||||
|
@ -99,6 +103,7 @@ class FullSync(backgroundthread.KillableThread, common.libsync_mixin):
|
|||
except RuntimeError:
|
||||
LOG.error('Could not entirely process section %s', section)
|
||||
continue
|
||||
self.queue.join()
|
||||
|
||||
LOG.debug('Finished processing %ss', self.plex_type)
|
||||
return True
|
||||
|
@ -110,50 +115,55 @@ class FullSync(backgroundthread.KillableThread, common.libsync_mixin):
|
|||
(v.PLEX_TYPE_MOVIE, itemtypes.Movie, False),
|
||||
(v.PLEX_TYPE_SHOW, itemtypes.Show, False),
|
||||
(v.PLEX_TYPE_SEASON, itemtypes.Season, False),
|
||||
(v.PLEX_TYPE_EPISODE, itemtypes.Episode, False),
|
||||
(v.PLEX_TYPE_ARTIST, itemtypes.Artist, False),
|
||||
(v.PLEX_TYPE_ALBUM, itemtypes.Album, True),
|
||||
(v.PLEX_TYPE_SONG, itemtypes.Song, False),
|
||||
(v.PLEX_TYPE_EPISODE, itemtypes.Episode, False)
|
||||
]
|
||||
if state.ENABLE_MUSIC:
|
||||
kinds.extend(
|
||||
(v.PLEX_TYPE_ARTIST, itemtypes.Artist, False),
|
||||
(v.PLEX_TYPE_ALBUM, itemtypes.Album, True),
|
||||
(v.PLEX_TYPE_SONG, itemtypes.Song, False))
|
||||
for kind in kinds:
|
||||
# Setup our variables
|
||||
self.plex_type = kind[0]
|
||||
self.context = kind[1]
|
||||
self.get_children = kind[2]
|
||||
# Now do the heavy lifting
|
||||
if self.isCanceled() or not self.process_kind():
|
||||
return False
|
||||
if self.new_items_only:
|
||||
# Delete movies that are not on Plex anymore - do this only once
|
||||
self.process_delete()
|
||||
with PlexDB() as self.plex_db:
|
||||
if self.isCanceled() or not self.process_kind():
|
||||
return False
|
||||
if self.new_items_only:
|
||||
# Delete movies that are not on Plex anymore - do this only once
|
||||
self.process_delete()
|
||||
return True
|
||||
|
||||
@utils.log_time
|
||||
def run(self):
|
||||
if self.isCanceled():
|
||||
return
|
||||
successful = False
|
||||
self.last_sync = time.time()
|
||||
if self.isCanceled():
|
||||
return
|
||||
LOG.info('Running fullsync for NEW PMS items with repair=%s',
|
||||
self.repair)
|
||||
if not sections.sync_from_pms():
|
||||
return
|
||||
if self.isCanceled():
|
||||
return
|
||||
try:
|
||||
# Fire up our single processing thread
|
||||
self.queue = backgroundthread.Queue.Queue(maxsize=200)
|
||||
self.processing_thread = process_metadata.ProcessMetadata(
|
||||
self.queue, self.last_sync)
|
||||
self.processing_thread.start()
|
||||
|
||||
# Actual syncing - do only new items first
|
||||
LOG.info('Running fullsync for **NEW** items with repair=%s',
|
||||
self.repair)
|
||||
self.new_items_only = True
|
||||
# This will also update playstates and userratings!
|
||||
if self.full_library_sync(new_items_only=True) is False:
|
||||
if not self.full_library_sync():
|
||||
return
|
||||
if self.isCanceled():
|
||||
return
|
||||
# This will NOT update playstates and userratings!
|
||||
LOG.info('Running fullsync for CHANGED PMS items with repair=%s',
|
||||
LOG.info('Running fullsync for **CHANGED** items with repair=%s',
|
||||
self.repair)
|
||||
self.new_items_only = False
|
||||
if not self.full_library_sync():
|
||||
return
|
||||
if self.isCanceled():
|
||||
|
@ -174,58 +184,8 @@ class FullSync(backgroundthread.KillableThread, common.libsync_mixin):
|
|||
LOG.info('Done full_sync')
|
||||
|
||||
|
||||
def process_updatelist(item_class, show_sync_info=True):
|
||||
def start(repair, callback):
|
||||
"""
|
||||
Downloads all XMLs for item_class (e.g. Movies, TV-Shows). Processes
|
||||
them by then calling item_classs.<item_class>()
|
||||
|
||||
Input:
|
||||
item_class: 'Movies', 'TVShows' (itemtypes.py classes)
|
||||
"""
|
||||
search_fanart = (item_class in ('Movies', 'TVShows') and
|
||||
utils.settings('FanartTV') == 'true')
|
||||
LOG.debug("Starting sync threads")
|
||||
# Spawn GetMetadata threads for downloading
|
||||
for _ in range(state.SYNC_THREAD_NUMBER):
|
||||
thread = get_metadata.ThreadedGetMetadata(DOWNLOAD_QUEUE,
|
||||
PROCESS_QUEUE)
|
||||
thread.start()
|
||||
THREADS.append(thread)
|
||||
LOG.debug("%s download threads spawned", state.SYNC_THREAD_NUMBER)
|
||||
# Spawn one more thread to process Metadata, once downloaded
|
||||
thread = process_metadata.ThreadedProcessMetadata(PROCESS_QUEUE,
|
||||
item_class)
|
||||
thread.start()
|
||||
THREADS.append(thread)
|
||||
# Start one thread to show sync progress ONLY for new PMS items
|
||||
if show_sync_info:
|
||||
sync_info.GET_METADATA_COUNT = 0
|
||||
sync_info.PROCESS_METADATA_COUNT = 0
|
||||
sync_info.PROCESSING_VIEW_NAME = ''
|
||||
thread = sync_info.ThreadedShowSyncInfo(item_number, item_class)
|
||||
thread.start()
|
||||
THREADS.append(thread)
|
||||
# Process items we need to download
|
||||
for _ in generator:
|
||||
DOWNLOAD_QUEUE.put(self.updatelist.pop(0))
|
||||
if search_fanart:
|
||||
pass
|
||||
# Wait until finished
|
||||
DOWNLOAD_QUEUE.join()
|
||||
PROCESS_QUEUE.join()
|
||||
# Kill threads
|
||||
LOG.debug("Waiting to kill threads")
|
||||
for thread in THREADS:
|
||||
# Threads might already have quit by themselves (e.g. Kodi exit)
|
||||
try:
|
||||
thread.stop()
|
||||
except AttributeError:
|
||||
pass
|
||||
LOG.debug("Stop sent to all threads")
|
||||
# Wait till threads are indeed dead
|
||||
for thread in threads:
|
||||
try:
|
||||
thread.join(1.0)
|
||||
except AttributeError:
|
||||
pass
|
||||
LOG.debug("Sync threads finished")
|
||||
# backgroundthread.BGThreader.addTask(FullSync().setup(repair, callback))
|
||||
FullSync(repair, callback).start()
|
||||
|
|
|
@ -80,9 +80,9 @@ class ProcessMetadata(backgroundthread.KillableThread, common.libsync_mixin):
|
|||
while self.isCanceled() is False:
|
||||
# grabs item from queue. This will block!
|
||||
xml = self.queue.get()
|
||||
self.queue.task_done()
|
||||
if xml is InitNewSection or xml is None:
|
||||
section = xml
|
||||
self.queue.task_done()
|
||||
break
|
||||
try:
|
||||
context.add_update(xml[0],
|
||||
|
@ -97,6 +97,7 @@ class ProcessMetadata(backgroundthread.KillableThread, common.libsync_mixin):
|
|||
xml[0].get('title'))
|
||||
self.update_dialog()
|
||||
self.current += 1
|
||||
self.queue.task_done()
|
||||
finally:
|
||||
self.dialog.close()
|
||||
LOG.debug('Processing thread terminated')
|
||||
|
|
|
@ -95,7 +95,7 @@ def _process_section(section_xml, kodi_db, plex_db, sorted_sections,
|
|||
# Prevent duplicate for playlists of the same type
|
||||
playlists = PLAYLISTS[plex_type]
|
||||
# Get current media folders from plex database
|
||||
section = plex_db.section_by_id(section_id)
|
||||
section = plex_db.section(section_id)
|
||||
try:
|
||||
current_sectionname = section[1]
|
||||
current_sectiontype = section[2]
|
||||
|
@ -137,7 +137,10 @@ def _process_section(section_xml, kodi_db, plex_db, sorted_sections,
|
|||
tagid = kodi_db.create_tag(section_name)
|
||||
|
||||
# Update view with new info
|
||||
plex_db.update_section(section_name, tagid, section_id)
|
||||
plex_db.add_section(section_id,
|
||||
section_name,
|
||||
plex_type,
|
||||
tagid)
|
||||
|
||||
if plex_db.section_id_by_name(current_sectionname) is None:
|
||||
# The tag could be a combined view. Ensure there's
|
||||
|
@ -210,7 +213,7 @@ def delete_sections(old_sections):
|
|||
video_library_update = False
|
||||
music_library_update = False
|
||||
with plexdb.PlexDB() as plex_db:
|
||||
old_sections = [plex_db.section_by_id(x) for x in old_sections]
|
||||
old_sections = [plex_db.section(x) for x in old_sections]
|
||||
LOG.info("Removing entire Plex library sections: %s", old_sections)
|
||||
with kodidb.GetKodiDB() as kodi_db:
|
||||
for section in old_sections:
|
||||
|
|
|
@ -476,33 +476,39 @@ class API(object):
|
|||
"""
|
||||
Returns the title of the element as unicode or 'Missing Title Name'
|
||||
"""
|
||||
return utils.try_decode(self.item.get('title', 'Missing Title Name'))
|
||||
|
||||
def title(self):
|
||||
"""
|
||||
Returns an item's name/title or "Missing Title".
|
||||
"""
|
||||
return self.item.get('title', 'Missing Title')
|
||||
return cast(unicode, self.item.get('title', 'Missing Title Name'))
|
||||
|
||||
def sorttitle(self):
|
||||
"""
|
||||
Returns an item's sorting name/title or the title itself if not found
|
||||
"Missing Title" if both are not present
|
||||
"""
|
||||
return self.item.get('titleSort',
|
||||
self.item.get('title','Missing Title'))
|
||||
return cast(unicode, self.item.get('titleSort',
|
||||
self.item.get('title','Missing Title')))
|
||||
|
||||
def plot(self):
|
||||
"""
|
||||
Returns the plot or None.
|
||||
"""
|
||||
return self.item.get('summary')
|
||||
return cast(unicode, self.item.get('summary'))
|
||||
|
||||
def shortplot(self):
|
||||
"""
|
||||
Not yet implemented
|
||||
"""
|
||||
pass
|
||||
|
||||
def votecount(self):
|
||||
"""
|
||||
Not yet implemented
|
||||
"""
|
||||
pass
|
||||
|
||||
def tagline(self):
|
||||
"""
|
||||
Returns a shorter tagline or None
|
||||
"""
|
||||
return self.item.get('tagline')
|
||||
return cast(unicode, self.item.get('tagline'))
|
||||
|
||||
def audience_rating(self):
|
||||
"""
|
||||
|
@ -755,7 +761,7 @@ class API(object):
|
|||
answ.append(extra)
|
||||
return answ
|
||||
|
||||
def trailers(self):
|
||||
def trailer(self):
|
||||
"""
|
||||
Returns the URL for a single trailer (local trailer preferred; first
|
||||
trailer found returned) or an add-on path to list all Plex extras
|
||||
|
|
|
@ -2,42 +2,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
from .common import PlexDBBase
|
||||
from .tvshows import
|
||||
from .. import utils, variables as v
|
||||
from .common import PlexDBBase, initialize, wipe
|
||||
from .tvshows import TVShows
|
||||
from .movies import Movies
|
||||
|
||||
|
||||
class PlexDB(object):
|
||||
"""
|
||||
Usage: with PlexDB() as plex_db:
|
||||
plex_db.do_something()
|
||||
|
||||
On exiting "with" (no matter what), commits get automatically committed
|
||||
and the db gets closed
|
||||
"""
|
||||
def __init__(self, kind=None):
|
||||
pass
|
||||
|
||||
def __enter__(self):
|
||||
self.plexconn = utils.kodi_sql('plex')
|
||||
if kind is None:
|
||||
func = PlexDBBase
|
||||
return func(self.plexconn.cursor())
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
self.plexconn.commit()
|
||||
self.plexconn.close()
|
||||
|
||||
|
||||
def wipe_dbs():
|
||||
"""
|
||||
Completely resets the Plex database
|
||||
"""
|
||||
query = "SELECT name FROM sqlite_master WHERE type = 'table'"
|
||||
with PlexDB() as plex_db:
|
||||
plex_db.plexcursor.execute(query)
|
||||
tables = plex_db.plexcursor.fetchall()
|
||||
tables = [i[0] for i in tables]
|
||||
for table in tables:
|
||||
delete_query = 'DELETE FROM %s' % table
|
||||
plex_db.plexcursor.execute(delete_query)
|
||||
class PlexDB(PlexDBBase, TVShows, Movies):
|
||||
pass
|
||||
|
|
|
@ -2,14 +2,26 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
from . import utils
|
||||
|
||||
class PlexDB(object):
|
||||
|
||||
class PlexDBBase(object):
|
||||
"""
|
||||
Methods used for all types of items
|
||||
"""
|
||||
def __init__(self, cursor):
|
||||
def __init__(self, cursor=None):
|
||||
# Allows us to use this class with a cursor instead of context mgr
|
||||
self.cursor = cursor
|
||||
|
||||
def __enter__(self):
|
||||
self.plexconn = utils.kodi_sql('plex')
|
||||
self.cursor = self.plexconn.cursor()
|
||||
return self
|
||||
|
||||
def __exit__(self, e_typ, e_val, trcbak):
|
||||
self.plexconn.commit()
|
||||
self.plexconn.close()
|
||||
|
||||
def section_ids(self):
|
||||
"""
|
||||
Returns an iterator for section Plex ids for all sections
|
||||
|
@ -35,14 +47,14 @@ class PlexDB(object):
|
|||
'kodi_tagid': x[3],
|
||||
'sync_to_kodi': x[4]} for x in self.cursor)
|
||||
|
||||
def section_by_id(self, section_id):
|
||||
def section(self, section_id):
|
||||
"""
|
||||
For section_id, returns tuple (or None)
|
||||
(section_id,
|
||||
section_name,
|
||||
plex_type,
|
||||
kodi_tagid,
|
||||
sync_to_kodi)
|
||||
For section_id, returns the tuple (or None)
|
||||
section_id INTEGER PRIMARY KEY,
|
||||
section_name TEXT,
|
||||
plex_type TEXT,
|
||||
kodi_tagid INTEGER,
|
||||
sync_to_kodi INTEGER
|
||||
"""
|
||||
self.cursor.execute('SELECT * FROM sections WHERE section_id = ? LIMIT 1',
|
||||
(section_id, ))
|
||||
|
@ -66,7 +78,7 @@ class PlexDB(object):
|
|||
sync=False: Plex library won't be synced to Kodi
|
||||
"""
|
||||
query = '''
|
||||
INSERT INTO sections(
|
||||
INSERT OR REPLACE INTO sections(
|
||||
section_id, section_name, plex_type, kodi_tagid, sync_to_kodi)
|
||||
VALUES (?, ?, ?, ?, ?)
|
||||
'''
|
||||
|
@ -77,17 +89,6 @@ class PlexDB(object):
|
|||
kodi_tagid,
|
||||
sync_to_kodi))
|
||||
|
||||
def update_section(self, section_name, kodi_tagid, section_id):
|
||||
"""
|
||||
Updates the section_id with section_name and kodi_tagid
|
||||
"""
|
||||
query = '''
|
||||
UPDATE sections
|
||||
SET section_name = ?, kodi_tagid = ?
|
||||
WHERE section_id = ?
|
||||
'''
|
||||
self.cursor.execute(query, (section_name, kodi_tagid, section_id))
|
||||
|
||||
def remove_section(self, section_id):
|
||||
"""
|
||||
Removes the Plex db entry for the section with section_id
|
||||
|
@ -95,18 +96,147 @@ class PlexDB(object):
|
|||
self.cursor.execute('DELETE FROM sections WHERE section_id = ?',
|
||||
(section_id, ))
|
||||
|
||||
def item_by_id(self, plex_id):
|
||||
def plex_id_by_last_sync(self, plex_type, last_sync):
|
||||
"""
|
||||
For plex_id, returns the tuple
|
||||
(kodi_id, kodi_fileid, kodi_pathid, parent_id, kodi_type, plex_type)
|
||||
Returns an iterator for all items where the last_sync is NOT identical
|
||||
"""
|
||||
query = 'SELECT plex_id FROM %s WHERE last_sync <> ?' % plex_type
|
||||
self.cursor.execute(query, (last_sync, ))
|
||||
return (x[0] for x in self.cursor)
|
||||
|
||||
None if not found
|
||||
def update_last_sync(self, plex_type, plex_id, last_sync):
|
||||
"""
|
||||
query = '''
|
||||
SELECT kodi_id, kodi_fileid, kodi_pathid, parent_id, kodi_type,
|
||||
plex_type
|
||||
FROM plex WHERE plex_id = ?
|
||||
LIMIT 1
|
||||
'''
|
||||
self.cursor.execute(query, (plex_id,))
|
||||
return self.cursor.fetchone()
|
||||
Sets a new timestamp for plex_id
|
||||
"""
|
||||
query = 'UPDATE %s SET last_sync = ? WHERE plex_id = ?' % plex_type
|
||||
self.cursor.execute(query, (last_sync, plex_id))
|
||||
|
||||
def remove(self, plex_id, plex_type):
|
||||
"""
|
||||
Removes the item from our Plex db
|
||||
"""
|
||||
query = 'DELETE FROM ? WHERE plex_id = ?' % plex_type
|
||||
self.cursor.execute(query, (plex_id, ))
|
||||
|
||||
|
||||
def initialize():
|
||||
"""
|
||||
Run once during startup to verify that plex db exists.
|
||||
"""
|
||||
with PlexDBBase() as plex_db:
|
||||
# Create the tables for the plex database
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS sections(
|
||||
section_id INTEGER PRIMARY KEY,
|
||||
section_name TEXT,
|
||||
plex_type TEXT,
|
||||
kodi_tagid INTEGER,
|
||||
sync_to_kodi INTEGER)
|
||||
''')
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS movie(
|
||||
plex_id INTEGER PRIMARY KEY ASC,
|
||||
checksum INTEGER UNIQUE,
|
||||
section_id INTEGER,
|
||||
kodi_id INTEGER,
|
||||
kodi_fileid INTEGER,
|
||||
kodi_pathid INTEGER,
|
||||
fanart_synced INTEGER,
|
||||
last_sync INTEGER)
|
||||
''')
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS show(
|
||||
plex_id INTEGER PRIMARY KEY ASC,
|
||||
checksum INTEGER UNIQUE,
|
||||
section_id INTEGER,
|
||||
kodi_id INTEGER,
|
||||
kodi_pathid INTEGER,
|
||||
fanart_synced INTEGER,
|
||||
last_sync INTEGER)
|
||||
''')
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS season(
|
||||
plex_id INTEGER PRIMARY KEY,
|
||||
checksum INTEGER UNIQUE,
|
||||
section_id INTEGER,
|
||||
show_id INTEGER, # plex_id of the parent show
|
||||
parent_id INTEGER, # kodi_id of the parent show
|
||||
kodi_id INTEGER,
|
||||
fanart_synced INTEGER,
|
||||
last_sync INTEGER)
|
||||
''')
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS episode(
|
||||
plex_id INTEGER PRIMARY KEY,
|
||||
checksum INTEGER UNIQUE,
|
||||
section_id INTEGER,
|
||||
show_id INTEGER, # plex_id of the parent show
|
||||
grandparent_id INTEGER, # kodi_id of the parent show
|
||||
season_id INTEGER, # plex_id of the parent season
|
||||
parent_id INTEGER, # kodi_id of the parent season
|
||||
kodi_id INTEGER,
|
||||
kodi_fileid INTEGER,
|
||||
kodi_pathid INTEGER,
|
||||
fanart_synced INTEGER,
|
||||
last_sync INTEGER)
|
||||
''')
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS artist(
|
||||
plex_id INTEGER PRIMARY KEY ASC,
|
||||
checksum INTEGER UNIQUE,
|
||||
section_id INTEGER,
|
||||
kodi_id INTEGER,
|
||||
fanart_synced INTEGER,
|
||||
last_sync INTEGER)
|
||||
''')
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS album(
|
||||
plex_id INTEGER PRIMARY KEY,
|
||||
checksum INTEGER UNIQUE,
|
||||
section_id INTEGER,
|
||||
artist_id INTEGER, # plex_id of the parent artist
|
||||
parent_id INTEGER, # kodi_id of the parent artist
|
||||
kodi_id INTEGER,
|
||||
fanart_synced INTEGER,
|
||||
last_sync INTEGER)
|
||||
''')
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS track(
|
||||
plex_id INTEGER PRIMARY KEY,
|
||||
checksum INTEGER UNIQUE,
|
||||
section_id INTEGER,
|
||||
artist_id INTEGER, # plex_id of the parent artist
|
||||
grandparent_id INTEGER, # kodi_id of the parent artist
|
||||
album_id INTEGER, # plex_id of the parent album
|
||||
parent_id INTEGER, # kodi_id of the parent album
|
||||
kodi_id INTEGER,
|
||||
kodi_fileid INTEGER,
|
||||
kodi_pathid INTEGER,
|
||||
fanart_synced INTEGER,
|
||||
last_sync INTEGER)
|
||||
''')
|
||||
plex_db.cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS playlists(
|
||||
plex_id INTEGER PRIMARY KEY ASC,
|
||||
plex_name TEXT,
|
||||
plex_updatedat INTEGER,
|
||||
kodi_path TEXT,
|
||||
kodi_type TEXT,
|
||||
kodi_hash TEXT)
|
||||
''')
|
||||
# Create an index for actors to speed up sync
|
||||
utils.create_actor_db_index()
|
||||
|
||||
|
||||
def wipe():
|
||||
"""
|
||||
Completely resets the Plex database
|
||||
"""
|
||||
query = "SELECT name FROM sqlite_master WHERE type = 'table'"
|
||||
with PlexDBBase() as plex_db:
|
||||
plex_db.cursor.execute(query)
|
||||
tables = plex_db.cursor.fetchall()
|
||||
tables = [i[0] for i in tables]
|
||||
for table in tables:
|
||||
delete_query = 'DELETE FROM %s' % table
|
||||
plex_db.cursor.execute(delete_query)
|
||||
|
|
50
resources/lib/plex_db/movies.py
Normal file
50
resources/lib/plex_db/movies.py
Normal file
|
@ -0,0 +1,50 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
|
||||
class Movies(object):
|
||||
def add_movie(self, plex_id=None, checksum=None, section_id=None,
|
||||
kodi_id=None, kodi_fileid=None, kodi_pathid=None,
|
||||
last_sync=None):
|
||||
"""
|
||||
Appends or replaces an entry into the plex table for movies
|
||||
"""
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO movie(
|
||||
plex_id,
|
||||
checksum,
|
||||
section_id,
|
||||
kodi_id,
|
||||
kodi_fileid,
|
||||
kodi_pathid,
|
||||
fanart_synced,
|
||||
last_sync)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.plexcursor.execute(
|
||||
query,
|
||||
(plex_id,
|
||||
checksum,
|
||||
section_id,
|
||||
kodi_id,
|
||||
kodi_fileid,
|
||||
kodi_pathid,
|
||||
0,
|
||||
last_sync))
|
||||
|
||||
def movie(self, plex_id):
|
||||
"""
|
||||
Returns the show info as a tuple for the TV show with plex_id:
|
||||
plex_id INTEGER PRIMARY KEY ASC,
|
||||
checksum INTEGER UNIQUE,
|
||||
section_id INTEGER,
|
||||
kodi_id INTEGER,
|
||||
kodi_fileid INTEGER,
|
||||
kodi_pathid INTEGER,
|
||||
fanart_synced INTEGER,
|
||||
last_sync INTEGER
|
||||
"""
|
||||
self.cursor.execute('SELECT * FROM movie WHERE plex_id = ?',
|
||||
(plex_id, ))
|
||||
return self.cursor.fetchone()
|
|
@ -2,55 +2,59 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division, unicode_literals
|
||||
|
||||
from . import common
|
||||
from .. import variables as v
|
||||
|
||||
###############################################################################
|
||||
class TVShows(object):
|
||||
def add_show(self, plex_id=None, checksum=None, section_id=None,
|
||||
kodi_id=None, kodi_pathid=None, last_sync=None):
|
||||
"""
|
||||
Appends or replaces tv show entry into the plex table
|
||||
"""
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO show(
|
||||
plex_id, checksum, section_id, kodi_id, kodi_pathid,
|
||||
fanart_synced, last_sync)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.plexcursor.execute(
|
||||
query,
|
||||
(plex_id, checksum, section_id, kodi_id, kodi_pathid, 0,
|
||||
last_sync))
|
||||
|
||||
|
||||
class PlexDB(common.PlexDB):
|
||||
def add_reference(self, plex_type=None, plex_id=None, checksum=None,
|
||||
section_id=None, show_id=None, grandparent_id=None,
|
||||
season_id=None, parent_id=None, kodi_id=None,
|
||||
kodi_fileid=None, kodi_pathid=None, last_sync=None):
|
||||
def add_season(self, plex_id=None, checksum=None, section_id=None,
|
||||
show_id=None, parent_id=None, kodi_id=None, last_sync=None):
|
||||
"""
|
||||
Appends or replaces an entry into the plex table
|
||||
"""
|
||||
if plex_type == v.PLEX_TYPE_EPISODE:
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO episode(
|
||||
plex_id, checksum, section_id, show_id, grandparent_id,
|
||||
season_id, parent_id, kodi_id, kodi_fileid, kodi_pathid,
|
||||
fanart_synced, last_sync)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.plexcursor.execute(
|
||||
query,
|
||||
(plex_id, checksum, section_id, show_id, grandparent_id,
|
||||
season_id, parent_id, kodi_id, kodi_fileid, kodi_pathid,
|
||||
0, last_sync))
|
||||
elif plex_type == v.PLEX_TYPE_SEASON:
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO season(
|
||||
plex_id, checksum, section_id, show_id, parent_id,
|
||||
kodi_id, fanart_synced, last_sync)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO season(
|
||||
plex_id, checksum, section_id, show_id, parent_id,
|
||||
kodi_id, fanart_synced, last_sync)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.plexcursor.execute(
|
||||
query,
|
||||
(plex_id, checksum, section_id, show_id, parent_id,
|
||||
kodi_id, 0, last_sync))
|
||||
|
||||
def add_episode(self, plex_id=None, checksum=None, section_id=None,
|
||||
show_id=None, grandparent_id=None, season_id=None,
|
||||
parent_id=None, kodi_id=None, kodi_fileid=None,
|
||||
kodi_pathid=None, last_sync=None):
|
||||
"""
|
||||
Appends or replaces an entry into the plex table
|
||||
"""
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO episode(
|
||||
plex_id, checksum, section_id, show_id, grandparent_id,
|
||||
season_id, parent_id, kodi_id, kodi_fileid, kodi_pathid,
|
||||
fanart_synced, last_sync)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.plexcursor.execute(
|
||||
query,
|
||||
(plex_id, checksum, section_id, show_id, parent_id,
|
||||
kodi_id, 0, last_sync))
|
||||
elif plex_type == v.PLEX_TYPE_SHOW:
|
||||
query = '''
|
||||
INSERT OR REPLACE INTO show(
|
||||
plex_id, checksum, section_id, kodi_id, kodi_pathid,
|
||||
fanart_synced, last_sync)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
self.plexcursor.execute(
|
||||
query,
|
||||
(plex_id, checksum, section_id, kodi_id, kodi_pathid, 0,
|
||||
last_sync))
|
||||
self.plexcursor.execute(
|
||||
query,
|
||||
(plex_id, checksum, section_id, show_id, grandparent_id,
|
||||
season_id, parent_id, kodi_id, kodi_fileid, kodi_pathid,
|
||||
0, last_sync))
|
||||
|
||||
def show(self, plex_id):
|
||||
"""
|
||||
|
@ -63,7 +67,7 @@ class PlexDB(common.PlexDB):
|
|||
fanart_synced INTEGER,
|
||||
last_sync INTEGER
|
||||
"""
|
||||
self.cursor.execute('SELECT * FROM show WHERE plex_id = ?',
|
||||
self.cursor.execute('SELECT * FROM show WHERE plex_id = ? LIMIT 1',
|
||||
(plex_id, ))
|
||||
return self.cursor.fetchone()
|
||||
|
||||
|
@ -79,7 +83,7 @@ class PlexDB(common.PlexDB):
|
|||
fanart_synced INTEGER,
|
||||
last_sync INTEGER
|
||||
"""
|
||||
self.cursor.execute('SELECT * FROM season WHERE plex_id = ?',
|
||||
self.cursor.execute('SELECT * FROM season WHERE plex_id = ? LIMIT 1',
|
||||
(plex_id, ))
|
||||
return self.cursor.fetchone()
|
||||
|
||||
|
@ -99,26 +103,6 @@ class PlexDB(common.PlexDB):
|
|||
fanart_synced INTEGER,
|
||||
last_sync INTEGER
|
||||
"""
|
||||
self.cursor.execute('SELECT * FROM episode WHERE plex_id = ?',
|
||||
self.cursor.execute('SELECT * FROM episode WHERE plex_id = ? LIMIT 1',
|
||||
(plex_id, ))
|
||||
return self.cursor.fetchone()
|
||||
|
||||
def plex_id_by_last_sync(self, plex_type, last_sync):
|
||||
"""
|
||||
Returns an iterator for all items where the last_sync is NOT identical
|
||||
"""
|
||||
self.cursor.execute('SELECT plex_id FROM ? WHERE last_sync <> ?',
|
||||
(plex_type, last_sync, ))
|
||||
return (x[0] for x in self.cursor)
|
||||
|
||||
def shows_plex_id_section_id(self):
|
||||
"""
|
||||
Iterator for tuples (plex_id, section_id) of all our TV shows
|
||||
"""
|
||||
self.cursor.execute('SELECT plex_id, section_id FROM show')
|
||||
return self.cursor
|
||||
|
||||
def update_last_sync(self, plex_type, plex_id, last_sync):
|
||||
"""
|
||||
Sets a new timestamp for plex_id
|
||||
"""
|
||||
|
|
Loading…
Reference in a new issue