]> git.pld-linux.org Git - packages/griffith.git/blame - Kodi.py
download posters, as griffith does not accept urls
[packages/griffith.git] / Kodi.py
CommitLineData
489423d6
ER
1# -*- coding: utf-8 -*-
2
3__revision__ = '$Id: $'
4
5# Copyright (c) 2015
6
7# This program is free software; you can redistribute it and/or modify
8# it under the terms of the GNU General Public License as published by
9# the Free Software Foundation; either version 2 of the License, or
10# (at your option) any later version.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU Library General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
20
21# You may use and distribute this software under the terms of the
22# GNU General Public License, version 2 or later
23
24from plugins.imp import ImportPlugin as IP
25import os
26import gutils
489423d6 27from lxml import etree
0a532283
ER
28import tempfile
29from urllib2 import urlopen, URLError, HTTPError
489423d6
ER
30
31import logging
32log = logging.getLogger("Griffith")
33
34"""
880cc34c
ER
35Supports importing videodb.xml exported as single file from Kodi/XBMC.
36
37http://kodi.wiki/view/Import-export_library
38http://kodi.wiki/view/HOW-TO:Backup_the_video_library
39
489423d6
ER
40See lib/plugins/imp/__init__.py for workflow how importer invokes methods from importer plugins
41"""
42class ImportPlugin(IP):
43 description = 'Kodi/XBMC MovieDB importer'
44 author = 'Elan Ruusamäe'
45 email = 'glen@pld-linux.org'
46 version = '1.0'
47 file_filters = 'videodb.xml'
48 mime_types = None
49
50 fileversion = None
51 xml = None
52 items = None
53 itemindex = 0
0a532283 54 poster_file = None
489423d6
ER
55
56 # used by get_movie_details method
57 # griffith field => kodi field
58 # griffith field is actual SQL column in 'movies' table
59 field_map = {
60 'title': 'title',
61 'o_title': 'originaltitle',
62 'year': 'year',
5411d3e0 63 'runtime': 'runtime',
489423d6
ER
64 'rating': 'rating',
65 'plot': 'plot',
66 'director': 'director',
67 'studio': 'studio',
68 'country': 'country',
91cfb43d 69 'classification': 'mpaa',
489423d6
ER
70 # while the trailer field exists, it is not useful for griffith
71 # as it's something like: "plugin://plugin.video.youtube/?action=play_video&videoid=..."
72 # however youtube urls can be probably fixed.
73 'trailer': 'trailer',
74 }
75
91cfb43d
ER
76 # rest of the stuff to insert into notes field
77 notes_map = {
78 _('Id') : 'id',
79 _('Play count'): 'playcount',
80 _('Date added'): 'dateadded',
81 _('Last played'): 'lastplayed',
82 _('Collection'): 'set',
83 _('Premiered'): 'premiered',
84 _('Aired'): 'aired',
85 }
86
489423d6
ER
87 def initialize(self):
88 if not IP.initialize(self):
89 return False
90 self.edit = False
91 return True
92
93 def set_source(self, name):
94 IP.set_source(self, name)
95 self.filename = name
96 self.fileversion = self.read_fileversion()
97 if self.fileversion == None:
98 gutils.error(_('The format of the file is not supported.'))
99 return False
100 return True
101
102 def clear(self):
103 """clear plugin state before next source file"""
104 IP.clear(self)
105 if self.xml:
106 self.xml = None
107 self.fileversion = None
108 self.items = None
109 self.itemindex = 0
0a532283
ER
110 if self.poster_file:
111 os.unlink(self.poster_file)
112 self.poster_file = None
489423d6
ER
113
114 def destroy(self):
115 """close all resources"""
116 IP.destroy(self)
117
118 def read_fileversion(self):
119 version = None
120 try:
121 self.xml = etree.parse(self.filename)
122 version = self.xml.xpath('/videodb/version')[0].text
123 except Exception, e:
124 log.error(str(e))
125 log.info('Found file version %s' % version)
126 return version
127
128 def count_movies(self):
129 """Returns number of movies in file which is about to be imported"""
130 if not self.xml:
131 log.error('No XML object')
132 return 0
133
134 count = 0
135
136 try:
137 count = int(self.xml.xpath('count(/videodb/movie)'))
138 except Exception, e:
139 log.exception(e)
140
141 log.info('%s movies for import' % count)
142 return count
143
144 def get_movie_details(self):
145 """Returns dictionary with movie details"""
146 if not self.xml:
147 log.error('XML not opened')
148 return None
149
150 if not self.items:
151 self.items = self.xml.xpath('/videodb/movie')
152 self.itemindex = 0
153
154 # don't bother for empty db (shouldn't happen really)
155 if not self.items or len(self.items) < 1:
156 return None
157
158 # no more items
159 if self.itemindex >= len(self.items):
160 return None
161
162 item = self.items[self.itemindex]
163
164 # fill details
165 details = {}
166 for k,v in self.field_map.items():
167 details[k] = item.findtext(v)
168
169 # if playcount set, means it's seen
170 details['seen'] = int(item.find('playcount').text) > 0
171
172 # genre can be multiple items, join by comma
173 details['genre'] = ', '.join(n.text for n in item.findall('genre'))
174
5411d3e0
ER
175 # build text for 'cast' field
176 cast = []
177 for actor in item.findall('actor'):
178 cast.append('%s as %s' % (actor.findtext('name'), actor.findtext('role')))
179
180 if cast:
181 details['cast'] = "\n".join(cast)
182
91cfb43d
ER
183 # put rest of information into notes field
184 notes = []
185 for k,v in self.notes_map.items():
186 v = item.findtext(v)
187 if v:
188 notes.append('%s: %s' % (k, v))
189
190 # credits can have multiple values, handle separately
191 credits = ', '.join(n.text for n in item.findall('credits'))
192 if credits:
193 notes.append(_('Credits: %s') % credits)
194
195 if notes:
196 details['notes'] = "\n".join(notes)
197
78f08559
ER
198 # handle poster
199 # take first <thumb aspect="poster"> element
200 posters = item.xpath('thumb[@aspect="poster"]')
201 if posters:
0a532283
ER
202 self.poster_file = self.grab_url(posters[0].get('preview'), prefix = 'poster_', suffix = '.jpg')
203 details['image'] = self.poster_file
78f08559 204
489423d6
ER
205 # increment for next iteration
206 self.itemindex = self.itemindex + 1
207
208 return details
0a532283
ER
209
210 # grab url, return temp filename with remote file contents
211 # XXX could not figure out how to use griffith own downloader with ui interaction, etc
212 # XXX: grabbing urls while processing import xml blocks the ui
213 def grab_url(self, url, prefix = None, suffix=None):
214 log.debug("Downloading: %s" % url)
215 (fd, local_file) = tempfile.mkstemp(suffix=suffix, prefix=prefix)
216 try:
217 f = urlopen(url)
218 os.write(fd, f.read())
219 os.close(fd)
220
221 except HTTPError, e:
222 log.error("HTTP Error: %s: %s" % (e.code, url))
223 return None
224 except URLError, e:
225 log.error("URL Error: %s: %s" % (e.reason, url))
226 return None
227 else:
228 return local_file
229
230 # we get here with an exception, cleanup and return None
231 os.unlink(local_file)
232 return None
This page took 0.095652 seconds and 4 git commands to generate.