Advertisement
Guest User

Untitled

a guest
Apr 7th, 2017
1,056
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 29.81 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3.  
  4. # OpenSubtitlesDownload.py / Version 3.6
  5. # This software is designed to help you find and download subtitles for your favorite videos!
  6.  
  7. # You can browse the official website:
  8. # https://emericg.github.io/OpenSubtitlesDownload
  9. # You can browse the project's GitHub page:
  10. # https://github.com/emericg/OpenSubtitlesDownload
  11. # Learn much more about OpenSubtitlesDownload.py on its wiki:
  12. # https://github.com/emericg/OpenSubtitlesDownload/wiki
  13.  
  14. # Copyright (c) 2017 by Emeric GRANGE <emeric.grange@gmail.com>
  15. #
  16. # This program is free software: you can redistribute it and/or modify
  17. # it under the terms of the GNU General Public License as published by
  18. # the Free Software Foundation, either version 3 of the License, or
  19. # (at your option) any later version.
  20. #
  21. # This program is distributed in the hope that it will be useful,
  22. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  23. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  24. # GNU General Public License for more details.
  25. #
  26. # You should have received a copy of the GNU General Public License
  27. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  28.  
  29. # Contributors / special thanks:
  30. # jeroenvdw for his work on the 'subtitles automatic selection' and the 'search by filename'
  31. # Gui13 for his work on the arguments parsing
  32. # Tomáš Hnyk <tomashnyk@gmail.com> for his work on the 'multiple language' feature
  33. # Carlos Acedo <carlos@linux-labs.net> for his work on the original script
  34.  
  35. import os
  36. import re
  37. import sys
  38. import struct
  39. import mimetypes
  40. import subprocess
  41. import argparse
  42. import time
  43.  
  44. if sys.version_info >= (3,0):
  45. import shutil
  46. import urllib.request
  47. from xmlrpc.client import ServerProxy, Error
  48. else: # python2
  49. import urllib2
  50. from xmlrpclib import ServerProxy, Error
  51.  
  52. # ==== Opensubtitles.org server settings =======================================
  53. # XML-RPC server domain for opensubtitles.org:
  54. osd_server = ServerProxy('http://api.opensubtitles.org/xml-rpc')
  55.  
  56. # You can use your opensubtitles.org account to avoid "in-subtitles" advertisment and bypass download limits
  57. # Be careful about your password security, it will be stored right here in plain text...
  58. # You can also change opensubtitles.org language, it will be used for error codes and stuff
  59. osd_username = ''
  60. osd_password = ''
  61. osd_language = 'en'
  62.  
  63. # ==== Language settings =======================================================
  64.  
  65. # 1/ Change the search language by using any supported 3-letter (ISO 639-2) language codes:
  66. # > Supported ISO codes: http://www.opensubtitles.org/addons/export_languages.php
  67. # 2/ Search for subtitles in several languages ​​at once by using multiple language codes separated by a comma:
  68. # > Exemple: opt_languages = ['eng,fre']
  69. opt_languages = ['eng']
  70.  
  71. # Write 2-letter language code (ex: _en) at the end of the subtitles file. 'on', 'off' or 'auto'.
  72. # If you are regularly searching for several language at once, you sould use 'on'.
  73. opt_language_suffix = 'auto'
  74. opt_language_separator = '_'
  75.  
  76. # ==== GUI settings ============================================================
  77.  
  78. # Select your GUI. Can be overridden at run time with '--gui=xxx' argument.
  79. # - auto (autodetection, fallback on CLI)
  80. # - gnome (GNOME/GTK based environments, using 'zenity' backend)
  81. # - kde (KDE/Qt based environments, using 'kdialog' backend)
  82. # - cli (Command Line Interface)
  83. opt_gui = 'auto'
  84.  
  85. # Change the subtitles selection GUI size:
  86. opt_gui_width = 720
  87. opt_gui_height = 320
  88.  
  89. # If the search by movie hash fails, search by file name will be used as backup
  90. opt_backup_searchbyname = 'on'
  91.  
  92. # Subtitles selection mode. Can be overridden at run time with '-a' argument.
  93. # - manual (in case of multiple results, let you choose the subtitles you want)
  94. # - auto (automatically select the most downloaded subtitles)
  95. opt_selection_mode = 'manual'
  96.  
  97. # Various GUI options. You can set them to 'on', 'off' or 'auto'.
  98. opt_selection_language = 'auto'
  99. opt_selection_hi = 'auto'
  100. opt_selection_rating = 'off'
  101. opt_selection_count = 'off'
  102.  
  103. # Enables extra output. Can be overridden at run time with '-v' argument.
  104. opt_verbose = 'off'
  105.  
  106. # ==== Super Print =============================================================
  107. # priority: info, warning, error
  108. # title: only for zenity messages
  109. # message: full text, with tags and breaks (tag cleanup for terminal)
  110. # verbose: is this message important?
  111.  
  112. def superPrint(priority, title, message):
  113. """Print messages through terminal, zenity or kdialog"""
  114. if opt_gui == 'gnome':
  115. if title:
  116. subprocess.call(['zenity', '--' + priority, '--title=' + title, '--text=' + message])
  117. else:
  118. subprocess.call(['zenity', '--' + priority, '--text=' + message])
  119. else:
  120. # Clean up formating tags from the zenity messages
  121. message = message.replace("\n\n", "\n")
  122. message = message.replace("<i>", "")
  123. message = message.replace("</i>", "")
  124. message = message.replace("<b>", "")
  125. message = message.replace("</b>", "")
  126. message = message.replace('\\"', '"')
  127.  
  128. # Print message
  129. if opt_gui == 'kde':
  130. if priority == 'warning':
  131. priority = 'sorry'
  132. elif priority == 'info':
  133. priority = 'msgbox'
  134.  
  135. if title:
  136. subprocess.call(['kdialog', '--' + priority, '--title=' + title, '--text=' + message])
  137. else:
  138. subprocess.call(['kdialog', '--' + priority, '--text=' + message])
  139.  
  140. else: # CLI
  141. print(">> " + message)
  142.  
  143. # ==== Check file path & file ==================================================
  144.  
  145. def checkFile(path):
  146. """Check mimetype and/or file extension to detect valid video file"""
  147. if os.path.isfile(path) == False:
  148. superPrint("error", "File type error!", "This is not a file:\n<i>" + path + "</i>")
  149. return False
  150.  
  151. fileMimeType, encoding = mimetypes.guess_type(path)
  152. if fileMimeType == None:
  153. fileExtension = path.rsplit('.', 1)
  154. if fileExtension[1] not in ['avi', 'mp4', 'mov', 'mkv', 'mk3d', 'webm', \
  155. 'ts', 'mts', 'm2ts', 'ps', 'vob', 'evo', 'mpeg', 'mpg', \
  156. 'm1v', 'm2p', 'm2v', 'm4v', 'movhd', 'movx', 'qt', \
  157. 'mxf', 'ogg', 'ogm', 'ogv', 'rm', 'rmvb', 'flv', 'swf', \
  158. 'asf', 'wm', 'wmv', 'wmx', 'divx', 'x264', 'xvid']:
  159. superPrint("error", "File type error!", "This file is not a video (unknown mimetype AND invalid file extension):\n<i>" + path + "</i>")
  160. return False
  161. else:
  162. fileMimeType = fileMimeType.split('/', 1)
  163. if fileMimeType[0] != 'video':
  164. superPrint("error", "File type error!", "This file is not a video (unknown mimetype):\n<i>" + path + "</i>")
  165. return False
  166.  
  167. return True
  168.  
  169. # ==== Hashing algorithm =======================================================
  170. # Infos: http://trac.opensubtitles.org/projects/opensubtitles/wiki/HashSourceCodes
  171. # This particular implementation is coming from SubDownloader: http://subdownloader.net/
  172.  
  173. def hashFile(path):
  174. """Produce a hash for a video file: size + 64bit chksum of the first and
  175. last 64k (even if they overlap because the file is smaller than 128k)"""
  176. try:
  177. longlongformat = 'Q' # unsigned long long little endian
  178. bytesize = struct.calcsize(longlongformat)
  179. format = "<%d%s" % (65536//bytesize, longlongformat)
  180.  
  181. f = open(path, "rb")
  182.  
  183. filesize = os.fstat(f.fileno()).st_size
  184. hash = filesize
  185.  
  186. if filesize < 65536 * 2:
  187. superPrint("error", "File size error!", "File size error while generating hash for this file:\n<i>" + path + "</i>")
  188. return "SizeError"
  189.  
  190. buffer = f.read(65536)
  191. longlongs = struct.unpack(format, buffer)
  192. hash += sum(longlongs)
  193.  
  194. f.seek(-65536, os.SEEK_END) # size is always > 131072
  195. buffer = f.read(65536)
  196. longlongs = struct.unpack(format, buffer)
  197. hash += sum(longlongs)
  198. hash &= 0xFFFFFFFFFFFFFFFF
  199.  
  200. f.close()
  201. returnedhash = "%016x" % hash
  202. return returnedhash
  203.  
  204. except IOError:
  205. superPrint("error", "I/O error!", "Input/Output error while generating hash for this file:\n<i>" + path + "</i>")
  206. return "IOError"
  207.  
  208. # ==== Gnome selection window ==================================================
  209.  
  210. def selectionGnome(subtitlesList):
  211. """Gnome subtitles selection window using zenity"""
  212. searchMode = 'moviehash'
  213. subtitlesSelected = ''
  214. subtitlesItems = ''
  215. columnLn = ''
  216. columnHi = ''
  217. columnRate = ''
  218. columnCount = ''
  219.  
  220. # Generate selection window content
  221. for item in subtitlesList['data']:
  222. if item['MatchedBy'] != 'moviehash':
  223. searchMode = item['MatchedBy']
  224. subtitlesItems += '"' + item['SubFileName'] + '" '
  225. if opt_selection_hi == 'on':
  226. columnHi = '--column="HI" '
  227. if item['SubHearingImpaired'] == '1':
  228. subtitlesItems += '"✔" '
  229. else:
  230. subtitlesItems += '"" '
  231. if opt_selection_language == 'on':
  232. columnLn = '--column="Language" '
  233. subtitlesItems += '"' + item['LanguageName'] + '" '
  234. if opt_selection_rating == 'on':
  235. columnRate = '--column="Rating" '
  236. subtitlesItems += '"' + item['SubRating'] + '" '
  237. if opt_selection_count == 'on':
  238. columnCount = '--column="Downloads" '
  239. subtitlesItems += '"' + item['SubDownloadsCnt'] + '" '
  240.  
  241. # Spawn zenity "list" dialog
  242. if searchMode == 'moviehash':
  243. process_subtitlesSelection = subprocess.Popen('zenity --width=' + str(opt_gui_width) + ' --height=' + str(opt_gui_height) + \
  244. ' --list --title="Synchronized subtitles for: ' + videoTitle + '"' + \
  245. ' --text="<b>Title:</b> ' + videoTitle + '\n<b>Filename:</b> ' + videoFileName + '"' + \
  246. ' --column="Available subtitles (synchronized)" ' + columnHi + columnLn + columnRate + columnCount + subtitlesItems,
  247. shell=True, stdout=subprocess.PIPE)
  248. else:
  249. process_subtitlesSelection = subprocess.Popen('zenity --width=' + str(opt_gui_width) + ' --height=' + str(opt_gui_height) + \
  250. ' --list --title="Subtitles found!"' + \
  251. ' --text="<b>Filename:</b> ' + videoFileName + '\n<b>>> These results comes from search by file name (not using movie hash) and may be unreliable...</b>"' + \
  252. ' --column="Available subtitles" ' + columnHi + columnLn + columnRate + columnCount + subtitlesItems,
  253. shell=True, stdout=subprocess.PIPE)
  254.  
  255. # Get back the result
  256. result_subtitlesSelection = process_subtitlesSelection.communicate()
  257.  
  258. # The results contain a subtitles?
  259. if result_subtitlesSelection[0]:
  260. if sys.version_info >= (3,0):
  261. subtitlesSelected = str(result_subtitlesSelection[0], 'utf-8').strip("\n")
  262. else: # python2
  263. subtitlesSelected = str(result_subtitlesSelection[0]).strip("\n")
  264.  
  265. # Hack against recent zenity version?
  266. if len(subtitlesSelected.split("|")) > 1:
  267. if subtitlesSelected.split("|")[0] == subtitlesSelected.split("|")[1]:
  268. subtitlesSelected = subtitlesSelected.split("|")[0]
  269. else:
  270. if process_subtitlesSelection.returncode == 0:
  271. subtitlesSelected = subtitlesList['data'][0]['SubFileName']
  272.  
  273. # Return the result
  274. return subtitlesSelected
  275.  
  276. # ==== KDE selection window ====================================================
  277.  
  278. def selectionKde(subtitlesList):
  279. """KDE subtitles selection window using kdialog"""
  280. return selectionAuto(subtitlesList)
  281.  
  282. # ==== CLI selection mode ======================================================
  283.  
  284. def selectionCLI(subtitlesList):
  285. """Command Line Interface, subtitles selection inside your current terminal"""
  286. subtitlesIndex = 0
  287. subtitlesItem = ''
  288.  
  289. # Print video infos
  290. print("\n>> Title: " + videoTitle)
  291. print(">> Filename: " + videoFileName)
  292.  
  293. # Print subtitles list on the terminal
  294. print(">> Available subtitles:")
  295. for item in subtitlesList['data']:
  296. subtitlesIndex += 1
  297. subtitlesItem = '"' + item['SubFileName'] + '" '
  298. if opt_selection_hi == 'on':
  299. if item['SubHearingImpaired'] == '1':
  300. subtitlesItem += '> "HI" '
  301. if opt_selection_language == 'on':
  302. subtitlesItem += '> "LanguageName: ' + item['LanguageName'] + '" '
  303. if opt_selection_rating == 'on':
  304. subtitlesItem += '> "SubRating: ' + item['SubRating'] + '" '
  305. if opt_selection_count == 'on':
  306. subtitlesItem += '> "SubDownloadsCnt: ' + item['SubDownloadsCnt'] + '" '
  307. print("\033[93m[" + str(subtitlesIndex) + "]\033[0m " + subtitlesItem)
  308.  
  309. # Ask user selection
  310. print("\033[91m[0]\033[0m Cancel search")
  311. sub_selection = -1
  312. while( sub_selection < 0 or sub_selection > subtitlesIndex ):
  313. try:
  314. sub_selection = int(input(">> Enter your choice (0-" + str(subtitlesIndex) + "): "))
  315. except:
  316. sub_selection = -1
  317.  
  318. # Return the result
  319. if sub_selection == 0:
  320. print("Cancelling search...")
  321. return
  322. else:
  323. return subtitlesList['data'][sub_selection-1]['SubFileName']
  324.  
  325. # ==== Automatic selection mode ================================================
  326.  
  327. def selectionAuto(subtitlesList):
  328. """Automatic subtitles selection using filename match"""
  329.  
  330. videoFileParts = videoFileName.replace('-','.').replace(' ','.').replace('_','.').lower().split('.')
  331. maxScore = -1
  332.  
  333. for subtitle in subtitlesList['data']:
  334. subFileParts = subtitle['SubFileName'].replace('-','.').replace(' ','.').replace('_','.').lower().split('.');
  335. score = 0
  336. if subtitle['MatchedBy'] == 'moviehash':
  337. score = score + 1 # extra point if the sub is found by hash, which is the preferred way to find subs
  338. for subPart in subFileParts:
  339. for filePart in videoFileParts:
  340. if subPart == filePart:
  341. score = score + 1
  342. if score > maxScore:
  343. maxScore = score
  344. subtitlesSelected = subtitle['SubFileName']
  345.  
  346. return subtitlesSelected
  347.  
  348. # ==== Check dependencies ======================================================
  349.  
  350. def dependencyChecker():
  351. """Check the availability of tools used as dependencies"""
  352.  
  353. if sys.version_info >= (3,3):
  354. for tool in ['gunzip', 'wget']:
  355. path = shutil.which(tool)
  356. if path is None:
  357. superPrint("error", "Missing dependency!", "The <b>'" + tool + "'</b> tool is not available, please install it!")
  358. return False
  359.  
  360. return True
  361.  
  362. # ==== Main program (execution starts here) ====================================
  363. # ==============================================================================
  364.  
  365. # ==== Argument parsing
  366.  
  367. # Get OpenSubtitlesDownload.py script path
  368. execPath = str(sys.argv[0])
  369.  
  370. # Setup parser
  371. parser = argparse.ArgumentParser(prog='OpenSubtitlesDownload.py',
  372. description='This software is designed to help you find and download subtitles for your favorite videos!',
  373. formatter_class=argparse.RawTextHelpFormatter)
  374.  
  375. parser.add_argument('-g', '--gui', help="Select the GUI you want from: auto, kde, gnome, cli (default: auto)")
  376. parser.add_argument('-a', '--auto', help="Automatically choose the best subtitles, without human interaction (default: disabled)", action='store_true')
  377. parser.add_argument('-v', '--verbose', help="Enables verbose output (default: disabled)", action='store_true')
  378. parser.add_argument('-l', '--lang', help="Specify the language in which the subtitles should be downloaded (default: eng).\nSyntax:\n-l eng,fre : search in both language\n-l eng -l fre : download both language", nargs='?', action='append')
  379. parser.add_argument('filePathListArg', help="The video file(s) for which subtitles should be searched and downloaded", nargs='+')
  380.  
  381. # Only use ArgumentParser if we have arguments...
  382. if len(sys.argv) > 1:
  383.  
  384. # Parsing
  385. result = parser.parse_args()
  386.  
  387. # Handle results
  388. if result.gui:
  389. opt_gui = result.gui
  390. if result.auto:
  391. opt_selection_mode = 'auto'
  392. if result.verbose:
  393. opt_verbose = 'on'
  394. if result.lang:
  395. if opt_languages != result.lang:
  396. opt_languages = result.lang
  397. opt_selection_language = 'on'
  398. if opt_language_suffix != 'off':
  399. opt_language_suffix = 'on'
  400.  
  401. # ==== GUI auto detection
  402.  
  403. if opt_gui == 'auto':
  404. # Note: "ps cax" only output the first 15 characters of the executable's names
  405. ps = str(subprocess.Popen(['ps', 'cax'], stdout=subprocess.PIPE).communicate()[0]).split('\n')
  406. for line in ps:
  407. if ('gnome-session' in line) or ('cinnamon-sessio' in line) or ('mate-session' in line) or ('xfce4-session' in line):
  408. opt_gui = 'gnome'
  409. break
  410. elif ('ksmserver' in line):
  411. opt_gui = 'kde'
  412. break
  413.  
  414. # Fallback
  415. if opt_gui not in ['gnome', 'kde', 'cli']:
  416. opt_gui = 'cli'
  417. opt_selection_mode = 'auto'
  418. print("Unknown GUI, falling back to an automatic CLI mode")
  419.  
  420. # ==== Check for the necessary tools (must be done after GUI auto detection)
  421.  
  422. if dependencyChecker() == False:
  423. sys.exit(1)
  424.  
  425. # ==== Get valid video paths
  426.  
  427. videoPathList = []
  428.  
  429. if 'result' in locals():
  430. # Go through the paths taken from arguments, and extract only valid video paths
  431. for i in result.filePathListArg:
  432. if checkFile(os.path.abspath(i)):
  433. videoPathList.append(os.path.abspath(i))
  434. else:
  435. # No filePathListArg from the arg parser? Try selected file(s) from nautilus environment variables:
  436. # $NAUTILUS_SCRIPT_SELECTED_FILE_PATHS (only for local storage)
  437. # $NAUTILUS_SCRIPT_SELECTED_URIS
  438. if opt_gui == 'gnome':
  439. # Try to get file(s) provided by nautilus
  440. filePathListEnv = os.environ.get('NAUTILUS_SCRIPT_SELECTED_URIS')
  441. if filePathListEnv != None:
  442. # Check file(s) type and validity
  443. for filePath in filePathListEnv.splitlines():
  444. # Work a little bit of magic (Make sure we have a clean and absolute path, even from an URI)
  445. filePath = os.path.abspath(os.path.basename(filePath))
  446. if sys.version_info >= (3,0):
  447. filePath = urllib.request.url2pathname(filePath)
  448. else: # python2
  449. filePath = urllib2.url2pathname(filePath)
  450. if checkFile(filePath):
  451. videoPathList.append(filePath)
  452.  
  453. # ==== Instances dispatcher
  454.  
  455. # If videoPathList is empty, abort!
  456. if len(videoPathList) == 0:
  457. parser.print_help()
  458. sys.exit(1)
  459.  
  460. # The first video file will be processed by this instance
  461. videoPath = videoPathList[0]
  462. videoPathList.pop(0)
  463.  
  464. # The remaining file(s) are dispatched to new instance(s) of this script
  465. for videoPathDispatch in videoPathList:
  466.  
  467. # Handle current options
  468. command = execPath + " -g " + opt_gui
  469. if opt_selection_mode == 'auto':
  470. command += " -a "
  471. if opt_verbose == 'on':
  472. command += " -v "
  473. if not (len(opt_languages) == 1 and opt_languages[0] == 'eng'):
  474. for resultlangs in opt_languages:
  475. command += " -l " + resultlangs
  476.  
  477. # Split command string
  478. command_splitted = command.split()
  479. # The videoPath filename can contain spaces, but we do not want to split that, so add it right after the split
  480. command_splitted.append(videoPathDispatch)
  481.  
  482. if opt_gui == 'cli' and opt_selection_mode == 'manual':
  483. # Synchronous call
  484. process_videoDispatched = subprocess.call(command_splitted)
  485. else:
  486. # Asynchronous call
  487. process_videoDispatched = subprocess.Popen(command_splitted)
  488.  
  489. # Do not spawn too many instances at the same time
  490. time.sleep(0.33)
  491.  
  492. # ==== Search and download subtitles
  493.  
  494. try:
  495. try:
  496. # Connection to opensubtitles.org server
  497. session = osd_server.LogIn(osd_username, osd_password, osd_language, 'opensubtitles-download 3.6')
  498. except Exception:
  499. # Retry once, it could be a momentary overloaded server?
  500. time.sleep(3)
  501. try:
  502. # Connection to opensubtitles.org server
  503. session = osd_server.LogIn(osd_username, osd_password, osd_language, 'opensubtitles-download 3.6')
  504. except Exception:
  505. # Failed connection attempts?
  506. superPrint("error", "Connection error!", "Unable to reach opensubtitles.org servers!\n\nPlease check:\n- Your Internet connection status\n- www.opensubtitles.org availability\n- Your downloads limit (200 subtitles per 24h)\nThe subtitles search and download service is powered by opensubtitles.org. Be sure to donate if you appreciate the service provided!")
  507. sys.exit(1)
  508.  
  509. # Connection refused?
  510. if session['status'] != '200 OK':
  511. superPrint("error", "Connection error!", "Opensubtitles.org servers refused the connection: " + session['status'] + ".\n\nPlease check:\n- Your Internet connection status\n- www.opensubtitles.org availability\n- Your 200 downloads per 24h limit")
  512. sys.exit(1)
  513.  
  514. searchLanguage = 0
  515. searchLanguageResult = 0
  516. videoTitle = 'Unknown video title'
  517. videoHash = hashFile(videoPath)
  518. videoSize = os.path.getsize(videoPath)
  519. videoFileName = os.path.basename(videoPath)
  520.  
  521. # Count languages marked for this search
  522. for SubLanguageID in opt_languages:
  523. searchLanguage += len(SubLanguageID.split(','))
  524.  
  525. # Search for available subtitles using file hash and size
  526. for SubLanguageID in opt_languages:
  527. searchList = []
  528. searchList.append({'sublanguageid':SubLanguageID, 'moviehash':videoHash, 'moviebytesize':str(videoSize)})
  529. try:
  530. subtitlesList = osd_server.SearchSubtitles(session['token'], searchList)
  531. except Exception:
  532. # Retry once, we are already connected, the server is probably momentary overloaded
  533. time.sleep(3)
  534. try:
  535. subtitlesList = osd_server.SearchSubtitles(session['token'], searchList)
  536. except Exception:
  537. superPrint("error", "Search error!", "Unable to reach opensubtitles.org servers!\n<b>Search error</b>")
  538.  
  539. # No results using search by hash? Retry with filename
  540. if (not subtitlesList['data']) and (opt_backup_searchbyname == 'on'):
  541. searchList = []
  542. searchList.append({'sublanguageid':SubLanguageID, 'query':videoFileName})
  543. try:
  544. subtitlesList = osd_server.SearchSubtitles(session['token'], searchList)
  545. except Exception:
  546. # Retry once, we are already connected, the server is probably momentary overloaded
  547. time.sleep(3)
  548. try:
  549. subtitlesList = osd_server.SearchSubtitles(session['token'], searchList)
  550. except Exception:
  551. superPrint("error", "Search error!", "Unable to reach opensubtitles.org servers!\n<b>Search error</b>")
  552. else:
  553. opt_backup_searchbyname = 'off'
  554.  
  555. # Parse the results of the XML-RPC query
  556. if subtitlesList['data']:
  557.  
  558. # Mark search as successful
  559. searchLanguageResult += 1
  560. subtitlesSelected = ''
  561.  
  562. # If there is only one subtitles, which wasn't found by filename, auto-select it
  563. if (len(subtitlesList['data']) == 1) and (opt_backup_searchbyname == 'off'):
  564. subtitlesSelected = subtitlesList['data'][0]['SubFileName']
  565.  
  566. # Get video title
  567. videoTitle = subtitlesList['data'][0]['MovieName']
  568.  
  569. # Title and filename may need string sanitizing to avoid zenity/kdialog handling errors
  570. if opt_gui != 'cli':
  571. videoTitle = videoTitle.replace('"', '\\"')
  572. videoTitle = videoTitle.replace("'", "\'")
  573. videoTitle = videoTitle.replace('`', '\`')
  574. videoTitle = videoTitle.replace("&", "&amp;")
  575. videoFileName = videoFileName.replace('"', '\\"')
  576. videoFileName = videoFileName.replace("'", "\'")
  577. videoFileName = videoFileName.replace('`', '\`')
  578. videoFileName = videoFileName.replace("&", "&amp;")
  579.  
  580. # If there is more than one subtitles and opt_selection_mode != 'auto',
  581. # then let the user decide which one will be downloaded
  582. if subtitlesSelected == '':
  583. # Automatic subtitles selection?
  584. if opt_selection_mode == 'auto':
  585. subtitlesSelected = selectionAuto(subtitlesList)
  586. else:
  587. # Go through the list of subtitles and handle 'auto' settings activation
  588. for item in subtitlesList['data']:
  589. if opt_selection_language == 'auto':
  590. if searchLanguage > 1:
  591. opt_selection_language = 'on'
  592. if opt_selection_hi == 'auto':
  593. if item['SubHearingImpaired'] == '1':
  594. opt_selection_hi = 'on'
  595. if opt_selection_rating == 'auto':
  596. if item['SubRating'] != '0.0':
  597. opt_selection_rating = 'on'
  598. if opt_selection_count == 'auto':
  599. opt_selection_count = 'on'
  600.  
  601. # Spaw selection window
  602. if opt_gui == 'gnome':
  603. subtitlesSelected = selectionGnome(subtitlesList)
  604. elif opt_gui == 'kde':
  605. subtitlesSelected = selectionKde(subtitlesList)
  606. else: # CLI
  607. subtitlesSelected = selectionCLI(subtitlesList)
  608.  
  609. # If a subtitles has been selected at this point, download it!
  610. if subtitlesSelected:
  611. subIndex = 0
  612. subIndexTemp = 0
  613.  
  614. # Select the subtitles file to download
  615. for item in subtitlesList['data']:
  616. if item['SubFileName'] == subtitlesSelected:
  617. subIndex = subIndexTemp
  618. break
  619. else:
  620. subIndexTemp += 1
  621.  
  622. subLangId = opt_language_separator + subtitlesList['data'][subIndex]['ISO639']
  623. subLangName = subtitlesList['data'][subIndex]['LanguageName']
  624. subURL = subtitlesList['data'][subIndex]['SubDownloadLink']
  625. subPath = videoPath.rsplit('.', 1)[0] + '.' + subtitlesList['data'][subIndex]['SubFormat']
  626.  
  627. # Write language code into the filename?
  628. if ((opt_language_suffix == 'on') or
  629. (opt_language_suffix == 'auto' and searchLanguageResult > 1)):
  630. subPath = videoPath.rsplit('.', 1)[0] + subLangId + '.' + subtitlesList['data'][subIndex]['SubFormat']
  631.  
  632. # Escape non-alphanumeric characters from the subtitles path
  633. subPath = re.escape(subPath)
  634.  
  635. # Download and unzip the selected subtitles (with progressbar)
  636. if opt_gui == 'gnome':
  637. process_subtitlesDownload = subprocess.call("(wget -q -O - " + subURL + " | gunzip > " + subPath + ") 2>&1" + ' | (zenity --auto-close --progress --pulsate --title="Downloading subtitles, please wait..." --text="Downloading <b>' + subtitlesList['data'][subIndex]['LanguageName'] + '</b> subtitles for <b>' + videoTitle + '</b>...")', shell=True)
  638. elif opt_gui == 'kde':
  639. process_subtitlesDownload = subprocess.call("(wget -q -O - " + subURL + " | gunzip > " + subPath + ") 2>&1", shell=True)
  640. else: # CLI
  641. print(">> Downloading '" + subtitlesList['data'][subIndex]['LanguageName'] + "' subtitles for '" + videoTitle + "'")
  642. process_subtitlesDownload = subprocess.call("wget -nv -O - " + subURL + " | gunzip > " + subPath, shell=True)
  643.  
  644. # If an error occur, say so
  645. if process_subtitlesDownload != 0:
  646. superPrint("error", "Subtitling error!", "An error occurred while downloading or writing <b>" + subtitlesList['data'][subIndex]['LanguageName'] + "</b> subtitles for <b>" + videoTitle + "</b>.")
  647. osd_server.LogOut(session['token'])
  648. sys.exit(1)
  649.  
  650. # Print a message if no subtitles have been found, for any of the languages
  651. if searchLanguageResult == 0:
  652. superPrint("info", "No subtitles found for: " + videoFileName, '<b>No subtitles found</b> for this video:\n<i>' + videoFileName + '</i>')
  653.  
  654. # Disconnect from opensubtitles.org server, then exit
  655. if session['token']: osd_server.LogOut(session['token'])
  656. sys.exit(0)
  657.  
  658. except (OSError, IOError, RuntimeError, TypeError, NameError, KeyError):
  659.  
  660. # Do not warn about remote disconnection # bug/feature of python 3.5
  661. if "http.client.RemoteDisconnected" in str(sys.exc_info()[0]):
  662. sys.exit(1)
  663.  
  664. # An unknown error occur, let's apologize before exiting
  665. superPrint("error", "Unknown error!", "OpenSubtitlesDownload encountered an <b>unknown error</b>, sorry about that...\n\n" + \
  666. "Error: <b>" + str(sys.exc_info()[0]).replace('<', '[').replace('>', ']') + "</b>\n\n" + \
  667. "Just to be safe, please check:\n- www.opensubtitles.org availability\n- Your downloads limit (200 subtitles per 24h)\n- Your Internet connection status\n- That are using the latest version of this software ;-)")
  668.  
  669. # Disconnect from opensubtitles.org server, then exit
  670. if session['token']: osd_server.LogOut(session['token'])
  671.  
  672. sys.exit(1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement