mirror of
https://github.com/morpheus65535/bazarr
synced 2024-12-22 15:54:26 +00:00
Added TuSubtitulo provider
This commit is contained in:
parent
1d0d6821eb
commit
27d078b719
3 changed files with 265 additions and 0 deletions
|
@ -70,6 +70,7 @@ If you need something that is not already part of Bazarr, feel free to create a
|
|||
* Supersubtitles
|
||||
* Titlovi
|
||||
* Titrari.ro
|
||||
* TuSubtitulo
|
||||
* TVSubtitles
|
||||
* Wizdom
|
||||
* XSubs
|
||||
|
|
252
libs/subliminal_patch/providers/tusubtitulo.py
Normal file
252
libs/subliminal_patch/providers/tusubtitulo.py
Normal file
|
@ -0,0 +1,252 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
from urllib import parse
|
||||
import re
|
||||
from bs4 import BeautifulSoup as bso
|
||||
|
||||
from requests import Session
|
||||
from subzero.language import Language
|
||||
|
||||
from subliminal import Episode
|
||||
from subliminal.exceptions import ServiceUnavailable
|
||||
from subliminal_patch.subtitle import Subtitle
|
||||
from subliminal.subtitle import fix_line_ending
|
||||
from subliminal_patch.providers import Provider
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
BASE = "https://www.tusubtitulo.com/series.php?/"
|
||||
|
||||
|
||||
class TuSubtituloSubtitle(Subtitle):
|
||||
provider_name = "tusubtitulo"
|
||||
|
||||
def __init__(self, language, filename, download_link, page_link, matches):
|
||||
super(TuSubtituloSubtitle, self).__init__(
|
||||
language, hearing_impaired=False, page_link=page_link
|
||||
)
|
||||
self.download_link = download_link
|
||||
self.page_link = page_link
|
||||
self.language = language
|
||||
self.release_info = filename
|
||||
self.filename = filename
|
||||
self.found_matches = matches
|
||||
|
||||
@property
|
||||
def id(self):
|
||||
return self.download_link
|
||||
|
||||
def get_matches(self, video):
|
||||
if video.resolution and video.resolution.lower() in self.release_info.lower():
|
||||
self.found_matches.add("resolution")
|
||||
|
||||
if video.source and video.source.lower() in self.release_info.lower():
|
||||
self.found_matches.add("source")
|
||||
|
||||
if video.video_codec:
|
||||
if video.video_codec == "H.264" and "x264" in self.release_info.lower():
|
||||
self.found_matches.add("video_codec")
|
||||
elif video.video_codec == "H.265" and "x265" in self.release_info.lower():
|
||||
self.found_matches.add("video_codec")
|
||||
elif video.video_codec.lower() in self.release_info.lower():
|
||||
self.found_matches.add("video_codec")
|
||||
|
||||
if video.audio_codec:
|
||||
if video.audio_codec.lower().replace(" ", ".") in self.release_info.lower():
|
||||
self.found_matches.add("audio_codec")
|
||||
return self.found_matches
|
||||
|
||||
|
||||
class TuSubtituloProvider(Provider):
|
||||
"""TuSubtitulo.com Provider"""
|
||||
|
||||
BASE = "https://www.tusubtitulo.com/series.php?/"
|
||||
languages = {Language.fromalpha2(l) for l in ["es"]}
|
||||
language_list = list(languages)
|
||||
logger.debug(languages)
|
||||
video_types = (Episode,)
|
||||
|
||||
def initialize(self):
|
||||
self.session = Session()
|
||||
self.session.headers = {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36",
|
||||
"referer": "https://www.tusubtitulo.com",
|
||||
}
|
||||
|
||||
def terminate(self):
|
||||
self.session.close()
|
||||
|
||||
def index_titles(self):
|
||||
r = self.session.get(BASE)
|
||||
r.raise_for_status()
|
||||
soup = bso(r.content, "html.parser")
|
||||
titles = []
|
||||
for a in soup.find_all("a"):
|
||||
href_url = a.get("href")
|
||||
if "show" in href_url:
|
||||
titles.append({"title": a.text, "url": href_url})
|
||||
return titles
|
||||
|
||||
def is_season_available(self, seasons, season):
|
||||
for i in seasons:
|
||||
if i == season:
|
||||
return True
|
||||
|
||||
def title_available(self, item):
|
||||
try:
|
||||
title_content = item[2].find_all("a")[0]
|
||||
episode_number = re.search(
|
||||
r".*\d+x(0+)?(\d+) - .*?", title_content.text
|
||||
).group(2)
|
||||
episode_id = title_content.get("href").split("/")[4]
|
||||
return {
|
||||
"episode_number": episode_number,
|
||||
"episode_id": episode_id,
|
||||
"episode_url": title_content.get("href"),
|
||||
}
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
def source_separator(self, item):
|
||||
try:
|
||||
text = item[3].text.replace("\n", "")
|
||||
if "Vers" in text:
|
||||
source = text.replace("Versión ", "")
|
||||
if not source:
|
||||
source = "Unknown"
|
||||
return source
|
||||
except IndexError:
|
||||
return
|
||||
|
||||
def get_episodes(self, show_id, season):
|
||||
logger.debug("https://www.tusubtitulo.com/show/{}/{}".format(show_id, season))
|
||||
r2 = self.session.get(
|
||||
"https://www.tusubtitulo.com/show/{}/{}".format(show_id, season),
|
||||
)
|
||||
r2.raise_for_status()
|
||||
sopa = bso(r2.content, "lxml")
|
||||
tables = sopa.find_all("tr")
|
||||
seasons = [i.text for i in tables[1].find_all("a")]
|
||||
if not self.is_season_available(seasons, season):
|
||||
logger.debug("Season not found")
|
||||
return
|
||||
season_subs = []
|
||||
episodes = []
|
||||
|
||||
for tr in range(len(tables)):
|
||||
data = tables[tr].find_all("td")
|
||||
title = self.title_available(data)
|
||||
if title:
|
||||
episodes.append(title)
|
||||
source_var = self.source_separator(data)
|
||||
if source_var:
|
||||
inc = 1
|
||||
while True:
|
||||
try:
|
||||
content = tables[tr + inc].find_all("td")
|
||||
language = content[4].text
|
||||
completed = content[5]
|
||||
url = content[6].find_all("a")[0].get("href")
|
||||
sub_id = parse.parse_qs(parse.urlparse(url).query)["id"][0]
|
||||
lang_id = parse.parse_qs(parse.urlparse(url).query)["lang"][0]
|
||||
version_ = parse.parse_qs(parse.urlparse(url).query)["version"][
|
||||
0
|
||||
]
|
||||
download_url = (
|
||||
"https://www.tusubtitulo.com/updated/{}/{}/{}".format(
|
||||
lang_id, sub_id, version_
|
||||
)
|
||||
)
|
||||
if "esp" in language.lower():
|
||||
season_subs.append(
|
||||
{
|
||||
"episode_id": sub_id,
|
||||
"metadata": source_var,
|
||||
"download_url": download_url,
|
||||
}
|
||||
)
|
||||
inc += 1
|
||||
except IndexError:
|
||||
break
|
||||
|
||||
final_list = []
|
||||
for i in episodes:
|
||||
for t in season_subs:
|
||||
if i["episode_id"] == t["episode_id"]:
|
||||
final_list.append(
|
||||
{
|
||||
"episode_number": i["episode_number"],
|
||||
"episode_url": i["episode_url"],
|
||||
"metadata": t["metadata"],
|
||||
"download_url": t["download_url"],
|
||||
}
|
||||
)
|
||||
return final_list
|
||||
|
||||
def search(self, title, season, episode):
|
||||
titles = self.index_titles()
|
||||
found_tv_show = None
|
||||
for i in titles:
|
||||
if title.lower() == i["title"].lower():
|
||||
found_tv_show = i
|
||||
break
|
||||
if not found_tv_show:
|
||||
logger.debug("Show not found")
|
||||
return
|
||||
tv_show_id = found_tv_show["url"].split("/")[2].replace(" ", "")
|
||||
results = self.get_episodes(tv_show_id, season)
|
||||
episode_list = []
|
||||
if results:
|
||||
for i in results:
|
||||
if i["episode_number"] == episode:
|
||||
episode_list.append(i)
|
||||
if episode_list:
|
||||
return episode_list
|
||||
logger.debug("Episode not found")
|
||||
|
||||
def query(self, languages, video):
|
||||
language = self.language_list[0]
|
||||
query = "{} {} {}".format(video.series, video.season, video.episode)
|
||||
logger.debug("Searching subtitles: {}".format(query))
|
||||
results = self.search(video.series, str(video.season), str(video.episode))
|
||||
|
||||
if results:
|
||||
subtitles = []
|
||||
for i in results:
|
||||
matches = set()
|
||||
# self.search only returns results for the specific episode
|
||||
matches.add("title")
|
||||
matches.add("series")
|
||||
matches.add("season")
|
||||
matches.add("episode")
|
||||
matches.add("year")
|
||||
subtitles.append(
|
||||
TuSubtituloSubtitle(
|
||||
language,
|
||||
i["metadata"],
|
||||
i["download_url"],
|
||||
i["episode_url"],
|
||||
matches,
|
||||
)
|
||||
)
|
||||
return subtitles
|
||||
else:
|
||||
logger.debug("No subtitles found")
|
||||
return []
|
||||
|
||||
def list_subtitles(self, video, languages):
|
||||
return self.query(languages, video)
|
||||
|
||||
def _check_response(self, response):
|
||||
if response.status_code != 200:
|
||||
raise ServiceUnavailable("Bad status code: " + str(response.status_code))
|
||||
|
||||
def download_subtitle(self, subtitle):
|
||||
logger.info("Downloading subtitle %r", subtitle)
|
||||
response = self.session.get(
|
||||
subtitle.download_link, headers={"Referer": subtitle.page_link}, timeout=10
|
||||
)
|
||||
response.raise_for_status()
|
||||
self._check_response(response)
|
||||
subtitle.content = fix_line_ending(response.content)
|
|
@ -589,6 +589,18 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
<b>Tusubtitulo.com</b>
|
||||
</div>
|
||||
<div class="form-group col-sm-8">
|
||||
<label class="custom-control custom-checkbox">
|
||||
<input type="checkbox" class="custom-control-input provider" id="tusubtitulo">
|
||||
<span class="custom-control-label">Spanish subtitles provider.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-sm-3 text-right">
|
||||
<b>TVSubtitles</b>
|
||||
|
|
Loading…
Reference in a new issue