Fixed some issues with Titulki provider

pull/1600/head
Samuel Bartík 3 years ago committed by GitHub
parent 1eada712d6
commit 006e17bdc2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -53,7 +53,18 @@ class TitulkySubtitle(Subtitle):
self.download_link = download_link self.download_link = download_link
self.skip_wrong_fps = skip_wrong_fps self.skip_wrong_fps = skip_wrong_fps
self.matches = None self.matches = None
# Try to parse S00E00 string from the main subtitle name
season_episode_string = re.findall('S(\d+)E(\d+)', self.names[0], re.IGNORECASE)
# If we did not search for subtitles with season and episode numbers in search query,
# try to parse it from the main subtitle name that most likely contains it
if season_episode_string:
if self.season is None:
self.season = int(season_episode_string[0][0])
if self.episode is None:
self.episode = int(season_episode_string[0][1])
@property @property
def id(self): def id(self):
return self.sub_id return self.sub_id
@ -61,41 +72,54 @@ class TitulkySubtitle(Subtitle):
def get_fps(self): def get_fps(self):
return self.fps return self.fps
def get_matches(self, video): def get_matches(self, video):
matches = set() matches = set()
_type = 'movie' if isinstance(video, Movie) else 'episode' _type = 'movie' if isinstance(video, Movie) else 'episode'
if _type == 'episode': if _type == 'episode':
## EPISODE ## EPISODE
# match season/episode
if self.season and self.season == video.season: if self.season and self.season == video.season:
matches.add('season') matches.add('season')
if self.episode and self.episode == video.episode: if self.episode and self.episode == video.episode:
matches.add('episode') matches.add('episode')
name_matches = [video.series and sanitize(name) in sanitize(video.series) for name in self.names] # match series name
if any(name_matches): series_names = [video.series] + video.alternative_series
if _contains_element(_from=series_names, _in=self.names):
matches.add('series') matches.add('series')
# match episode title
episode_titles = [video.title]
if _contains_element(_from=episode_titles, _in=self.names):
matches.add('title')
elif _type == 'movie': elif _type == 'movie':
## MOVIE ## MOVIE
name_matches = [video.title and sanitize(name) in sanitize(video.title) for name in self.names]
if any(name_matches): # match movie title
video_titles = [video.title] + video.alternative_titles
if _contains_element(_from=video_titles, _in=self.names):
matches.add('title') matches.add('title')
## MOVIE OR EPISODE ## MOVIE OR EPISODE
# match year
if video.year and video.year == self.year: if video.year and video.year == self.year:
matches.add('year') matches.add('year')
# match other properties based on release info
matches |= guess_matches(video, guessit(self.release_info, {"type": _type})) matches |= guess_matches(video, guessit(self.release_info, {"type": _type}))
# If turned on in settings, then do not match if video FPS is not equal to subtitle FPS
if self.skip_wrong_fps and video.fps and self.fps and not framerate_equal(video.fps, self.fps): if self.skip_wrong_fps and video.fps and self.fps and not framerate_equal(video.fps, self.fps):
logger.info(f"Titulky.com: Skipping subtitle {self}: wrong FPS") logger.info(f"Titulky.com: Skipping subtitle {self}: wrong FPS")
matches.clear() matches.clear()
self.matches = matches self.matches = matches
return matches return matches
@ -317,7 +341,7 @@ class TitulkyProvider(Provider):
'year': year 'year': year
} }
def process_row(self, row, keyword, thread_id=None, threads_data=None): def process_row(self, row, video_names, thread_id=None, threads_data=None):
try: try:
# The first anchor tag is an image preview, the second is the name # The first anchor tag is an image preview, the second is the name
anchor_tag = row.find_all('a')[1] anchor_tag = row.find_all('a')[1]
@ -330,19 +354,20 @@ class TitulkyProvider(Provider):
# Approved subtitles have a pbl1 class for their row, others have a pbl0 class # Approved subtitles have a pbl1 class for their row, others have a pbl0 class
approved = True if 'pbl1' in row.get('class') else False approved = True if 'pbl1' in row.get('class') else False
# Name + alternative names # Subtitle name + its alternative names
table_columns = row.findAll("td") table_columns = row.findAll("td")
main_name = anchor_tag.get_text(strip=True) main_sub_name = anchor_tag.get_text(strip=True)
alt_names = [alt_name.strip() for alt_name in table_columns[2].get_text(strip=True).split("/")] alt_sub_names = [alt_sub_name.strip() for alt_sub_name in table_columns[2].get_text(strip=True).split("/")]
names = [main_name] + alt_names sub_names = [main_sub_name] + alt_sub_names
# Does at least one subtitle name contain one of the video names?
# Loop over all subtitle names and check if the keyword contains them # Skip subtitles that do not match
name_matches = [keyword and sanitize(keyword) not in sanitize(name) for name in names] # Video names -> the main title and alternative titles of a movie or an episode and so on...
# Subtitle names -> the main name and alternative names of a subtitle displayed in search results.
# Skip subtitles that do not contain the keyword in their name(s) # Could be handled in TitulkySubtitle class, however we want to keep the number of requests
if keyword and all(name_matches) is False: # as low as possible and this prevents the from requesting the details page unnecessarily
logger.debug(f"Titulky.com: Skipping subtitle with names: '{names}', because it does not not contain the keyword: '{keyword}'") if not _contains_element(_from=video_names, _in=sub_names):
logger.debug(f"Titulky.com: Skipping subtitle with names: {sub_names}, because there was no match with video names: {video_names}")
if type(threads_data) is list and type(thread_id) is int: if type(threads_data) is list and type(thread_id) is int:
threads_data[thread_id] = { threads_data[thread_id] = {
'sub_info': None, 'sub_info': None,
@ -364,7 +389,7 @@ class TitulkyProvider(Provider):
# Combine all subtitle data into one dict # Combine all subtitle data into one dict
result = { result = {
'names': names, 'names': sub_names,
'id': sub_id, 'id': sub_id,
'approved': approved, 'approved': approved,
'details_link': details_link, 'details_link': details_link,
@ -411,7 +436,7 @@ class TitulkyProvider(Provider):
# - Subtitles are here categorised by seasons and episodes # - Subtitles are here categorised by seasons and episodes
# - URL: https://premium.titulky.com/?action=serial&step=<SEASON>&id=<IMDB ID> # - URL: https://premium.titulky.com/?action=serial&step=<SEASON>&id=<IMDB ID>
# - it seems that the url redirects to a page with their own internal ID, redirects should be allowed here # - it seems that the url redirects to a page with their own internal ID, redirects should be allowed here
def query(self, language, type, keyword=None, year=None, season=None, episode=None, imdb_id=None): def query(self, language, video_names, type, keyword=None, year=None, season=None, episode=None, imdb_id=None):
## Build the search URL ## Build the search URL
params = {} params = {}
@ -483,23 +508,14 @@ class TitulkyProvider(Provider):
# Process the rows sequentially # Process the rows sequentially
logger.info("Titulky.com: processing results in sequence") logger.info("Titulky.com: processing results in sequence")
for i, row in enumerate(rows): for i, row in enumerate(rows):
sub_info = self.process_row(row, keyword) sub_info = self.process_row(row, video_names)
# If subtitle info was returned, then everything was okay # If subtitle info was returned, then everything was okay
# and we can instationate it and add it to the list # and we can instationate it and add it to the list
if sub_info: if sub_info:
logger.debug(f"Titulky.com: Sucessfully retrieved subtitle info, row: {i}") logger.debug(f"Titulky.com: Sucessfully retrieved subtitle info, row: {i}")
# Try to parse S00E00 string from the main subtitle name subtitle_instance = self.subtitle_class(sub_info['id'], sub_info['language'], sub_info['names'], season, episode, sub_info['year'], sub_info['release'], sub_info['fps'],
sub_season = None
sub_episode = None
season_episode_string = re.findall('S(\d+)E(\d+)', sub_info['names'][0], re.IGNORECASE)
if season_episode_string:
sub_season = season_episode_string[0][0]
sub_episode = season_episode_string[0][1]
subtitle_instance = self.subtitle_class(sub_info['id'], sub_info['language'], sub_info['names'], sub_season, sub_episode, sub_info['year'], sub_info['release'], sub_info['fps'],
sub_info['uploader'], sub_info['approved'], sub_info['details_link'], sub_info['download_link'], skip_wrong_fps=self.skip_wrong_fps) sub_info['uploader'], sub_info['approved'], sub_info['details_link'], sub_info['download_link'], skip_wrong_fps=self.skip_wrong_fps)
subtitles.append(subtitle_instance) subtitles.append(subtitle_instance)
else: else:
@ -527,7 +543,7 @@ class TitulkyProvider(Provider):
# Row number j # Row number j
logger.debug(f"Titulky.com: Creating thread {j} (batch: {i})") logger.debug(f"Titulky.com: Creating thread {j} (batch: {i})")
# Create a thread for row j and start it # Create a thread for row j and start it
threads[j] = Thread(target=self.process_row, args=[rows[j], keyword], kwargs={'thread_id': j, 'threads_data': threads_data}) threads[j] = Thread(target=self.process_row, args=[rows[j], video_names], kwargs={'thread_id': j, 'threads_data': threads_data})
threads[j].start() threads[j].start()
# Wait for all created threads to finish before moving to another batch of rows # Wait for all created threads to finish before moving to another batch of rows
@ -555,15 +571,7 @@ class TitulkyProvider(Provider):
logger.debug(f"Titulky.com: Sucessfully retrieved subtitle info, thread ID: {i}") logger.debug(f"Titulky.com: Sucessfully retrieved subtitle info, thread ID: {i}")
sub_info = thread_data['sub_info'] sub_info = thread_data['sub_info']
# Try to parse S00E00 string from the main subtitle name subtitle_instance = self.subtitle_class(sub_info['id'], sub_info['language'], sub_info['names'], season, episode, sub_info['year'], sub_info['release'], sub_info['fps'],
sub_season = None
sub_episode = None
season_episode_string = re.findall('S(\d+)E(\d+)', sub_info['names'][0], re.IGNORECASE)
if season_episode_string:
sub_season = season_episode_string[0][0]
sub_episode = season_episode_string[0][1]
subtitle_instance = self.subtitle_class(sub_info['id'], sub_info['language'], sub_info['names'], sub_season, sub_episode, sub_info['year'], sub_info['release'], sub_info['fps'],
sub_info['uploader'], sub_info['approved'], sub_info['details_link'], sub_info['download_link'], skip_wrong_fps=self.skip_wrong_fps) sub_info['uploader'], sub_info['approved'], sub_info['details_link'], sub_info['download_link'], skip_wrong_fps=self.skip_wrong_fps)
subtitles.append(subtitle_instance) subtitles.append(subtitle_instance)
else: else:
@ -589,32 +597,36 @@ class TitulkyProvider(Provider):
for language in languages: for language in languages:
if isinstance(video, Episode): if isinstance(video, Episode):
video_names = [video.series, video.title] + video.alternative_series
# (1) # (1)
logger.debug("Titulky.com: Finding subtitles by IMDB ID (1)") logger.debug("Titulky.com: Finding subtitles by IMDB ID, Season and Episode (1)")
if video.series_imdb_id: if video.series_imdb_id:
partial_subs = self.query(language, 'episode', imdb_id=video.series_imdb_id, season=video.season, episode=video.episode) partial_subs = self.query(language, video_names, 'episode', imdb_id=video.series_imdb_id, season=video.season, episode=video.episode)
if(len(partial_subs) > 0): if(len(partial_subs) > 0):
subtitles += partial_subs subtitles += partial_subs
continue continue
# (2) # (2)
logger.debug("Titulky.com: Finding subtitles by keyword (2)") logger.debug("Titulky.com: Finding subtitles by keyword, Season and Episode (2)")
keyword = video.series keyword = video.series
partial_subs = self.query(language, 'episode', keyword=keyword, season=video.season, episode=video.episode) partial_subs = self.query(language, video_names, 'episode', keyword=keyword, season=video.season, episode=video.episode)
if(len(partial_subs) > 0): if(len(partial_subs) > 0):
subtitles += partial_subs subtitles += partial_subs
continue continue
# (3) # (3)
logger.debug("Titulky.com: Finding subtitles by keyword (3)") logger.debug("Titulky.com: Finding subtitles by keyword only (3)")
keyword = f"{video.series} S{video.season:02d}E{video.episode:02d}" keyword = f"{video.series} S{video.season:02d}E{video.episode:02d}"
partial_subs = self.query(language, 'episode', keyword=keyword) partial_subs = self.query(language, video_names, 'episode', keyword=keyword)
subtitles += partial_subs subtitles += partial_subs
elif isinstance(video, Movie): elif isinstance(video, Movie):
video_names = [video.title] + video.alternative_titles
# (1) # (1)
logger.debug("Titulky.com: Finding subtitles by IMDB ID (1)") logger.debug("Titulky.com: Finding subtitles by IMDB ID (1)")
if video.imdb_id: if video.imdb_id:
partial_subs = self.query(language, 'movie', imdb_id=video.imdb_id) partial_subs = self.query(language, video_names, 'movie', imdb_id=video.imdb_id)
if(len(partial_subs) > 0): if(len(partial_subs) > 0):
subtitles += partial_subs subtitles += partial_subs
continue continue
@ -622,7 +634,7 @@ class TitulkyProvider(Provider):
# (2) # (2)
logger.debug("Titulky.com: Finding subtitles by keyword (2)") logger.debug("Titulky.com: Finding subtitles by keyword (2)")
keyword = video.title keyword = video.title
partial_subs = self.query(language, 'movie', keyword=keyword) partial_subs = self.query(language, video_names, 'movie', keyword=keyword)
subtitles += partial_subs subtitles += partial_subs
return subtitles return subtitles
@ -671,3 +683,16 @@ def _get_subtitle_from_archive(archive):
return archive.read(name) return archive.read(name)
return None return None
# Check if any element from source array is **contained** in any element from target array
# Returns on the first match
def _contains_element(_from=None, _in=None):
source_array = _from
target_array = _in
for source in source_array:
for target in target_array:
if sanitize(source) in sanitize(target):
return True
return False
Loading…
Cancel
Save