Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

New Subtitle handler registration mode, small fixes and corrections

  • Loading branch information...
commit 37f4cd513d2d1c6503812057262e3c0fe2768bf4 1 parent 07af82a
@murbaniak authored
View
113 Docs/plugins/subtitles.txt
@@ -5,93 +5,74 @@ Plugin video.subtitles provides framework that allows individual
plugins or handlers as I'd like to call them to download subtitles from
(currently) the follwoing sites:
- http://napiprojekt.pl
- http://opensubtitles.org
-
+ http://napiprojekt.pl
+ http://opensubtitles.org
+
Subtitles plugin on it's own does not know how to download the sobtitles
from these sites. It needs at least one specialised handler (napiprojekt
or opensubtitles) registered for the download to work.
To enable the plugin and the handlers all one needs to do is to insert
-following lines into the local_config.py as a bare minimum:
+following lines into the local_config.py:
- plugin.activate('video.subtitles')
- SUBS_HANDLERS = ['video.napiprojekt', 'video.opensubtitles', ]
-
-The specialised plugins can be activated explicitly within the local_config.py
-but this is not necessary. Main Subtitles plugin will activate the plugins it
-found from the entries in the SUBS_HANDLERS variable.
+ plugin.activate('video.subtitles')
+ plugin.activate('video.subtitles.napiprojekt')
+ plugin.activate('video.subtitles.opensubtitles')
Each handler knows how to get a list available subtitles, download,
decompress and save subtitles.
By default the plugin support following subtitle langauges:
- English
- German
- Polish
-
-NOTE: napirojekt only supports 2 languages, Polish and English!!!
-
-BTW; Subtitles plugin works with ISO 639-2 language codes.
-Vist http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes for details.
+ English
-If you want to narrow the list of the subtitles being pulled, declare
-the following for example:
+but it can easly configured to support additional langauges:
- SUBS_LANGS = { 'eng': ('English'), 'ger': ('German'), }
-
+ SUBS_LANGS = { 'eng': ('English'), 'ger': ('German'), }
+
This will only pull English and German subtitles. in the above dictionary,
key represents the ISO 639-2 language code and value represents
the language name as used by the plugin to display on OSD, menus etc.
+NOTE: napirojekt only supports 2 languages, Polish and English!!!
+
+BTW; Subtitles plugin works with ISO 639-2 language codes.
+Vist http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes for details.
+
User will be presented with the Menu of available Subtitle files in these
languages and will be allowed to make a choice which Subs to save to
the local filesystem.
-If you are interested only in the English subtitles, then:
-
- SUBS_LANGS = { 'eng': ('English'), }
-
-If you require some other language, that the plugin is not configured with
-by default, you'd need to tell the Plugin which language you require
-(only opensubtitles handler can be extended but napiprojekt supports only
-two languages, Polish and English).
-
-For example:
-
- SUBS_LANGS = { 'eng': ('English'), 'ita': ('Italian'), }
-
There are some other configuration variables that modify the behaviour
of main Subtitles plugin as well as individual handlers (with default values):
- # Blindly download all subs available, otherwise the
- # menu with available aubtitles will be presented and choice can be made
- SUBS_AUTOACCEPT = False
+ # Blindly download all subs available, otherwise the
+ # menu with available aubtitles will be presented and choice can be made
+ SUBS_AUTOACCEPT = False
- # Override existing subtitle file (if exists)
- SUBS_FORCE_UPDATE = True
+ # Override existing subtitle file (if exists)
+ SUBS_FORCE_UPDATE = True
- # Backup old file if in update mode above
- SUBS_FORCE_BACKUP = True
+ # Backup old file if in update mode above
+ SUBS_FORCE_BACKUP = True
- # by default plugin will use follwing filename convention
- # xxx.os.eng where os is the handler's ID (os or np)
- # and eng is the language code of the subtitles.
+ # by default plugin will use follwing filename convention
+ # xxx.os.eng where os is the handler's ID (os or np)
+ # and eng is the language code of the subtitles.
- # Force use of the subtitle lagnguage code in the filename i.e. xxx.eng.txt
- SUBS_FORCE_LANG_EXT = True,
-
- # Force use of the subtitle handler id in the filename i.e. xxx.os.txt
- SUBS_FORCE_HANDLER_ID = True,
-
- # opensubtitles user agent and domain
- OSUBS_USER_AGENT = "Freevo v1.9"
- OSUBS_DOMAIAN = "http://api.opensubtitles.org/xml-rpc"
-
- # napiprojekt URL and zip password
- NAPI_URL = "http://napiprojekt.pl/unit_napisy/dl.php?l=%s&f=%s&t=%s&v=other&kolejka=false&nick=&pass=&napios=%s"
- NAPI_PWD = "iBlm8NTigvru0Jr0"
+ # Force use of the subtitle lagnguage code in the filename i.e. xxx.eng.txt
+ SUBS_FORCE_LANG_EXT = True,
+
+ # Force use of the subtitle handler id in the filename i.e. xxx.os.txt
+ SUBS_FORCE_HANDLER_ID = True,
+
+ # opensubtitles user agent and domain
+ OSUBS_USER_AGENT = "Freevo v1.9"
+ OSUBS_DOMAIAN = "http://api.opensubtitles.org/xml-rpc"
+
+ # napiprojekt URL and zip password
+ NAPI_URL = "http://napiprojekt.pl/unit_napisy/dl.php?l=%s&f=%s&t=%s&v=other&kolejka=false&nick=&pass=&napios=%s"
+ NAPI_PWD = "iBlm8NTigvru0Jr0"
If you define SUBS_FORCE_LANG_EXT or SUBS_FORCE_HANDLER_ID make sure
@@ -113,11 +94,11 @@ Enjoy!
-----
TODO:
-----
- # By default opensubtitles handler downloads only one set of subs
- # for a give movie, the one most often downloaded. Often there are more
- # that one set availabe for download, if you want to get a choice of more
- # that one set, increase the number below (not implemented yet).
- OSUBS_MAX_SUBS = 1
+ # By default opensubtitles handler downloads only one set of subs
+ # for a give movie, the one most often downloaded. Often there are more
+ # that one set availabe for download, if you want to get a choice of more
+ # that one set, increase the number below (not implemented yet).
+ OSUBS_MAX_SUBS = 1
-------
PS/BTW:
@@ -135,6 +116,6 @@ This behaviour is enabled by default and if you do not like it and prefer
mplayer to silently change subs then you can disable it by setting following
in your local_config.py:
- # Prevents freevo from using mplayer's show_ext_prop_text to display
- # current subs and audio track info on the screen
- MPLAYER_USE_OSD_SHOW_PROPS = True
+ # Prevents freevo from using mplayer's show_ext_prop_text to display
+ # current subs and audio track info on the screen
+ MPLAYER_USE_OSD_SHOW_PROPS = True
View
5 freevo_config.py
@@ -791,8 +791,9 @@
# add subtitle search to the video item menu
plugin.activate('video.subtitles')
-SUBS_HANDLERS = [('video.opensubtitles'), ('video.napiprojekt'), ]
-SUBS_LANGS = { 'eng': ('English'), }
+plugin.activate('video.subtitles.napiprojekt')
+plugin.activate('video.subtitles.opensubtitles')
+SUBS_LANGS = { 'eng': ('English') }
# delete file in menu
plugin.activate('file_ops', level=20)
View
3  local_conf.py.example
@@ -494,7 +494,8 @@ CACHE_IMAGES = 1
# ======================================================================
# add subtitle search to the video item menu
# plugin.activate('video.subtitles')
-# SUBS_HANDLERS = [('video.opensubtitles'), ('video.napiprojekt'), ]
+# plugin.activate('video.subtitles.napiprojekt')
+# plugin.activate('video.subtitles.opensubtitles')
# SUBS_LANGS = { 'eng': ('English'), }
View
BIN  share/images/osd/base/status_bg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  share/images/osd/blurr/status_bg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  share/images/osd/geexbox/status_bg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
6 share/skins/osd/base.fxd 100755 → 100644
@@ -132,9 +132,9 @@
<text name="Text1" x="10" y="100" width="480" height="25" expression="progress_text" font="message" align="center" valign="center" fgcolor="white"/>
<image name="Image1" x="200" y="140" width="100" height="100" expression="indeterminate" scale="aspect" align="left" valign="top" srcexpr="'misc/osd_busy%02d' % (counter % 12)"/>
</osd>
- <osd name="status" x="25" y="490" width="750" height="40">
@charrea6
charrea6 added a note

Please revert these changes as status is a specific type of message dialog.
Message dialogs don't stop the user interacting with the rest of freevo

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
- <image name="Background" x="0" y="0" width="750" height="40" expression="True" scale="both" align="left" valign="top" src="message_bg.png"/>
- <text name="Message" x="5" y="0" width="740" height="40" expression="message" font="message" align="left" valign="center"/>
+ <osd name="status" x="200" y="200" width="400" height="200">
+ <image name="Background" x="0" y="0" width="400" height="200" expression="True" scale="both" align="left" valign="top" src="status_bg.png"/>
+ <text name="Message" x="5" y="5" width="390" height="190" expression="message" font="message" align="center" valign="center"/>
</osd>
<osd name="shutdown" x="150" y="200" width="500" height="300">
<image name="background" x="0" y="0" width="500" height="300" expression="True" scale="both" align="left" valign="top" src="dialog_bg.png"/>
View
12 share/skins/osd/blurr.fxd 100755 → 100644
@@ -29,8 +29,8 @@
<text name="current_time" x="10" y="563" width="780" height="30" expression="current_time_str" font="menu" align="left" valign="top"/>
<text name="total_time" x="10" y="563" width="780" height="30" expression="total_time_str" font="menu" align="right" valign="top"/>
</osd>
- <osd name="message" x="10" y="62" width="780" height="40">
- <image name="Background" x="0" y="0" width="780" height="40" expression="True" scale="both" align="left" valign="top" src="message_bg.png"/>
+ <osd name="message" x="10" y="62" width="780" height="50">
+ <image name="Background" x="0" y="0" width="780" height="50" expression="True" scale="both" align="left" valign="center" src="message_bg.png"/>
<text name="Message" x="5" y="0" width="770" height="40" expression="message" font="message" align="left" valign="center" fgcolor="white"/>
</osd>
<osd name="1button" x="150" y="200" width="500" height="250">
@@ -121,7 +121,7 @@
</widgetstate>
</widgetstyle>
<font label="clock" name="DejaVuSans-Bold" size="16" color="white"/>
- <font label="message" name="DejaVuSans" size="24" color="white"/>
+ <font label="message" name="DejaVuSans" size="20" color="white"/>
<font label="button" name="DejaVuSans" size="12" color="black"/>
<font label="button_selected" name="DejaVuSans-Bold" size="14" color="white"/>
<font label="button_pressed" name="DejaVuSans-Bold" size="14" color="black"/>
@@ -146,9 +146,9 @@
<text name="Text1" x="10" y="100" width="480" height="25" expression="progress_text" font="message" align="center" valign="center" fgcolor="white"/>
<image name="Image2" x="200" y="140" width="100" height="100" expression="indeterminate" scale="aspect" align="left" valign="top" srcexpr="'misc/osd_busy%02d' % (counter % 12)"/>
</osd>
- <osd name="status" x="25" y="490" width="750" height="40">
- <image name="Background" x="0" y="0" width="750" height="40" expression="True" scale="both" align="left" valign="top" src="message_bg.png"/>
- <text name="Message" x="5" y="0" width="740" height="40" expression="message" font="message" align="left" valign="center"/>
+ <osd name="status" x="200" y="200" width="400" height="200">
@charrea6
charrea6 added a note

Please revert

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ <image name="Background" x="0" y="0" width="400" height="200" expression="True" scale="both" align="left" valign="top" src="status_bg.png"/>
+ <text name="Message" x="5" y="5" width="390" height="190" expression="message" font="message" align="center" valign="center"/>
</osd>
<osd name="shutdown" x="150" y="200" width="500" height="300">
<image name="background" x="0" y="0" width="500" height="300" expression="True" scale="both" align="left" valign="top" src="dialog_bg.png"/>
View
6 share/skins/osd/geexbox.fxd
@@ -145,9 +145,9 @@
<text name="Text1" x="10" y="100" width="480" height="25" expression="progress_text" font="message" align="center" valign="center" fgcolor="white"/>
<image name="Image3" x="200" y="140" width="100" height="100" expression="indeterminate" scale="aspect" align="left" valign="top" srcexpr="'misc/osd_busy%02d' % (counter % 12)"/>
</osd>
- <osd name="status" x="25" y="490" width="750" height="40">
- <image name="Background" x="0" y="0" width="750" height="40" expression="True" scale="both" align="left" valign="top" src="message_bg.png"/>
- <text name="Message" x="5" y="0" width="740" height="40" expression="message" font="message" align="left" valign="center"/>
+ <osd name="status" x="200" y="200" width="400" height="200">
@charrea6
charrea6 added a note

Please revert

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ <image name="Background" x="0" y="0" width="400" height="200" expression="True" scale="both" align="left" valign="top" src="status_bg.png"/>
+ <text name="Message" x="5" y="5" width="390" height="190" expression="message" font="message" align="center" valign="center"/>
</osd>
<osd name="shutdown" x="150" y="200" width="500" height="250">
<image name="background" x="0" y="0" width="500" height="250" expression="True" scale="noscale" align="left" valign="top" src="dialog_bg.png"/>
View
41 src/dialog/utils.py
@@ -32,8 +32,8 @@
import os.path
import config
-
import dialog
+from dialog.dialogs import MessageDialog
def get_xine_config_file():
"""
@@ -69,3 +69,42 @@ def get_xine_config_file():
outfile.close()
return config_file
+
+
+def show_message(message, name='message', duration=None):
@charrea6
charrea6 added a note

You don't need either of these 2 functions. Messages should hide automatically after a time out as they require no interaction from the user.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ """
+ Helper function that shows the skinnable osd message dialog
+ @param message: message to be displayed
+ @param name: name of the dialog used to load appropriate skin object
+ Default is ’message’, ‘status’ is also available.
+ See dialog/dialogs.py and osd skin definitions for available
+ names/dialog types
+ @param duration: duration the msg is displayed. Default is None which defaults
+ to the standard duration of the MessageDialog, currently 3 secs
+ 0 will display indefinitely, until hide_message() is called
+ In this cae caller is responsible for cleaning up, either hide
+ and finish the dialog or call dialog.util.hide_message()!
+ @return: instantiated MessageDialog object, needed for subsequent call
+ to hide_message
+ """
+ dialog = MessageDialog(message)
+ dialog.name = name
+ if duration is None:
+ dialog.show()
+ else:
+ dialog.show(duration)
+
+ return dialog
+
+
+def hide_message(dialog):
+ """
+ Helper function that hides and finishes the osd message dialog,
+ created by show_dialog()
+ @param dialog: dialog object returned previously by show_dialog()
+ """
+ # check if we have a valid object and check the type too, in case
+ # someone passed us wrong type, to prevent runtime errors.
+ if dialog and isinstance(dialog, MessageDialog):
+ dialog.hide()
+ dialog.finish()
@charrea6
charrea6 added a note

FYI finish is called by the dialog system to indicate the window has been removed from the stack of dialogs, so shouldn't be called by the user.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
View
3  src/image/viewer.py
@@ -2,7 +2,7 @@
# -----------------------------------------------------------------------
# Freevo image viewer
# -----------------------------------------------------------------------
-# $Id$
+# $Id: $
# -----------------------------------------------------------------------
# Freevo - A Home Theater PC framework
# Copyright (C) 2002 Krister Lagerstrom, et al.
@@ -75,6 +75,7 @@ def get_singleton():
class ImageZoomPosition():
def __init__(self, pos_x = 0, pos_y = 0):
"""
+ Represents the current position/coordinates within the zoomed in image
"""
logger.log(9, 'ImageZoomPosition.__init__()')
self.pos_x = pos_x
View
9 src/plugins/archive.py
@@ -2,7 +2,7 @@
# -----------------------------------------------------------------------
# Freevo Archive file (zip, tar and rar) handling
# -----------------------------------------------------------------------
-# $Id$
+# $Id: $
#
# Notes: To use RAR file handling you must install both 'unrar' utility
# and python rar module. This plugin has been tested with version
@@ -319,11 +319,8 @@ def set_cover_image(self, dir):
return None
try:
- # FIX ME It's more efficient to use symlinks but only on Windows. It's to complicated
- # to detect the system type and then make a decision if use symlinks or copy (for now)
- # maybe in the future ???
- # os.symlink(os.path.join(dir, normalize(image), os.path.join(dir, ('cover' + ext)))
- shutil.copy(os.path.join(dir, normalize(image)), os.path.join(dir, ('cover' + ext)))
+ os.symlink(os.path.join(dir, normalize(image)), os.path.join(dir, ('cover' + ext)))
+ #shutil.copy(os.path.join(dir, normalize(image)), os.path.join(dir, ('cover' + ext)))
logger.debug('Cover image %s, copied to %s', normalize(image), dir)
except (OSError, ShutilError) as exc:
logger.warning('Error while getting cover image for archive %s, %s', self.archive, exc)
View
37 src/video/plugins/imdb.py
@@ -38,10 +38,10 @@
# based on original implementation by 'den_RDC (rdc@kokosnoot.com)'
__author__ = 'den_RDC (rdc@kokosnoot.com)'
-__maintainer__ = 'Maciej Mike Urbaniak'
+__maintainer__ = 'Maciej Urbaniak'
__maintainer_email__ = 'maciej@urbaniak.org'
-__version__ = 'Revision 0.2'
-__license__ = 'GPL'
+__version__ = '$Revision$'
+__license__ = 'GPL'
# Module Imports
import os
@@ -51,9 +51,10 @@
import plugin
import re
import time
+import dialog
+import dialog.utils
from util.fxdimdb import FxdImdb, makeVideo, makePart, point_maker, FxdImdb_Error
-from gui.PopupBox import PopupBox
try:
import imdb
@@ -135,9 +136,7 @@ def imdb_search(self, arg=None, menuw=None):
"""
items = []
-
- box = PopupBox(text=_('Searching IMDB...'))
- box.show()
+ dlg = dialog.utils.show_message(_('Searching IMDB...'), 'status', 0)
@charrea6
charrea6 added a note

use dialog.show_working_indicator here rather than message.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
if self.disc_set:
self.searchstring = self.item.media.label
@@ -162,14 +161,11 @@ def imdb_search(self, arg=None, menuw=None):
except FxdImdb_Error, error:
logger.warning('%s', error)
- box.destroy()
- box = PopupBox(text=_('Connection to IMDB failed: ') + str(error))
- box.show()
- time.sleep(2)
- box.destroy()
+ dialog.utils.hide_message(dlg)
@charrea6
charrea6 added a note

Use dialog.show_alert() to inform the user of something you want them to confirm, or dialog.show_message() for something that you think they want to know but don't need to confirm.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ dialog.utils.show_message(_('Connection to IMDB failed'))
return
- box.destroy()
+ dialog.utils.hide_message(dlg)
if config.IMDB_AUTOACCEPT_SINGLE_HIT and len(items) == 1:
self.imdb_create_fxd(arg=items[0].arg, menuw=menuw)
@@ -180,10 +176,7 @@ def imdb_search(self, arg=None, menuw=None):
menuw.pushmenu(moviemenu)
return
- box = PopupBox(text=_('No information available from IMDB'))
- box.show()
- time.sleep(2)
- box.destroy()
+ dialog.utils.show_message(_('No information available from IMDB'))
@charrea6
charrea6 added a note

I think you probably want dialog.show_message() here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
return
@@ -218,15 +211,14 @@ def imdb_create_fxd(self, arg=None, menuw=None):
"""
create fxd file for the item
"""
- box = PopupBox(text=_('Getting data...'))
- box.show()
+ dlg = dialog.utils.show_message(_('Getting data...'), 'status', 0)
@charrea6
charrea6 added a note

dialog.show_working_indicator() here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
try:
self.fxd.retrieveImdbData(arg[0], self.fxd.ctitle[1], self.fxd.ctitle[2])
except FxdImdb_Error, error:
logger.warning('%s', error)
- box.destroy()
+ dialog.utils.hide_message(dlg)
return
#if this exists we got a cdrom/dvdrom
@@ -252,9 +244,6 @@ def imdb_create_fxd(self, arg=None, menuw=None):
self.fxd.writeFxd()
self.fxd = FxdImdb()
- print 'About to go back'
self.imdb_menu_back(menuw)
- box.destroy()
- print 'Box destroyed'
+ dialog.utils.hide_message(dlg)
-
View
2  src/video/plugins/mplayer.py
@@ -553,8 +553,6 @@ def eventhandler(self, event, menuw=None):
# check again if seek is allowed
if self.item_length <= self.item.elapsed + event.arg + seek_safety_time:
logger.debug('unable to seek %s secs at time %s, length %s', event.arg, self.item.elapsed, self.item_length)
-
-
dialog.show_message(_('Seeking not possible'))
return False
View
192 src/video/plugins/subtitles.py → src/video/plugins/subtitles/__init__.py
@@ -68,8 +68,8 @@
import re
import time
import util
-
-from gui.PopupBox import PopupBox
+import dialog
+import dialog.utils
HEAD = 'head'
TAIL = 'tail'
@@ -81,28 +81,33 @@ def trunc(what, cnt, where=HEAD, ellipsis='...'):
class Error(Exception):
- """Base class for exceptions in Subs"""
+ """
+ Base class for exceptions in Subs
+ """
def __str__(self):
return self.message
def __init__(self, message):
self.message = message
-class SubsError(Error):
- """used to raise Subtitle specific exceptions"""
+class SubtitlesError(Error):
+ """
+ used to raise Subtitle specific exceptions
+ """
pass
-class SubsHandler():
+class SubtitlesPlugin(plugin.Plugin):
"""
- Base Subtitles handler class definition including all methods that subclasses
+ Base Subtitles Plugin handler class definition including all methods that subclasses
shall overwrite
"""
-
def __init__(self, id, name, langs):
+ plugin.Plugin.__init__(self)
self.id = id
self.name = name
self.langs = langs
+ self._type = 'subtitles'
def __getitem__(self, key):
@@ -116,20 +121,18 @@ def __getitem__(self, key):
if key == 'id':
return self.id
- if key == 'langs':
- return self.langs
-
return ''
def get_subs(self, vfile_, langs_):
"""
Derived class must overwrite this method
-
Get all available subtitles for the item
- @returns: the collection of subtitles keyed by the subtitle id
+ @param vfile_ : filename of the video file
+ @param langs_ : requested languages
+ @returns: the collection of subtitles keyed by the subtitle id
"""
- pass
+ return {}
class Subtitles():
@@ -149,27 +152,12 @@ def __init__(self, handler, vfile, lang):
def __getitem__(self, key):
"""
Get the item's attribute.
-
- @returns: the specific attribute
+ @param key: key
+ @returns: the specific attribute
"""
if key == 'id':
return hash((self.handler['id'], self.lang, self.vfile))
- if key == 'handler':
- return self.handler
-
- if key == 'vfile':
- return self.vfile
-
- if key == 'sfile':
- return self.sfile
-
- if key == 'lang':
- return self.lang
-
- if key == 'data':
- return self.data
-
def download(self):
"""
@@ -202,7 +190,7 @@ def backup(self):
if not config.SUBS_FORCE_UPDATE and os.path.exists(self.sfile):
msg = 'Skipping, subtitles %s aready exist and forced update is disabled' % (self.sfile)
logger.warning(msg)
- raise SubsError(msg)
+ raise SubtitlesError(msg)
if config.SUBS_FORCE_BACKUP and os.path.exists(self.sfile):
vfile_bkp = self.sfile + '.bkp'
@@ -215,7 +203,7 @@ def backup(self):
except (IOError, OSError), e:
msg = 'Skipping due to backup of \'%s\' as \'%s\' failure: %s' % (self.sfile, vfile_bkp, e)
logger.warning(msg)
- raise SubsError(msg)
+ raise SubtitlesError(msg)
else:
logger.info('Old subtitle backed up as \'%s\'', vfile_bkp)
@@ -228,20 +216,12 @@ class PluginInterface(plugin.ItemPlugin):
Activate with:
| plugin.activate('video.subtitles')
-
Make sure the suitable subtitles handler plugin is activated too:
- | plugin.activate('video.napiprojekt')
-
+ | plugin.activate('video.subtitles.napiprojekt')
and/or
- | plugin.activate('video.opensubtitles')
-
+ | plugin.activate('video.subtitles.opensubtitles')
etc.
- Make sure the
- | SUBS_HANDLERS = [ ('video.napiprojekt'), ('video.opensubtitles') ]
- is set in your local_config.py for the this subtitles plugin
- to be able to use the available handlers
-
You can also set subs_search on a key (e.g. 't') by setting
| EVENTS['menu']['t'] = Event(MENU_CALL_ITEM_ACTION, arg='subs_search')
"""
@@ -255,24 +235,9 @@ def __init__(self):
self.subs = {}
self.subfiles = []
- try:
- handlers = config.SUBS_HANDLERS
- except:
- self.reason = 'Plugin \'video.subtitles\' activated but SUBS_HANDLERS not defined!'
- return
-
- logger.info('Available Handlers : %s', handlers)
-
- for item in handlers:
- if not plugin.is_active(item):
- logger.warning('Plugin \'%s\' listed as available but not activated, activating now!', item)
- plugin.activate(item)
-
- handler = plugin.getbyname(item)['handler']
- self.handlers[handler['id']] = handler
- logger.info('Successfuly loaded subtitle handler %s', handler.name)
-
plugin.ItemPlugin.__init__(self)
+
+ self.handlers = self.get_handlers()
def config(self):
@@ -280,7 +245,7 @@ def config(self):
Returns the config variables used by this plugin
"""
return [
- ('SUBS_LANGS', { 'pol': ('Polish'), 'eng': ('English'), 'ger': ('German') },
+ ('SUBS_LANGS', { 'eng': ('English') },
'Subtitles to download'),
('SUBS_EXTS', [ '.srt', '.sub', '.txt', '.ssa', '.smi', '.ass', '.mpl'],
'Known subtitles file extensions'),
@@ -342,6 +307,22 @@ def get_existing_subs(self, file):
if os.path.splitext(n)[1] in config.SUBS_EXTS]
+ def get_handlers(self):
+ """
+ Get all regitered subtitle plugins into the local dictionary
+ @return: Hanlders dictionary keyed by the handler ID.
+ """
+ if self.handlers is None or len(self.handlers) < 1:
+ handlers = plugin.get('subtitles')
+ logger.info('Available subtitles handlers : %s', handlers)
+
+ for handler in handlers:
+ self.handlers[handler['id']] = handler
+ logger.info('Successfuly loaded subtitle handler %s', handler.name)
+
+ return self.handlers
+
+
def subs_search(self, arg=None, menuw=None):
"""
@@ -349,12 +330,12 @@ def subs_search(self, arg=None, menuw=None):
"""
self.subs = {}
items = []
+ dlg = None
try:
#get the subtitles from each active handler
- for handler in self.handlers.values():
- box = PopupBox(text=_('Searching %s for subtitles...' % (handler['name'])))
- box.show()
+ for handler in self.get_handlers().values():
+ dlg = dialog.utils.show_message(_('Searching %s...' % (handler['name'])), 'status', 0)
if self.item.subitems:
for i in range(len(self.item.subitems)):
@@ -362,38 +343,35 @@ def subs_search(self, arg=None, menuw=None):
else:
self.subs.update(handler.get_subs(self.item.filename, config.SUBS_LANGS.keys()))
- box.destroy()
-
+ dialog.utils.hide_message(dlg)
+
for subs in sorted(self.subs.values(), key=attrgetter('handler.id', 'lang', 'vfile')):
try:
- lang = config.SUBS_LANGS[subs['lang']]
+ lang = config.SUBS_LANGS[subs.lang]
if self.item.subitems:
- items.append(menu.MenuItem(_('%s subtitles for "%s" (from %s)' % \
- (lang, trunc(os.path.basename(subs['vfile']), 20), subs.handler['name'])),
+ items.append(menu.MenuItem(_('%s subtitles for "%s" (%s from %s)' % \
+ (lang, trunc(os.path.basename(subs.vfile), 20), subs.fmt, subs.handler['name'])),
self.subs_create_subs, (subs['id'])))
else:
- items.append(menu.MenuItem(_('%s subtitles (from %s)' % \
- (lang, subs.handler['name'])),
+ items.append(menu.MenuItem(_('%s subtitles (%s from %s)' % \
+ (lang, subs.fmt, subs.handler['name'])),
self.subs_create_subs, (subs['id'])))
- except Unicode, e:
- print e
+ except (Unicode) as err:
+ logger.warning(err)
# if we have more then 1 set of subs, we give user an option to save all
if len(self.subs) > 1:
items.insert(0, menu.MenuItem(_('Get all available subtitles listed below'),
self.subs_create_subs, ('all')))
- except (Exception), error:
- logger.error('%s' % (error,))
- box.destroy()
- box = PopupBox(text=_('Connection to service failed: ') + str(error))
- box.show()
- time.sleep(2)
- box.destroy()
+ except (Exception), err:
+ dialog.utils.hide_message(dlg)
+ logger.error('%s' % (err))
+ dialog.utils.show_message(_('Connection to subtitle service failed'))
@charrea6
charrea6 added a note

Same as in the previous file use the dialog.show_message() function for these.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
return
- if config.SUBS_AUTOACCEPT and len(items > 0):
+ if config.SUBS_AUTOACCEPT and len(items) > 0:
self.subs_create_subs(arg=('all'), menuw=menuw)
return
@@ -402,10 +380,7 @@ def subs_search(self, arg=None, menuw=None):
menuw.pushmenu(moviemenu)
return
- box = PopupBox(text=_('No subtitles available'))
- box.show()
- time.sleep(2)
- box.destroy()
+ dialog.utils.show_message(_('No subtitles available'))
return
@@ -422,6 +397,7 @@ def subs_delete(self, arg=None, menuw=None):
if hasattr(self.item, 'subitems') and self.item.subitems:
for i in range(len(self.item.subitems)):
self.subfiles.extend(self.get_existing_subs(self.item.subitems[i].filename))
+
else:
self.subfiles = self.get_existing_subs(self.item.filename)
@@ -429,6 +405,7 @@ def subs_delete(self, arg=None, menuw=None):
try:
items.append(menu.MenuItem(_('%s' % (os.path.split(subfile)[1])),
self.subs_delete_subs, (subfile)))
+
except Unicode, e:
print e
@@ -437,7 +414,7 @@ def subs_delete(self, arg=None, menuw=None):
items.insert(0, menu.MenuItem(_('Delete all subtitle files listed below'),
self.subs_delete_subs, ('all')))
- if config.SUBS_AUTOACCEPT and len(items > 0):
+ if config.SUBS_AUTOACCEPT and len(items) > 0:
self.subs_delete_subs(arg='all', menuw=menuw)
return
@@ -446,10 +423,7 @@ def subs_delete(self, arg=None, menuw=None):
menuw.pushmenu(moviemenu)
return
- box = PopupBox(text=_('No subtitles to be deleted for %s' % (os.path.base(self.item.filename))))
- box.show()
- time.sleep(2)
- box.destroy()
+ dialog.utils.show_message(_('No subtitles to be deleted'))
return
@@ -484,60 +458,54 @@ def subs_create_subs(self, arg=None, menuw=None):
"""
create subs for the item
"""
- box = PopupBox(text=_('Saving subtitles...'))
- box.show()
-
+ dlg = dialog.utils.show_message(_('Saving subtitles...'), 'status', 0)
+
try:
if arg == None or arg == 'all':
# we write all available subs
for subs in self.subs.values():
subs.save()
+
else:
# we write only chosen subs
subs = self.subs[arg]
- logger.debug('Writing subs from %s for lang %s', subs.handler['name'], subs['lang'])
+ logger.debug('Writing subs from %s for lang %s', subs.handler['name'], subs.lang)
subs.save()
- except (Exception), error:
- logger.error('%s' % (error,))
- box.destroy()
- box = PopupBox(text=_(error))
- box.show()
- time.sleep(2)
+ except (Exception), err:
+ logger.error('%s' % (err))
+ dialog.utils.hide_message(dlg)
+ dlg = dialog.utils.show_message(_('Error while saving subtitles'))
# reset subs
self.subs = {}
-
self.subs_menu_back(menuw)
- box.destroy()
+ dialog.utils.hide_message(dlg)
def subs_delete_subs(self, arg=None, menuw=None):
"""
delete subtitle file(s) for the item
"""
- box = PopupBox(text=_('Deleting subtitles...'))
- box.show()
+ dlg = dialog.utils.show_message(_('Deleting subtitles...'), 'status', 0)
try:
if arg == None or arg == 'all':
# we delete all available subtitle files
for subs in self.subfiles:
os.remove(subs)
+
else:
# we delete only chosen subtitle file
logger.debug('Deleting subtitle file %s', arg)
os.remove(arg)
except (Exception), error:
- logger.error('%s' % (error,))
- box.destroy()
- box = PopupBox(text=_(error))
- box.show()
- time.sleep(2)
+ logger.error('%s' % (err))
+ dialog.utils.hide_message(dlg)
+ dlg = dialog.utils.show_message(_('Error while deleting subtitles'))
self.subfiles = []
-
self.subs_menu_back(menuw)
- box.destroy()
-
+ dialog.utils.hide_message(dlg)
+
View
175 src/video/plugins/napiprojekt.py → src/video/plugins/subtitles/napiprojekt.py
@@ -9,7 +9,7 @@
# with this plugin. Only two langauges supported, Polish and English.
# Check out the video.subtitles plugin for more configuration options
#
-# This code is based on some anonymous code found in the depths
+# This code is partially based on some anonymous code found in the depths
# of the www :-)
#
# Todo: none
@@ -63,30 +63,25 @@
except ImportError:
from md5 import md5
-# http://www.joachim-bauch.de/projects/pylzma/
NAPI_LANGS = [ 'pol', 'eng' ]
-from subtitles import SubsHandler, SubsError, Subtitles
+from video.plugins.subtitles import SubtitlesPlugin, SubtitlesError, Subtitles
-class PluginInterface(plugin.Plugin):
+class PluginInterface(SubtitlesPlugin):
"""
This is a handler plugin for http://napiprojekt.pl subtitle provider
and is used by main subtitle plugin.
-
Only polish and english subtitles are supported by napiprojekt.pl
Activate with:
- | plugin.activate('video.napiprojekt')
-
- and make sure the SUBS_HANDLERS = [ ('video.napiprojekt'), ]
- is set for the main subtitles plugin to be able to use this plugin
-
+ | plugin.activate('video.subtitles.napiprojekt')
and of course make sure the main subtitles plugin is activated too:
| plugin.activate('video.subtitles')
-
"""
-
def __init__(self):
+ """
+ Constructor
+ """
if not config.SYS_USE_NETWORK:
self.reason = 'SYS_USE_NETWORK not enabled'
return
@@ -95,17 +90,23 @@ def __init__(self):
self.reason = 'Plugin \'video.subtitles\' not active, activate it first in your local_config.py!'
return
- self.handler = NapiHandler()
-
- plugin.Plugin.__init__(self)
+ langs = []
+
+ try:
+ langs = config.NAPI_LANGS
+ except:
+ langs = NAPI_LANGS
- plugin.register(self, 'video.napiprojekt')
+ SubtitlesPlugin.__init__(self, 'np', 'napiprojekt.pl', langs)
+ plugin.register(self, 'video.subtitles.napiprojekt')
def config(self):
- """returns the config variables used by this plugin"""
+ """
+ Returns the config variables used by this plugin
+ """
return [
- ('NAPI_LANGS', [ 'pol', 'eng', ],
+ ('NAPI_LANGS', NAPI_LANGS,
'All Supported by napiprojekt.pl ISO 639-2 subtitles language codes'),
('NAPI_LANG_MAP', { 'pol': ('PL'), 'eng': ('ENG') },
'Maps ISO 639-2 lang code to the one used by napiprojekt.pl'),
@@ -116,39 +117,73 @@ def config(self):
]
- def __getitem__(self, key):
+ def get_subs(self, vfile, langs_):
"""
- Get the item's attribute.
+ Get all available subtitles for the item
+ @returns: the collection of subtitles keyed by the subtitle id
+ """
+ # based on requested languages, create intersect of capabilites vs. request
+ langs = filter(lambda x: x in langs_, self.langs)
+ subs = {}
+ hash = self._hash(vfile)
+
+ if not hash:
+ logger.warning('Hashing of %s failed, aborting...', vfile)
+ return subs
- @returns: the specific attribute
+ for lang in langs:
+ sub = NapiSubtitles(self, vfile, lang, hash)
+ if not sub.download():
+ continue
+
+ subs[sub['id']] = sub
+
+ return subs
+
+
+ #
+ # Class' private methods below
+ #
+ def _hash(self, vfile):
"""
- if key == 'name':
- return self.handler.name
-
- if key == 'id':
- return self.handler.id
+ Calculates the hash of chunk of of the video file
+ used in subsequent lookup at the remote server
+ """
+ hash = md5()
- if key == 'handler':
- return self.handler
+ try:
+ hash.update(open(vfile).read(10485760))
+ except (IOError, OSError), e:
+ logger.warning('Hashing failed: %s', e)
+ return None
- return plugin.Plugin.__getitem__(self, key)
+ return hash
class NapiSubtitles(Subtitles):
+ """
+ Specialised napiprojekt class that knows how to download, decompress
+ and write subtitles from napiprojekt.pl
+ """
def __init__(self, handler, vfile, lang, hash):
+ """
+ Constructor
+ """
self.hash = hash
Subtitles.__init__(self, handler, vfile, lang)
def download(self):
- logger.info('Downloading subtitles for %s in %s', self.vfile, self.lang)
+ """
+ Based on requested languages, downloads subtitles from the remote server
+ @return: True if successful
+ """
+ logger.debug('Downloading subtitles for %s in %s', self.vfile, self.lang)
- # TODO try to hash again, if not hashed already
if not self.hash:
return False
data = None
-
url = config.NAPI_URL % \
(config.NAPI_LANG_MAP[self.lang], self.hash.hexdigest(), self._f(self.hash.hexdigest()), os.name)
@@ -201,11 +236,13 @@ def save(self):
return True
- """
- Class' private methods below
- """
-
+ #
+ # Class' private methods below
+ #
def _decompress(self):
+ """
+ Decompresses download data (napiprojekt uses 7Zip compression)
+ """
fp = tempfile.NamedTemporaryFile('wb', suffix=".7z")
tfp = fp.name
fp.write(self.data)
@@ -223,7 +260,7 @@ def _decompress(self):
fp.close()
msg = 'Skipping, subtitle decompression failed: %s' % (e)
logger.warning(msg)
- raise SubsError(msg)
+ raise SubtitlesError(msg)
fp.close()
@@ -231,6 +268,9 @@ def _decompress(self):
def _f(self, z):
+ """
+ Magic number calculation
+ """
idx = [ 0xe, 0x3, 0x6, 0x8, 0x2 ]
mul = [ 2, 2, 5, 4, 3 ]
add = [ 0, 0xd, 0x10, 0xb, 0x5 ]
@@ -246,64 +286,3 @@ def _f(self, z):
b.append( ("%x" % (v*m))[-1] )
return ''.join(b)
-
-
-class NapiHandler(SubsHandler):
-
- def __init__(self):
- langs = []
-
- try:
- langs = config.NAPI_LANGS
- except:
- langs = NAPI_LANGS
-
- SubsHandler.__init__(self, 'np', 'napiprojekt.pl', langs)
-
-
- def __getitem__(self, key):
- """
- Get the item's attribute.
-
- @returns: the specific attribute
- """
- return SubsHandler.__getitem__(self, key)
-
-
- def get_subs(self, vfile, langs_):
- # based on requested languages, create intersect of capabilites vs. request
- langs = filter(lambda x: x in langs_, self.langs)
- subs = {}
- hash = self._hash(vfile)
-
- if not hash:
- logger.warning('Hashing of %s failed, aborting...', vfile)
- return subs
-
- for lang in langs:
- sub = NapiSubtitles(self, vfile, lang, hash)
- if not sub.download():
- continue
-
- subs[sub['id']] = sub
-
- return subs
-
- #return [map(lambda x: x['lang'], self.subs)]
-
-
- """
- Class' private methods below
- """
- def _hash(self, vfile):
- hash = md5()
-
- try:
- hash.update(open(vfile).read(10485760))
- except (IOError, OSError), e:
- logger.warning('Hashing failed: %s', e)
- return None
-
- return hash
-
-
View
367 src/video/plugins/opensubtitles.py → src/video/plugins/subtitles/opensubtitles.py
@@ -60,27 +60,15 @@
import plugin
import time
-from subtitles import SubsHandler, SubsError, Subtitles
+from video.plugins.subtitles import SubtitlesPlugin, SubtitlesError, Subtitles
-# User agent is essential to request opensubtitles
-# be sure to update it before any change
-
-class PluginInterface(plugin.Plugin):
+class PluginInterface(SubtitlesPlugin):
"""
This is a handler plugin for http://opensubtitles.org subtitle provider
and is used by main subtitle plugin.
-
Activate with:
- | plugin.activate('video.opensubtitles')
-
- and make sure the SUBS_HANDLERS = [ ('opensubtitles'), ]
- is set for the main subtitles plugin to be able to use this plugin.
- Even if this plugin is not explicitly activated in the local_config.py, main
- video.subtitles plugin will activate it automagically, providing that
- SUBS_HANDLERS variable is properly initialised with 'video.opensubtitles'
- plugin name.
-
+ | plugin.activate('video.subtitles.opensubtitles')
and of course make sure the main subtitles plugin is activated too:
| plugin.activate('video.subtitles')
@@ -99,189 +87,34 @@ def __init__(self):
self.reason = 'Plugin \'video.subtitles\' not active, activate it first in your local_config.py!'
return
- self.handler = OpenSubtitlesHandler()
+ # opensubtitles XMLRPC server and token
+ self.server = None
+ self.token = None
- plugin.Plugin.__init__(self)
-
- plugin.register(self, 'video.opensubtitles')
+ SubtitlesPlugin.__init__(self, 'os', 'opensubtitles.org', [])
+ plugin.register(self, 'video.subtitles.opensubtitles')
def config(self):
- """returns the config variables used by this plugin"""
+ """
+ Returns the config variables used by this plugin
+ User agent is essential to request opensubtitles
+ be sure to update it before any change
+ """
return [
- ('OSUBS_USER_AGENT', 'OS Test User Agent',
+ ('OSUBS_USER_AGENT', 'Freevo v1.9',
'Opensubtitles User Agent String'),
('OSUBS_DOMAIN', 'http://api.opensubtitles.org/xml-rpc',
'Opensubtitles domain'),
]
- def __getitem__(self, key):
- """
- Get the item's attribute.
-
- @returns: the specific attribute
- """
- if key == 'name':
- return 'video.opensubtitles'
-
- if key == 'id':
- return self.handler.id
-
- if key == 'handler':
- return self.handler
-
- return plugin.Plugin.__getitem__(self, key)
-
-
-class OpenSubtitles(Subtitles):
- def __init__(self, handler, vfile, lang, hash, info):
- Subtitles.__init__(self, handler, vfile, lang)
-
- self.hash = hash
- self.info = info
- # default format from opensubtitles is srt
- self.fmt = 'srt'
-
-
- def download(self):
- logger.info('Downloading subtitles for %s in %s', self.vfile, self.lang)
-
- refs = self.handler.search(self._build_query())
-
- if refs:
- if refs['data'] != False:
- # we narrow down to one only but best match
- fltd = self._filter(refs['data'])
- id = fltd['IDSubtitleFile']
- logger.debug('Sub id to download: %s', id)
-
- # we get the sub file from opensubtitles
- res = self.handler.download(id)
-
- if res and res['data'] != 'False':
- for sub in res['data']:
- # we get the first result
- self.data = sub['data']
- self.fmt = fltd['SubFormat']
- self.compressed = True
- logger.info('Downloaded subtitles id %s, lang %s, format %s',
- id, self.lang, self.fmt)
-
- else:
- logger.info('No subtitles found: %s', str(refs))
- return False
-
- else:
- logger.warning('Failed to download subtitles: %s', str(refs))
- return False
-
- logger.info('Downloaded subtitles for %s in %s', self.vfile, self.lang)
-
- return True
-
-
- def save(self):
- """
- Saves downloaded subtitles
- """
- logger.info('Saving subtitles for %s in %s', self.vfile, self.lang)
-
- if self.compressed:
- self._decompress()
-
- # we need to back up old subs if exist before we actually overwrite the old subs
- self.backup()
-
- logger.debug('Writing file %s', self.sfile)
-
- fp = codecs.open(self.sfile,'wb')
- fp.write(self.data)
- fp.close()
-
- return True
-
- """
- Class' private methods below
- """
-
- def _decompress(self):
- sub_d = base64.standard_b64decode(self.data)
- sub_d = zlib.decompress(sub_d, 47)
- self.data = sub_d
- logger.debug('Decompressed subs for %s', self.lang)
-
-
- def _build_query(self):
- """
- build a useful info dictionary and the list of queries
- to be passed as argument to SearchSubtitles XMLRPC call
- """
- query = []
-
- imdbid = self.info['MovieImdbID']
- size = os.path.getsize(self.vfile)
- vfile = os.path.basename(self.vfile)
-
- if imdbid:
- query.append({ 'sublanguageid':self.lang,
- 'moviehash':str(self.hash),
- 'moviebytesize':str(size)})
-
- # even if hash is found in opensubtitles, we add
- # another query with imdbid
- query.append({'sublanguageid':self.lang,
- 'imdbid':imdbid})
-
- logger.debug('Built query %s', str(query))
- return query
-
-
- def _filter(self, subs):
- """
- filters subs (list result of SearchSubtitles call)
- best found subtitles (hash match) or most downloaded subtitles
- @param subs: result['data'] of a SearchSubtitles XMLRPC call
- """
-
- keep = [ s for s in subs if s['MovieHash'] == self.hash ]
-
- if len(keep) == 0:
- keep = [ s for s in subs if s['IDMovieImdb'] == str(int(self.info['MovieImdbID']))]
-
- if len(keep) > 0:
- keep.sort( key=lambda k: k['SubDownloadsCnt'], reverse=True )
-
- return keep[0]
-
- return None
-
-
-class OpenSubtitlesHandler(SubsHandler):
- """
- friend class OpenSubtitles
- """
- def __init__(self):
- # opensubtitles XMLRPC server and token
- self.server = None
- self.token = None
-
- SubsHandler.__init__(self, 'os', 'opensubtitles.org', [])
-
-
- def __getitem__(self, key):
+ def get_subs(self, vfile_, langs_):
"""
- Get the item's attribute.
-
- @returns: the specific attribute
+ Get all available subtitles for the item
+ @returns: the collection of subtitles keyed by the subtitle id
"""
- return SubsHandler.__getitem__(self, key)
-
-
- def get_subs(self, vfile_, langs_):
subs = {}
- # based on requested languages, create intersect of capabilites vs. request
- # langs = filter(lambda x: x in langs_, self.langs)
langs = langs_
hash = self._hash(vfile_)
@@ -304,11 +137,13 @@ def get_subs(self, vfile_, langs_):
subs[sub['id']] = sub
return subs
-
- #return [map(lambda x: x['lang'], self.subs)]
-
+
def search(self, query):
+ """
+ search the opensubtitles given the query
+ @param id; opensubtitles sub id
+ """
if self._login():
refs = self.server.SearchSubtitles(self.token, query)
@@ -325,8 +160,11 @@ def search(self, query):
def download(self, id):
- # download a subtitles for a given id
- # @param id; opensubtitle sub id
+ """
+ Based on requested languages, downloads subtitles from the remote server
+ @param id: opensubtitle sub id
+ @return: downloaded subtiltle data
+ """
if self._login():
try:
# we pass a list of ids because opensubtitles expect this
@@ -346,10 +184,14 @@ def download(self, id):
return None
- """
- Class' private methods below
- """
+ #
+ # Class' private methods below
+ #
def _hash(self, vfile_):
+ """
+ Calculates the hash of chunk of of the video file
+ used in subsequent lookup at the remote server
+ """
try:
longlongformat = 'q' # long long
bytesize = struct.calcsize(longlongformat)
@@ -388,6 +230,9 @@ def _hash(self, vfile_):
def _status_ok(self, ans):
+ """
+ Verify the connetion status
+ """
status = False
try:
if ans.has_key('status') and ans['status'] == '200 OK':
@@ -404,6 +249,9 @@ def _status_ok(self, ans):
def _login(self, user='', password=''):
+ """
+ Login to the remote server
+ """
try:
server = xmlrpclib.ServerProxy(config.OSUBS_DOMAIN)
log = server.LogIn(user,password, 'en', config.OSUBS_USER_AGENT)
@@ -413,7 +261,7 @@ def _login(self, user='', password=''):
self.server = server
self.token = log['token']
else:
- raise SubsError(str(log))
+ raise SubtitlesError(str(log))
except Exception, e:
logger.warning('Failed to login to opensubtitles: %s', e)
@@ -423,6 +271,9 @@ def _login(self, user='', password=''):
def _logout(self):
+ """
+ Logout from the remote server
+ """
if self.token:
try:
self.server.LogOut(self.token)
@@ -434,8 +285,10 @@ def _logout(self):
return True
- # retrive general info for a list of movie hash
def _get_info(self, hash):
+ """
+ Retrive general info for a list of movie hash
+ """
data = None
logger.debug('Requesting opensubtitle info for hash %s', hash)
@@ -453,12 +306,138 @@ def _get_info(self, hash):
return data
+class OpenSubtitles(Subtitles):
+ """
+ Specialised opnsubtitles class that knows how to download, decompress
+ and write subtitles from opensubtitles.org
+ """
+
+ def __init__(self, handler, vfile, lang, hash, info):
+ Subtitles.__init__(self, handler, vfile, lang)
+
+ self.hash = hash
+ self.info = info
+ # default format from opensubtitles is srt
+ self.fmt = 'srt'
+
+
+ def download(self):
+ """
+ Based on requested languages, downloads subtitles from the remote server
+ @return: True if successful
+ """
+ logger.debug('Downloading subtitles for %s in %s', self.vfile, self.lang)
+
+ refs = self.handler.search(self._build_query())
+
+ if refs:
+ if refs['data'] != False:
+ # we narrow down to one only but best match
+ fltd = self._filter(refs['data'])
+ id = fltd['IDSubtitleFile']
+ logger.debug('Sub id to download: %s', id)
+
+ # we get the sub file from opensubtitles
+ res = self.handler.download(id)
+
+ if res and res['data'] != 'False':
+ for sub in res['data']:
+ # we get the first result
+ self.data = sub['data']
+ self.fmt = fltd['SubFormat']
+ self.compressed = True
+ logger.info('Downloaded subtitles id %s, lang %s, format %s',
+ id, self.lang, self.fmt)
+
+ else:
+ logger.info('No subtitles found: %s', str(refs))
+ return False
+
+ else:
+ logger.warning('Failed to download subtitles: %s', str(refs))
+ return False
+
+ logger.info('Downloaded subtitles for %s in %s', self.vfile, self.lang)
+ return True
+
+
+ def save(self):
+ """
+ Saves downloaded subtitles
+ @return: True if successful
+ """
+ logger.debug('Saving subtitles for %s in %s', self.vfile, self.lang)
+ if self.compressed:
+ self._decompress()
+
+ # we need to back up old subs if exist before we actually overwrite the old subs
+ self.backup()
+ logger.debug('Writing file %s', self.sfile)
+ fp = codecs.open(self.sfile,'wb')
+ fp.write(self.data)
+ fp.close()
+ return True
+ #
+ # Class' private methods below
+ #
+ def _decompress(self):
+ """
+ Decompresses download data (napiprojekt uses 7Zip compression)
+ """
+ sub_d = base64.standard_b64decode(self.data)
+ sub_d = zlib.decompress(sub_d, 47)
+ self.data = sub_d
+ logger.debug('Decompressed subs for %s', self.lang)
+ def _build_query(self):
+ """
+ Build a useful info dictionary and the list of queries
+ to be passed as argument to SearchSubtitles XMLRPC call
+ @return: constructed query
+ """
+ query = []
+ imdbid = self.info['MovieImdbID']
+ size = os.path.getsize(self.vfile)
+ vfile = os.path.basename(self.vfile)
+
+ if imdbid:
+ query.append({ 'sublanguageid':self.lang,
+ 'moviehash':str(self.hash),
+ 'moviebytesize':str(size)})
+
+ # even if hash is found in opensubtitles, we add
+ # another query with imdbid
+ query.append({'sublanguageid':self.lang,
+ 'imdbid':imdbid})
+
+ logger.debug('Built query %s', str(query))
+ return query
+
+
+ def _filter(self, subs):
+ """
+ Filters subs (list result of SearchSubtitles call)
+ best found subtitles (hash match) or most downloaded subtitles
+ @param subs: result['data'] of a SearchSubtitles XMLRPC call
+ @return: filtered subtitle list
+ """
+
+ keep = [ s for s in subs if s['MovieHash'] == self.hash ]
+
+ if len(keep) == 0:
+ keep = [ s for s in subs if s['IDMovieImdb'] == str(int(self.info['MovieImdbID']))]
+
+ if len(keep) > 0:
+ keep.sort( key=lambda k: k['SubDownloadsCnt'], reverse=True )
+
+ return keep[0]
+
+ return None

1 comment on commit 37f4cd5

@charrea6

Looking good, only some comments on the use of the new dialogs.
Thanks for fixing the message dialog, but the status dialog should be reverted please.
When you want to indicate to the user that you're doing something and the user has to wait, use dialog.show_working_indicator().
When you want the user to confirm they've seen something, use dialog.show_alert()
When you just want the user to know something but not interrupt them, use dialog.show_message(). For example you may want to use this when a download has finished, as they probably don't want to interrupt what they are doing to close a box saying something has finished downloading...

Please sign in to comment.
Something went wrong with that request. Please try again.