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