Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f264092e74 | |||
| 052481c0a1 | |||
| 4e3f622de0 | |||
| 143c46fff0 | |||
| bc8b0c762d | |||
| 9ec92d1be4 | |||
| 29ee43a67d | |||
| 0f15f8f52d |
Executable
+100
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Subliminal - Subtitles, faster than your thoughts
|
||||
# Copyright (c) 2008-2011 Patrick Dessalle <patrick@dessalle.be>
|
||||
# Copyright (c) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
#
|
||||
# This file is part of Subliminal.
|
||||
#
|
||||
# Subliminal is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the Lesser GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Subliminal is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# Lesser GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the Lesser GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from optparse import OptionParser
|
||||
import subliminal
|
||||
import logging
|
||||
import mimetypes
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
def main():
|
||||
'''Download subtitles'''
|
||||
# parse command line options
|
||||
parser = OptionParser("usage: %prog [options] file1 file2", version=subliminal.__version__)
|
||||
parser.add_option("-l", "--language", action="append", dest="languages", help="wanted language (ISO 639-1 two chars) for the subtitles (e.g. fr, en). Multiple uses allowed such that `%prog -l fr -l en file1`")
|
||||
parser.add_option("-m", "--multi", action="store_true", dest="multi", help="download one subtitle per specified language (instead of one of them) and name them accordingly (e.g. .fr.srt, .en.srt)")
|
||||
parser.add_option("-p", "--plugin", action="append", dest="plugins", help="plugins to activate")
|
||||
parser.add_option("-f", "--force", action="store_true", dest="force", help="force download of a subtitle even there is already one present")
|
||||
parser.add_option("-C", "--no-config-file", action="store_false", dest="config", help="do not use configuration file (requires -l to be specified)")
|
||||
parser.add_option("-c", "--config-file", action="store", dest="config", help="configuration file to use")
|
||||
parser.add_option("-w", "--workers", action="store", dest="workers", help="specify the number of threads to use")
|
||||
parser.add_option("--cache-dir", action="store", dest="cache_dir", help="cache directory to use")
|
||||
parser.add_option("--no-cache-dir", action="store_false", dest="cache_dir", help="do not use cache directory (some plugins may not work)")
|
||||
parser.add_option("--list-all-plugins", action="store_true", dest="list_all_plugins", help="list all plugins available")
|
||||
parser.add_option("--list-api-plugins", action="store_true", dest="list_api_plugins", help="list api-based plugins")
|
||||
parser.add_option("--list-active-plugins", action="store_true", dest="list_active_plugins", help="list currently active plugins")
|
||||
parser.add_option("-v", "--verbose", action="count", dest="verbose", help="increase verbosity (maximum 2 times)")
|
||||
parser.set_defaults(verbose=0, cache_dir=True, config=True, workers=4)
|
||||
(options, args) = parser.parse_args()
|
||||
if not args:
|
||||
print parser.print_help()
|
||||
exit(1)
|
||||
if options.verbose == 2:
|
||||
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(name)-24s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
|
||||
elif options.verbose == 1:
|
||||
logging.basicConfig(level=logging.WARN, format='%(levelname)s: %(name)s %(message)s')
|
||||
else:
|
||||
logging.basicConfig(level=logging.ERROR)
|
||||
if not options.config and not options.languages:
|
||||
parser.error("Option -C (--no-config-file) is used without -l (--language)")
|
||||
subliminal_client = subliminal.Subliminal(config=options.config, cache_dir=options.cache_dir, workers=options.workers, multi=options.multi, force=options.force, max_depth=3, autostart=False)
|
||||
if options.plugins:
|
||||
subliminal_client.plugins = options.plugins
|
||||
if options.list_all_plugins:
|
||||
plugins = subliminal_client.listExistingPlugins()
|
||||
print ', '.join(subliminal_client.listExistingPlugins())
|
||||
exit(0)
|
||||
if options.list_api_plugins:
|
||||
plugins = subliminal_client.list_api_plugins()
|
||||
print ', '.join(subliminal_client.listExistingPlugins())
|
||||
exit(0)
|
||||
if options.list_active_plugins:
|
||||
plugins = subliminal_client.plugins
|
||||
print ', '.join(subliminal_client.listExistingPlugins())
|
||||
exit(0)
|
||||
if options.languages:
|
||||
subliminal_client.languages = options.languages
|
||||
else:
|
||||
logging.info(u"No language given, looking into configuration file")
|
||||
languages = subliminal_client.languages
|
||||
if not languages:
|
||||
logging.error(u"No language found in configuration file")
|
||||
sys.stderr.write("No language found in configuration file")
|
||||
exit(1)
|
||||
parser.exit
|
||||
subliminal_client.startWorkers()
|
||||
subtitles = subliminal_client.downloadSubtitles(args)
|
||||
subliminal_client.stopWorkers()
|
||||
if len(subtitles) == 0:
|
||||
sys.stderr.write("No subtitles found")
|
||||
exit(1)
|
||||
print "*" * 50
|
||||
print "Downloaded %s subtitles" % len(subtitles)
|
||||
for s in subtitles:
|
||||
print s['lang'] + " - " + s['subtitlepath']
|
||||
print "*" * 50
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -21,13 +21,13 @@
|
||||
#
|
||||
|
||||
from setuptools import setup
|
||||
from subliminal import __version__
|
||||
|
||||
|
||||
execfile('subliminal/version.py')
|
||||
setup(name='subliminal',
|
||||
version=__version__,
|
||||
license="LGPLv3",
|
||||
description="Subliminal - Subtitles, faster than your thoughts",
|
||||
license='LGPLv3',
|
||||
description='Subliminal - Subtitles, faster than your thoughts',
|
||||
classifiers=['Development Status :: 4 - Beta',
|
||||
'License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)',
|
||||
'Intended Audience :: Developers',
|
||||
@@ -36,9 +36,10 @@ setup(name='subliminal',
|
||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||
'Topic :: Multimedia :: Video'],
|
||||
keywords='subliminal video movie subtitle python library',
|
||||
author="Antoine Bertin",
|
||||
author_email="diaoulael@gmail.com",
|
||||
url="https://github.com/Diaoul/subliminal",
|
||||
packages=["subliminal", "subliminal/plugins"],
|
||||
py_modules=["subliminal"],
|
||||
install_requires=["BeautifulSoup>=3.2.0", "guessit>=0.2"])
|
||||
author='Antoine Bertin',
|
||||
author_email='diaoulael@gmail.com',
|
||||
url='https://github.com/Diaoul/subliminal',
|
||||
packages=['subliminal', 'subliminal/plugins'],
|
||||
scripts=['scripts/subliminal'],
|
||||
py_modules=['subliminal'],
|
||||
install_requires=['BeautifulSoup>=3.2.0', 'guessit>=0.2'])
|
||||
|
||||
@@ -54,10 +54,10 @@ class PluginWorker(threading.Thread):
|
||||
while task['subtitle']:
|
||||
subtitle = task['subtitle'].pop(0)
|
||||
# get the corresponding plugin
|
||||
plugin = getattr(plugins, subtitle["plugin"])(task['config'])
|
||||
plugin = getattr(plugins, subtitle['plugin'])(task['config'])
|
||||
path = plugin.download(subtitle)
|
||||
if path:
|
||||
subtitle["subtitlepath"] = path
|
||||
subtitle['subtitlepath'] = path
|
||||
result = subtitle
|
||||
break
|
||||
else:
|
||||
@@ -68,4 +68,4 @@ class PluginWorker(threading.Thread):
|
||||
finally:
|
||||
self.resultQueue.put(result)
|
||||
self.taskQueue.task_done()
|
||||
self.logger.debug(u"Thread %s terminated" % self.name)
|
||||
self.logger.debug(u'Thread %s terminated' % self.name)
|
||||
|
||||
@@ -19,7 +19,5 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
__version__ = '0.2'
|
||||
|
||||
|
||||
from subliminal import *
|
||||
from subliminal import Subliminal
|
||||
from version import __version__
|
||||
|
||||
@@ -94,7 +94,7 @@ class Addic7ed(PluginBase.PluginBase):
|
||||
release_group.add(guess['title'])
|
||||
if 'screenSize' in guess:
|
||||
release_group.add(guess['screenSize'])
|
||||
if len(release_group) == 0:
|
||||
if 'series' not in guess or len(release_group) == 0:
|
||||
return []
|
||||
self.release_group = release_group # used to sort results
|
||||
return self.query(guess['series'], guess['season'], guess['episodeNumber'], release_group, filepath, languages)
|
||||
|
||||
@@ -88,7 +88,7 @@ class BierDopje(PluginBase.PluginBase):
|
||||
release_group.add(guess['title'].lower())
|
||||
if 'screenSize' in guess:
|
||||
release_group.add(guess['screenSize'].lower())
|
||||
if len(release_group) == 0:
|
||||
if 'series' not in guess or len(release_group) == 0:
|
||||
return []
|
||||
self.release_group = release_group # used to sort results
|
||||
return self.query(guess['series'], guess['season'], guess['episodeNumber'], release_group, filepath, languages)
|
||||
|
||||
@@ -33,7 +33,7 @@ class OpenSubtitles(PluginBase.PluginBase):
|
||||
site_url = 'http://www.opensubtitles.org'
|
||||
site_name = 'OpenSubtitles'
|
||||
server_url = 'http://api.opensubtitles.org/xml-rpc'
|
||||
user_agent = 'Subliminal v0.2'
|
||||
user_agent = 'Subliminal v0.3'
|
||||
multi_languages_queries = True
|
||||
multi_filename_queries = False
|
||||
api_based = True
|
||||
@@ -112,6 +112,7 @@ class OpenSubtitles(PluginBase.PluginBase):
|
||||
f = ek.ek(gzip.open, subtitleFilename + ".gz")
|
||||
dump = ek.ek(open, subtitleFilename, "wb")
|
||||
dump.write(f.read())
|
||||
self.adjustPermissions(subtitleFilename)
|
||||
dump.close()
|
||||
f.close()
|
||||
ek.ek(os.remove, subtitleFilename + ".gz")
|
||||
@@ -133,7 +134,7 @@ class OpenSubtitles(PluginBase.PluginBase):
|
||||
if not imdbID and not moviehash and not bytesize:
|
||||
self.logger.debug(u"No search term, we'll use the filename")
|
||||
guess = guessit.guess_file_info(filepath, 'autodetect')
|
||||
if guess['type'] == 'episode':
|
||||
if guess['type'] == 'episode' and 'series' in guess:
|
||||
search['query'] = guess['series']
|
||||
elif guess['type'] == 'movie':
|
||||
search['query'] = guess['title']
|
||||
|
||||
@@ -95,6 +95,7 @@ class PluginBase(object):
|
||||
f = urllib2.urlopen(req, data=data)
|
||||
dump = ek.ek(open, filename, "wb")
|
||||
dump.write(f.read())
|
||||
self.adjustPermissions(filename)
|
||||
dump.close()
|
||||
f.close()
|
||||
self.logger.debug(u"Download finished for file %s. Size: %s" % (filename, ek.ek(os.path.getsize, filename)))
|
||||
@@ -103,6 +104,10 @@ class PluginBase(object):
|
||||
except urllib2.URLError, e:
|
||||
self.logger.error(u"URL Error:", e.reason, url)
|
||||
|
||||
def adjustPermissions(self, filepath):
|
||||
if self.config_dict and 'files_mode' in self.config_dict and self.config_dict['files_mode'] != -1:
|
||||
ek.ek(os.chmod, filepath, self.config_dict['files_mode'])
|
||||
|
||||
@abc.abstractmethod
|
||||
def list(self, filenames, languages):
|
||||
"""Main method to call when you want to list subtitles"""
|
||||
|
||||
@@ -113,6 +113,7 @@ class SubScene(PluginBase.PluginBase):
|
||||
outfile = ek.ek(open, subtitlefilename, "wb")
|
||||
outfile.write(zf.read(el.orig_filename))
|
||||
outfile.flush()
|
||||
self.adjustPermissions(subtitlefilename)
|
||||
outfile.close()
|
||||
else:
|
||||
self.logger.info(u"File %s does not seem to be valid " % el.orig_filename)
|
||||
|
||||
@@ -75,7 +75,7 @@ class SubsWiki(PluginBase.PluginBase):
|
||||
release_group.add(guess['title'])
|
||||
if 'screenSize' in guess:
|
||||
release_group.add(guess['screenSize'])
|
||||
if len(release_group) == 0:
|
||||
if 'series' not in guess or len(release_group) == 0:
|
||||
return []
|
||||
self.release_group = release_group # used to sort results
|
||||
return self.query(guess['series'], guess['season'], guess['episodeNumber'], release_group, filepath, languages)
|
||||
|
||||
@@ -75,7 +75,7 @@ class Subtitulos(PluginBase.PluginBase):
|
||||
release_group.add(guess['title'].lower())
|
||||
if 'screenSize' in guess:
|
||||
release_group.add(guess['screenSize'].lower())
|
||||
if len(release_group) == 0:
|
||||
if 'series' not in guess or len(release_group) == 0:
|
||||
return []
|
||||
self.release_group = release_group # used to sort results
|
||||
return self.query(guess['series'], guess['season'], guess['episodeNumber'], release_group, filepath, languages)
|
||||
|
||||
@@ -50,7 +50,7 @@ if not SYS_ENCODING or SYS_ENCODING in ('ANSI_X3.4-1968', 'US-ASCII', 'ASCII'):
|
||||
class Subliminal(object):
|
||||
"""Main Subliminal class"""
|
||||
|
||||
def __init__(self, config=True, cache_dir=True, workers=4, multi=False, force=False, max_depth=3, autostart=False, plugins_config=None):
|
||||
def __init__(self, config=True, cache_dir=True, workers=4, multi=False, force=False, max_depth=3, autostart=False, plugins_config=None, files_mode=-1):
|
||||
# set default values
|
||||
self.multi = multi
|
||||
self.force = force
|
||||
@@ -64,6 +64,7 @@ class Subliminal(object):
|
||||
self._plugins = self.listAPIPlugins()
|
||||
self.workers = workers
|
||||
self.plugins_config = plugins_config
|
||||
self.files_mode = files_mode
|
||||
if autostart:
|
||||
self.startWorkers()
|
||||
# handle configuration file preferences
|
||||
@@ -193,7 +194,7 @@ class Subliminal(object):
|
||||
|
||||
def set_plugins(self, value):
|
||||
"""Set plugins and save to configuration file if specified by the constructor"""
|
||||
logger.debug(u"Setting plugins to %s" % value)
|
||||
logger.debug(u'Setting plugins to %r' % value)
|
||||
self._plugins = filter(self.isValidPlugin, value)
|
||||
if self.config:
|
||||
self._savePluginsToConfig()
|
||||
@@ -422,4 +423,5 @@ class Subliminal(object):
|
||||
if self.plugins_config and 'subtitlesource_key' in self.plugins_config:
|
||||
config['subtitlesource_key'] = self.plugins_config['subtitlesource_key']
|
||||
config['force'] = self.force
|
||||
config['files_mode'] = self.files_mode
|
||||
return config
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Subliminal - Subtitles, faster than your thoughts
|
||||
# Copyright (c) 2011 Antoine Bertin <diaoulael@gmail.com>
|
||||
#
|
||||
# This file is part of Subliminal.
|
||||
#
|
||||
# Subliminal is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the Lesser GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Subliminal is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# Lesser GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the Lesser GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
__version__ = '0.3'
|
||||
Reference in New Issue
Block a user