1# -*- coding: utf-8 -*- 2import io 3import logging 4import os 5 6from zipfile import ZipFile, is_zipfile 7from requests import Session 8from guessit import guessit 9 10from subliminal import Movie 11from subliminal.subtitle import SUBTITLE_EXTENSIONS, fix_line_ending 12from subliminal_patch.exceptions import APIThrottled 13from subliminal_patch.providers import Provider 14from subliminal_patch.subtitle import Subtitle, guess_matches 15from subzero.language import Language 16 17logger = logging.getLogger(__name__) 18 19SERVER_URL = "https://www.subsynchro.com/include/ajax/subMarin.php" 20PAGE_URL = "https://www.subsynchro.com" 21 22 23class SubsynchroSubtitle(Subtitle): 24 provider_name = "subsynchro" 25 hash_verifiable = False 26 27 def __init__( 28 self, 29 language, 30 release_info, 31 filename, 32 download_url, 33 file_type, 34 matches, 35 ): 36 super(SubsynchroSubtitle, self).__init__( 37 language, hearing_impaired=False, page_link=download_url 38 ) 39 self.download_url = download_url 40 self.language = language 41 self.file_type = file_type 42 self.release_info = release_info 43 self.filename = filename 44 self.release_info = ( 45 release_info if len(release_info) > len(filename) else filename 46 ) 47 self.found_matches = matches 48 49 @property 50 def id(self): 51 return self.download_url 52 53 def get_matches(self, video): 54 self.found_matches |= guess_matches( 55 video, 56 guessit( 57 self.filename, 58 ), 59 ) 60 self.found_matches |= guess_matches( 61 video, 62 guessit( 63 self.release_info, 64 ), 65 ) 66 return self.found_matches 67 68 69class SubsynchroProvider(Provider): 70 """Subsynchro Provider""" 71 72 languages = {Language.fromalpha2(l) for l in ["fr"]} 73 language_list = list(languages) 74 video_types = (Movie,) 75 76 def initialize(self): 77 self.session = Session() 78 self.session.headers = {"User-Agent": "Bazarr", "Referer": PAGE_URL} 79 80 def terminate(self): 81 self.session.close() 82 83 def query(self, languages, video): 84 language = self.language_list[0] 85 86 params = {"title": video.title, "year": video.year} 87 88 logger.debug("Searching subtitles from params: %s", params) 89 90 result = self.session.get(SERVER_URL, params=params, timeout=10) 91 result.raise_for_status() 92 93 subtitles = [] 94 results = result.json() or {} 95 96 status_ = results.get("status") 97 98 if status_ != 200: 99 logger.debug(f"No subtitles found (status {status_})") 100 return subtitles 101 102 for i in results.get("data", []): 103 matches = set() 104 if any( 105 video.title.lower() in title.lower() 106 for title in (i.get("titre", "n/a"), i.get("titre_original", "n/a")) 107 ): 108 # Year is already set on query 109 matches.update(["title", "year"]) 110 111 subtitles.append( 112 SubsynchroSubtitle( 113 language, 114 i.get("release", "n/a"), 115 i.get("filename", "n/a"), 116 i.get("telechargement"), 117 i.get("fichier"), 118 matches, 119 ) 120 ) 121 return subtitles 122 123 def list_subtitles(self, video, languages): 124 return self.query(languages, video) 125 126 def get_file(self, archive): 127 for name in archive.namelist(): 128 if os.path.split(name)[-1].startswith("."): 129 continue 130 131 if not name.lower().endswith(SUBTITLE_EXTENSIONS): 132 continue 133 134 logger.debug(f"Returning from archive: {name}") 135 return archive.read(name) 136 137 raise APIThrottled("Can not find the subtitle in the zip file") 138 139 def download_subtitle(self, subtitle): 140 logger.debug(f"Downloading subtitle {subtitle.download_url}") 141 142 response = self.session.get( 143 subtitle.download_url, allow_redirects=True, timeout=10 144 ) 145 response.raise_for_status() 146 147 stream = io.BytesIO(response.content) 148 if is_zipfile(stream): 149 logger.debug("Zip file found") 150 subtitle_ = self.get_file(ZipFile(stream)) 151 subtitle.content = fix_line_ending(subtitle_) 152 else: 153 raise APIThrottled(f"Unknown file type: {subtitle.download_url}") 154