~ubuntu-branches/ubuntu/oneiric/totem/oneiric-updates

« back to all changes in this revision

Viewing changes to src/plugins/opensubtitles/opensubtitles.py

Tags: 2.26.2-1
New upstream bugfix release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import totem
 
2
import gobject, gtk, gio, gconf
 
3
gobject.threads_init()
 
4
import xmlrpclib
 
5
import threading
 
6
import xdg.BaseDirectory
 
7
from os import sep
 
8
import gettext
 
9
 
 
10
from hash import hashFile
 
11
 
 
12
D_ = gettext.dgettext
 
13
 
 
14
USER_AGENT = 'Totem'
 
15
OK200 = '200 OK'
 
16
TOTEM_REMOTE_COMMAND_REPLACE = 14
 
17
 
 
18
SUBTITLES_EXT = [
 
19
        "asc",
 
20
        "txt",
 
21
        "sub",
 
22
        "srt",
 
23
        "smi",
 
24
        "ssa",
 
25
        "ass",
 
26
]
 
27
 
 
28
# Map of the language codes used by opensubtitles.org's API to their human-readable name
 
29
LANGUAGES_STR = [(D_('iso_639_3', 'Albanian'), 'sq'),
 
30
                 (D_('iso_639_3', 'Arabic'), 'ar'),
 
31
                 (D_('iso_639_3', 'Armenian'), 'hy'),
 
32
                 (D_('iso_639_3', 'Neo-Aramaic, Assyrian'), 'ay'),
 
33
                 (D_('iso_639_3', 'Bosnian'), 'bs'),
 
34
                 (_('Brasilian Portuguese'), 'pb'),
 
35
                 (D_('iso_639_3', 'Bulgarian'), 'bg'),
 
36
                 (D_('iso_639_3', 'Catalan'), 'ca'),
 
37
                 (D_('iso_639_3', 'Chinese'), 'zh'),
 
38
                 (D_('iso_639_3', 'Croatian'), 'hr'),
 
39
                 (D_('iso_639_3', 'Czech'), 'cs'),
 
40
                 (D_('iso_639_3', 'Danish'), 'da'),
 
41
                 (D_('iso_639_3', 'Dutch'), 'nl'),
 
42
                 (D_('iso_639_3', 'English'), 'en'),
 
43
                 (D_('iso_639_3', 'Esperanto'), 'eo'),
 
44
                 (D_('iso_639_3', 'Estonian'), 'et'),
 
45
                 (D_('iso_639_3', 'Finnish'), 'fi'),
 
46
                 (D_('iso_639_3', 'French'), 'fr'),
 
47
                 (D_('iso_639_3', 'Galician'), 'gl'),
 
48
                 (D_('iso_639_3', 'Georgian'), 'ka'),
 
49
                 (D_('iso_639_3', 'German'), 'de'),
 
50
                 (D_('iso_639_3', 'Greek, Modern (1453-)'), 'el'),
 
51
                 (D_('iso_639_3', 'Hebrew'), 'he'),
 
52
                 (D_('iso_639_3', 'Hindi'), 'hi'),
 
53
                 (D_('iso_639_3', 'Hungarian'), 'hu'),
 
54
                 (D_('iso_639_3', 'Icelandic'), 'is'),
 
55
                 (D_('iso_639_3', 'Indonesian'), 'id'),
 
56
                 (D_('iso_639_3', 'Italian'), 'it'),
 
57
                 (D_('iso_639_3', 'Japanese'), 'ja'),
 
58
                 (D_('iso_639_3', 'Kazakh'), 'kk'),
 
59
                 (D_('iso_639_3', 'Korean'), 'ko'),
 
60
                 (D_('iso_639_3', 'Latvian'), 'lv'),
 
61
                 (D_('iso_639_3', 'Lithuanian'), 'lt'),
 
62
                 (D_('iso_639_3', 'Luxembourgish'), 'lb'),
 
63
                 (D_('iso_639_3', 'Macedonian'), 'mk'),
 
64
                 (D_('iso_639_3', 'Malay (macrolanguage)'), 'ms'),
 
65
                 (D_('iso_639_3', 'Norwegian'), 'no'),
 
66
                 (D_('iso_639_3', 'Occitan (post 1500)'), 'oc'),
 
67
                 (D_('iso_639_3', 'Persian'), 'fa'),
 
68
                 (D_('iso_639_3', 'Polish'), 'pl'),
 
69
                 (D_('iso_639_3', 'Portuguese'), 'pt'),
 
70
                 (D_('iso_639_3', 'Romanian'), 'ro'),
 
71
                 (D_('iso_639_3', 'Russian'), 'ru'),
 
72
                 (D_('iso_639_3', 'Serbian'), 'sr'),
 
73
                 (D_('iso_639_3', 'Slovak'), 'sk'),
 
74
                 (D_('iso_639_3', 'Slovenian'), 'sl'),
 
75
                 (D_('iso_639_3', 'Spanish'), 'es'),
 
76
                 (D_('iso_639_3', 'Swedish'), 'sv'),
 
77
                 (D_('iso_639_3', 'Thai'), 'th'),
 
78
                 (D_('iso_639_3', 'Turkish'), 'tr'),
 
79
                 (D_('iso_639_3', 'Ukrainian'), 'uk'),
 
80
                 (D_('iso_639_3', 'Vietnamese'), 'vi'),]
 
81
 
 
82
# Map of ISO 639-1 language codes to the codes used by opensubtitles.org's API
 
83
LANGUAGES =     {'sq':'alb',
 
84
                 'ar':'ara',
 
85
                 'hy':'arm',
 
86
                 'ay':'ass',
 
87
                 'bs':'bos',
 
88
                 'pb':'pob',
 
89
                 'bg':'bul',
 
90
                 'ca':'cat',
 
91
                 'zh':'chi',
 
92
                 'hr':'hrv',
 
93
                 'cs':'cze',
 
94
                 'da':'dan',
 
95
                 'nl':'dut',
 
96
                 'en':'eng',
 
97
                 'eo':'epo',
 
98
                 'et':'est',
 
99
                 'fi':'fin',
 
100
                 'fr':'fre',
 
101
                 'gl':'glg',
 
102
                 'ka':'geo',
 
103
                 'de':'ger',
 
104
                 'el':'ell',
 
105
                 'he':'heb',
 
106
                 'hi':'hin',
 
107
                 'hu':'hun',
 
108
                 'is':'ice',
 
109
                 'id':'ind',
 
110
                 'it':'ita',
 
111
                 'ja':'jpn',
 
112
                 'kk':'kaz',
 
113
                 'ko':'kor',
 
114
                 'lv':'lav',
 
115
                 'lt':'lit',
 
116
                 'lb':'ltz',
 
117
                 'mk':'mac',
 
118
                 'ms':'may',
 
119
                 'no':'nor',
 
120
                 'oc':'oci',
 
121
                 'fa':'per',
 
122
                 'pl':'pol',
 
123
                 'pt':'por',
 
124
                 'ro':'rum',
 
125
                 'ru':'rus',
 
126
                 'sr':'scc',
 
127
                 'sk':'slo',
 
128
                 'sl':'slv',
 
129
                 'es':'spa',
 
130
                 'sv':'swe',
 
131
                 'th':'tha',
 
132
                 'tr':'tur',
 
133
                 'uk':'ukr',
 
134
                 'vi':'vie',}
 
135
 
 
136
class SearchThread(threading.Thread):
 
137
    """
 
138
    This is the thread started when the dialog is searching for subtitles
 
139
    """
 
140
    def __init__(self, model):
 
141
        self.model = model
 
142
        self._done = False
 
143
        self._lock = threading.Lock()
 
144
        threading.Thread.__init__(self)
 
145
 
 
146
    def run(self):
 
147
        self.model.lock.acquire(True)
 
148
        self.model.results = self.model.os_search_subtitles()
 
149
        self.model.lock.release()
 
150
        self._done = True
 
151
        
 
152
    @property
 
153
    def done(self):
 
154
        """ Thread-safe property to know whether the query is done or not """
 
155
        self._lock.acquire(True)
 
156
        res = self._done
 
157
        self._lock.release()
 
158
        return res
 
159
 
 
160
class DownloadThread(threading.Thread):
 
161
    """
 
162
    This is the thread started when the dialog is downloading the subtitles.
 
163
    """
 
164
    def __init__(self, model, subtitle_id):
 
165
        self.model = model
 
166
        self.subtitle_id = subtitle_id
 
167
        self._done = False
 
168
        self._lock = threading.Lock()
 
169
        threading.Thread.__init__(self)
 
170
 
 
171
    def run(self):
 
172
        self.model.lock.acquire(True)
 
173
        self.model.subtitles = self.model.os_download_subtitles(self.subtitle_id)
 
174
        self.model.lock.release()
 
175
        self._done = True
 
176
    
 
177
    @property
 
178
    def done(self):
 
179
        """ Thread-safe property to know whether the query is done or not """
 
180
        self._lock.acquire(True)
 
181
        res = self._done
 
182
        self._lock.release()
 
183
        return res
 
184
 
 
185
# OpenSubtitles.org API abstraction
 
186
 
 
187
class OpenSubtitlesModel(object):
 
188
    """
 
189
    This contains the logic of the opensubtitles service.
 
190
    """
 
191
    def __init__(self, server):
 
192
        self.server = server
 
193
        self.token = None
 
194
 
 
195
        try:
 
196
            import locale
 
197
            self.lang = LANGUAGES[locale.getlocale()[0].split('_')[0]]
 
198
        except:
 
199
            self.lang = 'eng'
 
200
        self.hash = None
 
201
        self.size = 0
 
202
 
 
203
        self.lock = threading.Lock()
 
204
        self.results = []
 
205
        self.subtitles = ''
 
206
 
 
207
        self.message = ''
 
208
 
 
209
    def os_login(self, username='', password=''):
 
210
        """
 
211
        Logs into the opensubtitles web service and gets a valid token for
 
212
        the comming comunications. If we are already logged it only checks
 
213
        the if the token is still valid.
 
214
 
 
215
        @rtype : bool
 
216
        """
 
217
        result = None
 
218
        self.message = ''
 
219
 
 
220
        if self.token:
 
221
            # We have already logged-in before, check the connection
 
222
            try:
 
223
                result = self.server.NoOperation(self.token)
 
224
            except:
 
225
                pass
 
226
            if result and result['status'] != OK200:
 
227
                return True
 
228
        try:
 
229
            result = self.server.LogIn(username, password, self.lang, USER_AGENT)
 
230
        except:
 
231
            pass
 
232
        if result and result.get('status') == OK200:
 
233
            self.token = result.get('token')
 
234
            if self.token:
 
235
                return True
 
236
 
 
237
        self.message = _('Could not contact the OpenSubtitles website')
 
238
 
 
239
        return False
 
240
 
 
241
    def os_search_subtitles(self):
 
242
        """
 
243
 
 
244
        """
 
245
        self.message = ''
 
246
        if self.os_login():
 
247
            searchdata = {'sublanguageid': self.lang, 
 
248
                          'moviehash'    : self.hash, 
 
249
                          'moviebytesize': str(self.size)}
 
250
            try:
 
251
                result = self.server.SearchSubtitles(self.token, [searchdata])
 
252
            except xmlrpclib.ProtocolError:
 
253
                self.message = _('Could not contact the OpenSubtitles website')
 
254
 
 
255
            if result.get('data'):
 
256
                return result['data']
 
257
            else:
 
258
                self.message = _('No results found')
 
259
 
 
260
        return None
 
261
 
 
262
    def os_download_subtitles(self, subtitleId):
 
263
        """
 
264
        """
 
265
        self.message = ''
 
266
        if self.os_login():
 
267
            try:
 
268
                result = self.server.DownloadSubtitles(self.token, [subtitleId])
 
269
            except xmlrpclib.ProtocolError:
 
270
                self.message = _('Could not contact the OpenSubtitles website')
 
271
 
 
272
            if result and result.get('status') == OK200:
 
273
                try:
 
274
                    subtitle64 = result['data'][0]['data']
 
275
                except:
 
276
                    self.message = _('Could not contact the OpenSubtitles website')
 
277
                    return None
 
278
 
 
279
                import StringIO, gzip, base64
 
280
                subtitleDecoded = base64.decodestring(subtitle64)
 
281
                subtitleGzipped = StringIO.StringIO(subtitleDecoded)
 
282
                subtitleGzippedFile = gzip.GzipFile(fileobj=subtitleGzipped)
 
283
 
 
284
                return subtitleGzippedFile.read()
 
285
 
 
286
        return None
 
287
 
 
288
 
 
289
class OpenSubtitles(totem.Plugin):
 
290
    def __init__(self):
 
291
        totem.Plugin.__init__(self)
 
292
        self.dialog = None
 
293
        self.gconf_client = gconf.client_get_default()
 
294
        self.GCONF_BASE_DIR = "/apps/totem/plugins/opensubtitles/"
 
295
        self.GCONF_LANGUAGE = "language"
 
296
 
 
297
    # totem.Plugin methods
 
298
 
 
299
    def activate(self, totem_object):
 
300
        """
 
301
        Called when the plugin is activated.
 
302
        Here the sidebar page is initialized(set up the treeview, connect 
 
303
        the callbacks, ...) and added to totem.
 
304
 
 
305
        @param totem_object:
 
306
        @type  totem_object: {totem.TotemObject}
 
307
        """
 
308
        self.totem = totem_object
 
309
        self.filename = None
 
310
 
 
311
        self.manager = self.totem.get_ui_manager()
 
312
        self.os_append_menu()
 
313
 
 
314
        self.totem.connect('file-opened', self.on_totem__file_opened)
 
315
        self.totem.connect('file-closed', self.on_totem__file_closed)
 
316
 
 
317
        # Obtain the ServerProxy and init the model
 
318
        server = xmlrpclib.Server('http://www.opensubtitles.org/xml-rpc')
 
319
        self.model = OpenSubtitlesModel(server)
 
320
 
 
321
    def deactivate(self, totem):
 
322
        if self.dialog:
 
323
            self.dialog.destroy()
 
324
            self.dialog = None
 
325
        
 
326
        self.os_delete_menu()
 
327
 
 
328
    # UI related code
 
329
 
 
330
    def os_build_dialog(self, action, totem_object):
 
331
        builder = self.load_interface("opensubtitles.ui", 
 
332
                                       True, 
 
333
                                       self.totem.get_main_window(), 
 
334
                                       self)
 
335
 
 
336
        # Obtain all the widgets we need to initialize
 
337
        combobox =       builder.get_object('language_combobox')
 
338
        languages =      builder.get_object('language_model')
 
339
        self.progress =  builder.get_object('progress_bar')
 
340
        self.treeview =  builder.get_object('subtitle_treeview')
 
341
        self.liststore = builder.get_object('subtitle_model')
 
342
        self.dialog =    builder.get_object('subtitles_dialog')
 
343
        self.find_button = builder.get_object('find_button')
 
344
        self.apply_button = builder.get_object('apply_button')
 
345
        self.close_button = builder.get_object('close_button')
 
346
 
 
347
        # Set up and populate the languages combobox
 
348
        renderer = gtk.CellRendererText()
 
349
        sorted_languages = gtk.TreeModelSort(languages)
 
350
        sorted_languages.set_sort_column_id(0, gtk.SORT_ASCENDING)
 
351
        combobox.set_model(sorted_languages)
 
352
        combobox.pack_start(renderer, True)
 
353
        combobox.add_attribute(renderer, 'text', 0)
 
354
 
 
355
        self.model.lang = self.gconf_get_str (self.GCONF_BASE_DIR + self.GCONF_LANGUAGE, self.model.lang)
 
356
        for lang in LANGUAGES_STR:
 
357
            it = languages.append(lang)
 
358
            if LANGUAGES[lang[1]] == self.model.lang:
 
359
                parentit = sorted_languages.convert_child_iter_to_iter (None, it)
 
360
                combobox.set_active_iter(parentit)
 
361
 
 
362
        # Set up the results treeview 
 
363
        renderer = gtk.CellRendererText()
 
364
        self.treeview.set_model(self.liststore)
 
365
        self.treeview.set_headers_visible(False)
 
366
        self.treeview.insert_column_with_attributes(0, _("Subtitles"), renderer, text=0)
 
367
        # translators comment:
 
368
        # This is the file-type of the subtitle file detected
 
369
        self.treeview.insert_column_with_attributes(1, _("Format"), renderer, text=1)
 
370
        # translators comment:
 
371
        # This is a rating of the quality of the subtitle
 
372
        self.treeview.insert_column_with_attributes(2, _("Rating"), renderer, text=2)
 
373
 
 
374
        self.apply_button.set_sensitive(False)
 
375
 
 
376
        self.apply_button.connect('clicked', self.on_apply_clicked)
 
377
        self.find_button.connect('clicked', self.on_find_clicked)
 
378
        self.close_button.connect('clicked', self.on_close_clicked)
 
379
 
 
380
        # Set up signals
 
381
 
 
382
        combobox_changed_id = combobox.connect('changed', self.on_combobox__changed)
 
383
        self.dialog.connect ('delete-event', self.dialog.hide_on_delete)
 
384
        self.dialog.set_transient_for (self.totem.get_main_window())
 
385
        self.dialog.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
 
386
 
 
387
        # Connect the callback
 
388
        self.treeview.get_selection().connect('changed', self.on_treeview__row_change)
 
389
        self.treeview.connect('row-activated', self.on_treeview__row_activate)
 
390
 
 
391
    def os_show_dialog(self, action, totem_object):
 
392
        if not self.dialog:
 
393
            self.os_build_dialog(action, totem_object)
 
394
 
 
395
        filename = self.totem.get_current_mrl()
 
396
        if not self.model.results or filename != self.filename:
 
397
            self.filename = filename
 
398
 
 
399
        self.dialog.show_all()
 
400
 
 
401
        self.progress.set_fraction(0.0)
 
402
 
 
403
    def os_append_menu(self):
 
404
        """
 
405
        """
 
406
        
 
407
        self.os_action_group = gtk.ActionGroup('OpenSubtitles')
 
408
 
 
409
        self.action = gtk.Action('opensubtitles',
 
410
                             _('_Download Movie Subtitles...'),
 
411
                             _("Download movie subtitles from OpenSubtitles"),
 
412
                             '')
 
413
 
 
414
        self.os_action_group.add_action(self.action)
 
415
 
 
416
        self.manager.insert_action_group(self.os_action_group, 0)
 
417
 
 
418
        self.menu_id = self.manager.new_merge_id()
 
419
        self.manager.add_ui(self.menu_id,
 
420
                             '/tmw-menubar/view/subtitle-download-placeholder',
 
421
                             'opensubtitles',
 
422
                             'opensubtitles',
 
423
                             gtk.UI_MANAGER_MENUITEM,
 
424
                             False
 
425
                            )
 
426
        self.action.set_visible(True)
 
427
 
 
428
        self.manager.ensure_update()
 
429
 
 
430
        self.action.connect('activate', self.os_show_dialog, self.totem)
 
431
 
 
432
        self.action.set_sensitive(self.totem.is_playing() and
 
433
                                  self.os_check_allowed_scheme() and
 
434
                                  not self.os_check_is_audio())
 
435
 
 
436
    def os_check_allowed_scheme(self):
 
437
        scheme = gio.File(self.totem.get_current_mrl()).get_uri_scheme()
 
438
        if scheme == 'dvd' or scheme == 'http' or scheme == 'dvb' or scheme == 'vcd':
 
439
            return False
 
440
        return True
 
441
 
 
442
    def os_check_is_audio(self):
 
443
        # FIXME need to use something else here
 
444
        # I think we must use video widget metadata but I don't found a way 
 
445
        # to get this info from python
 
446
        filename = self.totem.get_current_mrl()
 
447
        if gio.content_type_guess(filename).split('/')[0] == 'audio':
 
448
            return True
 
449
        return False
 
450
 
 
451
    def os_delete_menu(self):
 
452
        self.manager.remove_action_group(self.os_action_group)
 
453
        self.manager.remove_ui(self.menu_id)
 
454
 
 
455
    def os_get_results(self):
 
456
        """
 
457
        """
 
458
        self.liststore.clear()
 
459
        self.treeview.set_headers_visible(False)
 
460
        self.model.results = []
 
461
        self.apply_button.set_sensitive(False)
 
462
        self.find_button.set_sensitive(False)        
 
463
 
 
464
        self.dialog.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
 
465
 
 
466
        thread = SearchThread(self.model)
 
467
        thread.start()
 
468
        gobject.idle_add(self.os_populate_treeview)
 
469
 
 
470
        self.progress.set_text(_('Searching subtitles...'))
 
471
        gobject.timeout_add(350, self.os_progress_bar_increment, thread)
 
472
 
 
473
    def os_populate_treeview(self):
 
474
        """
 
475
        """
 
476
        if self.model.lock.acquire(False) == False:
 
477
            return True
 
478
 
 
479
        if self.model.results:
 
480
            self.apply_button.set_sensitive(True)
 
481
            for subData in self.model.results:
 
482
                if not SUBTITLES_EXT.count(subData['SubFormat']):
 
483
                        continue
 
484
                self.liststore.append([subData['SubFileName'], subData['SubFormat'], subData['SubRating'], subData['IDSubtitleFile'],])
 
485
                self.treeview.set_headers_visible(True)
 
486
        else:
 
487
            self.apply_button.set_sensitive(False)
 
488
 
 
489
        self.model.lock.release()
 
490
 
 
491
        self.dialog.window.set_cursor(None)
 
492
 
 
493
        return False
 
494
 
 
495
    def os_save_selected_subtitle(self, filename=None):
 
496
        """
 
497
        """
 
498
        self.dialog.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
 
499
 
 
500
        model, rows = self.treeview.get_selection().get_selected_rows()
 
501
        if rows:
 
502
            iter = model.get_iter(rows[0])
 
503
            subtitle_id = model.get_value(iter, 3)
 
504
            subtitle_format = model.get_value(iter, 1)
 
505
 
 
506
            gfile = None
 
507
 
 
508
            if not filename:
 
509
                directory = gio.File(xdg.BaseDirectory.xdg_cache_home + sep + 'totem' + sep + 'subtitles' + sep) 
 
510
                if not directory.query_exists():
 
511
                    directory.make_directory_with_parents()
 
512
 
 
513
                file = gio.File(self.filename)
 
514
                movie_name = file.get_basename().rpartition('.')[0]
 
515
                filename = directory.get_uri() + sep + movie_name + '.' + subtitle_format
 
516
 
 
517
            self.model.subtitles = ''
 
518
 
 
519
            thread = DownloadThread(self.model, subtitle_id)
 
520
            thread.start()
 
521
            gobject.idle_add(self.os_save_subtitles, filename)
 
522
 
 
523
            self.progress.set_text(_('Downloading the subtitles...'))
 
524
            gobject.timeout_add(350, self.os_progress_bar_increment, thread)
 
525
        else:
 
526
            #warn user!
 
527
            pass
 
528
 
 
529
    def os_save_subtitles(self, filename):
 
530
        if self.model.lock.acquire(False) == False:
 
531
            return True
 
532
 
 
533
        if self.model.subtitles:
 
534
            # Delete all previous cached subtitle for this file 
 
535
            for ext in SUBTITLES_EXT:
 
536
                fp = gio.File(filename[:-3] + ext)
 
537
                if fp.query_exists():
 
538
                    fp.delete()
 
539
 
 
540
            fp = gio.File(filename)
 
541
            suburi = fp.get_uri ()
 
542
 
 
543
            subFile  = fp.replace('', False)
 
544
            subFile.write(self.model.subtitles)
 
545
            subFile.close()
 
546
 
 
547
        self.model.lock.release()
 
548
 
 
549
        self.dialog.window.set_cursor(None)
 
550
 
 
551
        if suburi:
 
552
            self.totem.set_current_subtitle(suburi)
 
553
 
 
554
        return False
 
555
 
 
556
    def os_progress_bar_increment(self, thread):
 
557
 
 
558
        if not thread.done:
 
559
            self.progress.pulse()
 
560
            return True
 
561
 
 
562
        if self.model.message:
 
563
            self.progress.set_text(self.model.message)
 
564
        else:
 
565
            self.progress.set_text('')
 
566
        
 
567
        self.progress.set_fraction(0.0)
 
568
        self.find_button.set_sensitive(True)
 
569
        self.apply_button.set_sensitive(False)
 
570
        self.treeview.set_sensitive(True)
 
571
        return False
 
572
 
 
573
    def os_download_and_apply(self):
 
574
        self.apply_button.set_sensitive(False)
 
575
        self.find_button.set_sensitive(False)
 
576
        self.action.set_sensitive(False)
 
577
        self.treeview.set_sensitive(False)
 
578
        self.os_save_selected_subtitle()
 
579
 
 
580
    # Callbacks
 
581
 
 
582
    def on_treeview__row_change(self, selection):
 
583
        if selection.count_selected_rows() > 0:
 
584
            self.apply_button.set_sensitive(True)
 
585
        else:
 
586
            self.apply_button.set_sensitive(False)
 
587
 
 
588
    def on_treeview__row_activate(self, path, column, data):
 
589
        self.os_download_and_apply()
 
590
 
 
591
    def on_totem__file_opened(self, totem, filename):
 
592
        """
 
593
        """
 
594
        # Check if allows subtitles
 
595
        if self.os_check_allowed_scheme() and not self.os_check_is_audio():
 
596
            self.action.set_sensitive(True)
 
597
            if self.dialog:
 
598
                self.find_button.set_sensitive(True)
 
599
                self.filename = self.totem.get_current_mrl()
 
600
                self.liststore.clear()
 
601
                self.treeview.set_headers_visible(False)
 
602
                self.apply_button.set_sensitive(False)
 
603
                self.results = [] 
 
604
        else:
 
605
            self.action.set_sensitive(False)
 
606
            if self.dialog and self.dialog.is_active():
 
607
                self.liststore.clear()
 
608
                self.treeview.set_headers_visible(False)
 
609
                self.apply_button.set_sensitive(False)
 
610
                self.find_button.set_sensitive(False)
 
611
 
 
612
    def on_totem__file_closed(self, totem):
 
613
        self.action.set_sensitive(False)
 
614
        if self.dialog:
 
615
            self.apply_button.set_sensitive(False)
 
616
            self.find_button.set_sensitive(False)
 
617
 
 
618
    def on_combobox__changed(self, combobox):
 
619
        iter = combobox.get_active_iter()
 
620
        self.model.lang = LANGUAGES[combobox.get_model().get_value(iter, 1)]
 
621
        self.gconf_set_str(self.GCONF_BASE_DIR + self.GCONF_LANGUAGE,
 
622
                           self.model.lang)
 
623
 
 
624
    def on_close_clicked(self, data):
 
625
        self.dialog.destroy()
 
626
        self.dialog = None
 
627
 
 
628
    def on_apply_clicked(self, data):
 
629
        self.os_download_and_apply()
 
630
 
 
631
    def on_find_clicked(self, data):
 
632
        self.apply_button.set_sensitive(False)
 
633
        self.find_button.set_sensitive(False)
 
634
        self.filename = self.totem.get_current_mrl()
 
635
        self.model.hash , self.model.size = hashFile(self.filename)
 
636
 
 
637
        self.os_get_results()
 
638
 
 
639
    def gconf_get_str(self, key, default = ""):
 
640
        val = self.gconf_client.get(key)
 
641
        
 
642
        if val is not None and val.type == gconf.VALUE_STRING:
 
643
            return val.get_string()
 
644
        else:
 
645
            return default
 
646
 
 
647
    def gconf_set_str(self, key, val):
 
648
        self.gconf_client.set_string(key, val)
 
649