1# -*- coding: UTF-8 -*- 2# vim: fdm=marker 3 4__revision__ = '$Id$' 5 6# Copyright (c) 2005-2011 Vasco Nunes, Piotr Ożarowski 7# 8# This program is free software; you can redistribute it and/or modify 9# it under the terms of the GNU General Public License as published byp 10# the Free Software Foundation; either version 2 of the License, or 11# (at your option) any later version. 12# 13# This program is distributed in the hope that it will be useful, 14# but WITHOUT ANY WARRANTY; without even the implied warranty of 15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16# GNU Library General Public License for more details. 17# 18# You should have received a copy of the GNU General Public License 19# along with this program; if not, write to the Free Software 20# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 21 22# You may use and distribute this software under the terms of the 23# GNU General Public License, version 2 or later 24 25import logging 26import os 27import urllib.request, urllib.error, urllib.parse 28from gi.repository import Gtk 29from gi.repository import GdkPixbuf 30from sqlalchemy.exc import IntegrityError 31 32import quick_filter 33import db 34import gutils 35import initialize 36import main_treeview 37import imp 38 39log = logging.getLogger("Griffith") 40 41### widgets ################################################### 42 43 44def clear(self): 45 """clears all fields in dialog""" 46 set_details(self, {}) 47 self.widgets['add']['cb_only_empty'].set_active(False) 48 49 50def add_movie(self, details={}): 51 set_details(self, details) 52 53 self.active_plugin = '' 54 self.widgets['add']['add_button'].show() 55 self.widgets['add']['add_close_button'].show() 56 self.widgets['add']['clear_button'].show() 57 self.widgets['add']['save_button'].hide() 58 self.widgets['add']['window'].set_title(_('Add a new movie')) 59 self.widgets['add']['window'].show() 60 61 62def edit_movie(self, details={}): 63 if not 'number' in details: 64 details['number'] = gutils.find_next_available(self.db) 65 self.selected_iter_edit = self.selected_iter 66 set_details(self, details) 67 self.widgets['add']['add_button'].hide() 68 self.widgets['add']['add_close_button'].hide() 69 self.widgets['add']['clear_button'].show() 70 self.widgets['add']['save_button'].show() 71 self.widgets['add']['window'].set_title(_('Edit movie')) 72 self.widgets['add']['window'].show() 73 74 75def update_movie(self): 76 session = self.db.Session() 77 78 if self._am_movie_id is not None: 79 movie = session.query(db.Movie).filter_by(movie_id=self._am_movie_id).one() 80 else: 81 movie = session.query(db.Movie).filter_by(movie_id=self._movie_id).one() 82 if movie is None: # movie was deleted in the meantime 83 return add_movie_db(self, True) 84 85 details = get_details(self) 86 87 old_poster_md5 = movie.poster_md5 88 new_poster_md5 = old_poster_md5 89 if details['image']: 90 if old_poster_md5 != details['image']: # details["image"] can contain MD5 or file path 91 new_image_path = details['image'] 92 if not os.path.isfile(new_image_path): 93 new_image_path = os.path.join(self.locations['temp'], "poster_%s.jpg" % details['image']) 94 if not os.path.isfile(new_image_path): 95 log.warn("cannot read temporary file: %s", new_image_path) 96 else: 97 new_poster_md5 = gutils.md5sum(open(new_image_path, 'rb')) 98 if session.query(db.Poster).filter_by(md5sum=new_poster_md5).count() == 0: 99 try: 100 data = open(new_image_path, 'rb').read() 101 except Exception as e: 102 log.warning("cannot read poster data") 103 old_poster_md5 = new_poster_md5 104 else: 105 poster = db.Poster(md5sum=new_poster_md5, data=data) 106 del details["image"] 107 details['poster_md5'] = new_poster_md5 108 session.add(poster) 109 else: 110 details['poster_md5'] = new_poster_md5 111 else: 112 details['poster_md5'] = None 113 114 update_movie_instance(movie, details, session) 115 session.add(movie) 116 117 # delete old image 118 if old_poster_md5 and old_poster_md5 != new_poster_md5: 119 import delete 120 old_poster = session.query(db.Poster).filter_by(md5sum=old_poster_md5).first() 121 if old_poster and len(old_poster.movies) == 1: # other movies are not using the same poster 122 session.delete(old_poster) 123 delete.delete_poster_from_cache(old_poster_md5, self.locations['posters']) 124 125 if commit(session): 126 main_treeview.setmovie(self, movie, self.selected_iter_edit[0], self.treemodel) 127 128 # close add window 129 self.widgets['add']['window'].hide() 130 # refresh 131 self.treeview_clicked() 132 self.update_statusbar(_('Movie information has been updated')) 133 134 135def change_rating_from_slider(self): 136 rating = int(self.widgets['add']['rating_slider'].get_value()) 137 self.widgets['add']['image_rating'].show() 138 try: 139 rimage = int(str(self.config.get('rating_image'))) 140 except: 141 rimage = 0 142 if rimage: 143 prefix = '' 144 else: 145 prefix = "meter" 146 rating_file = "%s/%s0%d.png" % (self.locations['images'], prefix, rating) 147 handler = self.widgets['add']['image_rating'].set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_file(rating_file)) 148 149 150def populate_with_results(self): 151 w = self.widgets['add'] 152 m_id = None 153 if self.founded_results_id: 154 log.info("selected id: %s", self.founded_results_id) 155 m_id = self.founded_results_id 156 else: 157 self.founded_results_id = 0 158 treeselection = self.widgets['results']['treeview'].get_selection() 159 (tmp_model, tmp_iter) = treeselection.get_selected() 160 if tmp_iter is None: 161 return False 162 m_id = tmp_model.get_value(tmp_iter, 0) 163 164 self.treemodel_results.clear() 165 self.widgets['results']['window'].hide() 166 167 plugin_name = 'PluginMovie' + self.active_plugin 168 plugin = __import__(plugin_name) 169 self.movie = plugin.Plugin(m_id) 170 self.movie.locations = self.locations 171 self.movie.config = self.config 172 173 fields_to_fetch = ['o_title', 'title', 'director', 'plot', 'cast', 'country', 'genre', 174 'classification', 'studio', 'o_site', 'site', 'trailer', 'year', 175 'notes', 'runtime', 'image', 'rating', 'screenplay', 'cameraman', 176 'resolution', 'barcode'] 177 # remove fields that user doesn't want to fetch: (see preferences window) 178 fields_to_fetch = [i for i in fields_to_fetch if self.config.get("s_%s" % i, True, section='add')] 179 180 if w['cb_only_empty'].get_active(): # only empty fields 181 details = get_details(self) 182 fields_to_fetch = [i for i in fields_to_fetch if details[i] is None or details[i] == 0.0] 183 self.movie.fields_to_fetch = fields_to_fetch 184 185 if not self.movie.get_movie(w['window']): 186 return None 187 self.movie.parse_movie() 188 189 if 'year' in fields_to_fetch: 190 w['year'].set_value(int(self.movie.year)) 191 fields_to_fetch.pop(fields_to_fetch.index('year')) 192 if 'runtime' in fields_to_fetch: 193 w['runtime'].set_value(int(self.movie.runtime)) 194 fields_to_fetch.pop(fields_to_fetch.index('runtime')) 195 if 'cast' in fields_to_fetch: 196 cast_buffer = w['cast'].get_buffer() 197 cast_buffer.set_text(gutils.convert_entities(self.movie.cast)) 198 fields_to_fetch.pop(fields_to_fetch.index('cast')) 199 if 'plot' in fields_to_fetch: 200 plot_buffer = w['plot'].get_buffer() 201 plot_buffer.set_text(gutils.convert_entities(self.movie.plot)) 202 fields_to_fetch.pop(fields_to_fetch.index('plot')) 203 if 'notes' in fields_to_fetch: 204 notes_buffer = w['notes'].get_buffer() 205 notes_buffer.set_text(gutils.convert_entities(self.movie.notes)) 206 fields_to_fetch.pop(fields_to_fetch.index('notes')) 207 if 'rating' in fields_to_fetch: 208 if self.movie.rating: 209 w['rating_slider'].set_value(float(self.movie.rating)) 210 fields_to_fetch.pop(fields_to_fetch.index('rating')) 211 if 'resolution' in fields_to_fetch: 212 w['resolution'].get_child().set_text(gutils.convert_entities(self.movie.resolution)) 213 fields_to_fetch.pop(fields_to_fetch.index('resolution')) 214 # poster 215 if 'image' in fields_to_fetch: 216 w['image'].set_text('') 217 if self.movie.image: 218 image = os.path.join(self.locations['temp'], "poster_%s.jpg" % self.movie.image) 219 try: 220 handler = self.Image.set_from_file(image) 221 pixbuf = self.Image.get_pixbuf() 222 w['picture'].set_from_pixbuf(pixbuf.scale_simple(100, 140, 3)) 223 w['image'].set_text(self.movie.image) 224 w['aremove_poster'].set_sensitive(True) 225 except: 226 image = gutils.get_defaultimage_fname(self) 227 handler = self.Image.set_from_file(image) 228 w['picture'].set_from_pixbuf(self.Image.get_pixbuf()) 229 w['aremove_poster'].set_sensitive(False) 230 else: 231 image = gutils.get_defaultimage_fname(self) 232 handler = self.Image.set_from_file(image) 233 Pixbuf = self.Image.get_pixbuf() 234 w['picture'].set_from_pixbuf(Pixbuf) 235 w['aremove_poster'].set_sensitive(False) 236 fields_to_fetch.pop(fields_to_fetch.index('image')) 237 # other fields 238 for i in fields_to_fetch: 239 w[i].set_text(gutils.convert_entities(self.movie[i])) 240 241 242def show_websearch_results(self): 243 total = self.founded_results_id = 0 244 for g in self.search_movie.ids: 245 if (str(g) != ''): 246 total += 1 247 if total > 1: 248 self.widgets['results']['window'].show() 249 self.widgets['results']['window'].set_keep_above(True) 250 row = None 251 key = 0 252 self.treemodel_results.clear() 253 for row in self.search_movie.ids: 254 if (str(row) != ''): 255 if isinstance(self.search_movie.titles[key], str): 256 title = self.search_movie.titles[key] 257 else: 258 title = str(self.search_movie.titles[key]).decode(self.search_movie.encode) 259 myiter = self.treemodel_results.insert_before(None, None) 260 self.treemodel_results.set_value(myiter, 0, str(row)) 261 self.treemodel_results.set_value(myiter, 1, title) 262 key += 1 263 self.widgets['results']['treeview'].show() 264 elif total == 1: 265 self.widgets['results']['treeview'].set_cursor(total-1) 266 for row in self.search_movie.ids: 267 if (str(row) != ''): 268 self.founded_results_id = str(row) 269 populate_with_results(self) 270 else: 271 gutils.error(_("No results"), self.widgets['add']['window']) 272 273 274def get_from_web(self): 275 """search the movie in web using the active plugin""" 276 277 title = self.widgets['add']['title'].get_text() 278 o_title = self.widgets['add']['o_title'].get_text() 279 280 if o_title or title: 281 option = gutils.on_combo_box_entry_changed_name(self.widgets['add']['source']) 282 self.active_plugin = option 283 plugin_name = 'PluginMovie%s' % option 284 plugin = __import__(plugin_name) 285 if self.debug_mode: 286 log.debug('reloading %s', plugin_name) 287 import sys 288 imp.reload(sys.modules[plugin_name]) 289 self.search_movie = plugin.SearchPlugin() 290 self.search_movie.config = self.config 291 self.search_movie.locations = self.locations 292 if o_title: 293 self.search_movie.url = self.search_movie.original_url_search 294 if self.search_movie.remove_accents: 295 self.search_movie.title = gutils.remove_accents(o_title, 'utf-8') 296 else: 297 self.search_movie.title = o_title 298 elif title: 299 self.search_movie.url = self.search_movie.translated_url_search 300 if self.search_movie.remove_accents: 301 self.search_movie.title = gutils.remove_accents(title, 'utf-8') 302 else: 303 self.search_movie.title = title 304 # check if internet connection is available 305 try: 306 #urllib2.urlopen("http://www.google.com") 307 urllib.request.urlopen(self.search_movie.url) 308 if self.search_movie.search_movies(self.widgets['add']['window']): 309 self.search_movie.get_searches() 310 if len(self.search_movie.ids) == 1 and o_title and title: 311 self.search_movie.url = self.search_movie.translated_url_search 312 if self.search_movie.remove_accents: 313 self.search_movie.title = gutils.remove_accents(title, 'utf-8') 314 else: 315 self.search_movie.title = str(title, 'utf-8') 316 if self.search_movie.search_movies(self.widgets['add']['window']): 317 self.search_movie.get_searches() 318 self.show_search_results(self.search_movie) 319 except: 320 log.exception('') 321 gutils.error(_("Connection failed.")) 322 else: 323 gutils.error(_("You should fill the original title\nor the movie title.")) 324 325 326def source_changed(self): 327 option = gutils.on_combo_box_entry_changed_name(self.widgets['add']['source']) 328 self.active_plugin = option 329 plugin_name = 'PluginMovie' + option 330 plugin = __import__(plugin_name) 331 self.widgets['add']['plugin_desc'].set_text(plugin.plugin_name + "\n" \ 332 + plugin.plugin_description + "\n" + _('Url: ') \ 333 + plugin.plugin_url + "\n" + _('Language: ') + plugin.plugin_language) 334 image = os.path.join(self.locations['images'], plugin_name + ".png") 335 # if movie plugin logo exists lets use it 336 if os.path.exists(image): 337 handler = self.widgets['add']['plugin_image'].set_from_pixbuf(GdkPixbuf.Pixbuf.new_from_file(image)) 338 339 340def get_details(self): #{{{ 341 w = self.widgets['add'] 342 343 cast_buffer = w['cast'].get_buffer() 344 notes_buffer = w['notes'].get_buffer() 345 plot_buffer = w['plot'].get_buffer() 346 347 t_movies = { 348 'cameraman': w['cameraman'].get_text(), 349 'classification': w['classification'].get_text(), 350 'barcode': str(gutils.digits_only(w['barcode'].get_text())), 351 'color': w['color'].get_active(), 352 'cond': w['condition'].get_active(), 353 'country': w['country'].get_text(), 354 'director': w['director'].get_text(), 355 'genre': w['genre'].get_text(), 356 'image': w['image'].get_text(), 357 'layers': w['layers'].get_active(), 358 'media_num': w['discs'].get_value(), 359 'number': w['number'].get_value(), 360 'o_site': w['o_site'].get_text(), 361 'o_title': w['o_title'].get_text(), 362 'rating': w['rating_slider'].get_value(), 363 'region': w['region'].get_active(), 364 'resolution': w['resolution'].get_child().get_text().strip(), 365 'runtime': w['runtime'].get_text(), 366 'screenplay': w['screenplay'].get_text(), 367 'site': w['site'].get_text(), 368 'studio': w['studio'].get_text(), 369 'title': w['title'].get_text(), 370 'trailer': w['trailer'].get_text(), 371 'year': w['year'].get_value(), 372 'collection_id': w['collection'].get_active(), 373 'medium_id': w['media'].get_active(), 374 'volume_id': w['volume'].get_active(), 375 'vcodec_id': w['vcodec'].get_active(), 376 'cast': cast_buffer.get_text(cast_buffer.get_start_iter(), cast_buffer.get_end_iter(), False), 377 'notes': notes_buffer.get_text(notes_buffer.get_start_iter(), notes_buffer.get_end_iter(), False), 378 'plot': plot_buffer.get_text(plot_buffer.get_start_iter(), plot_buffer.get_end_iter(), False), 379 'created': None, 380 'updated': None 381 } 382 if self._am_movie_id is not None: 383 t_movies['movie_id'] = self._am_movie_id 384 385 if t_movies['collection_id'] > 0: 386 t_movies['collection_id'] = self.collection_combo_ids[t_movies['collection_id']] 387 else: 388 t_movies['collection_id'] = None 389 if t_movies['volume_id'] > 0: 390 t_movies['volume_id'] = self.volume_combo_ids[t_movies['volume_id']] 391 else: 392 t_movies['volume_id'] = None 393 if t_movies['medium_id'] > 0: 394 t_movies['medium_id'] = self.media_ids[t_movies['medium_id']] 395 else: 396 t_movies['medium_id'] = None 397 if t_movies['vcodec_id'] > 0: 398 t_movies['vcodec_id'] = self.vcodecs_ids[t_movies['vcodec_id']] 399 else: 400 t_movies['vcodec_id'] = None 401 if t_movies['barcode'] == '0': 402 t_movies['barcode'] = None 403 404 if w['seen'].get_active(): 405 t_movies['seen'] = True 406 else: 407 t_movies['seen'] = False 408 if t_movies['year'] < 1900: 409 t_movies['year'] = None 410 411 def get_id(model, text): 412 for i in model: 413 if i[1] == text: 414 return i[0] 415 return None 416 # languages 417 t_movies['languages'] = set() 418 # isn't the best but it works. without it the current selection of a language field is lost 419 w['lang_treeview'].child_focus(Gtk.DirectionType.TAB_FORWARD) 420 for row in self.lang['model']: 421 lang_id = get_id(self.lang['lang'], row[0]) 422 lang_type = get_id(self.lang['type'], row[1]) 423 acodec = get_id(self.lang['acodec'], row[2]) 424 achannel = get_id(self.lang['achannel'], row[3]) 425 subformat = get_id(self.lang['subformat'], row[4]) 426 t_movies['languages'].add((lang_id, lang_type, acodec, achannel, subformat)) 427 428 # tags 429 t_movies['tags'] = {} 430 for i in self.tags_ids: 431 if self.am_tags[i].get_active() == True: 432 t_movies['tags'][self.tags_ids[i]] = 1 433 434 validate_details(t_movies) 435 436 return t_movies #}}} 437 438 439def set_details(self, item=None):#{{{ 440 if item is None: 441 item = {} 442 if 'movie_id' in item and item['movie_id']: 443 self._am_movie_id = item['movie_id'] 444 else: 445 self._am_movie_id = None 446 w = self.widgets['add'] 447 448 cast_buffer = w['cast'].get_buffer() 449 notes_buffer = w['notes'].get_buffer() 450 plot_buffer = w['plot'].get_buffer() 451 452 if 'o_title' in item and item['o_title']: 453 w['o_title'].set_text(item['o_title']) 454 else: 455 w['o_title'].set_text('') 456 if 'title' in item and item['title']: 457 w['title'].set_text(item['title']) 458 else: 459 w['title'].set_text('') 460 if 'number' in item and item['number']: 461 w['number'].set_value(int(item['number'])) 462 else: 463 w['number'].set_value(int(gutils.find_next_available(self.db))) 464 if 'title' in item and item['title']: 465 w['title'].set_text(item['title']) 466 if 'year' in item and item['year']: 467 w['year'].set_value(gutils.digits_only(item['year'], 2100)) 468 else: 469 w['year'].set_value(0) 470 if 'resolution' in item and item['resolution']: 471 if self.config.get('use_resolution_alias', True): 472 w['resolution'].get_child().set_text(item['resolution']) 473 elif 'height' in item and item['height'] and 'width' in item and item['width']: 474 w['resolution'].get_child().set_text("%dx%d" % (item['width'], item['height'])) 475 else: # failback to 'resolution' 476 w['resolution'].get_child().set_text(item['resolution']) 477 else: 478 w['resolution'].get_child().set_text('') 479 if 'runtime' in item and item['runtime']: 480 w['runtime'].set_value(gutils.digits_only(item['runtime'])) 481 else: 482 w['runtime'].set_value(0) 483 if 'barcode' in item and item['barcode']: 484 w['barcode'].set_text(item['barcode']) 485 else: 486 w['barcode'].set_text('') 487 if 'cameraman' in item and item['cameraman']: 488 w['cameraman'].set_text(item['cameraman']) 489 else: 490 w['cameraman'].set_text('') 491 if 'screenplay' in item and item['screenplay']: 492 w['screenplay'].set_text(item['screenplay']) 493 else: 494 w['screenplay'].set_text('') 495 if 'country' in item and item['country']: 496 w['country'].set_text(item['country']) 497 else: 498 w['country'].set_text('') 499 if 'classification' in item and item['classification']: 500 w['classification'].set_text(item['classification']) 501 else: 502 w['classification'].set_text('') 503 if 'studio' in item and item['studio']: 504 w['studio'].set_text(item['studio']) 505 else: 506 w['studio'].set_text('') 507 if 'o_site' in item and item['o_site']: 508 w['o_site'].set_text(item['o_site']) 509 else: 510 w['o_site'].set_text('') 511 if 'director' in item and item['director']: 512 w['director'].set_text(item['director']) 513 else: 514 w['director'].set_text('') 515 if 'site' in item and item['site']: 516 w['site'].set_text(item['site']) 517 else: 518 w['site'].set_text('') 519 if 'trailer' in item and item['trailer']: 520 w['trailer'].set_text(item['trailer']) 521 else: 522 w['trailer'].set_text('') 523 if 'genre' in item and item['genre']: 524 w['genre'].set_text(item['genre']) 525 else: 526 w['genre'].set_text('') 527 if 'color' in item and item['color']: 528 w['color'].set_active(gutils.digits_only(item['color'], 3)) 529 else: 530 w['color'].set_active(gutils.digits_only(self.config.get('color', 0, section='defaults'), 3)) 531 if 'layers' in item and item['layers']: 532 w['layers'].set_active(gutils.digits_only(item['layers'], 4)) 533 else: 534 w['layers'].set_active(gutils.digits_only(self.config.get('layers', 0, section='defaults'), 4)) 535 if 'region' in item and item['region'] >= 0: 536 w['region'].set_active(gutils.digits_only(item['region'], 11)) 537 else: 538 w['region'].set_active(gutils.digits_only(self.config.get('region', 0, section='defaults'), 11)) 539 if 'cond' in item and item['cond'] is not None: 540 w['condition'].set_active(gutils.digits_only(item['cond'], 5)) 541 else: 542 w['condition'].set_active(gutils.digits_only(self.config.get('condition', 0, section='defaults'), 5)) 543 if 'media_num' in item and item['media_num']: 544 w['discs'].set_value(gutils.digits_only(item['media_num'])) 545 else: 546 w['discs'].set_value(1) 547 if 'rating' in item and item['rating']: 548 w['rating_slider'].set_value(gutils.digits_only(item['rating'], 10)) 549 else: 550 w['rating_slider'].set_value(0) 551 if 'seen' in item: 552 if item['seen'] is True: 553 w['seen'].set_active(True) 554 else: 555 w['seen'].set_active(False) 556 else: 557 w['seen'].set_active(bool(self.config.get('seen', True, section='defaults'))) 558 if 'cast' in item and item['cast']: 559 cast_buffer.set_text(item['cast']) 560 else: 561 cast_buffer.set_text('') 562 if 'notes' in item and item['notes']: 563 notes_buffer.set_text(item['notes']) 564 else: 565 notes_buffer.set_text('') 566 if 'plot' in item and item['plot']: 567 plot_buffer.set_text(item['plot']) 568 else: 569 plot_buffer.set_text('') 570 pos = 0 571 if 'medium_id' in item and item['medium_id']: 572 pos = gutils.findKey(item['medium_id'], self.media_ids) 573 else: 574 pos = gutils.findKey(int(self.config.get('media', 0, section='defaults')), self.media_ids) 575 if pos is not None: 576 w['media'].set_active(int(pos)) 577 else: 578 w['media'].set_active(0) 579 pos = 0 580 if 'vcodec_id' in item and item['vcodec_id']: 581 pos = gutils.findKey(item['vcodec_id'], self.vcodecs_ids) 582 else: 583 pos = gutils.findKey(int(self.config.get('vcodec', 0, section='defaults')), self.vcodecs_ids) 584 if pos is not None: 585 w['vcodec'].set_active(int(pos)) 586 else: 587 w['vcodec'].set_active(0) 588 pos = 0 589 if 'volume_id' in item and item['volume_id']: 590 pos = gutils.findKey(item['volume_id'], self.volume_combo_ids) 591 if pos is not None: 592 w['volume'].set_active(int(pos)) 593 else: 594 w['volume'].set_active(0) 595 pos = 0 596 if 'collection_id' in item and item['collection_id']: 597 pos = gutils.findKey(item['collection_id'], self.collection_combo_ids) 598 if pos is not None: 599 w['collection'].set_active(int(pos)) 600 else: 601 w['collection'].set_active(0) 602 # tags 603 for tag in self.am_tags: 604 self.am_tags[tag].set_active(False) 605 if 'tags' in item: 606 for tag in item['tags']: 607 i = gutils.findKey(tag.tag_id, self.tags_ids) 608 self.am_tags[i].set_active(True) 609 # languages 610 w['lang_treeview'].get_model().clear() 611 if 'languages' in item and len(item['languages']) > 0: 612 for i in item['languages']: 613 self.create_language_row(i) 614 # poster 615 w['aremove_poster'].set_sensitive(True) 616 if 'poster_md5' in item and item['poster_md5']: 617 image_path = gutils.get_image_fname(item["poster_md5"], self.db, 'm') 618 if not image_path: 619 image_path = '' # isfile doesn't like bool 620 w['aremove_poster'].set_sensitive(False) 621 w['image'].set_text(item['poster_md5']) 622 elif 'image' in item and item['image']: 623 if len(item['image']) == 32: # md5 624 image_path = gutils.get_image_fname(item["image"], self.db, 'm') 625 if not image_path: 626 image_path = '' # isfile doesn't like bool 627 w['aremove_poster'].set_sensitive(False) 628 else: 629 w['image'].set_text(item['image']) 630 else: 631 image_path = os.path.join(self.locations['posters'], "m_%s.jpg" % item['image']) 632 log.warn("TODO: image=%s", item['image']) 633 else: 634 w['image'].set_text('') 635 image_path = gutils.get_defaultimage_fname(self) 636 w['aremove_poster'].set_sensitive(False) 637 if not os.path.isfile(image_path): 638 image_path = gutils.get_defaultimage_fname(self) 639 w['aremove_poster'].set_sensitive(False) 640 w['picture'].set_from_file(image_path) 641 642 w['notebook'].set_current_page(0) 643 w['o_title'].grab_focus() 644 #}}} 645 646 647def validate_details(t_movies, allow_only=None): 648 for i in list(t_movies.keys()): 649 if t_movies[i] == '': 650 t_movies[i] = None 651 for i in ('color', 'cond', 'layers', 'media', 'vcodec'): 652 if i in t_movies and t_movies[i] < 1: 653 t_movies[i] = None 654 for i in ('volume_id', 'collection_id', 'runtime'): 655 if i in t_movies and (t_movies[i] is None or int(t_movies[i]) == 0): 656 t_movies[i] = None 657 if allow_only is not None: 658 # iterate over a copy of keys of the dict because removing elements of a dict 659 # within a for enumeration of the same dict instance isn't supported 660 for i in list(t_movies.keys()): 661 if not i in allow_only: 662 t_movies.pop(i) 663 664 665### database part ############################################# 666 667 668def add_movie_db(self, close): 669 session = self.db.Session() 670 details = get_details(self) 671 672 if not details['o_title'] and not details['title']: 673 gutils.error(_("You should fill the original title\nor the movie title."), 674 parent=self.widgets['add']['window']) 675 return False 676 677 asked = False 678 if details['o_title']: 679 if session.query(db.Movie).filter_by(o_title=details['o_title']).count() > 0: 680 asked = True 681 if not gutils.question(_('Movie with that title already exists, are you sure you want to add?'), self.widgets['add']['window']): 682 return False 683 if not asked and details['title']: 684 if session.query(db.Movie).filter_by(title=details['title']).count() > 0: 685 if not gutils.question(_('Movie with that title already exists, are you sure you want to add?'), self.widgets['add']['window']): 686 return False 687 688 new_poster_md5 = None 689 if details['image']: 690 tmp_image_path = original_image_path = details['image'] 691 if not os.path.isfile(tmp_image_path): 692 tmp_image_path = os.path.join(self.locations['temp'], "poster_%s.jpg" % details['image']) 693 if os.path.isfile(tmp_image_path): 694 file_object = open(tmp_image_path, 'rb') 695 try: 696 new_poster_md5 = gutils.md5sum(file_object) 697 698 if session.query(db.Poster).filter_by(md5sum=new_poster_md5).count() == 0: 699 try: 700 file_object.seek(0, 0); 701 data = file_object.read() 702 except Exception as e: 703 log.warning("cannot read poster data") 704 else: 705 poster = db.Poster(md5sum=new_poster_md5, data=data) 706 del details["image"] 707 details["poster_md5"] = new_poster_md5 708 session.add(poster) 709 else: 710 details["poster_md5"] = new_poster_md5 711 finally: 712 file_object.close() 713 try: 714 if not tmp_image_path == original_image_path: 715 os.remove(tmp_image_path) 716 except Exception as e: 717 log.warn("cannot remove temporary file %s", tmp_image_path) 718 else: 719 log.warn("cannot read temporary file: %s", tmp_image_path) 720 721 722 movie = update_movie_instance(None, details, session) 723 session.add(movie) 724 if not commit(session): 725 return False 726 727 # create new entry, unselect current movie and select new entry in main treelist 728 myiter = main_treeview.addmovie(self, movie) 729 main_treeview.select(self, None) 730 main_treeview.select(self, myiter) 731 732 # update statusbar 733 self.total += 1 734 self.count_statusbar() 735 736 clear(self) 737 738 if close: 739 self.hide_add_window() 740 741 742def clone_movie(self): 743 session = self.db.Session() 744 745 if self.selected_iter[0] is None: 746 log.warn("cannot clone movie: no item selected") 747 return False 748 movie = session.query(db.Movie).filter_by(number=self.selected[0]).first() 749 750 if movie is None: 751 log.warn("cannot clone movie: Movie(%s) not found", number) 752 return False 753 754 next_number = gutils.find_next_available(self.db) 755 756 # integer problem workaround 757 if int(movie.seen) == 1: 758 seen = True 759 else: 760 seen = False 761 new_movie = db.Movie() 762 763 # TODO: WARNING: loan problems (don't copy volume/collection data until resolved) 764 new_movie.cast = movie.cast 765 new_movie.classification = movie.classification 766 new_movie.vcodec_id = movie.vcodec_id 767 new_movie.barcode = movie.barcode 768 new_movie.cameraman = movie.cameraman 769 new_movie.collection_id = movie.collection_id 770 new_movie.volume_id = movie.volume_id 771 new_movie.color = movie.color 772 new_movie.cond = movie.cond 773 new_movie.country = movie.country 774 new_movie.director = movie.director 775 new_movie.genre = movie.genre 776 new_movie.site = movie.site 777 new_movie.loaned = movie.loaned 778 new_movie.layers = movie.layers 779 new_movie.medium_id = movie.medium_id 780 new_movie.number = next_number 781 new_movie.media_num = movie.media_num 782 new_movie.notes = movie.notes 783 new_movie.o_title = movie.o_title 784 new_movie.plot = movie.plot 785 new_movie.poster_md5 = movie.poster_md5 786 new_movie.ratio_id = movie.ratio_id 787 new_movie.rating = movie.rating 788 new_movie.region = movie.region 789 new_movie.runtime = movie.runtime 790 new_movie.resolution = movie.resolution 791 new_movie.screenplay = movie.screenplay 792 new_movie.seen = seen 793 new_movie.o_site = movie.o_site 794 new_movie.studio = movie.studio 795 new_movie.title = movie.title 796 new_movie.trailer = movie.trailer 797 new_movie.year = movie.year 798 799 new_movie.tags = movie.tags 800 new_movie.languages = movie.languages 801 new_movie.loans = movie.loans 802 803 # save 804 session.add(new_movie) 805 if not commit(session): 806 return False 807 808 if movie.poster_md5: 809 image_path = gutils.get_image_fname(movie.poster_md5, self.db) 810 if not image_path or not os.path.isfile(image_path): 811 image_path = gutils.get_defaultimage_fname(self) 812 handler = self.Image.set_from_file(image_path) 813 814 # change_filter calls populate_treeview which updates the status bar 815 quick_filter.change_filter(self) 816 817 818def update_movie_instance(movie, details, session): 819 if not movie: 820 movie = db.Movie() 821 if details is not None: 822 t_tags = t_languages = None 823 if 'tags' in details: 824 t_tags = details.pop('tags') 825 if 'languages' in details: 826 t_languages = details.pop('languages') 827 #for i in db.tables.movies.columns.keys(): 828 for i in details: 829 if i not in ('created', 'updated') and hasattr(movie, i): 830 setattr(movie, i, details[i]) 831 832 # clear previous data (in case of updates) 833 if movie.languages: 834 movie.languages = [] 835 if movie.tags: 836 movie.tags = [] 837 # languages 838 if t_languages is not None: 839 for lang in t_languages: 840 if lang[0] > 0: 841 ml = db.MovieLang(lang_id=lang[0], type=lang[1], 842 acodec_id=lang[2], achannel_id=lang[3], subformat_id=lang[4]) 843 movie.languages.append(ml) 844 # tags 845 if t_tags is not None: 846 for tag in list(t_tags.keys()): 847 dbTag = session.query(db.Tag).filter_by(tag_id=tag).one() 848 #movie.tags.append(db.MovieTag(tag_id=tag)) 849 movie.tags.append(dbTag) 850 if hasattr(movie, 'image') and movie.image: # TODO: remove it once image will be removed from movies_table 851 movie.image = None # remove MD5 or link 852 return movie 853 854 855def commit(session): 856 try: 857 session.commit() 858 except IntegrityError as e: 859 session.rollback() 860 log.warn("Cannot commit movie: %s", e.message) 861 gutils.warning(str(e.orig)) 862 return False 863 except Exception as e: 864 log.error("Unexpected problem: %s", e) 865 return False 866 return True 867 868 869def add_medium(self, name): 870 session = self.db.Session() 871 medium = db.Medium(name=name) 872 session.add(medium) 873 try: 874 session.commit() 875 except Exception as e: 876 session.rollback() 877 log.warn("Cannot add medium entry: %s", e.message) 878 else: 879 initialize.media_combos(self) 880 return medium.medium_id 881 882 883def add_vcodec(self, name): 884 session = self.db.Session() 885 vcodec = db.VCodec(name=name) 886 session.add(vcodec) 887 try: 888 session.commit() 889 except Exception as e: 890 session.rollback() 891 log.warn("Cannot add video codec entry: %s", e.message) 892 else: 893 initialize.vcodec_combos(self) 894 return vcodec.vcodec_id 895 896 897def add_volume(self, name): 898 session = self.db.Session() 899 vol = db.Volume(name=name) 900 session.add(vol) 901 try: 902 session.commit() 903 except Exception as e: 904 session.rollback() 905 log.warn("Cannot add volume: %s", e.message) 906 else: 907 initialize.update_volume_combo_ids(self) 908 initialize.fill_volumes_combo(self, vol.volume_id) 909 return vol.volume_id 910 911 912def add_collection(self, name): 913 session = self.db.Session() 914 col = db.Collection(name=name) 915 session.add(col) 916 try: 917 session.commit() 918 except Exception as e: 919 session.rollback() 920 log.warn("Cannot add collection: %s", e.message) 921 else: 922 initialize.update_collection_combo_ids(self) 923 initialize.fill_collections_combo(self, col.collection_id) 924 return col.collection_id 925 926 927def change_poster(self): 928 from .edit import change_poster_select_file 929 if change_poster_select_file(self, -1, change_poster_new_movie): 930 self.widgets['add']['aremove_poster'].set_sensitive(True) 931 932 933def change_poster_new_movie(self, number, filename): 934 try: 935 handler = self.Image.set_from_file(filename) 936 pixbuf = self.Image.get_pixbuf() 937 handler = self.widgets['add']['picture'].set_from_pixbuf(pixbuf.scale_simple(100, 140, 3)) 938 gutils.garbage(handler) 939 self.widgets['add']['image'].set_text(filename) 940 return True 941 except: 942 image = gutils.get_defaultimage_fname(self) 943 handler = self.Image.set_from_file(image) 944 handler = self.widgets['add']['picture'].set_from_pixbuf(self.Image.get_pixbuf()) 945 gutils.garbage(handler) 946 return False 947 948 949def delete_poster(self): 950 w = self.widgets['add'] 951 w['image'].set_text('') 952 image_path = gutils.get_defaultimage_fname(self) 953 w['picture'].set_from_file(image_path) 954 w['aremove_poster'].set_sensitive(False) 955