summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md1
-rw-r--r--bazarr/config.py4
-rw-r--r--bazarr/get_providers.py5
-rw-r--r--bazarr/main.py4
-rw-r--r--libs/subliminal_patch/providers/legendasdivx.py327
-rw-r--r--views/providers.tpl41
6 files changed, 381 insertions, 1 deletions
diff --git a/README.md b/README.md
index b00e844e1..418c33ac4 100644
--- a/README.md
+++ b/README.md
@@ -48,6 +48,7 @@ If you need something that is not already part of Bazarr, feel free to create a
* BSPlayer
* GreekSubtitles
* Hosszupuska
+* LegendasDivx
* LegendasTV
* Napiprojekt
* Napisy24
diff --git a/bazarr/config.py b/bazarr/config.py
index ca61871e0..b64040ebf 100644
--- a/bazarr/config.py
+++ b/bazarr/config.py
@@ -102,6 +102,10 @@ defaults = {
'password': '',
'random_agents': 'True'
},
+ 'legendasdivx': {
+ 'username': '',
+ 'password': ''
+ },
'legendastv': {
'username': '',
'password': ''
diff --git a/bazarr/get_providers.py b/bazarr/get_providers.py
index c543f930d..d345b79ff 100644
--- a/bazarr/get_providers.py
+++ b/bazarr/get_providers.py
@@ -38,7 +38,7 @@ PROVIDER_THROTTLE_MAP = {
}
}
-PROVIDERS_FORCED_OFF = ["addic7ed", "tvsubtitles", "legendastv", "napiprojekt", "shooter", "hosszupuska",
+PROVIDERS_FORCED_OFF = ["addic7ed", "tvsubtitles", "legendasdivx", "legendastv", "napiprojekt", "shooter", "hosszupuska",
"supersubtitles", "titlovi", "argenteam", "assrt", "subscene"]
throttle_count = {}
@@ -114,6 +114,9 @@ def get_providers_auth():
'password': settings.subscene.password,
'only_foreign': False, # fixme
},
+ 'legendasdivx': {'username': settings.legendasdivx.username,
+ 'password': settings.legendasdivx.password,
+ },
'legendastv': {'username': settings.legendastv.username,
'password': settings.legendastv.password,
},
diff --git a/bazarr/main.py b/bazarr/main.py
index 0a149e31c..2115e2976 100644
--- a/bazarr/main.py
+++ b/bazarr/main.py
@@ -398,6 +398,8 @@ def save_wizard():
settings.addic7ed.password = request.forms.get('settings_addic7ed_password')
settings.addic7ed.random_agents = text_type(settings_addic7ed_random_agents)
settings.assrt.token = request.forms.get('settings_assrt_token')
+ settings.legendasdivx.username = request.forms.get('settings_legendasdivx_username')
+ settings.legendasdivx.password = request.forms.get('settings_legendasdivx_password')
settings.legendastv.username = request.forms.get('settings_legendastv_username')
settings.legendastv.password = request.forms.get('settings_legendastv_password')
settings.opensubtitles.username = request.forms.get('settings_opensubtitles_username')
@@ -1527,6 +1529,8 @@ def save_settings():
settings.addic7ed.password = request.forms.get('settings_addic7ed_password')
settings.addic7ed.random_agents = text_type(settings_addic7ed_random_agents)
settings.assrt.token = request.forms.get('settings_assrt_token')
+ settings.legendasdivx.username = request.forms.get('settings_legendasdivx_username')
+ settings.legendasdivx.password = request.forms.get('settings_legendasdivx_password')
settings.legendastv.username = request.forms.get('settings_legendastv_username')
settings.legendastv.password = request.forms.get('settings_legendastv_password')
settings.opensubtitles.username = request.forms.get('settings_opensubtitles_username')
diff --git a/libs/subliminal_patch/providers/legendasdivx.py b/libs/subliminal_patch/providers/legendasdivx.py
new file mode 100644
index 000000000..a6d297b5d
--- /dev/null
+++ b/libs/subliminal_patch/providers/legendasdivx.py
@@ -0,0 +1,327 @@
+# -*- coding: utf-8 -*-
+from __future__ import absolute_import
+import logging
+import io
+import os
+import sys
+import rarfile
+import zipfile
+
+from requests import Session
+from guessit import guessit
+from subliminal_patch.providers import Provider
+from subliminal.providers import ParserBeautifulSoup
+from subliminal_patch.subtitle import Subtitle
+from subliminal_patch.utils import sanitize
+from subliminal.exceptions import ProviderError
+from subliminal.utils import sanitize_release_group
+from subliminal.subtitle import guess_matches
+from subliminal.video import Episode, Movie
+from subliminal.subtitle import SUBTITLE_EXTENSIONS, fix_line_ending,guess_matches
+from subzero.language import Language
+
+import gzip
+
+logger = logging.getLogger(__name__)
+
+class LegendasdivxSubtitle(Subtitle):
+ """Legendasdivx Subtitle."""
+ provider_name = 'legendasdivx'
+
+ def __init__(self, language, video, data):
+ super(LegendasdivxSubtitle, self).__init__(language)
+ self.language = language
+ self.page_link = data['link']
+ self.hits=data['hits']
+ self.exact_match=data['exact_match']
+ self.description=data['description'].lower()
+ self.video = video
+ self.videoname =data['videoname']
+
+ @property
+ def id(self):
+ return self.page_link
+
+ @property
+ def release_info(self):
+ return self.description
+
+ def get_matches(self, video):
+ matches = set()
+
+ logger.info('got %s' % self.videoname)
+ logger.info('got %s' % self.description)
+ logger.info('title %s' % video.title)
+ if self.videoname.lower() in self.description:
+ matches.update(['title'])
+ matches.update(['season'])
+ matches.update(['episode'])
+
+ # episode
+ if video.title and video.title.lower() in self.description:
+ logger.info('title matched')
+ matches.update(['title'])
+ if video.year and '{:04d}'.format(video.year) in self.description:
+ logger.info('year matched')
+ matches.update(['year'])
+
+ if isinstance(video, Episode):
+ # already matched in search query
+ if video.season and 's{:02d}'.format(video.season) in self.description:
+ logger.info('season matched')
+ matches.update(['season'])
+ if video.episode and 'e{:02d}'.format(video.episode) in self.description:
+ logger.info('episode matched')
+ matches.update(['episode'])
+ if video.episode and video.season and video.series:
+ if '{}.s{:02d}e{:02d}'.format(video.series.lower(),video.season,video.episode) in self.description:
+ logger.info('series matched')
+ matches.update(['series'])
+ matches.update(['season'])
+ matches.update(['episode'])
+ if '{} s{:02d}e{:02d}'.format(video.series.lower(),video.season,video.episode) in self.description:
+ logger.info('series matched')
+ matches.update(['series'])
+ matches.update(['season'])
+ matches.update(['episode'])
+
+ logger.info('matches: %s' % matches)
+ # release_group
+ if video.release_group and video.release_group.lower() in self.description:
+ matches.update(['release_group'])
+
+ # resolution
+
+ if video.resolution and video.resolution.lower() in self.description:
+ matches.update(['resolution'])
+
+ # format
+ formats = []
+ if video.format:
+ formats = [video.format.lower()]
+ if formats[0] == "web-dl":
+ formats.append("webdl")
+ formats.append("webrip")
+ formats.append("web ")
+ for frmt in formats:
+ if frmt.lower() in self.description:
+ matches.update(['format'])
+ break
+
+ # video_codec
+ if video.video_codec:
+ video_codecs = [video.video_codec.lower()]
+ if video_codecs[0] == "h264":
+ formats.append("x264")
+ elif video_codecs[0] == "h265":
+ formats.append("x265")
+ for vc in formats:
+ if vc.lower() in self.description:
+ matches.update(['video_codec'])
+ break
+
+ matches |= guess_matches(video, guessit(self.description))
+ return matches
+
+
+
+
+class LegendasdivxProvider(Provider):
+ """Legendasdivx Provider."""
+ languages = {Language('por', 'BR')} | {Language('por')}
+ SEARCH_THROTTLE = 8
+ site = 'https://www.legendasdivx.pt'
+ headers = {
+ 'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:72.0) Gecko/20100101 Firefox/72.0',
+ 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
+ 'Origin': 'https://www.legendasdivx.pt',
+ 'Referer': 'https://www.legendasdivx.pt',
+ 'Pragma': 'no-cache',
+ 'Cache-Control': 'no-cache'
+ }
+ loginpage = site + '/forum/ucp.php?mode=login'
+ searchurl = site + '/modules.php?name=Downloads&file=jz&d_op=search&op=_jz00&query={query}'
+ language_list = list(languages)
+
+
+ def __init__(self, username, password):
+ self.username = username
+ self.password = password
+
+ def initialize(self):
+ self.session = Session()
+ self.login()
+
+ def terminate(self):
+ self.logout()
+ self.session.close()
+
+ def login(self):
+ logger.info('Starting login')
+ self.headers['Referer'] = self.site + '/index.php'
+ self.session.headers.update(self.headers.items())
+ res = self.session.get(self.loginpage)
+ bsoup = ParserBeautifulSoup(res.content, ['lxml'])
+
+ _allinputs = bsoup.findAll('input')
+ fields = {}
+ for field in _allinputs:
+ fields[field.get('name')] = field.get('value')
+ logger.debug('%s: %s' % (field.get('name'), field.get('value')))
+
+ fields['username'] = self.username
+ fields['password'] = self.password
+ fields['autologin'] = 'on'
+ fields['viewonline'] = 'on'
+
+ self.headers['Referer'] = self.loginpage
+ self.session.headers.update(self.headers.items())
+ res = self.session.post(self.loginpage, fields)
+ try:
+ logger.debug('Got session id %s' %
+ self.session.cookies.get_dict()['PHPSESSID'])
+ except KeyError as e:
+ logger.error(repr(e))
+ logger.error("Didn't get session id, check your credentials")
+ return False
+ except Exception as e:
+ logger.error(repr(e))
+ logger.error('uncached error #legendasdivx #AA')
+ return False
+
+ return True
+ def logout(self):
+ # need to figure this out
+ return True
+
+ def query(self, video, language):
+ try:
+ logger.debug('Got session id %s' %
+ self.session.cookies.get_dict()['PHPSESSID'])
+ except Exception as e:
+ self.login()
+ return []
+
+ language_ids = '0'
+ if isinstance(language, (tuple, list, set)):
+ logger.error('language %s' % language)
+ if len(language) == 1:
+ language_ids = ','.join(sorted(l.opensubtitles for l in language))
+ logger.error('language_ids %s' % language_ids)
+ if language_ids == 'por':
+ language_ids = '&form_cat=28'
+ else:
+ language_ids = '&form_cat=29'
+
+ querytext = video.name
+ querytext = os.path.basename(querytext)
+ querytext, _ = os.path.splitext(querytext)
+ videoname = querytext
+ querytext = querytext.lower()
+ querytext = querytext.replace(
+ ".", "+").replace("[", "").replace("]", "")
+ if language_ids != '0':
+ querytext = querytext + language_ids
+ self.headers['Referer'] = self.site + '/index.php'
+ self.session.headers.update(self.headers.items())
+ res = self.session.get(self.searchurl.format(query=querytext))
+ # form_cat=28 = br
+ # form_cat=29 = pt
+ if "A legenda não foi encontrada" in res.text:
+ logger.warning('%s not found', querytext)
+ return []
+ logger.warning(self.searchurl.format(query=querytext))
+
+ bsoup = ParserBeautifulSoup(res.content, ['html.parser'])
+ _allsubs = bsoup.findAll("div", {"class": "sub_box"})
+ subtitles = []
+ lang = Language.fromopensubtitles("pob")
+ for _subbox in _allsubs:
+ logger.info("============================================")
+ hits=0
+ for th in _subbox.findAll("th", {"class": "color2"}):
+ if th.string == 'Hits:':
+ hits = int(th.parent.find("td").string)
+ if th.string == 'Idioma:':
+ lang = th.parent.find("td").find ("img").get ('src')
+ logger.debug('lang img %s' % lang)
+ if 'brazil' in lang:
+ lang = Language.fromopensubtitles('pob')
+ else:
+ lang = Language.fromopensubtitles('por')
+
+
+ description = _subbox.find("td", {"class": "td_desc brd_up"})
+ download = _subbox.find("a", {"class": "sub_download"})
+ try:
+ # sometimes BSoup just doesn't get the link
+ logger.debug(download.get('href'))
+ except Exception as e:
+ logger.warning('skipping subbox on %s' % self.searchurl.format(query=querytext))
+ continue
+
+ logger.info(hits)
+ exact_match = False
+ if video.name.lower() in description.get_text().lower():
+ logger.info("exact match!")
+ exact_match = True
+ data = {'link': self.site + '/modules.php' + download.get('href'),
+ 'exact_match': exact_match,
+ 'hits': hits,
+ 'videoname': videoname,
+ 'description': description.get_text() }
+ subtitles.append(
+ LegendasdivxSubtitle(lang, video, data)
+ )
+
+ return subtitles
+
+ def list_subtitles(self, video, languages):
+ return self.query(video, languages)
+
+ def download_subtitle(self, subtitle):
+ res = self.session.get(subtitle.page_link)
+ if res:
+ if res.text == '500':
+ raise ValueError('Error 500 on server')
+
+ archive = self._get_archive(res.content)
+ # extract the subtitle
+ subtitle_content = self._get_subtitle_from_archive(archive)
+ subtitle.content = fix_line_ending(subtitle_content)
+ subtitle.normalize()
+
+ return subtitle
+ raise ValueError('Problems conecting to the server')
+
+ def _get_archive(self, content):
+ # open the archive
+ # stole^H^H^H^H^H inspired from subvix provider
+ archive_stream = io.BytesIO(content)
+ if rarfile.is_rarfile(archive_stream):
+ logger.debug('Identified rar archive')
+ archive = rarfile.RarFile(archive_stream)
+ elif zipfile.is_zipfile(archive_stream):
+ logger.debug('Identified zip archive')
+ archive = zipfile.ZipFile(archive_stream)
+ else:
+ # raise ParseResponseError('Unsupported compressed format')
+ raise Exception('Unsupported compressed format')
+
+ return archive
+
+ def _get_subtitle_from_archive(self, archive):
+ logger.warning(archive.namelist())
+ for name in archive.namelist():
+ # discard hidden files
+ if os.path.split(name)[-1].startswith('.'):
+ continue
+
+ # discard non-subtitle files
+ if not name.lower().endswith(SUBTITLE_EXTENSIONS):
+ continue
+
+ logger.warning(name)
+ return archive.read(name)
+
+ raise ParseResponseError('Can not find the subtitle in the compressed file')
diff --git a/views/providers.tpl b/views/providers.tpl
index 08148e895..510ee7857 100644
--- a/views/providers.tpl
+++ b/views/providers.tpl
@@ -228,6 +228,47 @@
<div class="middle aligned row">
<div class="right aligned four wide column">
+ <label>LegendasDivx</label>
+ </div>
+ <div class="one wide column">
+ <div id="legendasdivx" class="ui toggle checkbox provider">
+ <input type="checkbox">
+ <label></label>
+ </div>
+ </div>
+ <div class="collapsed column">
+ <div class="collapsed center aligned column">
+ <div class="ui basic icon" data-tooltip="Brazilian & Portuguese Subtitles Provider." data-inverted="">
+ <i class="help circle large icon"></i>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div id="legendasdivx_option" class="ui grid container">
+ <div class="middle aligned row">
+ <div class="right aligned six wide column">
+ <label>Username</label>
+ </div>
+ <div class="six wide column">
+ <div class="ui fluid input">
+ <input name="settings_legendasdivx_username" type="text" value="{{settings.legendasdivx.username if settings.legendasdivx.username != None else ''}}">
+ </div>
+ </div>
+ </div>
+ <div class="middle aligned row">
+ <div class="right aligned six wide column">
+ <label>Password</label>
+ </div>
+ <div class="six wide column">
+ <div class="ui fluid input">
+ <input name="settings_legendasdivx_password" type="password" value="{{settings.legendasdivx.password if settings.legendasdivx.password != None else ''}}">
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class="middle aligned row">
+ <div class="right aligned four wide column">
<label>LegendasTV</label>
</div>
<div class="one wide column">