PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/script.xbmc.subtitles/resources/lib/services/Sratim/service.py

https://github.com/darknao/script.xbmc.subtitles
Python | 251 lines | 211 code | 6 blank | 34 comment | 18 complexity | 102ed0930bd9abd6107007970994e24c MD5 | raw file
  1. # -*- coding: UTF-8 -*-
  2. #===============================================================================
  3. # Sratim.co.il subtitles service.
  4. # Version: 2.0
  5. #
  6. # Change log:
  7. # 1.1 - Fixed bug with movie search: forgot to replace spaces with + signs.
  8. # 1.2 - Better handling of search timeout (no results returned instead of error)
  9. # 2.0 - Changed RE patterns and links to match new site layout (Thanks Shai Bentin!)
  10. # Fixed TV show subtitles (now navigates site to find requested episode)
  11. #
  12. # Created by: Ori Varon
  13. #===============================================================================
  14. import os, re, xbmc, xbmcgui, string, time, urllib2
  15. from utilities import toOpenSubtitles_two, log
  16. BASE_URL = "http://www.sratim.co.il/"
  17. debug_pretext = ""
  18. #===============================================================================
  19. # Regular expression patterns
  20. #===============================================================================
  21. TV_SEARCH_RESULTS_PATTERN = "<td valign=\"top\"><a href=\"viewseries.php\?id=(\d+)"
  22. SEARCH_RESULTS_PATTERN = "<td valign=\"top\"><a href=\"view.php\?id=(\d+)"
  23. SUBTITLE_LIST_PATTERN = "downloadsubtitle\.php\?id=(?P<fid>\d*).*?subt_lang.*?title=\"(?P<language>.*?)\".*?subtitle_title.*?title=\"(?P<title>.*?)\""
  24. TV_SEASON_PATTERN = "seasonlink_(?P<slink>\d+).*?>(?P<snum>\d+)</a>"
  25. TV_EPISODE_PATTERN = "episodelink_(?P<elink>\d+).*?>(?P<enum>\d+)</a>"
  26. #===============================================================================
  27. # Private utility functions
  28. #===============================================================================
  29. # Returns the corresponding script language name for the Hebrew unicode language
  30. def sratimToScript(language):
  31. languages = {
  32. "עברית" : "Hebrew",
  33. "אנגלית" : "English",
  34. "ערבית" : "Arabic",
  35. "צרפתית" : "French",
  36. "גרמנית" : "German",
  37. "רוסית" : "Russian",
  38. "טורקית" : "Turkish",
  39. "ספרדית" : "Spanish"
  40. }
  41. return languages[language]
  42. # Returns the content of the given URL. Used for both html and subtitle files.
  43. # Based on Titlovi's service.py
  44. def getURL(url):
  45. content = None
  46. log( __name__ ,"Getting url: %s" % (url))
  47. try:
  48. response = urllib2.urlopen(url)
  49. content = response.read()
  50. except:
  51. log( __name__ ,"Failed to get url:%s" % (url))
  52. return content
  53. # The function receives a subtitles page id number, a list of user selected
  54. # languages and the current subtitles list and adds all found subtitles matching
  55. # the language selection to the subtitles list.
  56. def getAllSubtitles(subtitlePageID,languageList,subtitlesList):
  57. # Retrieve the subtitles page (html)
  58. subtitlePage = getURL(BASE_URL + "view.php?id=" + subtitlePageID + "&m=subtitles#")
  59. # Create a list of all subtitles found on page
  60. foundSubtitles = re.findall(SUBTITLE_LIST_PATTERN, subtitlePage)
  61. for (fid,language,title) in foundSubtitles:
  62. # Check if the subtitles found match one of our languages was selected
  63. # by the user
  64. if (sratimToScript(language) in languageList):
  65. subtitlesList.append({'rating': '0', 'sync': False,
  66. 'filename': title, 'subtitle_id': fid,
  67. 'language_flag': 'flags/' + \
  68. toOpenSubtitles_two(sratimToScript(language)) + \
  69. '.gif', 'language_name': sratimToScript(language)})
  70. # Same as getAllSubtitles() but receives season and episode numbers and find them.
  71. def getAllTVSubtitles(subtitlePageID,languageList,subtitlesList,season,episode):
  72. # Retrieve the subtitles page (html)
  73. subtitlePage = getURL(BASE_URL + "viewseries.php?id=" + subtitlePageID + "&m=subtitles#")
  74. # Retrieve the requested season
  75. foundSeasons = re.findall(TV_SEASON_PATTERN, subtitlePage)
  76. for (season_link,season_num) in foundSeasons:
  77. if (season_num == season):
  78. # Retrieve the requested episode
  79. subtitlePage = getURL(BASE_URL + "viewseries.php?id=" + subtitlePageID + "&m=subtitles&s="+str(season_link))
  80. foundEpisodes = re.findall(TV_EPISODE_PATTERN, subtitlePage)
  81. for (episode_link,episode_num) in foundEpisodes:
  82. if (episode_num == episode):
  83. subtitlePage = getURL(BASE_URL + "viewseries.php?id=" + subtitlePageID + "&m=subtitles&s="+str(season_link)+"&e="+str(episode_link))
  84. # Create a list of all subtitles found on page
  85. foundSubtitles = re.findall(SUBTITLE_LIST_PATTERN, subtitlePage)
  86. for (fid,language,title) in foundSubtitles:
  87. # Check if the subtitles found match one of our languages was selected
  88. # by the user
  89. if (sratimToScript(language) in languageList):
  90. subtitlesList.append({'rating': '0', 'sync': False,
  91. 'filename': title, 'subtitle_id': fid,
  92. 'language_flag': 'flags/' + \
  93. toOpenSubtitles_two(sratimToScript(language)) + \
  94. '.gif', 'language_name': sratimToScript(language)})
  95. # Extracts the downloaded file and find a new sub/srt file to return.
  96. # Note that Sratim.co.il currently isn't hosting subtitles in .txt format but
  97. # is adding txt info files in their zips, hence not looking for txt.
  98. # Based on Titlovi's service.py
  99. def extractAndFindSub(tempSubDir,tempZipFile):
  100. # Remember the files currently in the folder and their number
  101. files = os.listdir(tempSubDir)
  102. init_filecount = len(files)
  103. filecount = init_filecount
  104. max_mtime = 0
  105. # Determine which is the newest subtitles file in tempSubDir
  106. for file in files:
  107. if (string.split(file,'.')[-1] in ['srt','sub']):
  108. mtime = os.stat(os.path.join(tempSubDir, file)).st_mtime
  109. if mtime > max_mtime:
  110. max_mtime = mtime
  111. init_max_mtime = max_mtime
  112. # Wait 2 seconds so that the unpacked files are at least 1 second newer
  113. time.sleep(2)
  114. # Use XBMC's built-in extractor
  115. xbmc.executebuiltin("XBMC.Extract(" + tempZipFile + "," + tempSubDir +")")
  116. waittime = 0
  117. while ((filecount == init_filecount) and (waittime < 20) and
  118. (init_max_mtime == max_mtime)): # Nothing extracted yet
  119. # Wait 1 second to let the builtin function 'XBMC.extract' unpack
  120. time.sleep(1)
  121. files = os.listdir(tempSubDir)
  122. filecount = len(files)
  123. # Determine if there is a newer file created in tempSubDir
  124. # (indicates that the extraction had completed)
  125. for file in files:
  126. if (string.split(file,'.')[-1] in ['srt','sub']):
  127. mtime = os.stat(os.path.join(tempSubDir, file)).st_mtime
  128. if (mtime > max_mtime):
  129. max_mtime = mtime
  130. waittime = waittime + 1
  131. if waittime == 20:
  132. log( __name__ ,"Failed to unpack subtitles in '%s'" % (tempSubDir))
  133. return ""
  134. else:
  135. log( __name__ ,"Unpacked files in '%s'" % (tempSubDir))
  136. for file in files:
  137. # There could be more subtitle files in tempSubDir, so make sure we
  138. # get the newest subtitle file
  139. if ((string.split(file, '.')[-1] in ['srt', 'sub']) and
  140. (os.stat(os.path.join(tempSubDir, file)).st_mtime >
  141. init_max_mtime)):
  142. log( __name__ ,"Unpacked subtitles file '%s'" % (file))
  143. return os.path.join(tempSubDir, file)
  144. #===============================================================================
  145. # Public interface functions
  146. #===============================================================================
  147. # This function is called when the service is selected through the subtitles
  148. # addon OSD.
  149. # file_original_path -> Original system path of the file playing
  150. # title -> Title of the movie or episode name
  151. # tvshow -> Name of a tv show. Empty if video isn't a tv show (as are season and
  152. # episode)
  153. # year -> Year
  154. # season -> Season number
  155. # episode -> Episode number
  156. # set_temp -> True iff video is http:// stream
  157. # rar -> True iff video is inside a rar archive
  158. # lang1, lang2, lang3 -> Languages selected by the user
  159. def search_subtitles( file_original_path, title, tvshow, year, season, episode, set_temp, rar, lang1, lang2, lang3, stack ): #standard input
  160. subtitlesList = []
  161. # List of user languages - easier to manipulate
  162. languageList = [lang1, lang2, lang3]
  163. msg = ""
  164. # Check if searching for tv show or movie and build the search string
  165. if tvshow:
  166. searchString = tvshow.replace(" ","+")
  167. else:
  168. searchString = title.replace(" ","+")
  169. log( __name__ ,"%s Search string = %s" % (debug_pretext, searchString))
  170. # Retrieve the search results (html)
  171. searchResults = getURL(BASE_URL + "browse.php\?q=" + searchString)
  172. # Search most likely timed out, no results
  173. if (not searchResults):
  174. return subtitlesList, "", "Search timed out, please try again later."
  175. # When searching for episode 1 Sratim.co.il returns episode 1,10,11,12 etc'
  176. # so we need to catch with out pattern the episode and season numbers and
  177. # only retrieve subtitles from the right result pages.
  178. if tvshow:
  179. # Find sratim's subtitle page IDs
  180. subtitleIDs = re.findall(TV_SEARCH_RESULTS_PATTERN,
  181. unicode(searchResults,"utf-8"))
  182. # Go over all the subtitle pages and add results to our list if season
  183. # and episode match
  184. for sid in subtitleIDs:
  185. getAllTVSubtitles(sid,languageList,subtitlesList,season,episode)
  186. else:
  187. # Find sratim's subtitle page IDs
  188. subtitleIDs = re.findall(SEARCH_RESULTS_PATTERN, searchResults)
  189. # Go over all the subtitle pages and add results to our list
  190. for sid in subtitleIDs:
  191. getAllSubtitles(sid,languageList,subtitlesList)
  192. # Standard output -
  193. # subtitles list (list of tuples built in getAllSubtitles),
  194. # session id (e.g a cookie string, passed on to download_subtitles),
  195. # message to print back to the user
  196. return subtitlesList, "", msg
  197. # This function is called when a specific subtitle from the list generated by
  198. # search_subtitles() is selected in the subtitles addon OSD.
  199. # subtitles_list -> Same list returned in search function
  200. # pos -> The selected item's number in subtitles_list
  201. # zip_subs -> Full path of zipsubs.zip located in tmp location, if automatic
  202. # extraction is used (see return values for details)
  203. # tmp_sub_dir -> Temp folder used for both automatic and manual extraction
  204. # sub_folder -> Folder where the sub will be saved
  205. # session_id -> Same session_id returned in search function
  206. def download_subtitles (subtitles_list, pos, zip_subs, tmp_sub_dir, sub_folder, session_id): #standard input
  207. subtitle_id = subtitles_list[pos][ "subtitle_id" ]
  208. language = subtitles_list[pos][ "language_name" ]
  209. url = BASE_URL + "downloadsubtitle.php?id=" + subtitle_id
  210. log( __name__ ,"%s Fetching subtitles using url %s" % (debug_pretext, url))
  211. # Get the file content using geturl()
  212. content = getURL(url)
  213. if content:
  214. # Going to write them to standrad zip file (always zips in sratim)
  215. local_tmp_file = os.path.join(tmp_sub_dir, "zipsubs.zip")
  216. log( __name__ ,"%s Saving subtitles to '%s'" % (debug_pretext, local_tmp_file))
  217. try:
  218. local_file_handle = open(local_tmp_file, "wb")
  219. local_file_handle.write(content)
  220. local_file_handle.close()
  221. except:
  222. log( __name__ ,"%s Failed to save subtitles to '%s'" % (debug_pretext, local_tmp_file))
  223. # Extract the zip file and find the new sub/srt file
  224. subs_file = extractAndFindSub(tmp_sub_dir,local_tmp_file)
  225. # Standard output -
  226. # True iff the file is packed as zip: addon will automatically unpack it.
  227. # language of subtitles,
  228. # Name of subtitles file if not packed (or if we unpacked it ourselves)
  229. return False, language, subs_file