Merge pull request #23122 from joseluismarti/bionic
[xbmc.git] / addons / metadata.themoviedb.org.python / python / scraper.py
blobc976407a0bdf827fb2e44e65f00b53c7c9927b9c
1 import json
2 import sys
3 import xbmc
4 import xbmcaddon
5 import xbmcgui
6 import xbmcplugin
8 from lib.tmdbscraper.tmdb import TMDBMovieScraper
9 from lib.tmdbscraper.fanarttv import get_details as get_fanarttv_artwork
10 from lib.tmdbscraper.imdbratings import get_details as get_imdb_details
11 from lib.tmdbscraper.traktratings import get_trakt_ratinginfo
12 from scraper_datahelper import combine_scraped_details_info_and_ratings, \
13 combine_scraped_details_available_artwork, find_uniqueids_in_text, get_params
14 from scraper_config import configure_scraped_details, PathSpecificSettings, \
15 configure_tmdb_artwork, is_fanarttv_configured
17 ADDON_SETTINGS = xbmcaddon.Addon()
18 ID = ADDON_SETTINGS.getAddonInfo('id')
20 def log(msg, level=xbmc.LOGDEBUG):
21 xbmc.log(msg='[{addon}]: {msg}'.format(addon=ID, msg=msg), level=level)
23 def get_tmdb_scraper(settings):
24 language = settings.getSettingString('language')
25 certcountry = settings.getSettingString('tmdbcertcountry')
26 return TMDBMovieScraper(ADDON_SETTINGS, language, certcountry)
28 def search_for_movie(title, year, handle, settings):
29 log("Find movie with title '{title}' from year '{year}'".format(title=title, year=year), xbmc.LOGINFO)
30 title = _strip_trailing_article(title)
31 search_results = get_tmdb_scraper(settings).search(title, year)
32 if not search_results:
33 return
34 if 'error' in search_results:
35 header = "The Movie Database Python error searching with web service TMDB"
36 xbmcgui.Dialog().notification(header, search_results['error'], xbmcgui.NOTIFICATION_WARNING)
37 log(header + ': ' + search_results['error'], xbmc.LOGWARNING)
38 return
40 for movie in search_results:
41 listitem = _searchresult_to_listitem(movie)
42 uniqueids = {'tmdb': str(movie['id'])}
43 xbmcplugin.addDirectoryItem(handle=handle, url=build_lookup_string(uniqueids),
44 listitem=listitem, isFolder=True)
46 _articles = [prefix + article for prefix in (', ', ' ') for article in ("the", "a", "an")]
47 def _strip_trailing_article(title):
48 title = title.lower()
49 for article in _articles:
50 if title.endswith(article):
51 return title[:-len(article)]
52 return title
54 def _searchresult_to_listitem(movie):
55 movie_info = {'title': movie['title']}
56 movie_label = movie['title']
58 movie_year = movie['release_date'].split('-')[0] if movie.get('release_date') else None
59 if movie_year:
60 movie_label += ' ({})'.format(movie_year)
61 movie_info['year'] = movie_year
63 listitem = xbmcgui.ListItem(movie_label, offscreen=True)
65 listitem.setInfo('video', movie_info)
66 if movie['poster_path']:
67 listitem.setArt({'thumb': movie['poster_path']})
69 return listitem
71 # Low limit because a big list of artwork can cause trouble in some cases
72 # (a column can be too large for the MySQL integration),
73 # and how useful is a big list anyway? Not exactly rhetorical, this is an experiment.
74 IMAGE_LIMIT = 10
76 def add_artworks(listitem, artworks):
77 for arttype, artlist in artworks.items():
78 if arttype == 'fanart':
79 continue
80 for image in artlist[:IMAGE_LIMIT]:
81 listitem.addAvailableArtwork(image['url'], arttype)
83 fanart_to_set = [{'image': image['url'], 'preview': image['preview']}
84 for image in artworks['fanart'][:IMAGE_LIMIT]]
85 listitem.setAvailableFanart(fanart_to_set)
87 def get_details(input_uniqueids, handle, settings):
88 if not input_uniqueids:
89 return False
90 details = get_tmdb_scraper(settings).get_details(input_uniqueids)
91 if not details:
92 return False
93 if 'error' in details:
94 header = "The Movie Database Python error with web service TMDB"
95 xbmcgui.Dialog().notification(header, details['error'], xbmcgui.NOTIFICATION_WARNING)
96 log(header + ': ' + details['error'], xbmc.LOGWARNING)
97 return False
99 details = configure_tmdb_artwork(details, settings)
101 if settings.getSettingString('RatingS') == 'IMDb' or settings.getSettingBool('imdbanyway'):
102 imdbinfo = get_imdb_details(details['uniqueids'])
103 if 'error' in imdbinfo:
104 header = "The Movie Database Python error with website IMDB"
105 log(header + ': ' + imdbinfo['error'], xbmc.LOGWARNING)
106 else:
107 details = combine_scraped_details_info_and_ratings(details, imdbinfo)
109 if settings.getSettingString('RatingS') == 'Trakt' or settings.getSettingBool('traktanyway'):
110 traktinfo = get_trakt_ratinginfo(details['uniqueids'])
111 details = combine_scraped_details_info_and_ratings(details, traktinfo)
113 if is_fanarttv_configured(settings):
114 fanarttv_info = get_fanarttv_artwork(details['uniqueids'],
115 settings.getSettingString('fanarttv_clientkey'),
116 settings.getSettingString('fanarttv_language'),
117 details['_info']['set_tmdbid'])
118 details = combine_scraped_details_available_artwork(details, fanarttv_info)
120 details = configure_scraped_details(details, settings)
122 listitem = xbmcgui.ListItem(details['info']['title'], offscreen=True)
123 listitem.setInfo('video', details['info'])
124 listitem.setCast(details['cast'])
125 listitem.setUniqueIDs(details['uniqueids'], 'tmdb')
126 add_artworks(listitem, details['available_art'])
128 for rating_type, value in details['ratings'].items():
129 if 'votes' in value:
130 listitem.setRating(rating_type, value['rating'], value['votes'], value['default'])
131 else:
132 listitem.setRating(rating_type, value['rating'], defaultt=value['default'])
134 xbmcplugin.setResolvedUrl(handle=handle, succeeded=True, listitem=listitem)
135 return True
137 def find_uniqueids_in_nfo(nfo, handle):
138 uniqueids = find_uniqueids_in_text(nfo)
139 if uniqueids:
140 listitem = xbmcgui.ListItem(offscreen=True)
141 xbmcplugin.addDirectoryItem(
142 handle=handle, url=build_lookup_string(uniqueids), listitem=listitem, isFolder=True)
144 def build_lookup_string(uniqueids):
145 return json.dumps(uniqueids)
147 def parse_lookup_string(uniqueids):
148 try:
149 return json.loads(uniqueids)
150 except ValueError:
151 log("Can't parse this lookup string, is it from another add-on?\n" + uniqueids, xbmc.LOGWARNING)
152 return None
154 def run():
155 params = get_params(sys.argv[1:])
156 enddir = True
157 if 'action' in params:
158 settings = ADDON_SETTINGS if not params.get('pathSettings') else \
159 PathSpecificSettings(json.loads(params['pathSettings']), lambda msg: log(msg, xbmc.LOGWARNING))
160 action = params["action"]
161 if action == 'find' and 'title' in params:
162 search_for_movie(params["title"], params.get("year"), params['handle'], settings)
163 elif action == 'getdetails' and 'url' in params:
164 enddir = not get_details(parse_lookup_string(params["url"]), params['handle'], settings)
165 elif action == 'NfoUrl' and 'nfo' in params:
166 find_uniqueids_in_nfo(params["nfo"], params['handle'])
167 else:
168 log("unhandled action: " + action, xbmc.LOGWARNING)
169 else:
170 log("No action in 'params' to act on", xbmc.LOGWARNING)
171 if enddir:
172 xbmcplugin.endOfDirectory(params['handle'])
174 if __name__ == '__main__':
175 run()