mirror of
https://github.com/SickGear/SickGear.git
synced 2024-12-12 22:23:38 +00:00
47da38a914
* Change corrected spelling & better clarified various log messages * Change minor PEP8 tweaks in sab.py * Add api disabled error code for newznab providers
293 lines
12 KiB
Python
293 lines
12 KiB
Python
# Author: Nic Wolfe <nic@wolfeden.ca>
|
|
# URL: http://code.google.com/p/sickbeard/
|
|
#
|
|
# This file is part of SickGear.
|
|
#
|
|
# SickGear is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# SickGear is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with SickGear. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
import os.path
|
|
|
|
import sickbeard
|
|
|
|
from sickbeard import helpers, logger, exceptions
|
|
from sickbeard import encodingKludge as ek
|
|
|
|
from sickbeard.metadata.generic import GenericMetadata
|
|
|
|
from lib.hachoir_parser import createParser
|
|
from lib.hachoir_metadata import extractMetadata
|
|
|
|
|
|
class ImageCache:
|
|
def __init__(self):
|
|
pass
|
|
|
|
def __del__(self):
|
|
pass
|
|
|
|
def _cache_dir(self):
|
|
"""
|
|
Builds up the full path to the image cache directory
|
|
"""
|
|
return ek.ek(os.path.abspath, ek.ek(os.path.join, sickbeard.CACHE_DIR, 'images'))
|
|
|
|
def _thumbnails_dir(self):
|
|
"""
|
|
Builds up the full path to the thumbnails image cache directory
|
|
"""
|
|
return ek.ek(os.path.abspath, ek.ek(os.path.join, self._cache_dir(), 'thumbnails'))
|
|
|
|
def poster_path(self, indexer_id):
|
|
"""
|
|
Builds up the path to a poster cache for a given Indexer ID
|
|
|
|
returns: a full path to the cached poster file for the given Indexer ID
|
|
|
|
indexer_id: ID of the show to use in the file name
|
|
"""
|
|
poster_file_name = str(indexer_id) + '.poster.jpg'
|
|
return ek.ek(os.path.join, self._cache_dir(), poster_file_name)
|
|
|
|
def banner_path(self, indexer_id):
|
|
"""
|
|
Builds up the path to a banner cache for a given Indexer ID
|
|
|
|
returns: a full path to the cached banner file for the given Indexer ID
|
|
|
|
indexer_id: ID of the show to use in the file name
|
|
"""
|
|
banner_file_name = str(indexer_id) + '.banner.jpg'
|
|
return ek.ek(os.path.join, self._cache_dir(), banner_file_name)
|
|
|
|
def poster_thumb_path(self, indexer_id):
|
|
"""
|
|
Builds up the path to a poster cache for a given Indexer ID
|
|
|
|
returns: a full path to the cached poster file for the given Indexer ID
|
|
|
|
indexer_id: ID of the show to use in the file name
|
|
"""
|
|
posterthumb_file_name = str(indexer_id) + '.poster.jpg'
|
|
return ek.ek(os.path.join, self._thumbnails_dir(), posterthumb_file_name)
|
|
|
|
def banner_thumb_path(self, indexer_id):
|
|
"""
|
|
Builds up the path to a poster cache for a given Indexer ID
|
|
|
|
returns: a full path to the cached poster file for the given Indexer ID
|
|
|
|
indexer_id: ID of the show to use in the file name
|
|
"""
|
|
bannerthumb_file_name = str(indexer_id) + '.banner.jpg'
|
|
return ek.ek(os.path.join, self._thumbnails_dir(), bannerthumb_file_name)
|
|
|
|
def has_poster(self, indexer_id):
|
|
"""
|
|
Returns true if a cached poster exists for the given Indexer ID
|
|
"""
|
|
poster_path = self.poster_path(indexer_id)
|
|
logger.log(u"Checking if file " + str(poster_path) + " exists", logger.DEBUG)
|
|
return ek.ek(os.path.isfile, poster_path)
|
|
|
|
def has_banner(self, indexer_id):
|
|
"""
|
|
Returns true if a cached banner exists for the given Indexer ID
|
|
"""
|
|
banner_path = self.banner_path(indexer_id)
|
|
logger.log(u"Checking if file " + str(banner_path) + " exists", logger.DEBUG)
|
|
return ek.ek(os.path.isfile, banner_path)
|
|
|
|
def has_poster_thumbnail(self, indexer_id):
|
|
"""
|
|
Returns true if a cached poster thumbnail exists for the given Indexer ID
|
|
"""
|
|
poster_thumb_path = self.poster_thumb_path(indexer_id)
|
|
logger.log(u"Checking if file " + str(poster_thumb_path) + " exists", logger.DEBUG)
|
|
return ek.ek(os.path.isfile, poster_thumb_path)
|
|
|
|
def has_banner_thumbnail(self, indexer_id):
|
|
"""
|
|
Returns true if a cached banner exists for the given Indexer ID
|
|
"""
|
|
banner_thumb_path = self.banner_thumb_path(indexer_id)
|
|
logger.log(u"Checking if file " + str(banner_thumb_path) + " exists", logger.DEBUG)
|
|
return ek.ek(os.path.isfile, banner_thumb_path)
|
|
|
|
|
|
BANNER = 1
|
|
POSTER = 2
|
|
BANNER_THUMB = 3
|
|
POSTER_THUMB = 4
|
|
|
|
def which_type(self, path):
|
|
"""
|
|
Analyzes the image provided and attempts to determine whether it is a poster or banner.
|
|
|
|
returns: BANNER, POSTER if it concluded one or the other, or None if the image was neither (or didn't exist)
|
|
|
|
path: full path to the image
|
|
"""
|
|
|
|
if not ek.ek(os.path.isfile, path):
|
|
logger.log(u"Couldn't check the type of " + str(path) + " cause it doesn't exist", logger.WARNING)
|
|
return None
|
|
|
|
# use hachoir to parse the image for us
|
|
img_parser = createParser(path)
|
|
img_metadata = extractMetadata(img_parser)
|
|
|
|
if not img_metadata:
|
|
logger.log(u"Unable to get metadata from " + str(path) + ", not using your existing image", logger.DEBUG)
|
|
return None
|
|
|
|
img_ratio = float(img_metadata.get('width')) / float(img_metadata.get('height'))
|
|
|
|
img_parser.stream._input.close()
|
|
|
|
# most posters are around 0.68 width/height ratio (eg. 680/1000)
|
|
if 0.55 < img_ratio < 0.8:
|
|
return self.POSTER
|
|
|
|
# most banners are around 5.4 width/height ratio (eg. 758/140)
|
|
elif 5 < img_ratio < 6:
|
|
return self.BANNER
|
|
else:
|
|
logger.log(u"Image has size ratio of " + str(img_ratio) + ", unknown type", logger.WARNING)
|
|
return None
|
|
|
|
def _cache_image_from_file(self, image_path, img_type, indexer_id):
|
|
"""
|
|
Takes the image provided and copies it to the cache folder
|
|
|
|
returns: bool representing success
|
|
|
|
image_path: path to the image we're caching
|
|
img_type: BANNER or POSTER
|
|
indexer_id: id of the show this image belongs to
|
|
"""
|
|
|
|
# generate the path based on the type & indexer_id
|
|
if img_type == self.POSTER:
|
|
dest_path = self.poster_path(indexer_id)
|
|
elif img_type == self.BANNER:
|
|
dest_path = self.banner_path(indexer_id)
|
|
else:
|
|
logger.log(u"Invalid cache image type: " + str(img_type), logger.ERROR)
|
|
return False
|
|
|
|
# make sure the cache folder exists before we try copying to it
|
|
if not ek.ek(os.path.isdir, self._cache_dir()):
|
|
logger.log(u"Image cache directory doesn't exist, creating it at " + str(self._cache_dir()))
|
|
ek.ek(os.makedirs, self._cache_dir())
|
|
|
|
if not ek.ek(os.path.isdir, self._thumbnails_dir()):
|
|
logger.log(u"Thumbnails cache directory doesn't exist, creating it at " + str(self._thumbnails_dir()))
|
|
ek.ek(os.makedirs, self._thumbnails_dir())
|
|
|
|
logger.log(u"Copying from " + image_path + " to " + dest_path)
|
|
helpers.copyFile(image_path, dest_path)
|
|
|
|
return True
|
|
|
|
def _cache_image_from_indexer(self, show_obj, img_type):
|
|
"""
|
|
Retrieves an image of the type specified from indexer and saves it to the cache folder
|
|
|
|
returns: bool representing success
|
|
|
|
show_obj: TVShow object that we want to cache an image for
|
|
img_type: BANNER or POSTER
|
|
"""
|
|
|
|
# generate the path based on the type & indexer_id
|
|
if img_type == self.POSTER:
|
|
img_type_name = 'poster'
|
|
dest_path = self.poster_path(show_obj.indexerid)
|
|
elif img_type == self.BANNER:
|
|
img_type_name = 'banner'
|
|
dest_path = self.banner_path(show_obj.indexerid)
|
|
elif img_type == self.POSTER_THUMB:
|
|
img_type_name = 'poster_thumb'
|
|
dest_path = self.poster_thumb_path(show_obj.indexerid)
|
|
elif img_type == self.BANNER_THUMB:
|
|
img_type_name = 'banner_thumb'
|
|
dest_path = self.banner_thumb_path(show_obj.indexerid)
|
|
else:
|
|
logger.log(u"Invalid cache image type: " + str(img_type), logger.ERROR)
|
|
return False
|
|
|
|
# retrieve the image from indexer using the generic metadata class
|
|
#TODO: refactor
|
|
metadata_generator = GenericMetadata()
|
|
img_data = metadata_generator._retrieve_show_image(img_type_name, show_obj)
|
|
result = metadata_generator._write_image(img_data, dest_path)
|
|
|
|
return result
|
|
|
|
def fill_cache(self, show_obj):
|
|
"""
|
|
Caches all images for the given show. Copies them from the show dir if possible, or
|
|
downloads them from indexer if they aren't in the show dir.
|
|
|
|
show_obj: TVShow object to cache images for
|
|
"""
|
|
|
|
logger.log(u"Checking if we need any cache images for show " + str(show_obj.indexerid), logger.DEBUG)
|
|
|
|
# check if the images are already cached or not
|
|
need_images = {self.POSTER: not self.has_poster(show_obj.indexerid),
|
|
self.BANNER: not self.has_banner(show_obj.indexerid),
|
|
self.POSTER_THUMB: not self.has_poster_thumbnail(show_obj.indexerid),
|
|
self.BANNER_THUMB: not self.has_banner_thumbnail(show_obj.indexerid)}
|
|
|
|
if not need_images[self.POSTER] and not need_images[self.BANNER] and not need_images[self.POSTER_THUMB] and not \
|
|
need_images[self.BANNER_THUMB]:
|
|
logger.log(u"No new cache images needed, not retrieving new ones")
|
|
return
|
|
|
|
# check the show dir for poster or banner images and use them
|
|
if need_images[self.POSTER] or need_images[self.BANNER]:
|
|
try:
|
|
for cur_provider in sickbeard.metadata_provider_dict.values():
|
|
logger.log(u"Checking if we can use the show image from the " + cur_provider.name + " metadata",
|
|
logger.DEBUG)
|
|
if ek.ek(os.path.isfile, cur_provider.get_poster_path(show_obj)):
|
|
cur_file_name = os.path.abspath(cur_provider.get_poster_path(show_obj))
|
|
cur_file_type = self.which_type(cur_file_name)
|
|
|
|
if cur_file_type == None:
|
|
logger.log(u"Unable to retrieve image type, not using the image from " + str(cur_file_name),
|
|
logger.WARNING)
|
|
continue
|
|
|
|
logger.log(u"Checking if image " + cur_file_name + " (type " + str(
|
|
cur_file_type) + " needs metadata: " + str(need_images[cur_file_type]), logger.DEBUG)
|
|
|
|
if cur_file_type in need_images and need_images[cur_file_type]:
|
|
logger.log(
|
|
u"Found an image in the show directory that doesn't exist in the cache, caching it: " + cur_file_name + ", type " + str(
|
|
cur_file_type), logger.DEBUG)
|
|
self._cache_image_from_file(cur_file_name, cur_file_type, show_obj.indexerid)
|
|
need_images[cur_file_type] = False
|
|
except exceptions.ShowDirNotFoundException:
|
|
logger.log(u"Unable to search for images in show directory because it doesn't exist", logger.WARNING)
|
|
|
|
# download from indexer for missing ones
|
|
for cur_image_type in [self.POSTER, self.BANNER, self.POSTER_THUMB, self.BANNER_THUMB]:
|
|
logger.log(u"Seeing if we still need an image of type " + str(cur_image_type) + ": " + str(
|
|
need_images[cur_image_type]), logger.DEBUG)
|
|
if cur_image_type in need_images and need_images[cur_image_type]:
|
|
self._cache_image_from_indexer(show_obj, cur_image_type)
|
|
|
|
logger.log(u"Done cache check")
|