def test_converter_alpha3b(self): self.assertEqual(Language('fra').alpha3b, 'fre') self.assertEqual(Language.fromalpha3b('fre'), Language('fra')) self.assertEqual(Language.fromcode('fre', 'alpha3b'), Language('fra')) self.assertRaises(LanguageReverseError, lambda: Language.fromalpha3b('zzz')) self.assertRaises(LanguageConvertError, lambda: Language('aaa').alpha3b) self.assertEqual(len(language_converters['alpha3b'].codes), 418)
def test_converter_alpha3b(self): self.assertEqual(Language('fra').alpha3b, 'fre') self.assertEqual(Language.fromalpha3b('fre'), Language('fra')) self.assertEqual(Language.fromcode('fre', 'alpha3b'), Language('fra')) with self.assertRaises(LanguageReverseError): Language.fromalpha3b('zzz') with self.assertRaises(LanguageConvertError): Language('aaa').alpha3b self.assertEqual(len(get_language_converter('alpha3b').codes), 418)
def _get_embedded_subtitles(dirname, filename): """ Based on subliminal.video.scan_video(...) but only keep the check for embedded subtitles """ log.debug("Checking for embedded subtitle") embedded_subtitle_languages = set() try: path = os.path.join(dirname, filename) if filename.endswith('.mkv'): with open(path, 'rb') as f: mkv = MKV(f) # subtitle tracks if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: log.error('Embedded subtitle track language %r is not a valid language', st.language) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: log.debug('Embedded subtitle track name %r is not a valid language', st.name) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) log.debug('Found embedded subtitles %r with enzyme', embedded_subtitle_languages) else: log.debug('MKV has no subtitle track') except: log.exception('Parsing video metadata with enzyme failed') return embedded_subtitle_languages
def _language(self) -> Language: og_lang = self.tags.get("language") last_exc = None if og_lang is not None: if og_lang in _extra_languages: extra = _extra_languages[og_lang] title = self.tags.get("title", "n/a").lower() if any(possible in title for possible in extra["matches"]): logger.debug("Found extra language %s", extra["language_args"]) return Language(*extra["language_args"]) try: lang = Language.fromalpha3b(og_lang) # Test for suffix assert lang.alpha2 return lang except LanguageError as error: last_exc = error logger.debug("Error with '%s' language: %s", og_lang, error) raise LanguageNotFound( f"Couldn't detect language for stream: {self.tags}") from last_exc
def getAlpha3TCode(code): # We need to make sure that language codes are alpha3T """ :param code: Alpha2, Alpha3, or Alpha3b code. :type code: C{str} :return: Alpha3t language code (ISO 639-2/T) as C{str} """ lang = 'und' code = code.strip().lower() if len(code) == 3: try: lang = Language(code).alpha3t except: try: lang = Language.fromalpha3b(code).alpha3t except: try: lang = Language.fromalpha3t(code).alpha3t except: pass elif len(code) == 2: lang = Language.fromalpha2(code).alpha3t return lang
def getEmbeddedLanguages(video_path): embedded_subtitle_languages = set() try: with ek(io.open, video_path, 'rb') as f: mkv = MKV(f) if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: logging.debug('Embedded subtitle track is not a valid language') embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: logging.debug('Embedded subtitle track is not a valid language') embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) else: logging.debug('MKV has no subtitle track') except MalformedMKVError: logging.info('MKV seems to be malformed ( %s ), ignoring embedded subtitles' % video_path) return embedded_subtitle_languages
def getEmbeddedLanguages(video_path): embedded_subtitle_languages = set() try: with ek(io.open, video_path, 'rb') as f: mkv = MKV(f) if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add( Language.fromalpha3b(st.language)) except BabelfishError: logging.debug( 'Embedded subtitle track is not a valid language' ) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add( Language.fromname(st.name)) except BabelfishError: logging.debug( 'Embedded subtitle track is not a valid language' ) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) else: logging.debug('MKV has no subtitle track') except MalformedMKVError: logging.info( 'MKV seems to be malformed ( %s ), ignoring embedded subtitles' % video_path) return embedded_subtitle_languages
def subtitlesLanguages(video_path): """Return a list detected subtitles for the given video file""" resultList = [] embedded_subtitle_languages = set() # Serch for embedded subtitles if not sickbeard.EMBEDDED_SUBTITLES_ALL: if video_path.endswith('mkv'): try: with open(video_path.encode(sickbeard.SYS_ENCODING), 'rb') as f: mkv = MKV(f) if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: logger.log('Embedded subtitle track is not a valid language', logger.DEBUG) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: logger.log('Embedded subtitle track is not a valid language', logger.DEBUG) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) else: logger.log('MKV has no subtitle track', logger.DEBUG) except MalformedMKVError: logger.log('MKV seems to be malformed, ignoring embedded subtitles', logger.WARNING) # Search subtitles in the absolute path if sickbeard.SUBTITLES_DIR and ek(os.path.exists, sickbeard.SUBTITLES_DIR): video_path = ek(os.path.join, sickbeard.SUBTITLES_DIR, ek(os.path.basename, video_path)) # Search subtitles in the relative path elif sickbeard.SUBTITLES_DIR: video_path = ek(os.path.join, ek(os.path.dirname, video_path), sickbeard.SUBTITLES_DIR, ek(os.path.basename, video_path)) external_subtitle_languages = subliminal.video.scan_subtitle_languages(video_path) subtitle_languages = external_subtitle_languages.union(embedded_subtitle_languages) if (len(subtitle_languages) is 1 and len(wantedLanguages()) is 1) and Language('und') in subtitle_languages: subtitle_languages.remove(Language('und')) subtitle_languages.add(fromietf(wantedLanguages()[0])) for language in subtitle_languages: if hasattr(language, 'opensubtitles') and language.opensubtitles: resultList.append(language.opensubtitles) elif hasattr(language, 'alpha3') and language.alpha3: resultList.append(language.alpha3) elif hasattr(language, 'alpha2') and language.alpha2: resultList.append(language.alpha2) defaultLang = wantedLanguages() if ('pob' in defaultLang or 'pb' in defaultLang) and ('pt' not in defaultLang and 'por' not in defaultLang): resultList = [x if not x in ['por', 'pt'] else u'pob' for x in resultList] return sorted(resultList)
def checkLanguage(self, language): if not language: return None if len(language) < 2: self.log.error("Unable to set tag language, not enough characters [tag-language].") return None try: from babelfish import Language except: self.log.exception("Unable to important Language from babelfish [tag-language].") return None if len(language) == 2: try: return Language.fromalpha2(language).alpha3 self.log.exception("Unable to set tag language [tag-language].") except: return None try: return Language(language).alpha3 except: try: return Language.fromalpha3b(language).alpha3 except: try: return Language.fromalpha3t(language).alpha3 except: self.log.exception("Unable to set tag language [tag-language].") return None
def getEmbeddedLanguages(video_path): embedded_subtitle_languages = set() try: with open(video_path, 'rb') as f: mkv = MKV(f) if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: logger.log('Embedded subtitle track is not a valid language', logger.DEBUG) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: logger.log('Embedded subtitle track is not a valid language', logger.DEBUG) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) else: logger.log('MKV has no subtitle track', logger.DEBUG) except MalformedMKVError: logger.log('MKV seems to be malformed, ignoring embedded subtitles', logger.WARNING) return embedded_subtitle_languages
class BSPlayerProvider(Provider): """BSPlayer Provider. """ languages = { Language.fromalpha3b(l) for l in language_converters['alpha3b'].codes } server_url = 'https://api.bsplayer.org/xml-rpc' user_agent = 'subliminal v%s' % __short_version__ def __init__(self, search_url=None): self.server = ServerProxy(self.server_url, TimeoutSafeTransport(10)) # None values not allowed for logging in, so replace it by '' self.token = None self.session = Session() self.search_url = search_url or get_sub_domain() def _api_request(self, func_name='logIn', params='', tries=5): headers = { 'User-Agent': 'BSPlayer/2.x (1022.12360)', 'Content-Type': 'text/xml; charset=utf-8', 'Connection': 'close', 'SOAPAction': '"http://api.bsplayer-subtitles.com/v1.php#{func_name}"'.format( func_name=func_name) } data = ( '<?xml version="1.0" encoding="UTF-8"?>\n' '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' 'xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" ' 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' 'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="{search_url}">' '<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' '<ns1:{func_name}>{params}</ns1:{func_name}></SOAP-ENV:Body></SOAP-ENV:Envelope>' ).format(search_url=self.search_url, func_name=func_name, params=params) for i in xrange(tries): try: res = self.session.post(self.search_url, data=data, headers=headers) return ElementTree.fromstring(res.content) except Exception, ex: logger.error("[BSPlayer] ERROR: %s." % ex) if func_name == 'logIn': self.search_url = get_sub_domain() sleep(1) logger.error('[BSPlayer] ERROR: Too many tries (%d)...' % tries)
def get_embedded_subtitles(dirname, filename, log_scan=False): """Get the embedded subtitle languages for a video file. Based on subliminal.video.scan_video(...) but only keep the check for embedded subtitles. """ log.debug('Checking for embedded subtitle(s)') embedded_subtitle_languages = set() path = os.path.join(dirname, filename) try: if filename.endswith('.mkv'): with open(path, mode='rb') as f: mkv = MKV(f) # subtitle tracks if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add( Language.fromalpha3b(st.language)) except BabelfishError: log_scan and log.error( 'Embedded subtitle track language %r is not a valid language', st.language) elif st.name: try: embedded_subtitle_languages.add( Language.fromname(st.name)) except BabelfishError: log_scan and log.error( 'Embedded subtitle track name %r is not a valid language', st.name) else: log_scan and log.error( 'Embedded subtitle track language %r is not a valid language', st.language) log_scan and log.debug( 'Found embedded subtitles %r with enzyme', embedded_subtitle_languages) else: log_scan and log.debug('MKV has no subtitle track') else: log_scan and log.debug( 'Check is only supported for MKV containers, skipping') except Exception: log_scan and log.error('Parsing video metadata with enzyme failed') return [ Subtitle(EMBEDDED, text_type(language), path) for language in embedded_subtitle_languages if language != Language('und') ]
def query(self, languages, hash=None, size=None): # fill the search criteria root = self._api_request( func_name='searchSubtitles', params=('<handle>{token}</handle>' '<movieHash>{movie_hash}</movieHash>' '<movieSize>{movie_size}</movieSize>' '<languageId>{language_ids}</languageId>' '<imdbId>*</imdbId>').format(token=self.token, movie_hash=hash, movie_size=size, language_ids=','.join( map( lambda l: l.alpha3, languages)))) res = root.find('.//return/result') if res.find('status').text != 'OK': return [] items = root.findall('.//return/data/item') subtitles = [] if items: for item in items: subtitle_id = item.find('subID').text size = item.find('subSize').text download_link = item.find('subDownloadLink').text language = Language.fromalpha3b(item.find('subLang').text) filename = item.find('subName').text subtitle_format = item.find('subFormat').text subtitle_hash = item.find('subHash').text rating = item.find('subRating').text season = item.find('season').text episode = item.find('episode').text encoding = item.find('encsubtitle').text imdb_id = item.find('movieIMBDID').text imdb_rating = item.find('movieIMBDRating').text movie_year = item.find('movieYear').text movie_name = item.find('movieName').text movie_hash = item.find('movieHash').text movie_size = item.find('movieSize').text movie_fps = item.find('movieFPS').text subtitle = BSPlayerSubtitle( subtitle_id, size, download_link, language, filename, subtitle_format, subtitle_hash, rating, season, episode, encoding, imdb_id, imdb_rating, movie_year, movie_name, movie_hash, movie_size, movie_fps) logger.debug('Found subtitle %s', subtitle) subtitles.append(subtitle) return subtitles
def handle(self, value, context): """Handle languages.""" try: if len(value) == 3: return BabelfishLanguage.fromalpha3b(value) return BabelfishLanguage.fromietf(value) except (BabelfishError, ValueError): pass try: return BabelfishLanguage.fromname(value) except BabelfishError: pass logger.info('Invalid language: %r', value) return BabelfishLanguage('und')
def _get_embedded_subtitles(dirname, filename): """ Based on subliminal.video.scan_video(...) but only keep the check for embedded subtitles """ log.debug("Checking for embedded subtitle") embedded_subtitle_languages = set() try: path = os.path.join(dirname, filename) if filename.endswith('.mkv'): with open(path, 'rb') as f: mkv = MKV(f) # subtitle tracks if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add( Language.fromalpha3b(st.language)) except BabelfishError: log.error( 'Embedded subtitle track language %r is not a valid language', st.language) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add( Language.fromname(st.name)) except BabelfishError: log.debug( 'Embedded subtitle track name %r is not a valid language', st.name) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) log.debug('Found embedded subtitles %r with enzyme', embedded_subtitle_languages) else: log.debug('MKV has no subtitle track') except: log.exception('Parsing video metadata with enzyme failed') return embedded_subtitle_languages
def has_subtitle(self, language): """ Returns true if the video has already a subtitle for a specific language. """ has_subtitle = False # Look for embedded subtitle in mkv video if Video.is_mkv(self.signature): with open(self.filename, 'rb') as file_handler: mkv_video = enzyme.MKV(file_handler) for sub in mkv_video.subtitle_tracks: try: if sub.language and \ Language.fromalpha3b(sub.language) == language: has_subtitle = True break elif sub.name and \ Language.fromname(sub.name) == language: has_subtitle = True break except BabelfishError: LOG.error( "Embedded subtitle track" "language {} is not a valid language" .format(sub.language)) # Look for external subtitle dir_name = os.path.dirname(self.filename) base_name, _ = os.path.splitext(os.path.basename(self.filename)) search_subtitle = os.path.join( dir_name, "{}.{}.*".format(base_name, language.alpha2)) existing_subtitles = [ sub_file for sub_file in glob.glob(search_subtitle) if os.path.splitext(sub_file)[1] in Subtitle.EXTENSIONS ] if existing_subtitles: has_subtitle = True return has_subtitle
def get_embedded_subtitles(dirname, filename, log_scan=False): """Get the embedded subtitle languages for a video file. Based on subliminal.video.scan_video(...) but only keep the check for embedded subtitles. """ log.debug('Checking for embedded subtitle(s)') embedded_subtitle_languages = set() path = os.path.join(dirname, filename) try: if filename.endswith('.mkv'): with open(path, mode='rb') as f: mkv = MKV(f) # subtitle tracks if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: log_scan and log.error('Embedded subtitle track language %r is not a valid language', st.language) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: log_scan and log.error('Embedded subtitle track name %r is not a valid language', st.name) else: log_scan and log.error('Embedded subtitle track language %r is not a valid language', st.language) log_scan and log.debug('Found embedded subtitles %r with enzyme', embedded_subtitle_languages) else: log_scan and log.debug('MKV has no subtitle track') else: log_scan and log.debug('Check is only supported for MKV containers, skipping') except Exception: log_scan and log.error('Parsing video metadata with enzyme failed') return [Subtitle(EMBEDDED, text_type(language), path) for language in embedded_subtitle_languages if language != Language('und')]
def verify_embedded(self, tracks, language): track_match = False if tracks: for track in tracks: if track.language: try: current_language = Language.fromalpha3b(track.language) if current_language == str(language): track_match = True break except: continue elif track.name: try: current_language = Language.fromname(track.name) if current_language == str(language): track_match = True break except: continue return track_match
def has_subtitle(self, language): """ Returns true if the video has already a subtitle for a specific language. """ has_subtitle = False # Look for embedded subtitle in mkv video if Video.is_mkv(self.signature): with open(self.filename, 'rb') as file_handler: mkv_video = enzyme.MKV(file_handler) for sub in mkv_video.subtitle_tracks: try: if sub.language and \ Language.fromalpha3b(sub.language) == language: has_subtitle = True break elif sub.name and \ Language.fromname(sub.name) == language: has_subtitle = True break except BabelfishError: LOG.error("Embedded subtitle track" "language {} is not a valid language".format( sub.language)) # Look for external subtitle dir_name = os.path.dirname(self.filename) base_name, _ = os.path.splitext(os.path.basename(self.filename)) search_subtitle = os.path.join( dir_name, "{}.{}.*".format(base_name, language.alpha2)) existing_subtitles = [ sub_file for sub_file in glob.glob(search_subtitle) if os.path.splitext(sub_file)[1] in Subtitle.EXTENSIONS ] if existing_subtitles: has_subtitle = True return has_subtitle
def getAlpha3TCode(code, default=None): lang = default or UNDEFINED if not code or code == UNDEFINED: return lang code = code.strip().lower().replace('.', '') if len(code) == 3: try: lang = Language(code).alpha3t except: try: lang = Language.fromalpha3b(code).alpha3t except: try: lang = Language.fromalpha3t(code).alpha3t except: pass elif len(code) == 2: try: lang = Language.fromalpha2(code).alpha3t except: pass return lang
class BSPlayerProvider(Provider): """BSPlayer Provider.""" languages = {Language.fromalpha3b(l) for l in language_converters["alpha3b"].codes} server_url = "https://api.bsplayer.org/xml-rpc" user_agent = "subliminal v%s" % __short_version__ def __init__(self, search_url=None): self.server = ServerProxy(self.server_url, TimeoutSafeTransport(10), context=make_context(settings.SSL_VERIFY)) # None values not allowed for logging in, so replace it by '' self.token = None self.session = Session() self.search_url = search_url or get_sub_domain() def _api_request(self, func_name="logIn", params="", tries=5): headers = { "User-Agent": "BSPlayer/2.x (1022.12360)", "Content-Type": "text/xml; charset=utf-8", "Connection": "close", "SOAPAction": '"http://api.bsplayer-subtitles.com/v1.php#{func_name}"'.format(func_name=func_name), } data = ( '<?xml version="1.0" encoding="UTF-8"?>\n' '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' 'xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" ' 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' f'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="{self.search_url}">' '<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' f"<ns1:{func_name}>{params}</ns1:{func_name}></SOAP-ENV:Body></SOAP-ENV:Envelope>" ) for i in range(tries): try: res = self.session.post(self.search_url, data=data, headers=headers) return ElementTree.fromstring(res.content) except ElementTree.ParseError: logger.warning(f"[BSPlayer]: {res.content}") except Exception as ex: logger.error("[BSPlayer] ERROR: %s." % ex) if func_name == "logIn": self.search_url = get_sub_domain() sleep(2) logger.error("[BSPlayer] ERROR: Too many tries (%d)..." % tries) def initialize(self): root = self._api_request(func_name="logIn", params=("<username></username>" "<password></password>" "<AppID>BSPlayer v2.67</AppID>")) res = root.find(".//return") if res.find("status").text == "OK": self.token = res.find("data").text def terminate(self): root = self._api_request(func_name="logOut", params=f"<handle>{self.token}</handle>") res = root.find(".//return") if res.find("status").text != "OK": logger.error("[BSPlayer] ERROR: Unable to close session.") self.token = None def query(self, languages, name_hash=None, size=None): # fill the search criteria root = self._api_request( func_name="searchSubtitles", params=( "<handle>{token}</handle>" "<movieHash>{movie_hash}</movieHash>" "<movieSize>{movie_size}</movieSize>" "<languageId>{language_ids}</languageId>" "<imdbId>*</imdbId>" ).format(token=self.token, movie_hash=name_hash, movie_size=size, language_ids=",".join([l.alpha3 for l in languages])), ) res = root.find(".//return/result") if res.find("status").text != "OK": return [] items = root.findall(".//return/data/item") subtitles = [] if items: for item in items: subtitle_id = item.find("subID").text size = item.find("subSize").text download_link = item.find("subDownloadLink").text language = Language.fromalpha3b(item.find("subLang").text) filename = item.find("subName").text subtitle_source = item.find("subFormat").text subtitle_hash = item.find("subHash").text rating = item.find("subRating").text season = item.find("season").text episode = item.find("episode").text encoding = item.find("encsubtitle").text imdb_id = item.find("movieIMBDID").text imdb_rating = item.find("movieIMBDRating").text movie_year = item.find("movieYear").text movie_name = item.find("movieName").text movie_hash = item.find("movieHash").text movie_size = item.find("movieSize").text movie_fps = item.find("movieFPS").text subtitle = BSPlayerSubtitle( subtitle_id, size, download_link, language, filename, subtitle_source, subtitle_hash, rating, season, episode, encoding, imdb_id, imdb_rating, movie_year, movie_name, movie_hash, movie_size, movie_fps, ) logger.debug("Found subtitle %s", subtitle) subtitles.append(subtitle) return subtitles def list_subtitles(self, video, languages): return self.query(languages, name_hash=self.hash_bsplayer(video.name), size=video.size) def download_subtitle(self, subtitle): logger.info("Downloading subtitle %r", subtitle) headers = { "User-Agent": "BSPlayer/2.x (1022.12360)", "Content-Length": "0", } response = self.session.get(subtitle.page_link, headers=headers) subtitle.content = fix_line_ending(zlib.decompress(response.content, 47)) @staticmethod def hash_bsplayer(video_path): """Compute a hash using BSPlayer's algorithm. :param str video_path: path of the video. :return: the name_hash. :rtype: str """ little_endian_long_long = "<q" # little-endian long long byte_size = struct.calcsize(little_endian_long_long) with open(video_path, "rb") as f: file_size = os.path.getsize(video_path) file_hash = file_size if file_size < 65536 * 2: return for _ in range(65536 // byte_size): buff = f.read(byte_size) (l_value,) = struct.unpack(little_endian_long_long, buff) file_hash += l_value file_hash &= 0xFFFFFFFFFFFFFFFF # to remain as 64bit number f.seek(max(0, file_size - 65536), 0) for x in range(65536 // byte_size): buff = f.read(byte_size) (l_value,) = struct.unpack(little_endian_long_long, buff) file_hash += l_value file_hash &= 0xFFFFFFFFFFFFFFFF return "%016x" % file_hash
class BSPlayerProvider(Provider): """BSPlayer Provider. """ languages = {Language.fromalpha3b(l) for l in language_converters['alpha3b'].codes} server_url = 'https://api.bsplayer.org/xml-rpc' user_agent = 'subliminal v%s' % __short_version__ def __init__(self, search_url=None): self.server = ServerProxy(self.server_url, TimeoutSafeTransport(10)) # None values not allowed for logging in, so replace it by '' self.token = None self.session = Session() self.search_url = search_url or get_sub_domain() def _api_request(self, func_name='logIn', params='', tries=5): headers = { 'User-Agent': 'BSPlayer/2.x (1022.12360)', 'Content-Type': 'text/xml; charset=utf-8', 'Connection': 'close', 'SOAPAction': '"http://api.bsplayer-subtitles.com/v1.php#{func_name}"'.format(func_name=func_name) } data = ( '<?xml version="1.0" encoding="UTF-8"?>\n' '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" ' 'xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" ' 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ' 'xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ns1="{search_url}">' '<SOAP-ENV:Body SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' '<ns1:{func_name}>{params}</ns1:{func_name}></SOAP-ENV:Body></SOAP-ENV:Envelope>' ).format(search_url=self.search_url, func_name=func_name, params=params) for i in range(tries): try: res = self.session.post(self.search_url, data=data, headers=headers) return ElementTree.fromstring(res.content) except Exception as ex: logger.error("[BSPlayer] ERROR: %s." % ex) if func_name == 'logIn': self.search_url = get_sub_domain() sleep(1) logger.error('[BSPlayer] ERROR: Too many tries (%d)...' % tries) def initialize(self): root = self._api_request( func_name='logIn', params=('<username></username>' '<password></password>' '<AppID>BSPlayer v2.67</AppID>') ) res = root.find('.//return') if res.find('status').text == 'OK': self.token = res.find('data').text def terminate(self): root = self._api_request( func_name='logOut', params='<handle>{token}</handle>'.format(token=self.token) ) res = root.find('.//return') if res.find('status').text != 'OK': logger.error('[BSPlayer] ERROR: Unable to close session.') self.token = None def query(self, languages, hash=None, size=None): # fill the search criteria root = self._api_request( func_name='searchSubtitles', params=( '<handle>{token}</handle>' '<movieHash>{movie_hash}</movieHash>' '<movieSize>{movie_size}</movieSize>' '<languageId>{language_ids}</languageId>' '<imdbId>*</imdbId>' ).format(token=self.token, movie_hash=hash, movie_size=size, language_ids=','.join(map(lambda l: l.alpha3, languages))) ) res = root.find('.//return/result') if res.find('status').text != 'OK': return [] items = root.findall('.//return/data/item') subtitles = [] if items: for item in items: subtitle_id = item.find('subID').text size = item.find('subSize').text download_link = item.find('subDownloadLink').text language = Language.fromalpha3b(item.find('subLang').text) filename = item.find('subName').text subtitle_format = item.find('subFormat').text subtitle_hash = item.find('subHash').text rating = item.find('subRating').text season = item.find('season').text episode = item.find('episode').text encoding = item.find('encsubtitle').text imdb_id = item.find('movieIMBDID').text imdb_rating = item.find('movieIMBDRating').text movie_year = item.find('movieYear').text movie_name = item.find('movieName').text movie_hash = item.find('movieHash').text movie_size = item.find('movieSize').text movie_fps = item.find('movieFPS').text subtitle = BSPlayerSubtitle(subtitle_id, size, download_link, language, filename, subtitle_format, subtitle_hash, rating, season, episode, encoding, imdb_id, imdb_rating, movie_year, movie_name, movie_hash, movie_size, movie_fps) logger.debug('Found subtitle %s', subtitle) subtitles.append(subtitle) return subtitles def list_subtitles(self, video, languages): return self.query(languages, hash=self.hash_bsplayer(video.name), size=video.size) def download_subtitle(self, subtitle): logger.info('Downloading subtitle %r', subtitle) headers = { 'User-Agent': 'BSPlayer/2.x (1022.12360)', 'Content-Length': '0', } response = self.session.get(subtitle.page_link, headers=headers) subtitle.content = fix_line_ending(zlib.decompress(response.content, 47)) def hash_bsplayer(self, video_path): """Compute a hash using BSPlayer's algorithm. :param str video_path: path of the video. :return: the hash. :rtype: str """ little_endian_long_long = '<q' # little-endian long long byte_size = struct.calcsize(little_endian_long_long) with open(video_path, 'rb') as f: file_size = os.path.getsize(video_path) file_hash = file_size if file_size < 65536 * 2: return for _ in range(65536 // byte_size): buff = f.read(byte_size) (l_value,) = struct.unpack(little_endian_long_long, buff) file_hash += l_value file_hash &= 0xFFFFFFFFFFFFFFFF # to remain as 64bit number f.seek(max(0, file_size - 65536), 0) for x in range(65536 // byte_size): buff = f.read(byte_size) (l_value,) = struct.unpack(little_endian_long_long, buff) file_hash += l_value file_hash &= 0xFFFFFFFFFFFFFFFF return "%016x" % file_hash
def scan_video(path, subtitles=True, embedded_subtitles=True, subtitles_dir=None): """Scan a video and its subtitle languages from a video `path`. :param str path: existing path to the video. :param bool subtitles: scan for subtitles with the same name. :param bool embedded_subtitles: scan for embedded subtitles. :param str subtitles_dir: directory to search for subtitles. :return: the scanned video. :rtype: :class:`Video` """ # check for non-existing path if not os.path.exists(path): raise ValueError('Path does not exist') # check video extension if not path.endswith(VIDEO_EXTENSIONS): raise ValueError('%s is not a valid video extension' % os.path.splitext(path)[1]) dirpath, filename = os.path.split(path) logger.info('Scanning video %r in %r', filename, dirpath) # guess video = Video.fromguess(path, guessit(path)) # size and hashes video.size = os.path.getsize(path) if video.size > 10485760: logger.debug('Size is %d', video.size) video.hashes['opensubtitles'] = hash_opensubtitles(path) video.hashes['thesubdb'] = hash_thesubdb(path) video.hashes['napiprojekt'] = hash_napiprojekt(path) logger.debug('Computed hashes %r', video.hashes) else: logger.warning('Size is lower than 10MB: hashes not computed') # external subtitles if subtitles: video.subtitle_languages |= set(search_external_subtitles(path, directory=subtitles_dir).values()) # video metadata with enzyme try: if filename.endswith('.mkv'): with open(path, 'rb') as f: mkv = MKV(f) # main video track if mkv.video_tracks: video_track = mkv.video_tracks[0] # resolution if video_track.height in (480, 720, 1080): if video_track.interlaced: video.resolution = '%di' % video_track.height else: video.resolution = '%dp' % video_track.height logger.debug('Found resolution %s with enzyme', video.resolution) # video codec if video_track.codec_id == 'V_MPEG4/ISO/AVC': video.video_codec = 'h264' logger.debug('Found video_codec %s with enzyme', video.video_codec) elif video_track.codec_id == 'V_MPEG4/ISO/SP': video.video_codec = 'DivX' logger.debug('Found video_codec %s with enzyme', video.video_codec) elif video_track.codec_id == 'V_MPEG4/ISO/ASP': video.video_codec = 'XviD' logger.debug('Found video_codec %s with enzyme', video.video_codec) else: logger.warning('MKV has no video track') # main audio track if mkv.audio_tracks: audio_track = mkv.audio_tracks[0] # audio codec if audio_track.codec_id == 'A_AC3': video.audio_codec = 'AC3' logger.debug('Found audio_codec %s with enzyme', video.audio_codec) elif audio_track.codec_id == 'A_DTS': video.audio_codec = 'DTS' logger.debug('Found audio_codec %s with enzyme', video.audio_codec) elif audio_track.codec_id == 'A_AAC': video.audio_codec = 'AAC' logger.debug('Found audio_codec %s with enzyme', video.audio_codec) else: logger.warning('MKV has no audio track') # subtitle tracks if mkv.subtitle_tracks: if embedded_subtitles: embedded_subtitle_languages = set() for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: logger.error('Embedded subtitle track language %r is not a valid language', st.language) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: logger.debug('Embedded subtitle track name %r is not a valid language', st.name) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) logger.debug('Found embedded subtitle %r with enzyme', embedded_subtitle_languages) video.subtitle_languages |= embedded_subtitle_languages else: logger.debug('MKV has no subtitle track') except: logger.exception('Parsing video metadata with enzyme failed') return video
def fromalpha3b(cls, s): if s in repl_map: s = repl_map[s] return Language(*Language_.fromietf(s).__getstate__()) return Language(*Language_.fromalpha3b(s).__getstate__())
def scan_video(path, subtitles=True, embedded_subtitles=True): """Scan a video and its subtitle languages from a video `path`. :param str path: existing path to the video. :param bool subtitles: scan for subtitles with the same name. :param bool embedded_subtitles: scan for embedded subtitles. :return: the scanned video. :rtype: :class:`Video` """ # check for non-existing path if not os.path.exists(path): raise ValueError('Path does not exist') # check video extension if not path.endswith(VIDEO_EXTENSIONS): raise ValueError('%s is not a valid video extension' % os.path.splitext(path)[1]) dirpath, filename = os.path.split(path) logger.info('Scanning video %r in %r', filename, dirpath) # guess video = Video.fromguess(path, guess_file_info(path)) # size and hashes video.size = os.path.getsize(path) if video.size > 10485760: logger.debug('Size is %d', video.size) video.hashes['opensubtitles'] = hash_opensubtitles(path) video.hashes['thesubdb'] = hash_thesubdb(path) logger.debug('Computed hashes %r', video.hashes) else: logger.warning('Size is lower than 10MB: hashes not computed') # external subtitles if subtitles: video.subtitle_languages |= set(search_external_subtitles(path).values()) # video metadata with enzyme try: if filename.endswith('.mkv'): with open(path, 'rb') as f: mkv = MKV(f) # main video track if mkv.video_tracks: video_track = mkv.video_tracks[0] # resolution if video_track.height in (480, 720, 1080): if video_track.interlaced: video.resolution = '%di' % video_track.height else: video.resolution = '%dp' % video_track.height logger.debug('Found resolution %s with enzyme', video.resolution) # video codec if video_track.codec_id == 'V_MPEG4/ISO/AVC': video.video_codec = 'h264' logger.debug('Found video_codec %s with enzyme', video.video_codec) elif video_track.codec_id == 'V_MPEG4/ISO/SP': video.video_codec = 'DivX' logger.debug('Found video_codec %s with enzyme', video.video_codec) elif video_track.codec_id == 'V_MPEG4/ISO/ASP': video.video_codec = 'XviD' logger.debug('Found video_codec %s with enzyme', video.video_codec) else: logger.warning('MKV has no video track') # main audio track if mkv.audio_tracks: audio_track = mkv.audio_tracks[0] # audio codec if audio_track.codec_id == 'A_AC3': video.audio_codec = 'AC3' logger.debug('Found audio_codec %s with enzyme', video.audio_codec) elif audio_track.codec_id == 'A_DTS': video.audio_codec = 'DTS' logger.debug('Found audio_codec %s with enzyme', video.audio_codec) elif audio_track.codec_id == 'A_AAC': video.audio_codec = 'AAC' logger.debug('Found audio_codec %s with enzyme', video.audio_codec) else: logger.warning('MKV has no audio track') # subtitle tracks if mkv.subtitle_tracks: if embedded_subtitles: embedded_subtitle_languages = set() for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: logger.error('Embedded subtitle track language %r is not a valid language', st.language) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: logger.debug('Embedded subtitle track name %r is not a valid language', st.name) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) logger.debug('Found embedded subtitle %r with enzyme', embedded_subtitle_languages) video.subtitle_languages |= embedded_subtitle_languages else: logger.debug('MKV has no subtitle track') except EnzymeError: logger.exception('Parsing video metadata with enzyme failed') return video
def parse_video(fn, video_info, hints, external_subtitles=False, embedded_subtitles=False, known_embedded=None, forced_only=False, no_refining=False, dry_run=False, ignore_all=False, stored_subs=None): logger.debug("Parsing video: %s, hints: %s", os.path.basename(fn), hints) video = scan_video(fn, hints=hints, dont_use_actual_file=dry_run or no_refining) if no_refining: logger.debug("Taking parse_video shortcut") return video # refiners refine_kwargs = { "episode_refiners": ('tvdb', 'sz_omdb'), "movie_refiners": ('sz_omdb', ), "embedded_subtitles": False, } # our own metadata refiner :) if "stream" in video_info: for key, value in video_info["stream"].iteritems(): if hasattr(video, key) and not getattr(video, key): logger.info(u"Adding stream %s info: %s", key, value) setattr(video, key, value) plex_title = video_info.get("original_title") or video_info.get("title") if hints["type"] == "episode": plex_title = video_info.get("original_title") or video_info.get( "series") year = video_info.get("year") if not video.year and year: logger.info(u"Adding PMS year info: %s", year) video.year = year refine(video, **refine_kwargs) if hints["type"] == "movie" and not video.imdb_id: if plex_title: logger.info(u"Adding PMS title/original_title info: %s", plex_title) old_title = video.title video.title = plex_title.replace(" - ", " ").replace(" -", " ").replace( "- ", " ") # re-refine with new info logger.info(u"Re-refining with movie title: '%s' instead of '%s'", plex_title, old_title) refine(video, **refine_kwargs) # still no match? add our own data if not video.imdb_id: video.imdb_id = video_info.get("imdb_id") if video.imdb_id: logger.info(u"Adding PMS imdb_id info: %s", video.imdb_id) if hints["type"] == "episode": if not video.series_tvdb_id and not video.tvdb_id and plex_title: # add our title logger.info(u"Adding PMS title/original_title info: %s", plex_title) old_title = video.series video.series = plex_title # re-refine with new info logger.info(u"Re-refining with series title: '%s' instead of '%s'", plex_title, old_title) refine(video, **refine_kwargs) # still no match? add our own data if not video.series_tvdb_id: logger.info(u"Adding PMS series_tvdb_id info: %s", video_info.get("series_tvdb_id")) video.series_tvdb_id = video_info.get("series_tvdb_id") if not video.tvdb_id: logger.info(u"Adding PMS tvdb_id info: %s", video_info.get("tvdb_id")) video.tvdb_id = video_info.get("tvdb_id") # did it match? if (hints["type"] == "episode" and not video.series_tvdb_id and not video.tvdb_id and not video.series_imdb_id) or (hints["type"] == "movie" and not video.imdb_id): logger.warning( "Couldn't find corresponding series/movie in online databases, continuing" ) # scan for external subtitles external_langs_found = set( search_external_subtitles(video.name, forced_tag=forced_only).values()) # found external subtitles should be considered? if external_subtitles: # |= is update, thanks plex video.subtitle_languages.update(external_langs_found) else: # did we already download subtitles for this? if not ignore_all and stored_subs and external_langs_found: for lang in external_langs_found: if has_external_subtitle(video_info["plex_part"].id, stored_subs, lang): logger.info( "Not re-downloading subtitle for language %s, it already exists on the filesystem", lang) video.subtitle_languages.add(lang) # add known embedded subtitles if embedded_subtitles and known_embedded: embedded_subtitle_languages = set() # mp4 and stuff, check burned in for language in known_embedded: try: embedded_subtitle_languages.add(Language.fromalpha3b(language)) except LanguageError: logger.error( 'Embedded subtitle track language %r is not a valid language', language) embedded_subtitle_languages.add(Language('und')) logger.debug('Found embedded subtitle %r', embedded_subtitle_languages) video.subtitle_languages.update(embedded_subtitle_languages) # guess special if hints["type"] == "episode": if video.season == 0 or video.episode == 0: video.is_special = True else: # check parent folder name if os.path.dirname(fn).split( os.path.sep)[-1].lower() in ("specials", "season 00"): video.is_special = True return video
def fromalpha3b(cls, s): if s in repl_map: s = repl_map[s] return Language_.fromietf(s) return Language_.fromalpha3b(s)
def refine(video, embedded_subtitles=True, **kwargs): """Refine a video by searching its metadata. Several :class:`~subliminal.video.Video` attributes can be found: * :attr:`~subliminal.video.Video.resolution` * :attr:`~subliminal.video.Video.video_codec` * :attr:`~subliminal.video.Video.audio_codec` * :attr:`~subliminal.video.Video.subtitle_languages` :param bool embedded_subtitles: search for embedded subtitles. """ # skip non existing videos if not video.exists: return # check extensions extension = os.path.splitext(video.name)[1] if extension == '.mkv': with open(video.name, 'rb') as f: mkv = MKV(f) # main video track if mkv.video_tracks: video_track = mkv.video_tracks[0] # resolution if video_track.height in (480, 720, 1080): if video_track.interlaced: video.resolution = '%di' % video_track.height else: video.resolution = '%dp' % video_track.height logger.debug('Found resolution %s', video.resolution) # video codec if video_track.codec_id == 'V_MPEG4/ISO/AVC': video.video_codec = 'H.264' logger.debug('Found video_codec %s', video.video_codec) elif video_track.codec_id == 'V_MPEG4/ISO/SP': video.video_codec = 'DivX' logger.debug('Found video_codec %s', video.video_codec) elif video_track.codec_id == 'V_MPEG4/ISO/ASP': video.video_codec = 'Xvid' logger.debug('Found video_codec %s', video.video_codec) else: logger.warning('MKV has no video track') # main audio track if mkv.audio_tracks: audio_track = mkv.audio_tracks[0] # audio codec if audio_track.codec_id == 'A_AC3': video.audio_codec = 'Dolby Digital' logger.debug('Found audio_codec %s', video.audio_codec) elif audio_track.codec_id == 'A_DTS': video.audio_codec = 'DTS' logger.debug('Found audio_codec %s', video.audio_codec) elif audio_track.codec_id == 'A_AAC': video.audio_codec = 'AAC' logger.debug('Found audio_codec %s', video.audio_codec) else: logger.warning('MKV has no audio track') # subtitle tracks if mkv.subtitle_tracks: if embedded_subtitles: embedded_subtitle_languages = set() for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add( Language.fromalpha3b(st.language)) except BabelfishError: logger.error( 'Embedded subtitle track language %r is not a valid language', st.language) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add( Language.fromname(st.name)) except BabelfishError: logger.debug( 'Embedded subtitle track name %r is not a valid language', st.name) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) logger.debug('Found embedded subtitle %r', embedded_subtitle_languages) video.subtitle_languages |= embedded_subtitle_languages else: logger.debug('MKV has no subtitle track') else: logger.debug('Unsupported video extension %s', extension)
def refine(video, embedded_subtitles=True, **kwargs): """Refine a video by searching its metadata. Several :class:`~subliminal.video.Video` attributes can be found: * :attr:`~subliminal.video.Video.resolution` * :attr:`~subliminal.video.Video.video_codec` * :attr:`~subliminal.video.Video.audio_codec` * :attr:`~subliminal.video.Video.subtitle_languages` :param bool embedded_subtitles: search for embedded subtitles. """ # skip non existing videos if not video.exists: return # check extensions extension = os.path.splitext(video.name)[1] if extension == '.mkv': with open(video.name, 'rb') as f: mkv = MKV(f) # main video track if mkv.video_tracks: video_track = mkv.video_tracks[0] # resolution if video_track.height in (480, 720, 1080): if video_track.interlaced: video.resolution = '%di' % video_track.height else: video.resolution = '%dp' % video_track.height logger.debug('Found resolution %s', video.resolution) # video codec if video_track.codec_id == 'V_MPEG4/ISO/AVC': video.video_codec = 'H.264' logger.debug('Found video_codec %s', video.video_codec) elif video_track.codec_id == 'V_MPEG4/ISO/SP': video.video_codec = 'DivX' logger.debug('Found video_codec %s', video.video_codec) elif video_track.codec_id == 'V_MPEG4/ISO/ASP': video.video_codec = 'Xvid' logger.debug('Found video_codec %s', video.video_codec) else: logger.warning('MKV has no video track') # main audio track if mkv.audio_tracks: audio_track = mkv.audio_tracks[0] # audio codec if audio_track.codec_id == 'A_AC3': video.audio_codec = 'Dolby Digital' logger.debug('Found audio_codec %s', video.audio_codec) elif audio_track.codec_id == 'A_DTS': video.audio_codec = 'DTS' logger.debug('Found audio_codec %s', video.audio_codec) elif audio_track.codec_id == 'A_AAC': video.audio_codec = 'AAC' logger.debug('Found audio_codec %s', video.audio_codec) else: logger.warning('MKV has no audio track') # subtitle tracks if mkv.subtitle_tracks: if embedded_subtitles: embedded_subtitle_languages = set() for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: logger.error('Embedded subtitle track language %r is not a valid language', st.language) embedded_subtitle_languages.add(Language('und')) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: logger.debug('Embedded subtitle track name %r is not a valid language', st.name) embedded_subtitle_languages.add(Language('und')) else: embedded_subtitle_languages.add(Language('und')) logger.debug('Found embedded subtitle %r', embedded_subtitle_languages) video.subtitle_languages |= embedded_subtitle_languages else: logger.debug('MKV has no subtitle track') else: logger.debug('Unsupported video extension %s', extension)
def query(self, languages, name_hash=None, size=None): # fill the search criteria root = self._api_request( func_name="searchSubtitles", params=( "<handle>{token}</handle>" "<movieHash>{movie_hash}</movieHash>" "<movieSize>{movie_size}</movieSize>" "<languageId>{language_ids}</languageId>" "<imdbId>*</imdbId>" ).format(token=self.token, movie_hash=name_hash, movie_size=size, language_ids=",".join([l.alpha3 for l in languages])), ) res = root.find(".//return/result") if res.find("status").text != "OK": return [] items = root.findall(".//return/data/item") subtitles = [] if items: for item in items: subtitle_id = item.find("subID").text size = item.find("subSize").text download_link = item.find("subDownloadLink").text language = Language.fromalpha3b(item.find("subLang").text) filename = item.find("subName").text subtitle_source = item.find("subFormat").text subtitle_hash = item.find("subHash").text rating = item.find("subRating").text season = item.find("season").text episode = item.find("episode").text encoding = item.find("encsubtitle").text imdb_id = item.find("movieIMBDID").text imdb_rating = item.find("movieIMBDRating").text movie_year = item.find("movieYear").text movie_name = item.find("movieName").text movie_hash = item.find("movieHash").text movie_size = item.find("movieSize").text movie_fps = item.find("movieFPS").text subtitle = BSPlayerSubtitle( subtitle_id, size, download_link, language, filename, subtitle_source, subtitle_hash, rating, season, episode, encoding, imdb_id, imdb_rating, movie_year, movie_name, movie_hash, movie_size, movie_fps, ) logger.debug("Found subtitle %s", subtitle) subtitles.append(subtitle) return subtitles
def subtitlesLanguages(video_path): """Return a list detected subtitles for the given video file""" resultList = [] embedded_subtitle_languages = set() # Serch for embedded subtitles if not sickbeard.EMBEDDED_SUBTITLES_ALL: if video_path.endswith('mkv'): try: with open(video_path.encode(sickbeard.SYS_ENCODING), 'rb') as f: mkv = MKV(f) if mkv.subtitle_tracks: for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add( Language.fromalpha3b(st.language)) except BabelfishError: logger.log( 'Embedded subtitle track is not a valid language', logger.DEBUG) embedded_subtitle_languages.add( Language('und')) elif st.name: try: embedded_subtitle_languages.add( Language.fromname(st.name)) except BabelfishError: logger.log( 'Embedded subtitle track is not a valid language', logger.DEBUG) embedded_subtitle_languages.add( Language('und')) else: embedded_subtitle_languages.add(Language('und')) else: logger.log('MKV has no subtitle track', logger.DEBUG) except MalformedMKVError: logger.log( 'MKV seems to be malformed, ignoring embedded subtitles', logger.WARNING) # Search subtitles in the absolute path if sickbeard.SUBTITLES_DIR and ek(os.path.exists, sickbeard.SUBTITLES_DIR): video_path = ek(os.path.join, sickbeard.SUBTITLES_DIR, ek(os.path.basename, video_path)) # Search subtitles in the relative path elif sickbeard.SUBTITLES_DIR: video_path = ek(os.path.join, ek(os.path.dirname, video_path), sickbeard.SUBTITLES_DIR, ek(os.path.basename, video_path)) external_subtitle_languages = subliminal.video.scan_subtitle_languages( video_path) subtitle_languages = external_subtitle_languages.union( embedded_subtitle_languages) if (len(subtitle_languages) is 1 and len(wantedLanguages()) is 1 ) and Language('und') in subtitle_languages: subtitle_languages.remove(Language('und')) subtitle_languages.add(fromietf(wantedLanguages()[0])) for language in subtitle_languages: if hasattr(language, 'opensubtitles') and language.opensubtitles: resultList.append(language.opensubtitles) elif hasattr(language, 'alpha3') and language.alpha3: resultList.append(language.alpha3) elif hasattr(language, 'alpha2') and language.alpha2: resultList.append(language.alpha2) defaultLang = wantedLanguages() if ('pob' in defaultLang or 'pb' in defaultLang) and ('pt' not in defaultLang and 'por' not in defaultLang): resultList = [ x if not x in ['por', 'pt'] else u'pob' for x in resultList ] return sorted(resultList)
def scan_video(path, subtitles=True, embedded_subtitles=True, subtitles_dir=None): """Scan a video and its subtitle languages from a video `path`. :param str path: existing path to the video. :param bool subtitles: scan for subtitles with the same name. :param bool embedded_subtitles: scan for embedded subtitles. :param str subtitles_dir: directory to search for subtitles. :return: the scanned video. :rtype: :class:`Video` """ # check for non-existing path if not os.path.exists(path): raise ValueError("Path does not exist") # check video extension if not path.endswith(VIDEO_EXTENSIONS): raise ValueError("%s is not a valid video extension" % os.path.splitext(path)[1]) dirpath, filename = os.path.split(path) logger.info("Scanning video %r in %r", filename, dirpath) # guess video = Video.fromguess(path, guess_file_info(path)) # size and hashes video.size = os.path.getsize(path) if video.size > 10485760: logger.debug("Size is %d", video.size) video.hashes["opensubtitles"] = hash_opensubtitles(path) video.hashes["thesubdb"] = hash_thesubdb(path) video.hashes["napiprojekt"] = hash_napiprojekt(path) logger.debug("Computed hashes %r", video.hashes) else: logger.warning("Size is lower than 10MB: hashes not computed") # external subtitles if subtitles: video.subtitle_languages |= set(search_external_subtitles(path, directory=subtitles_dir).values()) # video metadata with enzyme try: if filename.endswith(".mkv"): with open(path, "rb") as f: mkv = MKV(f) # main video track if mkv.video_tracks: video_track = mkv.video_tracks[0] # resolution if video_track.height in (480, 720, 1080): if video_track.interlaced: video.resolution = "%di" % video_track.height else: video.resolution = "%dp" % video_track.height logger.debug("Found resolution %s with enzyme", video.resolution) # video codec if video_track.codec_id == "V_MPEG4/ISO/AVC": video.video_codec = "h264" logger.debug("Found video_codec %s with enzyme", video.video_codec) elif video_track.codec_id == "V_MPEG4/ISO/SP": video.video_codec = "DivX" logger.debug("Found video_codec %s with enzyme", video.video_codec) elif video_track.codec_id == "V_MPEG4/ISO/ASP": video.video_codec = "XviD" logger.debug("Found video_codec %s with enzyme", video.video_codec) else: logger.warning("MKV has no video track") # main audio track if mkv.audio_tracks: audio_track = mkv.audio_tracks[0] # audio codec if audio_track.codec_id == "A_AC3": video.audio_codec = "AC3" logger.debug("Found audio_codec %s with enzyme", video.audio_codec) elif audio_track.codec_id == "A_DTS": video.audio_codec = "DTS" logger.debug("Found audio_codec %s with enzyme", video.audio_codec) elif audio_track.codec_id == "A_AAC": video.audio_codec = "AAC" logger.debug("Found audio_codec %s with enzyme", video.audio_codec) else: logger.warning("MKV has no audio track") # subtitle tracks if mkv.subtitle_tracks: if embedded_subtitles: embedded_subtitle_languages = set() for st in mkv.subtitle_tracks: if st.language: try: embedded_subtitle_languages.add(Language.fromalpha3b(st.language)) except BabelfishError: logger.error("Embedded subtitle track language %r is not a valid language", st.language) embedded_subtitle_languages.add(Language("und")) elif st.name: try: embedded_subtitle_languages.add(Language.fromname(st.name)) except BabelfishError: logger.debug("Embedded subtitle track name %r is not a valid language", st.name) embedded_subtitle_languages.add(Language("und")) else: embedded_subtitle_languages.add(Language("und")) logger.debug("Found embedded subtitle %r with enzyme", embedded_subtitle_languages) video.subtitle_languages |= embedded_subtitle_languages else: logger.debug("MKV has no subtitle track") except: logger.exception("Parsing video metadata with enzyme failed") return video