1
0
mirror of https://github.com/moparisthebest/SickRage synced 2024-08-13 16:53:54 -04:00

Merge branch 'release/4.0.8'

This commit is contained in:
echel0n 2014-12-21 16:37:21 -08:00
commit 11269daeba
101 changed files with 2481 additions and 130 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 506 B

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 B

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 B

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 628 B

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 B

After

Width:  |  Height:  |  Size: 460 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 441 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 419 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 487 B

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 609 B

After

Width:  |  Height:  |  Size: 542 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 170 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 469 B

After

Width:  |  Height:  |  Size: 486 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 B

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 489 B

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 545 B

After

Width:  |  Height:  |  Size: 426 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 470 B

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 326 B

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 380 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 524 B

After

Width:  |  Height:  |  Size: 515 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 432 B

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 430 B

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 532 B

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 420 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 455 B

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 B

After

Width:  |  Height:  |  Size: 457 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 517 B

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 465 B

After

Width:  |  Height:  |  Size: 384 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 664 B

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 614 B

After

Width:  |  Height:  |  Size: 492 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 453 B

After

Width:  |  Height:  |  Size: 454 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

After

Width:  |  Height:  |  Size: 520 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

After

Width:  |  Height:  |  Size: 500 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 374 B

After

Width:  |  Height:  |  Size: 393 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 554 B

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 440 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 420 B

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 562 B

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 B

After

Width:  |  Height:  |  Size: 462 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 409 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 B

After

Width:  |  Height:  |  Size: 497 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 452 B

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 514 B

After

Width:  |  Height:  |  Size: 475 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 616 B

After

Width:  |  Height:  |  Size: 459 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 472 B

After

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 668 KiB

After

Width:  |  Height:  |  Size: 504 KiB

View File

@ -317,16 +317,6 @@
<fieldset class="component-group-list">
<div class="field-pair">
<label for="use_api">
<span class="component-title">Enable API</span>
<span class="component-desc">
<input type="checkbox" name="use_api" class="enabler" id="use_api" #if $sickbeard.USE_API then 'checked="checked"' else ''#/>
<p>allow the use of the SickRage API</p>
</span>
</label>
</div>
<div id="content_use_api">
<div class="field-pair">
<label for="api_key">
<span class="component-title">API key</span>
@ -337,7 +327,6 @@
</span>
</label>
</div>
</div>
<div class="field-pair">
<label for="web_log">
@ -581,10 +570,10 @@
<div class="field-pair">
<label for="git_reset">
<span class="component-title">Git branch reset</span>
<span class="component-title">Git reset</span>
<span class="component-desc">
<input type="checkbox" name="git_reset" id="git_reset" #if True == $sickbeard.GIT_RESET then 'checked="checked"' else ''#/>
<p>reset git branch automatically to help resolve update issues</p>
<p>removes untracked files and performs a hard reset on git branch automatically to help resolve update issues</p>
</span>
</label>
</div>

View File

@ -474,7 +474,7 @@
#if $sickbeard.USE_SUBTITLES and $show.subtitles:
<td class="col-subtitles" align="center">
#if $epResult["subtitles"]:
#for $sub_lang in subliminal.language.language_list($epResult["subtitles"].split(',')):
#for $sub_lang in subliminal.language.language_list([x.strip() for x in $epResult["subtitles"].split(',')]):
#if sub_lang.alpha2 != ""
<img src="$sbRoot/images/flags/${sub_lang.alpha2}.png" width="16" height="11" alt="${sub_lang}" />
#end if

View File

@ -133,7 +133,7 @@
<b>Sports: </b>
<input type="checkbox" name="sports" #if $show.sports == 1 then "checked=\"checked\"" else ""# /><br />
(check this if the show is a sporting or MMA event)<br />
(check this if the show is a sporting or MMA event and released as Show.03.02.2010 rather than Show.S02E03)<br />
<br />
<b>Anime: </b>

View File

@ -1,4 +1,5 @@
#import sickbeard
#import calendar
#import datetime
#from sickbeard.common import *
#from sickbeard import db, sbdatetime, network_timezones
@ -330,7 +331,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
#set $data_date = '6000000000.0'
#if $cur_airs_next:
#set $data_date = $time.mktime($sbdatetime.sbdatetime.convert_to_setting($network_timezones.parse_date_time($cur_airs_next,$curShow.airs,$curShow.network)).timetuple())
#set $data_date = $calendar.timegm($sbdatetime.sbdatetime.convert_to_setting($network_timezones.parse_date_time($cur_airs_next,$curShow.airs,$curShow.network)).timetuple())
#else if None is not $display_status
#if 'nded' not in $display_status and 1 == int($curShow.paused)
#set $data_date = '5000000500.0'
@ -528,7 +529,7 @@ $myShowList.sort(lambda x, y: cmp(x.name, y.name))
#if $cur_airs_next
#set $ldatetime = $sbdatetime.sbdatetime.convert_to_setting($network_timezones.parse_date_time($cur_airs_next,$curShow.airs,$curShow.network))
<td align="center" class="nowrap"><div class="${fuzzydate}">$sbdatetime.sbdatetime.sbfdate($ldatetime)</div><span class="sort_data">$time.mktime($ldatetime.timetuple())</span></td>
<td align="center" class="nowrap"><div class="${fuzzydate}">$sbdatetime.sbdatetime.sbfdate($ldatetime)</div><span class="sort_data">$calendar.timegm($ldatetime.timetuple())</span></td>
#else:
<td align="center" class="nowrap"></td>
#end if

111
lib/fanart/__init__.py Normal file
View File

@ -0,0 +1,111 @@
__author__ = 'Andrea De Marco <24erre@gmail.com>'
__version__ = '1.4.0'
__classifiers__ = [
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved :: Apache Software License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Software Development :: Libraries',
]
__copyright__ = "2012, %s " % __author__
__license__ = """
Copyright %s.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either expressed or implied.
See the License for the specific language governing permissions and
limitations under the License.
""" % __copyright__
__docformat__ = 'restructuredtext en'
__doc__ = """
:abstract: Python interface to fanart.tv API
:version: %s
:author: %s
:contact: http://z4r.github.com/
:date: 2012-04-04
:copyright: %s
""" % (__version__, __author__, __license__)
def values(obj):
return [v for k, v in obj.__dict__.iteritems() if not k.startswith('_')]
BASEURL = 'http://webservice.fanart.tv/v3/%s/%s?api_key=%s'
class FORMAT(object):
JSON = 'JSON'
XML = 'XML'
PHP = 'PHP'
class WS(object):
MUSIC = 'music'
MOVIE = 'movies'
TV = 'tv'
class TYPE(object):
ALL = 'all'
class TV(object):
LOGO = 'clearlogo'
CHARACTER = 'characterart'
BACKGROUND = 'showbackground'
HDLOGO = 'hdtvlogo'
HDART = 'hdclearart'
ART = 'clearart'
THUMB = 'tvthumb'
POSTER = 'tvposter'
BANNER = 'tvbanner'
SEASONTHUMB = 'seasonthumb'
SEASONPOSTER = 'seasonposter'
SEASONBANNER = 'seasonbanner'
class MUSIC(object):
DISC = 'cdart'
LOGO = 'musiclogo'
BACKGROUND = 'artistbackground'
COVER = 'albumcover'
THUMB = 'artistthumb'
class MOVIE(object):
ART = 'movieart'
LOGO = 'movielogo'
DISC = 'moviedisc'
POSTER = 'movieposter'
BACKGROUND = 'moviebackground'
HDLOGO = 'hdmovielogo'
HDART = 'hdmovieclearart'
BANNER = 'moviebanner'
THUMB = 'moviethumb'
class SORT(object):
POPULAR = 1
NEWEST = 2
OLDEST = 3
class LIMIT(object):
ONE = 1
ALL = 2
FORMAT_LIST = values(FORMAT)
WS_LIST = values(WS)
TYPE_LIST = values(TYPE.MUSIC) + values(TYPE.TV) + values(TYPE.MOVIE) + [TYPE.ALL]
MUSIC_TYPE_LIST = values(TYPE.MUSIC) + [TYPE.ALL]
TV_TYPE_LIST = values(TYPE.TV) + [TYPE.ALL]
MOVIE_TYPE_LIST = values(TYPE.MOVIE) + [TYPE.ALL]
SORT_LIST = values(SORT)
LIMIT_LIST = values(LIMIT)

35
lib/fanart/core.py Normal file
View File

@ -0,0 +1,35 @@
import requests
import fanart
from fanart.errors import RequestFanartError, ResponseFanartError
class Request(object):
def __init__(self, apikey, id, ws, type=None, sort=None, limit=None):
self._apikey = apikey
self._id = id
self._ws = ws
self._type = type or fanart.TYPE.ALL
self._sort = sort or fanart.SORT.POPULAR
self._limit = limit or fanart.LIMIT.ALL
self.validate()
self._response = None
def validate(self):
for attribute_name in ('ws', 'type', 'sort', 'limit'):
attribute = getattr(self, '_' + attribute_name)
choices = getattr(fanart, attribute_name.upper() + '_LIST')
if attribute not in choices:
raise RequestFanartError('Not allowed {0}: {1} [{2}]'.format(attribute_name, attribute, ', '.join(choices)))
def __str__(self):
return fanart.BASEURL % (self._ws, self._id, self._apikey)
def response(self):
try:
response = requests.get(str(self))
rjson = response.json()
if not isinstance(rjson, dict):
raise Exception(response.text)
return rjson
except Exception as e:
raise ResponseFanartError(str(e))

15
lib/fanart/errors.py Normal file
View File

@ -0,0 +1,15 @@
class FanartError(Exception):
def __str__(self):
return ', '.join(map(str, self.args))
def __repr__(self):
name = self.__class__.__name__
return '%s%r' % (name, self.args)
class ResponseFanartError(FanartError):
pass
class RequestFanartError(FanartError):
pass

46
lib/fanart/immutable.py Normal file
View File

@ -0,0 +1,46 @@
class Immutable(object):
_mutable = False
def __setattr__(self, name, value):
if self._mutable or name == '_mutable':
super(Immutable, self).__setattr__(name, value)
else:
raise TypeError("Can't modify immutable instance")
def __delattr__(self, name):
if self._mutable:
super(Immutable, self).__delattr__(name)
else:
raise TypeError("Can't modify immutable instance")
def __eq__(self, other):
return hash(self) == hash(other)
def __hash__(self):
return hash(repr(self))
def __repr__(self):
return '%s(%s)' % (
self.__class__.__name__,
', '.join(['{0}={1}'.format(k, repr(v)) for k, v in self])
)
def __iter__(self):
l = self.__dict__.keys()
l.sort()
for k in l:
if not k.startswith('_'):
yield k, getattr(self, k)
@staticmethod
def mutablemethod(f):
def func(self, *args, **kwargs):
if isinstance(self, Immutable):
old_mutable = self._mutable
self._mutable = True
res = f(self, *args, **kwargs)
self._mutable = old_mutable
else:
res = f(self, *args, **kwargs)
return res
return func

68
lib/fanart/items.py Normal file
View File

@ -0,0 +1,68 @@
import json
import os
import requests
from fanart.core import Request
from fanart.immutable import Immutable
class LeafItem(Immutable):
KEY = NotImplemented
@Immutable.mutablemethod
def __init__(self, id, url, likes):
self.id = int(id)
self.url = url
self.likes = int(likes)
self._content = None
@classmethod
def from_dict(cls, resource):
return cls(**dict([(str(k), v) for k, v in resource.iteritems()]))
@classmethod
def extract(cls, resource):
return [cls.from_dict(i) for i in resource.get(cls.KEY, {})]
@Immutable.mutablemethod
def content(self):
if not self._content:
self._content = requests.get(self.url).content
return self._content
def __str__(self):
return self.url
class ResourceItem(Immutable):
WS = NotImplemented
request_cls = Request
@classmethod
def from_dict(cls, map):
raise NotImplementedError
@classmethod
def get(cls, id):
map = cls.request_cls(
apikey=os.environ.get('FANART_APIKEY'),
id=id,
ws=cls.WS
).response()
return cls.from_dict(map)
def json(self, **kw):
return json.dumps(
self,
default=lambda o: dict([(k, v) for k, v in o.__dict__.items() if not k.startswith('_')]),
**kw
)
class CollectableItem(Immutable):
@classmethod
def from_dict(cls, key, map):
raise NotImplementedError
@classmethod
def collection_from_dict(cls, map):
return [cls.from_dict(k, v) for k, v in map.iteritems()]

103
lib/fanart/movie.py Normal file
View File

@ -0,0 +1,103 @@
import fanart
from fanart.items import LeafItem, Immutable, ResourceItem
__all__ = (
'ArtItem',
'DiscItem',
'LogoItem',
'PosterItem',
'BackgroundItem',
'HdLogoItem',
'HdArtItem',
'BannerItem',
'ThumbItem',
'Movie',
)
class MovieItem(LeafItem):
@Immutable.mutablemethod
def __init__(self, id, url, likes, lang):
super(MovieItem, self).__init__(id, url, likes)
self.lang = lang
class DiscItem(MovieItem):
KEY = fanart.TYPE.MOVIE.DISC
@Immutable.mutablemethod
def __init__(self, id, url, likes, lang, disc, disc_type):
super(DiscItem, self).__init__(id, url, likes, lang)
self.disc = int(disc)
self.disc_type = disc_type
class ArtItem(MovieItem):
KEY = fanart.TYPE.MOVIE.ART
class LogoItem(MovieItem):
KEY = fanart.TYPE.MOVIE.LOGO
class PosterItem(MovieItem):
KEY = fanart.TYPE.MOVIE.POSTER
class BackgroundItem(MovieItem):
KEY = fanart.TYPE.MOVIE.BACKGROUND
class HdLogoItem(MovieItem):
KEY = fanart.TYPE.MOVIE.HDLOGO
class HdArtItem(MovieItem):
KEY = fanart.TYPE.MOVIE.HDART
class BannerItem(MovieItem):
KEY = fanart.TYPE.MOVIE.BANNER
class ThumbItem(MovieItem):
KEY = fanart.TYPE.MOVIE.THUMB
class Movie(ResourceItem):
WS = fanart.WS.MOVIE
@Immutable.mutablemethod
def __init__(self, name, imdbid, tmdbid, arts, logos, discs, posters, backgrounds, hdlogos, hdarts,
banners, thumbs):
self.name = name
self.imdbid = imdbid
self.tmdbid = tmdbid
self.arts = arts
self.posters = posters
self.logos = logos
self.discs = discs
self.backgrounds = backgrounds
self.hdlogos = hdlogos
self.hdarts = hdarts
self.banners = banners
self.thumbs = thumbs
@classmethod
def from_dict(cls, resource):
assert len(resource) == 1, 'Bad Format Map'
name, resource = resource.items()[0]
return cls(
name=name,
imdbid=resource['imdb_id'],
tmdbid=resource['tmdb_id'],
arts=ArtItem.extract(resource),
logos=LogoItem.extract(resource),
discs=DiscItem.extract(resource),
posters=PosterItem.extract(resource),
backgrounds=BackgroundItem.extract(resource),
hdlogos=HdLogoItem.extract(resource),
hdarts=HdArtItem.extract(resource),
banners=BannerItem.extract(resource),
thumbs=ThumbItem.extract(resource),
)

80
lib/fanart/music.py Normal file
View File

@ -0,0 +1,80 @@
from fanart.items import Immutable, LeafItem, ResourceItem, CollectableItem
import fanart
__all__ = (
'BackgroundItem',
'CoverItem',
'LogoItem',
'ThumbItem',
'DiscItem',
'Artist',
'Album',
)
class BackgroundItem(LeafItem):
KEY = fanart.TYPE.MUSIC.BACKGROUND
class CoverItem(LeafItem):
KEY = fanart.TYPE.MUSIC.COVER
class LogoItem(LeafItem):
KEY = fanart.TYPE.MUSIC.LOGO
class ThumbItem(LeafItem):
KEY = fanart.TYPE.MUSIC.THUMB
class DiscItem(LeafItem):
KEY = fanart.TYPE.MUSIC.DISC
@Immutable.mutablemethod
def __init__(self, id, url, likes, disc, size):
super(DiscItem, self).__init__(id, url, likes)
self.disc = int(disc)
self.size = int(size)
class Artist(ResourceItem):
WS = fanart.WS.MUSIC
@Immutable.mutablemethod
def __init__(self, name, mbid, albums, backgrounds, logos, thumbs):
self.name = name
self.mbid = mbid
self.albums = albums
self.backgrounds = backgrounds
self.logos = logos
self.thumbs = thumbs
@classmethod
def from_dict(cls, resource):
assert len(resource) == 1, 'Bad Format Map'
name, resource = resource.items()[0]
return cls(
name=name,
mbid=resource['mbid_id'],
albums=Album.collection_from_dict(resource.get('albums', {})),
backgrounds=BackgroundItem.extract(resource),
thumbs=ThumbItem.extract(resource),
logos=LogoItem.extract(resource),
)
class Album(CollectableItem):
@Immutable.mutablemethod
def __init__(self, mbid, covers, arts):
self.mbid = mbid
self.covers = covers
self.arts = arts
@classmethod
def from_dict(cls, key, resource):
return cls(
mbid=key,
covers=CoverItem.extract(resource),
arts=DiscItem.extract(resource),
)

View File

@ -0,0 +1,3 @@
import os
LOCALDIR = os.path.dirname(__file__)

View File

@ -0,0 +1,196 @@
{
"logos": [
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/clearlogo/wilfred-us-4e04b6495dfd3.png",
"likes": 2,
"id": 11977
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/clearlogo/wilfred-us-517ac36e39f67.png",
"likes": 1,
"id": 28249
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/clearlogo/wilfred-us-51f557082cfde.png",
"likes": 0,
"id": 31817
}
],
"arts": [
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/clearart/wilfred-us-4e05f10e87711.png",
"likes": 2,
"id": 11987
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/clearart/wilfred-us-4e2f151d5ed62.png",
"likes": 1,
"id": 12470
}
],
"name": "Wilfred (US)",
"hdarts": [
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/hdclearart/wilfred-us-505f94ed0ba13.png",
"likes": 1,
"id": 21112
},
{
"lang": "he",
"url": "http://assets.fanart.tv/fanart/tv/239761/hdclearart/wilfred-us-52403264aa3ec.png",
"likes": 1,
"id": 33751
}
],
"backgrounds": [
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/showbackground/wilfred-us-5034dbd49115e.jpg",
"id": 19965,
"season": 0,
"likes": 0
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/showbackground/wilfred-us-50b0c92db6973.jpg",
"id": 23166,
"season": 0,
"likes": 0
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/showbackground/wilfred-us-50b0c92dbb46b.jpg",
"id": 23167,
"season": 0,
"likes": 0
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/showbackground/wilfred-us-50b0c92dbb9d1.jpg",
"id": 23168,
"season": 0,
"likes": 0
}
],
"thumbs": [
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/tvthumb/wilfred-us-501cf526174fe.jpg",
"likes": 1,
"id": 19596
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/tvthumb/wilfred-us-51bfb4a105904.jpg",
"likes": 0,
"id": 30060
}
],
"characters": [],
"posters": [
{
"lang": "he",
"url": "http://assets.fanart.tv/fanart/tv/239761/tvposter/wilfred-us-525d893230d7c.jpg",
"likes": 1,
"id": 34584
}
],
"seasons": [
{
"lang": "he",
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-52403782bab55.jpg",
"id": 33752,
"season": 1,
"likes": 1
},
{
"lang": "he",
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-5240379335232.jpg",
"id": 33753,
"season": 2,
"likes": 1
},
{
"lang": "he",
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-524037bc83c7d.jpg",
"id": 33754,
"season": 3,
"likes": 1
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-501bb0a8e60f9.jpg",
"id": 19586,
"season": 1,
"likes": 0
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-501bb0b4bf229.jpg",
"id": 19587,
"season": 2,
"likes": 0
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-501bb144e6a46.jpg",
"id": 19588,
"season": 0,
"likes": 0
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-51c953105ef77.jpg",
"id": 30309,
"season": 3,
"likes": 0
}
],
"banners": [
{
"lang": "he",
"url": "http://assets.fanart.tv/fanart/tv/239761/tvbanner/wilfred-us-52403a7185070.jpg",
"likes": 1,
"id": 33755
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/tvbanner/wilfred-us-5265193db51f7.jpg",
"likes": 0,
"id": 34716
}
],
"hdlogos": [
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/hdtvlogo/wilfred-us-505f373be58e6.png",
"likes": 1,
"id": 21101
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/hdtvlogo/wilfred-us-517ac360def17.png",
"likes": 1,
"id": 28248
},
{
"lang": "he",
"url": "http://assets.fanart.tv/fanart/tv/239761/hdtvlogo/wilfred-us-52402df7ed945.png",
"likes": 1,
"id": 33750
},
{
"lang": "en",
"url": "http://assets.fanart.tv/fanart/tv/239761/hdtvlogo/wilfred-us-51f556fb4abd3.png",
"likes": 0,
"id": 31816
}
],
"tvdbid": "239761"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 B

View File

@ -0,0 +1,174 @@
{
"The Hunger Games": {
"tmdb_id": "70160",
"imdb_id": "tt1392170",
"movieart": [
{
"id": "1226",
"url": "http://assets.fanart.tv/fanart/movies/70160/movieart/the-hunger-games-4f6dc995edb8f.png",
"lang": "en",
"likes": "3"
},
{
"id": "1225",
"url": "http://assets.fanart.tv/fanart/movies/70160/movieart/the-hunger-games-4f6dc980b4514.png",
"lang": "en",
"likes": "1"
}
],
"movielogo": [
{
"id": "1230",
"url": "http://assets.fanart.tv/fanart/movies/70160/movielogo/the-hunger-games-4f6e0e63a9d29.png",
"lang": "en",
"likes": "2"
},
{
"id": "8020",
"url": "http://assets.fanart.tv/fanart/movies/70160/movielogo/the-hunger-games-5018f873b5188.png",
"lang": "en",
"likes": "1"
},
{
"id": "1224",
"url": "http://assets.fanart.tv/fanart/movies/70160/movielogo/the-hunger-games-4f6dc95a08de1.png",
"lang": "en",
"likes": "0"
}
],
"moviedisc": [
{
"id": "8431",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviedisc/the-hunger-games-501db4437623f.png",
"lang": "en",
"likes": "1",
"disc": "1",
"disc_type": "dvd"
},
{
"id": "9787",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviedisc/the-hunger-games-502fd6d695a60.png",
"lang": "en",
"likes": "1",
"disc": "1",
"disc_type": "bluray"
}
],
"moviethumb": [
{
"id": "10687",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviethumb/the-hunger-games-503c88b32cf66.jpg",
"lang": "en",
"likes": "0"
}
],
"hdmovielogo": [
{
"id": "13004",
"url": "http://assets.fanart.tv/fanart/movies/70160/hdmovielogo/the-hunger-games-50500118613e3.png",
"lang": "en",
"likes": "0"
}
],
"moviebackground": [
{
"id": "14043",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5057c79ad3c56.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "14044",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5057c79ad5526.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15911",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071de49311d1.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15914",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071df619b835.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15917",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e01fee856.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15918",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e0adcc57a.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15919",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e12006159.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15921",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e206aa2ac.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15922",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e2869d774.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15925",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e30069b72.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15927",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e3c4979b7.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15930",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e5b3f039b.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15931",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e6369e812.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15936",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e8749e73a.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "15937",
"url": "http://assets.fanart.tv/fanart/movies/70160/moviebackground/the-hunger-games-5071e9913bfeb.jpg",
"lang": "en",
"likes": "0"
}
],
"hdmovieclearart": [
{
"id": "14104",
"url": "http://assets.fanart.tv/fanart/movies/70160/hdmovieclearart/the-hunger-games-50582453b1375.png",
"lang": "en",
"likes": "0"
}
]
}
}

View File

@ -0,0 +1,171 @@
{
"Avenged Sevenfold": {
"mbid_id": "24e1b53c-3085-4581-8472-0b0088d2508c",
"artistbackground": [
{
"id": "3027",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/artistbackground/avenged-sevenfold-4ddd7889a0fcf.jpg",
"likes": "0"
},
{
"id": "64046",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/artistbackground/avenged-sevenfold-50c4db9a2c6e2.jpg",
"likes": "0"
},
{
"id": "64048",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/artistbackground/avenged-sevenfold-50c4dc653f004.jpg",
"likes": "0"
}
],
"albums": {
"180560ee-2d9d-33cf-8de7-cdaaba610739": {
"albumcover": [
{
"id": "3028",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/albumcover/city-of-evil-4ddd79ca0beea.jpg",
"likes": "0"
}
],
"cdart": [
{
"id": "9921",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/cdart/city-of-evil-4e5f7b9f50d37.png",
"likes": "0",
"disc": "1",
"size": "1000"
}
]
},
"1c7120ae-32b6-3693-8974-599977b01601": {
"albumcover": [
{
"id": "3029",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/albumcover/waking-the-fallen-4ddd79ca1b11e.jpg",
"likes": "0"
}
],
"cdart": [
{
"id": "9922",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/cdart/waking-the-fallen-4e5f7b9f5ebdf.png",
"likes": "0",
"disc": "1",
"size": "1000"
}
]
},
"94672194-7f42-3965-a489-f2f3cdc1c79e": {
"albumcover": [
{
"id": "3030",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/albumcover/avenged-sevenfold-4ddd79ca1bcd6.jpg",
"likes": "0"
}
],
"cdart": [
{
"id": "9923",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/cdart/avenged-sevenfold-4e5f7b9f5fb7f.png",
"likes": "0",
"disc": "1",
"size": "1000"
}
]
},
"9d642393-0005-3e89-b3d4-35d89c2f6ad6": {
"albumcover": [
{
"id": "3031",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/albumcover/sounding-the-seventh-trumpet-4ddd79ca1d05e.jpg",
"likes": "0"
}
],
"cdart": [
{
"id": "9924",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/cdart/sounding-the-seventh-trumpet-4e5f7b9f62e47.png",
"likes": "0",
"disc": "1",
"size": "1000"
}
]
},
"fe4373ed-5e89-46b3-b4c0-31433ce217df": {
"albumcover": [
{
"id": "3032",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/albumcover/nightmare-4ddd79ca1dffe.jpg",
"likes": "0"
}
],
"cdart": [
{
"id": "11630",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/cdart/nightmare-4e8059a3c581c.png",
"likes": "0",
"disc": "1",
"size": "1000"
}
]
},
"41d1b72b-1eee-3319-937f-c85d6d2fcfbb": {
"albumcover": [
{
"id": "61014",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/albumcover/warmness-on-the-soul-509d2e9150bf4.jpg",
"likes": "0"
}
]
}
},
"musiclogo": [
{
"id": "5712",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/musiclogo/avenged-sevenfold-4dfc8aee78b49.png",
"likes": "0"
},
{
"id": "41835",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/musiclogo/avenged-sevenfold-4ffc75f3a7e54.png",
"likes": "0"
},
{
"id": "41836",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/musiclogo/avenged-sevenfold-4ffc75f3a8473.png",
"likes": "0"
}
],
"artistthumb": [
{
"id": "31109",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/artistthumb/avenged-sevenfold-4fb2b533bc73a.jpg",
"likes": "0"
},
{
"id": "64042",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/artistthumb/avenged-sevenfold-50c4d9279d6e9.jpg",
"likes": "0"
}
],
"hdmusiclogo": [
{
"id": "49644",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/hdmusiclogo/avenged-sevenfold-503fcebece042.png",
"likes": "0"
},
{
"id": "49645",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/hdmusiclogo/avenged-sevenfold-503fcebecf17e.png",
"likes": "0"
}
],
"musicbanner": [
{
"id": "52630",
"url": "http://assets.fanart.tv/fanart/music/24e1b53c-3085-4581-8472-0b0088d2508c/musicbanner/avenged-sevenfold-505b2346a559d.jpg",
"likes": "0"
}
]
}
}

View File

@ -0,0 +1,196 @@
{
"Wilfred (US)": {
"hdclearart": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/hdclearart/wilfred-us-505f94ed0ba13.png",
"lang": "en",
"id": "21112",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/hdclearart/wilfred-us-52403264aa3ec.png",
"lang": "he",
"id": "33751",
"likes": "1"
}
],
"seasonthumb": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-52403782bab55.jpg",
"lang": "he",
"id": "33752",
"season": "1",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-5240379335232.jpg",
"lang": "he",
"id": "33753",
"season": "2",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-524037bc83c7d.jpg",
"lang": "he",
"id": "33754",
"season": "3",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-501bb0a8e60f9.jpg",
"lang": "en",
"id": "19586",
"season": "1",
"likes": "0"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-501bb0b4bf229.jpg",
"lang": "en",
"id": "19587",
"season": "2",
"likes": "0"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-501bb144e6a46.jpg",
"lang": "en",
"id": "19588",
"season": "0",
"likes": "0"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/seasonthumb/wilfred-us-51c953105ef77.jpg",
"lang": "en",
"id": "30309",
"season": "3",
"likes": "0"
}
],
"tvbanner": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/tvbanner/wilfred-us-52403a7185070.jpg",
"lang": "he",
"id": "33755",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/tvbanner/wilfred-us-5265193db51f7.jpg",
"lang": "en",
"id": "34716",
"likes": "0"
}
],
"thetvdb_id": "239761",
"clearlogo": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/clearlogo/wilfred-us-4e04b6495dfd3.png",
"lang": "en",
"id": "11977",
"likes": "2"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/clearlogo/wilfred-us-517ac36e39f67.png",
"lang": "en",
"id": "28249",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/clearlogo/wilfred-us-51f557082cfde.png",
"lang": "en",
"id": "31817",
"likes": "0"
}
],
"tvposter": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/tvposter/wilfred-us-525d893230d7c.jpg",
"lang": "he",
"id": "34584",
"likes": "1"
}
],
"showbackground": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/showbackground/wilfred-us-5034dbd49115e.jpg",
"lang": "en",
"id": "19965",
"season": "all",
"likes": "0"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/showbackground/wilfred-us-50b0c92db6973.jpg",
"lang": "en",
"id": "23166",
"season": "all",
"likes": "0"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/showbackground/wilfred-us-50b0c92dbb46b.jpg",
"lang": "en",
"id": "23167",
"season": "all",
"likes": "0"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/showbackground/wilfred-us-50b0c92dbb9d1.jpg",
"lang": "en",
"id": "23168",
"season": "all",
"likes": "0"
}
],
"tvthumb": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/tvthumb/wilfred-us-501cf526174fe.jpg",
"lang": "en",
"id": "19596",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/tvthumb/wilfred-us-51bfb4a105904.jpg",
"lang": "en",
"id": "30060",
"likes": "0"
}
],
"clearart": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/clearart/wilfred-us-4e05f10e87711.png",
"lang": "en",
"id": "11987",
"likes": "2"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/clearart/wilfred-us-4e2f151d5ed62.png",
"lang": "en",
"id": "12470",
"likes": "1"
}
],
"hdtvlogo": [
{
"url": "http://assets.fanart.tv/fanart/tv/239761/hdtvlogo/wilfred-us-505f373be58e6.png",
"lang": "en",
"id": "21101",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/hdtvlogo/wilfred-us-517ac360def17.png",
"lang": "en",
"id": "28248",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/hdtvlogo/wilfred-us-52402df7ed945.png",
"lang": "he",
"id": "33750",
"likes": "1"
},
{
"url": "http://assets.fanart.tv/fanart/tv/239761/hdtvlogo/wilfred-us-51f556fb4abd3.png",
"lang": "en",
"id": "31816",
"likes": "0"
}
]
}
}

View File

@ -0,0 +1,756 @@
{
"Dexter": {
"thetvdb_id": "79349",
"hdtvlogo": [
{
"id": "20959",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdtvlogo/dexter-50575994eb118.png",
"lang": "en",
"likes": "10"
},
{
"id": "20378",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdtvlogo/dexter-503fc2f24d9b3.png",
"lang": "en",
"likes": "5"
}
],
"hdclearart": [
{
"id": "23059",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-50af98e73b0a5.png",
"lang": "en",
"likes": "8"
},
{
"id": "24313",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-50eb4363da522.png",
"lang": "en",
"likes": "5"
},
{
"id": "20560",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-504775fd50557.png",
"lang": "en",
"likes": "4"
},
{
"id": "29495",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-51aa63100548b.png",
"lang": "en",
"likes": "3"
},
{
"id": "26712",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-51400b1672938.png",
"lang": "en",
"likes": "1"
},
{
"id": "29496",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-51aa724f0a2ab.png",
"lang": "en",
"likes": "1"
},
{
"id": "29505",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-51aab23851368.png",
"lang": "en",
"likes": "1"
},
{
"id": "29594",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-51afbcdf38d5e.png",
"lang": "en",
"likes": "1"
},
{
"id": "29595",
"url": "http://assets.fanart.tv/fanart/tv/79349/hdclearart/dexter-51afbcdf3ea8e.png",
"lang": "en",
"likes": "1"
}
],
"clearlogo": [
{
"id": "20958",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearlogo/dexter-5057573260826.png",
"lang": "en",
"likes": "6"
},
{
"id": "2114",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearlogo/Dexter-79349-2.png",
"lang": "en",
"likes": "4"
},
{
"id": "14577",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearlogo/dexter-4ecdf0c030189.png",
"lang": "en",
"likes": "3"
},
{
"id": "16685",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearlogo/dexter-4f6879db58edf.png",
"lang": "ru",
"likes": "1"
}
],
"characterart": [
{
"id": "16825",
"url": "http://assets.fanart.tv/fanart/tv/79349/characterart/dexter-4f76318ae4410.png",
"lang": "en",
"likes": "5"
},
{
"id": "29497",
"url": "http://assets.fanart.tv/fanart/tv/79349/characterart/dexter-51aa726346bcf.png",
"lang": "en",
"likes": "3"
},
{
"id": "14981",
"url": "http://assets.fanart.tv/fanart/tv/79349/characterart/dexter-4eface5cee809.png",
"lang": "en",
"likes": "1"
},
{
"id": "16996",
"url": "http://assets.fanart.tv/fanart/tv/79349/characterart/dexter-4f8189d220d4b.png",
"lang": "en",
"likes": "1"
},
{
"id": "26713",
"url": "http://assets.fanart.tv/fanart/tv/79349/characterart/dexter-51400b26c65de.png",
"lang": "en",
"likes": "1"
},
{
"id": "29597",
"url": "http://assets.fanart.tv/fanart/tv/79349/characterart/dexter-51afbcf6002a7.png",
"lang": "en",
"likes": "1"
},
{
"id": "29598",
"url": "http://assets.fanart.tv/fanart/tv/79349/characterart/dexter-51afbcf6006e6.png",
"lang": "en",
"likes": "1"
},
{
"id": "29646",
"url": "http://assets.fanart.tv/fanart/tv/79349/characterart/dexter-51b0fc45e0dc0.png",
"lang": "en",
"likes": "1"
}
],
"clearart": [
{
"id": "4980",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearart/D_79349 (3).png",
"lang": "en",
"likes": "4"
},
{
"id": "14579",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearart/dexter-4ecdf0db2adf1.png",
"lang": "en",
"likes": "3"
},
{
"id": "16682",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearart/dexter-4f68753540f2d.png",
"lang": "ru",
"likes": "1"
},
{
"id": "4982",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearart/D_79349.png",
"lang": "en",
"likes": "0"
},
{
"id": "4983",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearart/D_79349 (1).png",
"lang": "en",
"likes": "0"
},
{
"id": "4984",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearart/D_79349 (0).png",
"lang": "en",
"likes": "0"
},
{
"id": "14578",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearart/dexter-4ecdf0cf3fb38.png",
"lang": "en",
"likes": "0"
},
{
"id": "17196",
"url": "http://assets.fanart.tv/fanart/tv/79349/clearart/dexter-4f8af83f3bde7.png",
"lang": "en",
"likes": "0"
}
],
"showbackground": [
{
"id": "18467",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-4fc683691dea7.jpg",
"lang": "en",
"likes": "4",
"season": "1"
},
{
"id": "18950",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-4fdf608e2df53.jpg",
"lang": "en",
"likes": "2",
"season": "3"
},
{
"id": "18466",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-4fc6830dc2ccc.jpg",
"lang": "en",
"likes": "1",
"season": "4"
},
{
"id": "18468",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-4fc683a5ab451.jpg",
"lang": "en",
"likes": "1",
"season": "6"
},
{
"id": "21524",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-506bdd9c35771.jpg",
"lang": "en",
"likes": "1",
"season": "all"
},
{
"id": "21526",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-506bddc9f04cb.jpg",
"lang": "en",
"likes": "1",
"season": ""
},
{
"id": "21530",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-506bde2654668.jpg",
"lang": "en",
"likes": "1",
"season": "all"
},
{
"id": "24058",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-50def777ea9c8.jpg",
"lang": "en",
"likes": "1",
"season": "all"
},
{
"id": "18515",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-4fc8eab16803c.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "18947",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-4fdf5e107be0d.jpg",
"lang": "en",
"likes": "0",
"season": "5"
},
{
"id": "18949",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-4fdf601385517.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "18952",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-4fdf6386ce1c1.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "21525",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-506bddb3bd3f4.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "21527",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-506bdddc3f476.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "21529",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-506bde113406e.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "24046",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-50de1f84e736f.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "24048",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-50de1f84e7d57.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "24049",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-50de21ac3ae25.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "24054",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-50def777e84d0.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "24055",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-50def777e8dbc.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "24056",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-50def777e9762.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "24986",
"url": "http://assets.fanart.tv/fanart/tv/79349/showbackground/dexter-5101fa187c857.jpg",
"lang": "en",
"likes": "0",
"season": "all"
}
],
"seasonthumb": [
{
"id": "18986",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fe21b7708ebe.jpg",
"lang": "en",
"likes": "3",
"season": "6"
},
{
"id": "5002",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (6).jpg",
"lang": "en",
"likes": "1",
"season": "3"
},
{
"id": "5003",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (5).jpg",
"lang": "en",
"likes": "1",
"season": "1"
},
{
"id": "17802",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fa981a7251d7.jpg",
"lang": "en",
"likes": "1",
"season": "5"
},
{
"id": "17823",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4faab0bccbfb6.jpg",
"lang": "en",
"likes": "1",
"season": "6"
},
{
"id": "18980",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fe21a6955116.jpg",
"lang": "en",
"likes": "1",
"season": "1"
},
{
"id": "18982",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fe21b0767edb.jpg",
"lang": "en",
"likes": "1",
"season": "2"
},
{
"id": "18983",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fe21b292d661.jpg",
"lang": "en",
"likes": "1",
"season": "3"
},
{
"id": "18984",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fe21b42d983d.jpg",
"lang": "en",
"likes": "1",
"season": "4"
},
{
"id": "18985",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fe21b5847d7b.jpg",
"lang": "en",
"likes": "1",
"season": "5"
},
{
"id": "21883",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-5071800d37e80.jpg",
"lang": "en",
"likes": "1",
"season": "7"
},
{
"id": "4989",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (9).jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "4990",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (19).jpg",
"lang": "en",
"likes": "0",
"season": "4"
},
{
"id": "4991",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (18).jpg",
"lang": "en",
"likes": "0",
"season": "4"
},
{
"id": "4992",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (17).jpg",
"lang": "en",
"likes": "0",
"season": "3"
},
{
"id": "4993",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (16).jpg",
"lang": "en",
"likes": "0",
"season": "2"
},
{
"id": "4994",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (15).jpg",
"lang": "en",
"likes": "0",
"season": "1"
},
{
"id": "4995",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (14).jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "4996",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (13).jpg",
"lang": "en",
"likes": "0",
"season": "4"
},
{
"id": "4997",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (12).jpg",
"lang": "en",
"likes": "0",
"season": "3"
},
{
"id": "4998",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (11).jpg",
"lang": "en",
"likes": "0",
"season": "2"
},
{
"id": "4999",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (10).jpg",
"lang": "en",
"likes": "0",
"season": "1"
},
{
"id": "5000",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (8).jpg",
"lang": "en",
"likes": "0",
"season": "2"
},
{
"id": "5001",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (7).jpg",
"lang": "en",
"likes": "0",
"season": "4"
},
{
"id": "5004",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter.jpg",
"lang": "en",
"likes": "0",
"season": "all"
},
{
"id": "5005",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (4).jpg",
"lang": "en",
"likes": "0",
"season": "5"
},
{
"id": "5006",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (3).jpg",
"lang": "en",
"likes": "0",
"season": "4"
},
{
"id": "5007",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (2).jpg",
"lang": "en",
"likes": "0",
"season": "3"
},
{
"id": "5008",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (1).jpg",
"lang": "en",
"likes": "0",
"season": "2"
},
{
"id": "5009",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/Dexter (0).jpg",
"lang": "en",
"likes": "0",
"season": "1"
},
{
"id": "17803",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fa981a7258fb.jpg",
"lang": "en",
"likes": "0",
"season": "5"
},
{
"id": "17804",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fa981a725c14.jpg",
"lang": "en",
"likes": "0",
"season": "5"
},
{
"id": "17805",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fa981c6607e4.jpg",
"lang": "en",
"likes": "0",
"season": "0"
},
{
"id": "17807",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fa98ac2b811d.jpg",
"lang": "en",
"likes": "0",
"season": "6"
},
{
"id": "17808",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fa98ac2b87ab.jpg",
"lang": "en",
"likes": "0",
"season": "6"
},
{
"id": "17810",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fa994697afa3.jpg",
"lang": "en",
"likes": "0",
"season": "6"
},
{
"id": "18514",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-4fc8e9fa79bf8.jpg",
"lang": "en",
"likes": "0",
"season": "7"
},
{
"id": "31022",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-51dc720661cb7.jpg",
"lang": "en",
"likes": "0",
"season": "8"
},
{
"id": "31023",
"url": "http://assets.fanart.tv/fanart/tv/79349/seasonthumb/dexter-51dc72a19a0bb.jpg",
"lang": "en",
"likes": "0",
"season": "8"
}
],
"tvthumb": [
{
"id": "5012",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (10).jpg",
"lang": "en",
"likes": "2"
},
{
"id": "5023",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (0).jpg",
"lang": "en",
"likes": "2"
},
{
"id": "14580",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/dexter-4ecdf5027a53c.jpg",
"lang": "en",
"likes": "2"
},
{
"id": "5013",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (9).jpg",
"lang": "en",
"likes": "1"
},
{
"id": "5016",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (6).jpg",
"lang": "en",
"likes": "1"
},
{
"id": "5020",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (2).jpg",
"lang": "en",
"likes": "1"
},
{
"id": "29341",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/dexter-51a338d376b4a.jpg",
"lang": "de",
"likes": "1"
},
{
"id": "31722",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/dexter-51f27112a2a89.jpg",
"lang": "en",
"likes": "1"
},
{
"id": "5010",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (12).jpg",
"lang": "en",
"likes": "0"
},
{
"id": "5011",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (11).jpg",
"lang": "en",
"likes": "0"
},
{
"id": "5014",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (8).jpg",
"lang": "en",
"likes": "0"
},
{
"id": "5015",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (7).jpg",
"lang": "en",
"likes": "0"
},
{
"id": "5017",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (5).jpg",
"lang": "en",
"likes": "0"
},
{
"id": "5018",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (4).jpg",
"lang": "en",
"likes": "0"
},
{
"id": "5019",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (3).jpg",
"lang": "en",
"likes": "0"
},
{
"id": "5021",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349.jpg",
"lang": "en",
"likes": "0"
},
{
"id": "5022",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/D_79349 (1).jpg",
"lang": "en",
"likes": "0"
},
{
"id": "14277",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvthumb/dexter-4ead4375923fd.jpg",
"lang": "en",
"likes": "0"
}
],
"tvbanner": [
{
"id": "30062",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvbanner/dexter-51bfc857c84fd.jpg",
"lang": "en",
"likes": "1"
},
{
"id": "30063",
"url": "http://assets.fanart.tv/fanart/tv/79349/tvbanner/dexter-51bfc89667267.jpg",
"lang": "en",
"likes": "1"
}
]
}
}

View File

@ -0,0 +1,23 @@
from unittest import TestCase
from fanart.core import Request
from fanart.errors import RequestFanartError, ResponseFanartError
from httpretty import httprettified, HTTPretty
class RequestTestCase(TestCase):
def test_valitate_error(self):
self.assertRaises(RequestFanartError, Request, 'key', 'id', 'sport')
@httprettified
def test_response_error(self):
request = Request('apikey', 'objid', 'series')
HTTPretty.register_uri(
HTTPretty.GET,
'http://api.fanart.tv/webservice/series/apikey/objid/JSON/all/1/2',
body='Please specify a valid API key',
)
try:
request.response()
except ResponseFanartError as e:
self.assertEqual(repr(e), "ResponseFanartError('No JSON object could be decoded',)")
self.assertEqual(str(e), 'No JSON object could be decoded')

View File

@ -0,0 +1,49 @@
from unittest import TestCase
from fanart.immutable import Immutable
class TestMutable(object):
def __init__(self, spam, ham, eggs):
self.spam = spam
self.ham = ham
self.eggs = eggs
@Immutable.mutablemethod
def anyway(self):
self.spam = self.ham + self.eggs
class TestImmutable(TestMutable, Immutable):
@Immutable.mutablemethod
def __init__(self, *args, **kwargs):
super(TestImmutable, self).__init__(*args, **kwargs)
class ImmutableTestCase(TestCase):
def setUp(self):
self.instance = TestImmutable('spam', 'ham', 'eggs')
def test_set_raises(self):
self.assertRaises(TypeError, self.instance.__setattr__, 'spam', 'ham')
def test_set(self):
self.instance._mutable = True
self.instance.spam = 'ham'
self.assertEqual(self.instance.spam, 'ham')
def test_del_raises(self):
self.assertRaises(TypeError, self.instance.__delattr__, 'spam')
def test_del(self):
self.instance._mutable = True
del self.instance.spam
self.assertRaises(AttributeError, self.instance.__getattribute__, 'spam')
def test_equal(self):
new_instance = TestImmutable('spam', 'ham', 'eggs')
self.assertEqual(self.instance, new_instance)
def test_mutable_dec(self):
instance = TestMutable('spam', 'ham', 'eggs')
instance.anyway()
self.assertEqual(instance.spam, 'hameggs')

View File

@ -0,0 +1,27 @@
from unittest import TestCase
import os
from fanart.items import LeafItem
from httpretty import httprettified, HTTPretty
from fanart.tests import LOCALDIR
class LeafItemTestCase(TestCase):
def setUp(self):
self.leaf = LeafItem(id=11977, likes=2, url='http://test.tv/50x50.txt')
def test_str(self):
self.assertEqual(str(self.leaf), 'http://test.tv/50x50.txt')
@httprettified
def test_content(self):
with open(os.path.join(LOCALDIR, 'response/50x50.png')) as fp:
body = fp.read()
HTTPretty.register_uri(
HTTPretty.GET,
'http://test.tv/50x50.txt',
body=body
)
self.assertEqual(self.leaf.content(), body)
self.assertEqual(len(HTTPretty.latest_requests), 1)
self.assertEqual(self.leaf.content(), body) # Cached
self.assertEqual(len(HTTPretty.latest_requests), 1)

View File

@ -0,0 +1,21 @@
import os
import unittest
from httpretty import HTTPretty, httprettified
from fanart.movie import *
from fanart.tests import LOCALDIR
os.environ['FANART_APIKEY'] = 'e3c7f0d0beeaf45b3a0dd3b9dd8a3338'
class TvItemTestCase(unittest.TestCase):
@httprettified
def test_get(self):
with open(os.path.join(LOCALDIR, 'response/movie_thg.json')) as fp:
body = fp.read()
HTTPretty.register_uri(
HTTPretty.GET,
'http://api.fanart.tv/webservice/movie/e3c7f0d0beeaf45b3a0dd3b9dd8a3338/70160/JSON/all/1/2',
body=body
)
hunger_games = Movie.get(id=70160)
self.assertEqual(hunger_games.tmdbid, '70160')
self.assertEqual(hunger_games, eval(repr(hunger_games)))

View File

@ -0,0 +1,22 @@
import os
import unittest
from httpretty import HTTPretty, httprettified
from fanart.music import *
from fanart.tests import LOCALDIR
os.environ['FANART_APIKEY'] = 'e3c7f0d0beeaf45b3a0dd3b9dd8a3338'
class ArtistItemTestCase(unittest.TestCase):
@httprettified
def test_get(self):
with open(os.path.join(LOCALDIR, 'response/music_a7f.json')) as fp:
body = fp.read()
HTTPretty.register_uri(
HTTPretty.GET,
'http://api.fanart.tv/webservice/artist/e3c7f0d0beeaf45b3a0dd3b9dd8a3338/24e1b53c-3085-4581-8472-0b0088d2508c/JSON/all/1/2',
body=body
)
a7f = Artist.get(id='24e1b53c-3085-4581-8472-0b0088d2508c')
self.assertEqual(a7f.mbid, '24e1b53c-3085-4581-8472-0b0088d2508c')
self.assertEqual(a7f, eval(repr(a7f)))
self.assertEqual(len(a7f.thumbs), 2)

View File

@ -0,0 +1,46 @@
import json
from fanart.errors import ResponseFanartError
import os
import unittest
from httpretty import HTTPretty, httprettified
from fanart.tv import *
from fanart.tests import LOCALDIR
os.environ['FANART_APIKEY'] = 'e3c7f0d0beeaf45b3a0dd3b9dd8a3338'
class TvItemTestCase(unittest.TestCase):
@httprettified
def test_get_wilfred(self):
with open(os.path.join(LOCALDIR, 'response/tv_239761.json')) as fp:
body = fp.read()
HTTPretty.register_uri(
HTTPretty.GET,
'http://api.fanart.tv/webservice/series/e3c7f0d0beeaf45b3a0dd3b9dd8a3338/239761/JSON/all/1/2',
body=body
)
wilfred = TvShow.get(id=239761)
self.assertEqual(wilfred.tvdbid, '239761')
with open(os.path.join(LOCALDIR, 'json/wilfred.json')) as fp:
self.assertEqual(json.loads(wilfred.json()), json.load(fp))
@httprettified
def test_get_dexter(self):
with open(os.path.join(LOCALDIR, 'response/tv_79349.json')) as fp:
body = fp.read()
HTTPretty.register_uri(
HTTPretty.GET,
'http://api.fanart.tv/webservice/series/e3c7f0d0beeaf45b3a0dd3b9dd8a3338/79349/JSON/all/1/2',
body=body
)
dexter = TvShow.get(id=79349)
self.assertEqual(dexter.tvdbid, '79349')
self.assertEqual(dexter, eval(repr(dexter)))
@httprettified
def test_get_null(self):
HTTPretty.register_uri(
HTTPretty.GET,
'http://api.fanart.tv/webservice/series/e3c7f0d0beeaf45b3a0dd3b9dd8a3338/79349/JSON/all/1/2',
body='null'
)
self.assertRaises(ResponseFanartError, TvShow.get, id=79349)

108
lib/fanart/tv.py Normal file
View File

@ -0,0 +1,108 @@
import fanart
from fanart.items import LeafItem, Immutable, ResourceItem
__all__ = (
'CharacterItem',
'ArtItem',
'LogoItem',
'BackgroundItem',
'SeasonItem',
'ThumbItem',
'HdLogoItem',
'HdArtItem',
'PosterItem',
'BannerItem',
'TvShow',
)
class TvItem(LeafItem):
@Immutable.mutablemethod
def __init__(self, id, url, likes, lang):
super(TvItem, self).__init__(id, url, likes)
self.lang = lang
class SeasonedTvItem(TvItem):
@Immutable.mutablemethod
def __init__(self, id, url, likes, lang, season):
super(SeasonedTvItem, self).__init__(id, url, likes, lang)
self.season = 0 if season == 'all' else int(season or 0)
class CharacterItem(TvItem):
KEY = fanart.TYPE.TV.CHARACTER
class ArtItem(TvItem):
KEY = fanart.TYPE.TV.ART
class LogoItem(TvItem):
KEY = fanart.TYPE.TV.LOGO
class BackgroundItem(SeasonedTvItem):
KEY = fanart.TYPE.TV.BACKGROUND
class SeasonItem(SeasonedTvItem):
KEY = fanart.TYPE.TV.SEASONTHUMB
class ThumbItem(TvItem):
KEY = fanart.TYPE.TV.THUMB
class HdLogoItem(TvItem):
KEY = fanart.TYPE.TV.HDLOGO
class HdArtItem(TvItem):
KEY = fanart.TYPE.TV.HDART
class PosterItem(TvItem):
KEY = fanart.TYPE.TV.POSTER
class BannerItem(TvItem):
KEY = fanart.TYPE.TV.BANNER
class TvShow(ResourceItem):
WS = fanart.WS.TV
@Immutable.mutablemethod
def __init__(self, name, tvdbid, backgrounds, characters, arts, logos, seasons, thumbs, hdlogos, hdarts, posters,
banners):
self.name = name
self.tvdbid = tvdbid
self.backgrounds = backgrounds
self.characters = characters
self.arts = arts
self.logos = logos
self.seasons = seasons
self.thumbs = thumbs
self.hdlogos = hdlogos
self.hdarts = hdarts
self.posters = posters
self.banners = banners
@classmethod
def from_dict(cls, resource):
assert len(resource) == 1, 'Bad Format Map'
name, resource = resource.items()[0]
return cls(
name=name,
tvdbid=resource['thetvdb_id'],
backgrounds=BackgroundItem.extract(resource),
characters=CharacterItem.extract(resource),
arts=ArtItem.extract(resource),
logos=LogoItem.extract(resource),
seasons=SeasonItem.extract(resource),
thumbs=ThumbItem.extract(resource),
hdlogos=HdLogoItem.extract(resource),
hdarts=HdArtItem.extract(resource),
posters=PosterItem.extract(resource),
banners=BannerItem.extract(resource),
)

View File

@ -736,7 +736,7 @@ class Tvdb:
return
banners = {}
for cur_banner in bannersEt['banner']:
for cur_banner in bannersEt['banner'] if isinstance(bannersEt['banner'], list) else [bannersEt['banner']]:
bid = cur_banner['id']
btype = cur_banner['bannertype']
btype2 = cur_banner['bannertype2']
@ -797,7 +797,7 @@ class Tvdb:
return
cur_actors = Actors()
for cur_actor in actorsEt['actor']:
for cur_actor in actorsEt['actor'] if isinstance(actorsEt['actor'], list) else [actorsEt['actor']]:
curActor = Actor()
for k, v in cur_actor.items():
if k is None or v is None:

View File

@ -58,7 +58,7 @@ CFG = None
CONFIG_FILE = None
# This is the version of the config we EXPECT to find
CONFIG_VERSION = 5
CONFIG_VERSION = 6
# Default encryption version (0 for None)
ENCRYPTION_VERSION = 0
@ -148,7 +148,6 @@ CPU_PRESET = None
ANON_REDIRECT = None
USE_API = False
API_KEY = None
API_ROOT = None
@ -472,6 +471,7 @@ CALENDAR_UNPROTECTED = False
TMDB_API_KEY = 'edc5f123313769de83a71e157758030b'
TRAKT_API_KEY = 'abd806c54516240c76e4ebc9c5ccf394'
FANART_API_KEY = '9b3afaf26f6241bdb57d6cc6bd798da7'
__INITIALIZED__ = False
@ -484,7 +484,7 @@ def get_backlog_cycle_time():
def initialize(consoleLogging=True):
with INIT_LOCK:
global BRANCH, GIT_RESET, GIT_REMOTE, GIT_REMOTE_URL, CUR_COMMIT_HASH, CUR_COMMIT_BRANCH, ACTUAL_LOG_DIR, LOG_DIR, WEB_PORT, WEB_LOG, ENCRYPTION_VERSION, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, USE_API, API_KEY, API_ROOT, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, \
global BRANCH, GIT_RESET, GIT_REMOTE, GIT_REMOTE_URL, CUR_COMMIT_HASH, CUR_COMMIT_BRANCH, ACTUAL_LOG_DIR, LOG_DIR, WEB_PORT, WEB_LOG, ENCRYPTION_VERSION, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, API_KEY, API_ROOT, ENABLE_HTTPS, HTTPS_CERT, HTTPS_KEY, \
HANDLE_REVERSE_PROXY, USE_NZBS, USE_TORRENTS, NZB_METHOD, NZB_DIR, DOWNLOAD_PROPERS, RANDOMIZE_PROVIDERS, CHECK_PROPERS_INTERVAL, ALLOW_HIGH_PRIORITY, TORRENT_METHOD, \
SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, SAB_CATEGORY_ANIME, SAB_HOST, \
NZBGET_USERNAME, NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_CATEGORY_ANIME, NZBGET_PRIORITY, NZBGET_HOST, NZBGET_USE_HTTPS, backlogSearchScheduler, \
@ -658,7 +658,6 @@ def initialize(consoleLogging=True):
SORT_ARTICLE = bool(check_setting_int(CFG, 'General', 'sort_article', 0))
USE_API = bool(check_setting_int(CFG, 'General', 'use_api', 0))
API_KEY = check_setting_str(CFG, 'General', 'api_key', '', censor_log=True)
ENABLE_HTTPS = bool(check_setting_int(CFG, 'General', 'enable_https', 0))
@ -1435,7 +1434,6 @@ def save_config():
new_config['General']['localhost_ip'] = LOCALHOST_IP
new_config['General']['cpu_preset'] = CPU_PRESET
new_config['General']['anon_redirect'] = ANON_REDIRECT
new_config['General']['use_api'] = int(USE_API)
new_config['General']['api_key'] = API_KEY
new_config['General']['debug'] = int(DEBUG)
new_config['General']['enable_https'] = int(ENABLE_HTTPS)

View File

@ -17,6 +17,7 @@
# along with SickRage. If not, see <http://www.gnu.org/licenses/>.
import re
import sys
import traceback
import sickbeard
@ -275,13 +276,6 @@ class UIError():
"""
def __init__(self, message):
try:
self.title = sys.exc_info()[1].message
except:
self.title = None
self.title = sys.exc_info()[-2]
self.message = message
self.time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
try:
self.exc_info = sys.exc_info()
except:
self.exc_info = None
self.time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')

View File

@ -457,7 +457,8 @@ class ConfigMigrator():
2: 'Sync backup number with version number',
3: 'Rename omgwtfnzb variables',
4: 'Add newznab catIDs',
5: 'Metadata update'
5: 'Metadata update',
6: 'Convert from XBMC to new KODI variables'
}
def migrate_config(self):
@ -673,11 +674,11 @@ class ConfigMigrator():
new format: 0|0|0|0|0|0|0|0|0|0 -- 10 places
Drop the use of use_banner option.
Migrate the poster override to just using the banner option (applies to kodi only).
Migrate the poster override to just using the banner option (applies to xbmc only).
"""
metadata_kodi = check_setting_str(self.config_obj, 'General', 'metadata_kodi', '0|0|0|0|0|0')
metadata_kodi_12plus = check_setting_str(self.config_obj, 'General', 'metadata_kodi_12plus', '0|0|0|0|0|0')
metadata_xbmc = check_setting_str(self.config_obj, 'General', 'metadata_xbmc', '0|0|0|0|0|0')
metadata_xbmc_12plus = check_setting_str(self.config_obj, 'General', 'metadata_xbmc_12plus', '0|0|0|0|0|0')
metadata_mediabrowser = check_setting_str(self.config_obj, 'General', 'metadata_mediabrowser', '0|0|0|0|0|0')
metadata_ps3 = check_setting_str(self.config_obj, 'General', 'metadata_ps3', '0|0|0|0|0|0')
metadata_wdtv = check_setting_str(self.config_obj, 'General', 'metadata_wdtv', '0|0|0|0|0|0')
@ -698,7 +699,7 @@ class ConfigMigrator():
# swap show fanart, show poster
cur_metadata[3], cur_metadata[2] = cur_metadata[2], cur_metadata[3]
# if user was using use_banner to override the poster, instead enable the banner option and deactivate poster
if metadata_name == 'KODI' and use_banner:
if metadata_name == 'XBMC' and use_banner:
cur_metadata[4], cur_metadata[3] = cur_metadata[3], '0'
# write new format
metadata = '|'.join(cur_metadata)
@ -717,10 +718,27 @@ class ConfigMigrator():
return metadata
sickbeard.METADATA_KODI = _migrate_metadata(metadata_kodi, 'KODI', use_banner)
sickbeard.METADATA_KODI_12PLUS = _migrate_metadata(metadata_kodi_12plus, 'KODI 12+', use_banner)
sickbeard.METADATA_XBMC = _migrate_metadata(metadata_xbmc, 'XBMC', use_banner)
sickbeard.METADATA_XBMC_12PLUS = _migrate_metadata(metadata_xbmc_12plus, 'XBMC 12+', use_banner)
sickbeard.METADATA_MEDIABROWSER = _migrate_metadata(metadata_mediabrowser, 'MediaBrowser', use_banner)
sickbeard.METADATA_PS3 = _migrate_metadata(metadata_ps3, 'PS3', use_banner)
sickbeard.METADATA_WDTV = _migrate_metadata(metadata_wdtv, 'WDTV', use_banner)
sickbeard.METADATA_TIVO = _migrate_metadata(metadata_tivo, 'TIVO', use_banner)
sickbeard.METADATA_MEDE8ER = _migrate_metadata(metadata_mede8er, 'Mede8er', use_banner)
# Migration v6: Convert from XBMC to KODI variables
def _migrate_v6(self):
sickbeard.USE_KODI = bool(check_setting_int(self.config_obj, 'XBMC', 'use_xbmc', 0))
sickbeard.KODI_ALWAYS_ON = bool(check_setting_int(self.config_obj, 'XBMC', 'xbmc_always_on', 1))
sickbeard.KODI_NOTIFY_ONSNATCH = bool(check_setting_int(self.config_obj, 'XBMC', 'xbmc_notify_onsnatch', 0))
sickbeard.KODI_NOTIFY_ONDOWNLOAD = bool(check_setting_int(self.config_obj, 'XBMC', 'xbmc_notify_ondownload', 0))
sickbeard.KODI_NOTIFY_ONSUBTITLEDOWNLOAD = bool(check_setting_int(self.config_obj, 'XBMC', 'xbmc_notify_onsubtitledownload', 0))
sickbeard.KODI_UPDATE_LIBRARY = bool(check_setting_int(self.config_obj, 'XBMC', 'xbmc_update_library', 0))
sickbeard.KODI_UPDATE_FULL = bool(check_setting_int(self.config_obj, 'XBMC', 'xbmc_update_full', 0))
sickbeard.KODI_UPDATE_ONLYFIRST = bool(check_setting_int(self.config_obj, 'XBMC', 'xbmc_update_onlyfirst', 0))
sickbeard.KODI_HOST = check_setting_str(self.config_obj, 'XBMC', 'xbmc_host', '')
sickbeard.KODI_USERNAME = check_setting_str(self.config_obj, 'XBMC', 'xbmc_username', '', censor_log=True)
sickbeard.KODI_PASSWORD = check_setting_str(self.config_obj, 'XBMC', 'xbmc_password', '', censor_log=True)
sickbeard.METADATA_KODI = check_setting_str(self.config_obj, 'General', 'metadata_xbmc', '0|0|0|0|0|0|0|0|0|0')
sickbeard.METADATA_KODI_12PLUS = check_setting_str(self.config_obj, 'General', 'metadata_xbmc_12plus', '0|0|0|0|0|0|0|0|0|0')

View File

@ -73,18 +73,9 @@ class DBConnection(object):
raise
def _execute(self, query, args):
def convert(x):
if isinstance(x, basestring):
try:
x = unicode(x).decode(sickbeard.SYS_ENCODING)
except:
pass
return x
try:
if not args:
return self.connection.cursor().execute(query)
# args = map(convert, args)
return self.connection.cursor().execute(query, args)
except Exception as e:
raise e
@ -238,7 +229,10 @@ class DBConnection(object):
return columns
def _unicode_text_factory(self, x):
return unicode(x, 'utf-8')
try:
return unicode(x, 'utf-8')
except:
return unicode(x, sickbeard.SYS_ENCODING)
def _dict_factory(self, cursor, row):
d = {}

View File

@ -45,11 +45,16 @@ reverseNames = {u'ERROR': ERROR,
censoredItems = {}
class NullHandler(logging.Handler):
def emit(self, record):
pass
class CensoredFormatter(logging.Formatter):
class CensoredFormatter(logging.Formatter, object):
def __init__(self, *args, **kwargs):
super(CensoredFormatter, self).__init__(*args, **kwargs)
def format(self, record):
msg = super(CensoredFormatter, self).format(record)
for k, v in censoredItems.items():
@ -57,6 +62,7 @@ class CensoredFormatter(logging.Formatter):
msg = msg.replace(v, len(v) * '*')
return msg
class Logger(object):
def __init__(self):
self.logger = logging.getLogger('sickrage')
@ -65,7 +71,7 @@ class Logger(object):
logging.getLogger('sickrage'),
logging.getLogger('tornado.general'),
logging.getLogger('tornado.application'),
#logging.getLogger('tornado.access'),
# logging.getLogger('tornado.access'),
]
self.consoleLogging = False
@ -119,13 +125,14 @@ class Logger(object):
# pass exception information if debugging enabled
kwargs["exc_info"] = 1 if level == ERROR else 0
self.logger.log(level, message, *args, **kwargs)
if level == ERROR:
self.logger.exception(message, *args, **kwargs)
classes.ErrorViewer.add(classes.UIError(message))
#if sickbeard.GIT_AUTOISSUES:
# if sickbeard.GIT_AUTOISSUES:
# self.submit_errors()
else:
self.logger.log(level, message, *args, **kwargs)
def log_error_and_exit(self, error_msg, *args, **kwargs):
self.log(error_msg, ERROR, *args, **kwargs)
@ -139,37 +146,33 @@ class Logger(object):
if not (sickbeard.GIT_USERNAME and sickbeard.GIT_PASSWORD and len(classes.ErrorViewer.errors) > 0):
return
title = "[APP SUBMITTED]: "
gh_org = sickbeard.GIT_ORG or 'SiCKRAGETV'
gh_repo = 'sickrage-issues'
self.gh_issues = Github(login_or_token=sickbeard.GIT_USERNAME, password=sickbeard.GIT_PASSWORD,
user_agent="SiCKRAGE").get_organization(gh_org).get_repo(gh_repo)
gh_issues = Github(login_or_token=sickbeard.GIT_USERNAME, password=sickbeard.GIT_PASSWORD,
user_agent="SiCKRAGE").get_organization(gh_org).get_repo(gh_repo)
try:
# read log file
if self.logFile and os.path.isfile(self.logFile):
with ek.ek(open, self.logFile) as f:
log_data = f.readlines()
except Exception as e:
pass
log_data = [line for line in reversed(log_data)]
try:
# parse and submit errors to issue tracker
for curError in sorted(classes.ErrorViewer.errors, key=lambda error: error.time, reverse=True)[:500]:
if not curError.title:
continue
regex = "^(%s)\s*([A-Z]+)\s*(.+?)\s*\:\:\s*(.*)$" % curError.time
maxlines = 50
pastebin_url = None
for i, x in enumerate(reversed(log_data)):
regex = "^(%s)\s*([A-Z]+)\s*(.+?)\s*\:\:\s*(.*)$" % curError.time
for i, x in enumerate(log_data):
x = ek.ss(x)
match = re.match(regex, x)
if match:
level = match.group(2)
if reverseNames[level] == ERROR:
paste_data = "".join(log_data[len(log_data) - i - 50:])
paste_data = "".join(log_data[i:50])
pastebin_url = PastebinAPI().paste('f59b8e9fa1fc2d033e399e6c7fb09d19', paste_data)
break
@ -187,14 +190,16 @@ class Logger(object):
message += u"---\n"
message += u"_STAFF NOTIFIED_: @SiCKRAGETV/owners @SiCKRAGETV/moderators"
issue = self.gh_issues.create_issue(title + curError.title, message)
issue = gh_issues.create_issue("[APP SUBMITTED]: " + curError.title, message)
if issue:
self.log('Your issue ticket #%s was submitted successfully!' % issue.number)
if not sickbeard.GIT_AUTOISSUES:
ui.notifications.message('Your issue ticket #%s was submitted successfully!' % issue.number)
finally:
classes.ErrorViewer.clear()
# clear error from error list
classes.ErrorViewer.errors.remove(curError)
return issue
except Exception as e:
self.log(sickbeard.exceptions.ex(e), ERROR)
class Wrapper(object):
@ -209,5 +214,6 @@ class Wrapper(object):
except AttributeError:
return getattr(self.instance, name)
_globals = sys.modules[__name__] = Wrapper(sys.modules[__name__])

View File

@ -26,7 +26,7 @@ import re
import sickbeard
from sickbeard import exceptions, helpers
from sickbeard import helpers
from sickbeard.metadata import helpers as metadata_helpers
from sickbeard import logger
from sickbeard import encodingKludge as ek
@ -35,6 +35,8 @@ from sickbeard.show_name_helpers import allPossibleShowNames
from lib.tmdb_api.tmdb_api import TMDB
import fanart
from fanart.core import Request as fanartRequest
class GenericMetadata():
"""
@ -616,6 +618,7 @@ class GenericMetadata():
continue
result = result + [self._write_image(seasonData, season_poster_file_path)]
if result:
return all(result)
else:
@ -664,6 +667,7 @@ class GenericMetadata():
continue
result = result + [self._write_image(seasonData, season_banner_file_path)]
if result:
return all(result)
else:
@ -774,19 +778,27 @@ class GenericMetadata():
if image_type == 'poster_thumb':
if getattr(indexer_show_obj, 'poster', None) is not None:
image_url = re.sub('posters', '_cache/posters', indexer_show_obj['poster'])
if not image_url:
# Try and get images from Fanart.TV
image_url = self._retrieve_show_images_from_fanart(show_obj, image_type)
if not image_url:
# Try and get images from TMDB
image_url = self._retrieve_show_images_from_tmdb(show_obj, image_type)
elif image_type == 'banner_thumb':
if getattr(indexer_show_obj, 'banner', None) is not None:
image_url = re.sub('graphical', '_cache/graphical', indexer_show_obj['banner'])
if not image_url:
# Try and get images from Fanart.TV
image_url = self._retrieve_show_images_from_fanart(show_obj, image_type)
else:
if getattr(indexer_show_obj, image_type, None) is not None:
image_url = indexer_show_obj[image_type]
# Try and get posters and fanart from TMDB
if image_url is None:
if image_type in ('poster', 'poster_thumb'):
image_url = self._retrieve_show_images_from_tmdb(show_obj, poster=True)
elif image_type == 'fanart':
image_url = self._retrieve_show_images_from_tmdb(show_obj, backdrop=True)
if not image_url:
# Try and get images from Fanart.TV
image_url = self._retrieve_show_images_from_fanart(show_obj, image_type)
if not image_url:
# Try and get images from TMDB
image_url = self._retrieve_show_images_from_tmdb(show_obj, image_type)
if image_url:
image_data = metadata_helpers.getShowImage(image_url, which)
@ -961,7 +973,13 @@ class GenericMetadata():
return (indexer_id, name, indexer)
def _retrieve_show_images_from_tmdb(self, show, backdrop=False, poster=False):
def _retrieve_show_images_from_tmdb(self, show, type):
types = {'poster': 'poster_path',
'banner': None,
'fanart': 'backdrop_path',
'poster_thumb': 'poster_path',
'banner_thumb': None}
# get TMDB configuration info
tmdb = TMDB(sickbeard.TMDB_API_KEY)
config = tmdb.Configuration()
@ -977,14 +995,41 @@ class GenericMetadata():
try:
search = tmdb.Search()
for show_name in set(allPossibleShowNames(show)):
for result in search.collection({'query': show_name})['results'] + search.tv({'query': show_name})[
'results']:
if backdrop and result['backdrop_path']:
return "{0}{1}{2}".format(base_url, max_size, result['backdrop_path'])
elif poster and result['poster_path']:
return "{0}{1}{2}".format(base_url, max_size, result['poster_path'])
for result in search.collection({'query': show_name})['results'] + search.tv({'query': show_name})['results']:
if types[type] and getattr(result, types[type]):
return "{0}{1}{2}".format(base_url, max_size, result[types[type]])
except Exception, e:
except Exception as e:
pass
logger.log(u"Could not find any posters or background for " + show.name, logger.DEBUG)
logger.log(u"Could not find any " + type + " images on TMDB for " + show.name, logger.DEBUG)
def _retrieve_show_images_from_fanart(self, show, type, thumb=False):
types = {'poster': fanart.TYPE.TV.POSTER,
'banner': fanart.TYPE.TV.BANNER,
'poster_thumb': fanart.TYPE.TV.POSTER,
'banner_thumb': fanart.TYPE.TV.BANNER,
'fanart': fanart.TYPE.TV.BACKGROUND,
}
try:
indexerid = helpers.mapIndexersToShow(show)[1]
if indexerid:
request = fanartRequest(
apikey=sickbeard.FANART_API_KEY,
id=indexerid,
ws=fanart.WS.TV,
type=types[type],
sort=fanart.SORT.POPULAR,
limit=fanart.LIMIT.ONE,
)
resp = request.response()
url = resp[types[type]][0]['url']
if thumb:
url = re.sub('/fanart/', '/preview/', url)
return url
except Exception as e:
pass
logger.log(u"Could not find any " + type + " images on Fanart.tv for " + show.name, logger.DEBUG)

View File

@ -24,6 +24,7 @@ import os
import re
import itertools
import urllib
import sickbeard
import requests
@ -124,7 +125,9 @@ class GenericProvider:
if not self._doLogin():
return
self.headers.update({'Referer': self.proxy.getProxyURL()})
if self.proxy.isEnabled():
self.headers.update({'Referer': self.proxy.getProxyURL()})
return helpers.getURL(self.proxy._buildURL(url), post_data=post_data, params=params, headers=self.headers, timeout=timeout,
session=self.session, json=json)

View File

@ -38,10 +38,6 @@ from sickbeard import logger
from sickbeard import tvcache
from sickbeard.exceptions import ex, AuthException
from lib import requests
from lib.requests import exceptions
from lib.bencode import bdecode
class NewznabProvider(generic.NZBProvider):
def __init__(self, name, url, key='', catIDs='5030,5040', search_mode='eponly', search_fallback=False,
enable_daily=False, enable_backlog=False):
@ -118,8 +114,6 @@ class NewznabProvider(generic.NZBProvider):
return (False, return_categories, "Error getting html for [%s]" %
("%s/api?%s" % (self.url, '&'.join("%s=%s" % (x,y) for x,y in params.items()) )))
#xml_categories = helpers.parse_xml(categories)
if not xml_categories:
logger.log(u"Error parsing xml for [%s]" % (self.name),
logger.DEBUG)

View File

@ -320,7 +320,7 @@ class QueueItemAdd(ShowQueueItem):
return
except exceptions.MultipleShowObjectsException:
logger.log(u"The show in " + self.showDir + " is already in your show list, skipping", logger.ERROR)
logger.log(u"The show in " + self.showDir + " is already in your show list, skipping", logger.WARNING)
ui.notifications.error('Show skipped', "The show in " + self.showDir + " is already in your show list")
self._finishEarly()
return
@ -335,7 +335,6 @@ class QueueItemAdd(ShowQueueItem):
try:
self.show.loadIMDbInfo()
except imdb_exceptions.IMDbError, e:
#todo Insert UI notification
logger.log(u" Something wrong on IMDb api: " + ex(e), logger.WARNING)
except Exception, e:
logger.log(u"Error loading IMDb info: " + ex(e), logger.ERROR)

View File

@ -1686,8 +1686,8 @@ class TVEpisode(object):
except (ValueError, IndexError):
logger.log(u"Malformed air date of " + str(firstaired) + " retrieved from " + sickbeard.indexerApi(
self.indexer).name + " for (" + self.show.name + " - " + str(season) + "x" + str(episode) + ")",
logger.ERROR)
# if I'm incomplete on TVDB but I once was complete then just delete myself from the DB for now
logger.WARNING)
# if I'm incomplete on the indexer but I once was complete then just delete myself from the DB for now
if self.indexerid != -1:
self.deleteEpisode()
return False

View File

@ -139,7 +139,8 @@ class TVCache():
logger.log(traceback.format_exc(), logger.DEBUG)
def getRSSFeed(self, url, post_data=None, items=[]):
self.provider.headers.update({'Referer': self.provider.proxy.getProxyURL()})
if self.provider.proxy.isEnabled():
self.provider.headers.update({'Referer': self.provider.proxy.getProxyURL()})
return RSSFeeds(self.providerID).getFeed(self.provider.proxy._buildURL(url), post_data, self.provider.headers, items)
def _translateTitle(self, title):

View File

@ -395,6 +395,11 @@ class GitUpdateManager(UpdateManager):
# update remote origin url
self.update_remote_origin()
# remove untracked files and performs a hard reset on git branch to avoid update issues
if sickbeard.GIT_RESET:
self.clean()
self.reset()
if self.branch == self._find_installed_branch():
output, err, exit_status = self._run_git(self._git_path, 'pull -f %s %s' % (sickbeard.GIT_REMOTE, self.branch)) # @UnusedVariable
else:
@ -406,26 +411,26 @@ class GitUpdateManager(UpdateManager):
# Notify update successful
if sickbeard.NOTIFY_ON_UPDATE:
notifiers.notify_git_update(sickbeard.CUR_COMMIT_HASH if sickbeard.CUR_COMMIT_HASH else "")
return True
else:
# perform a hard reset to try and resolve the issue
if self.reset() and self.update():
return True
return False
return True
def clean(self):
"""
Calls git clean to remove all untracked files. Returns a bool depending
on the call's success.
"""
output, err, exit_status = self._run_git(self._git_path, 'clean -d -fx ""') # @UnusedVariable
if exit_status == 0:
return True
def reset(self):
"""
Calls git reset --hard to perform a hard reset. Returns a bool depending
on the call's success.
"""
if sickbeard.GIT_RESET:
output, err, exit_status = self._run_git(self._git_path, 'reset --hard') # @UnusedVariable
if exit_status == 0:
return True
return False
output, err, exit_status = self._run_git(self._git_path, 'reset --hard') # @UnusedVariable
if exit_status == 0:
return True
def list_remote_branches(self):
# update remote origin url

View File

@ -94,13 +94,8 @@ class ApiHandler(RequestHandler):
'image': lambda x: x['image'],
}
if sickbeard.USE_API is not True:
accessMsg = u"API :: " + self.request.remote_ip + " - SB API Disabled. ACCESS DENIED"
logger.log(accessMsg, logger.WARNING)
return self.finish(outputCallbackDict['default'](_responds(RESULT_DENIED, msg=accessMsg)))
else:
accessMsg = u"API :: " + self.request.remote_ip + " - gave correct API KEY. ACCESS GRANTED"
logger.log(accessMsg, logger.DEBUG)
accessMsg = u"API :: " + self.request.remote_ip + " - gave correct API KEY. ACCESS GRANTED"
logger.log(accessMsg, logger.DEBUG)
# set the original call_dispatcher as the local _call_dispatcher
_call_dispatcher = self.call_dispatcher

View File

@ -3425,7 +3425,7 @@ class ConfigGeneral(Config):
def saveGeneral(self, log_dir=None, web_port=None, web_log=None, encryption_version=None, web_ipv6=None,
update_shows_on_start=None, trash_remove_show=None, trash_rotate_logs=None, update_frequency=None,
launch_browser=None, web_username=None,
use_api=None, api_key=None, indexer_default=None, timezone_display=None, cpu_preset=None,
api_key=None, indexer_default=None, timezone_display=None, cpu_preset=None,
web_password=None, version_notify=None, enable_https=None, https_cert=None, https_key=None,
handle_reverse_proxy=None, sort_article=None, auto_update=None, notify_on_update=None,
proxy_setting=None, proxy_indexers=None, anon_redirect=None, git_path=None, git_remote=None,
@ -3492,7 +3492,6 @@ class ConfigGeneral(Config):
if not config.change_LOG_DIR(log_dir, web_log):
results += ["Unable to create directory " + os.path.normpath(log_dir) + ", log directory not changed."]
sickbeard.USE_API = config.checkbox_to_value(use_api)
sickbeard.API_KEY = api_key
sickbeard.ENABLE_HTTPS = config.checkbox_to_value(enable_https)
@ -4713,6 +4712,8 @@ class ErrorLogs(WebRoot):
if not (sickbeard.GIT_USERNAME and sickbeard.GIT_PASSWORD):
logger.log(u'Please set your GitHub username and password in the config, unable to submit issue ticket to GitHub!')
else:
logger.submit_errors()
issue = logger.submit_errors()
if issue:
ui.notifications.message('Your issue ticket #%s was submitted successfully!' % issue.number)
return self.redirect("/errorlogs/")

View File

@ -0,0 +1,49 @@
# coding=UTF-8
# Author: Dennis Lutter <lad1337@gmail.com>
# URL: http://code.google.com/p/sickbeard/
#
# This file is part of SickRage.
#
# SickRage 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.
#
# SickRage 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 SickRage. If not, see <http://www.gnu.org/licenses/>.
from __future__ import with_statement
import unittest
import sys, os.path
from configobj import ConfigObj
sys.path.append(os.path.abspath('..'))
sys.path.append(os.path.abspath('../lib'))
import sickbeard
import test_lib as test
def error():
try:
raise Exception('FAKE EXCEPTION')
except Exception as e:
sickbeard.logger.log("FAKE ERROR: " + sickbeard.exceptions.ex(e), sickbeard.logger.ERROR)
sickbeard.logger.submit_errors()
raise
class IssueSubmitterBasicTests(unittest.TestCase):
def test_submitter(self):
self.assertRaises(Exception, error)
if __name__ == "__main__":
print "=================="
print "STARTING - ISSUE SUBMITTER TESTS"
print "=================="
print "######################################################################"
suite = unittest.TestLoader().loadTestsFromTestCase(IssueSubmitterBasicTests)

View File

@ -25,6 +25,7 @@ import sqlite3
import sys
import os.path
from configobj import ConfigObj
sys.path.append(os.path.abspath('..'))
sys.path.append(os.path.abspath('../lib'))
@ -54,9 +55,6 @@ FILEDIR = os.path.join(TESTDIR, SHOWNAME)
FILEPATH = os.path.join(FILEDIR, FILENAME)
SHOWDIR = os.path.join(TESTDIR, SHOWNAME + " final")
sickbeard.logger.logFile = os.path.join(os.path.join(TESTDIR, 'Logs'), 'test_sickbeard.log')
sickbeard.logger.initLogging()
#=================
# prepare env functions
#=================
@ -74,6 +72,7 @@ def createTestCacheFolder():
# sickbeard globals
#=================
sickbeard.SYS_ENCODING = 'UTF-8'
sickbeard.showList = []
sickbeard.QUALITY_DEFAULT = 4 # hdtv
sickbeard.FLATTEN_FOLDERS_DEFAULT = 0
@ -90,13 +89,23 @@ sickbeard.providerList = providers.makeProviderList()
sickbeard.PROG_DIR = os.path.abspath('..')
sickbeard.DATA_DIR = sickbeard.PROG_DIR
sickbeard.CONFIG_FILE = os.path.join(sickbeard.DATA_DIR, "config.ini")
sickbeard.CFG = ConfigObj(sickbeard.CONFIG_FILE)
sickbeard.BRANCG = sickbeard.config.check_setting_str(sickbeard.CFG, 'General', 'branch', '')
sickbeard.CUR_COMMIT_HASH = sickbeard.config.check_setting_str(sickbeard.CFG, 'General', 'cur_commit_hash', '')
sickbeard.GIT_USERNAME = sickbeard.config.check_setting_str(sickbeard.CFG, 'General', 'git_username', '')
sickbeard.GIT_PASSWORD = sickbeard.config.check_setting_str(sickbeard.CFG, 'General', 'git_password', '', censor_log=True)
sickbeard.LOG_DIR = os.path.join(TESTDIR, 'Logs')
sickbeard.logger.logFile = os.path.join(sickbeard.LOG_DIR, 'test_sickbeard.log')
createTestLogFolder()
sickbeard.logger.initLogging(False)
sickbeard.CACHE_DIR = os.path.join(TESTDIR, 'cache')
createTestCacheFolder()
sickbeard.logger.initLogging(False, True)
#=================
# dummy functions
#=================

Some files were not shown because too many files have changed in this diff Show More