Advertisement
Guest User

Untitled

a guest
May 7th, 2018
268
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.34 KB | None | 0 0
  1. # -*- coding: utf-8 -*-
  2. import httplib
  3. import json
  4. import os
  5. import random
  6. import sys
  7. import time
  8. import traceback
  9. import urllib
  10. from collections import defaultdict
  11. from datetime import datetime, timedelta
  12. from urlparse import urlparse
  13.  
  14. import xbmc
  15. import xbmcaddon
  16. import xbmcgui
  17. import xbmcplugin
  18. from xbmcplugin import addDirectoryItem
  19.  
  20. import ivysilani
  21.  
  22. ###############################################################################
  23. REMOTE_DBG = False
  24. # append pydev remote debugger
  25. if REMOTE_DBG:
  26. try:
  27. # sys.path.append(os.environ['HOME'] + r'/.kodi/system/python/Lib/pysrc') # Linux
  28. sys.path.append("C:\\eclipse\\plugins\\org.python.pydev_4.0.0.201504132356\\pysrc") # Windows
  29. import pydevd
  30.  
  31. pydevd.settrace('localhost', port=5678, stdoutToServer=True, stderrToServer=True)
  32. except ImportError:
  33. sys.stderr.write("Error: Could not load pysrc!")
  34. sys.exit(1)
  35. ###############################################################################
  36.  
  37. params = None
  38. _addon_ = xbmcaddon.Addon('plugin.video.ivysilani')
  39. _lang_ = _addon_.getLocalizedString
  40. _scriptname_ = _addon_.getAddonInfo('name')
  41. _version_ = _addon_.getAddonInfo('version')
  42. _first_error_ = False
  43. _send_errors_ = False
  44.  
  45.  
  46. ###############################################################################
  47. def log(msg, level=xbmc.LOGDEBUG):
  48. if type(msg).__name__ == 'unicode':
  49. msg = msg.encode('utf-8')
  50. xbmc.log("[%s] %s" % (_scriptname_, msg.__str__()), level)
  51.  
  52.  
  53. def logDbg(msg):
  54. log(msg, level=xbmc.LOGDEBUG)
  55.  
  56.  
  57. def logErr(msg):
  58. log(msg, level=xbmc.LOGERROR)
  59.  
  60.  
  61. ###############################################################################
  62.  
  63. def _exception_log(exc_type, exc_value, exc_traceback):
  64. global _first_error_
  65. global _send_errors_
  66. logErr(traceback.format_exception(exc_type, exc_value, exc_traceback))
  67. xbmcgui.Dialog().notification(_scriptname_, _toString(exc_value), xbmcgui.NOTIFICATION_ERROR)
  68. if not _first_error_:
  69. if xbmcgui.Dialog().yesno(_scriptname_, _lang_(30500), _lang_(30501)):
  70. _addon_.setSetting("send_errors", "true")
  71. _send_errors_ = (_addon_.getSetting('send_errors') == "true")
  72. _addon_.setSetting("first_error", "true")
  73. _first_error_ = (_addon_.getSetting('first_error') == "true")
  74. if _send_errors_:
  75. if _sendError(params, exc_type, exc_value, exc_traceback):
  76. xbmcgui.Dialog().notification(_scriptname_, _lang_(30502), xbmcgui.NOTIFICATION_INFO)
  77. else:
  78. xbmcgui.Dialog().notification(_scriptname_, _lang_(30503), xbmcgui.NOTIFICATION_ERROR)
  79.  
  80.  
  81. try:
  82. # First run
  83. if not (_addon_.getSetting("settings_init_done") == "true"):
  84. DEFAULT_SETTING_VALUES = {"quality": "576p",
  85. "auto_quality": "true",
  86. "quality_fallback": "true",
  87. "auto_view_mode": "true",
  88. "send_errors": "false",
  89. "show_subtitles": "false"}
  90. for setting in DEFAULT_SETTING_VALUES.keys():
  91. val = _addon_.getSetting(setting)
  92. if not val:
  93. _addon_.setSetting(setting, DEFAULT_SETTING_VALUES[setting])
  94. _addon_.setSetting("settings_init_done", "true")
  95. ###############################################################################
  96. _auto_quality_ = (_addon_.getSetting('auto_quality') == "true")
  97. _quality_ = _addon_.getSetting('quality')
  98. _quality_fallback_ = (_addon_.getSetting('quality_fallback') == "true")
  99. _first_error_ = (_addon_.getSetting('first_error') == "true")
  100. _send_errors_ = (_addon_.getSetting('send_errors') == "true")
  101. _auto_view_mode_ = (_addon_.getSetting('auto_view_mode') == "true")
  102. _show_subtitles_ = (_addon_.getSetting('show_subtitles') == "true")
  103. _subtitles_path_ = xbmc.translatePath(os.path.join(_addon_.getAddonInfo('profile'), "subtitles.str"))
  104. _icon_ = xbmc.translatePath(os.path.join(_addon_.getAddonInfo('path'), 'icon.png'))
  105. _next_ = xbmc.translatePath(os.path.join(_addon_.getAddonInfo('path'), 'resources', 'media', 'next.png'))
  106. _previous_ = xbmc.translatePath(os.path.join(_addon_.getAddonInfo('path'), 'resources', 'media', 'previous.png'))
  107. _fanArt = xbmc.translatePath(os.path.join(_addon_.getAddonInfo('path'), 'resources', 'media', 'fanart1.png'))
  108. _handle_ = int(sys.argv[1])
  109. _baseurl_ = sys.argv[0]
  110.  
  111. well_known_error_messages = [('Programme not found!', 30550),
  112. ('Playlisturl is empty!', 30550),
  113. ('Non playable programme!', 30550),
  114. ('error_nonEncoded', 30551)]
  115. SKIN_DATA = defaultdict(list, {
  116. 'skin.confluence': [
  117. {'name': 'List', 'id': 50},
  118. {'name': 'Big List', 'id': 51},
  119. {'name': 'Thumbnail', 'id': 500},
  120. {'name': 'Media info', 'id': 504},
  121. {'name': 'Media info 2', 'id': 503}
  122. ]
  123. })
  124.  
  125.  
  126. def _toString(text):
  127. if type(text).__name__ == 'unicode':
  128. output = text.encode('utf-8')
  129. else:
  130. output = str(text)
  131. return output
  132.  
  133.  
  134. def _fanart():
  135. fanartFolder = os.path.join(_addon_.getAddonInfo('path'), 'resources', 'media', 'fanart')
  136. listedDir = os.listdir(fanartFolder)
  137. r = random.randint(0, len(listedDir) - 1)
  138. selected = os.path.join(_addon_.getAddonInfo('path'), 'resources', 'media', 'fanart', listedDir[r])
  139. return xbmc.translatePath(selected)
  140.  
  141.  
  142. def _setViewMode(view_mode):
  143. if _auto_view_mode_:
  144. skin_dir = xbmc.getSkinDir()
  145. for sd in SKIN_DATA[skin_dir]:
  146. if sd['name'] == view_mode:
  147. view_mode_id = sd['id']
  148. xbmc.executebuiltin('Container.SetViewMode(%d)' % view_mode_id)
  149.  
  150.  
  151. def mainMenu():
  152. spotlight_labels = {"tipsMain": 30019,
  153. "topDay": 30020,
  154. "topWeek": 30021,
  155. "tipsNote": 30022,
  156. "tipsArchive": 30023,
  157. "watching": 30024}
  158. addDirectoryItem(_lang_(30015), _baseurl_ + "?menu=live")
  159. addDirectoryItem(_lang_(30016), _baseurl_ + "?menu=byDate")
  160. addDirectoryItem(_lang_(30017), _baseurl_ + "?menu=byLetter")
  161. addDirectoryItem(_lang_(30018), _baseurl_ + "?menu=byGenre")
  162. for spotlight in ivysilani.SPOTLIGHTS:
  163. addDirectoryItem(_lang_(spotlight_labels[spotlight.ID]), _baseurl_ + "?menu=" + spotlight.ID)
  164. xbmcplugin.endOfDirectory(_handle_, updateListing=True)
  165.  
  166.  
  167. def addDirectoryItem(label, url, ID=None, related=False, episodes=False, plot=None, title=None, date=None,
  168. duration=None,
  169. icon=_icon_, image=None, fanart=None, isFolder=True):
  170. li = xbmcgui.ListItem(label)
  171. if not title:
  172. title = label
  173. liVideo = {'title': title}
  174. if duration:
  175. liVideo['duration'] = duration
  176. if plot:
  177. liVideo['plot'] = plot
  178. if date:
  179. dt = datetime.fromtimestamp(time.mktime(time.strptime(date, "%d. %m. %Y")))
  180. liVideo['premiered'] = dt.strftime("%Y-%m-%d")
  181. if image:
  182. li.setThumbnailImage(image)
  183. li.setIconImage(icon)
  184. li.setInfo("video", liVideo)
  185. if not fanart:
  186. fanart = _fanart()
  187. li.setProperty('fanart_image', fanart)
  188. if episodes:
  189. url = _baseurl_ + "?episodes=" + ID
  190. if ID:
  191. cm = []
  192. cm.append((_lang_(30013), "XBMC.Container.Update(" + _baseurl_ + "?play=" + ID + "&skip_auto=1)"))
  193. if related:
  194. cm.append((_lang_(30003), "XBMC.Container.Update(" + _baseurl_ + "?related=" + ID + ")"))
  195. cm.append((_lang_(30004), "XBMC.Container.Update(" + _baseurl_ + "?episodes=" + ID + ")"))
  196. cm.append((_lang_(30005), "XBMC.Container.Update(" + _baseurl_ + "?bonuses=" + ID + ")"))
  197. li.addContextMenuItems(cm)
  198. xbmcplugin.addDirectoryItem(handle=_handle_, url=url, listitem=li, isFolder=isFolder)
  199.  
  200.  
  201. def listProgrammelist(programmelist, episodes=False):
  202. xbmcplugin.setContent(_handle_, "episodes")
  203. pList = programmelist.list()
  204. for item in pList:
  205. plot = None
  206. date = None
  207. if hasattr(item, "synopsis") and item.synopsis:
  208. plot = item.synopsis
  209. url = _baseurl_ + "?play=" + item.ID
  210. title = item.title
  211. if hasattr(item, 'time'):
  212. title = "[" + item.time + "] " + title
  213. active = True
  214. if hasattr(item, 'active'):
  215. active = (item.active == '1')
  216. if active:
  217. addDirectoryItem(title, url, ID=item.ID, related=True, episodes=episodes, plot=plot, date=date,
  218. image=item.imageURL)
  219. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  220.  
  221.  
  222. def playProgramme(ID, skipAutoQuality=False):
  223. programme = ivysilani.Programme(ID)
  224. if _auto_quality_ and not skipAutoQuality:
  225. u = autoSelectQuality(programme)
  226. if u:
  227. playUrl(_toString(programme.title), u, programme.imageURL)
  228. return
  229. for quality in programme.available_qualities():
  230. url = programme.url(quality)
  231. addDirectoryItem(quality.label(), url=url, title=_toString(programme.title), image=programme.imageURL,
  232. isFolder=False)
  233. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  234.  
  235.  
  236. def autoSelectQuality(playable):
  237. setting_quality = ivysilani.Quality(_quality_)
  238. url = playable.url(setting_quality)
  239. if url or not _quality_fallback_:
  240. return url
  241. all_qualities = ["1080p", "720p", "576p", "404p", "288p", "144p"]
  242. for q in all_qualities:
  243. quality = ivysilani.Quality(q)
  244. if setting_quality.height < quality.height:
  245. continue
  246. url = playable.url(quality)
  247. if url:
  248. return url
  249. return None
  250.  
  251.  
  252. def listLiveChannels():
  253. xbmcplugin.setContent(_handle_, "episodes")
  254. for liveChannel in ivysilani.LIVE_CHANNELS:
  255. title = _toString(liveChannel.title)
  256. live_programme = liveChannel.programme()
  257. if hasattr(live_programme, "title") and live_programme.title:
  258. title += ": " + _toString(live_programme.title)
  259. plot = None
  260. if hasattr(live_programme, "time") and live_programme.time:
  261. plot = _toString(_lang_(30001)) + " " + _toString(live_programme.time)
  262. if hasattr(live_programme, "elapsedPercentage") and live_programme.elapsedPercentage:
  263. plot += " (" + _toString(live_programme.elapsedPercentage) + "%)"
  264. if hasattr(live_programme, "synopsis") and live_programme.synopsis:
  265. plot += "\n\n" + _toString(live_programme.synopsis)
  266. if hasattr(live_programme, "ID") and live_programme.ID:
  267. try:
  268. url = _baseurl_ + "?play=" + liveChannel.ID
  269. addDirectoryItem(title, url, ID=liveChannel.ID, plot=plot, image=live_programme.imageURL)
  270. continue
  271. except:
  272. pass
  273. title += " [" + _toString(_lang_(30002)) + "]"
  274. url = _baseurl_ + "?menu=live"
  275. image = None
  276. if hasattr(live_programme, 'imageURL') and live_programme.imageURL:
  277. image = live_programme.imageURL
  278. addDirectoryItem(title, url, image=image)
  279. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  280.  
  281.  
  282. def playUrl(title, url, image, subtitles=False):
  283. try:
  284. xlistitem = xbmcgui.ListItem(title, iconImage="DefaultVideo.png", path=url)
  285. except:
  286. xlistitem = xbmcgui.ListItem(title, iconImage="DefaultVideo.png", )
  287. xlistitem.setInfo("video", { "Title": title })
  288.  
  289. playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
  290. playlist.clear()
  291. page = urllib.urlopen(url)
  292. playlist.add(page.geturl(), xlistitem)
  293.  
  294. player_type = xbmc.PLAYER_CORE_AUTO
  295. xbmcPlayer = xbmc.Player(player_type)
  296. xbmcPlayer.play(playlist)
  297. if subtitles:
  298. while not player.isPlaying():
  299. xbmc.sleep(2000)
  300. player.setSubtitles(_subtitles_path_)
  301.  
  302. def playPlayable(playable, skipAutoQuality=False, forceQuality=None):
  303. image = xbmc.translatePath(os.path.join(_addon_.getAddonInfo('path'), 'resources', 'media',
  304. 'logo_' + playable.ID.lower() + '_400x225.png'))
  305. if isinstance(playable, ivysilani.Programme):
  306. image = playable.imageURL
  307. if _auto_quality_ and not skipAutoQuality and not forceQuality:
  308. url = autoSelectQuality(playable)
  309. if url:
  310. playUrl(playable.title, url, image,
  311. subtitles=getattr(playable, 'subs_available', False))
  312. return
  313. if forceQuality:
  314. quality = ivysilani.Quality(forceQuality)
  315. url = playable.url(quality)
  316. if url:
  317. playUrl(playable.title, url, image,
  318. subtitles=getattr(playable, 'subs_available', False))
  319. return
  320. qualities = playable.available_qualities()
  321. for quality in qualities:
  322. addDirectoryItem(quality.label(), url=_baseurl_ + "?force_quality=" + str(quality) + "&play=" + playable.ID,
  323. title=_toString(playable.title), image=image, isFolder=False)
  324. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  325.  
  326.  
  327. def playLiveChannel(liveChannel, skipAutoQuality=False):
  328. image = xbmc.translatePath(os.path.join(_addon_.getAddonInfo('path'), 'resources', 'media',
  329. 'logo_' + liveChannel.ID.lower() + '_400x225.png'))
  330. if _auto_quality_ and not skipAutoQuality:
  331. url = autoSelectQuality(liveChannel)
  332. if url:
  333. playUrl(liveChannel.title, url, image)
  334. return
  335. qualities = liveChannel.available_qualities()
  336. for quality in qualities:
  337. url = liveChannel.url(quality)
  338. addDirectoryItem(quality.label(), url=url, title=_toString(liveChannel.title), image=image, isFolder=False)
  339. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  340.  
  341.  
  342. def selectLiveChannel(ID):
  343. for liveChannel in ivysilani.LIVE_CHANNELS:
  344. if liveChannel.ID == ID:
  345. return liveChannel
  346.  
  347.  
  348. def listAlphabet():
  349. for letter in ivysilani.alphabet():
  350. addDirectoryItem(letter.title, _baseurl_ + "?letter=" + urllib.quote_plus(_toString(letter.link)))
  351. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  352.  
  353.  
  354. def listGenres():
  355. for genre in ivysilani.genres():
  356. addDirectoryItem(genre.title, _baseurl_ + "?genre=" + urllib.quote_plus(_toString(genre.link)))
  357. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  358.  
  359.  
  360. def listDates():
  361. day_names = []
  362. for i in range(7):
  363. day_names.append(_lang_(31000 + i))
  364. dt = datetime.now();
  365. min_date = datetime.fromtimestamp(time.mktime(time.strptime(ivysilani.DATE_MIN, "%Y-%m-%d")))
  366. while dt > min_date:
  367. pretty_date = day_names[dt.weekday()] + " " + dt.strftime("%d.%m.%Y")
  368. formated_date = dt.strftime("%Y-%m-%d")
  369. addDirectoryItem(pretty_date, _baseurl_ + "?date=" + urllib.quote_plus(formated_date))
  370. dt = dt - timedelta(days=1)
  371. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  372.  
  373.  
  374. def listChannelsForDate(date):
  375. for channel in ivysilani.LIVE_CHANNELS:
  376. image = xbmc.translatePath(os.path.join(_addon_.getAddonInfo('path'), 'resources', 'media',
  377. 'logo_' + channel.ID.lower() + '_400x225.png'))
  378. url = _baseurl_ + "?date=" + urllib.quote_plus(date) + "&channel=" + channel.ID
  379. addDirectoryItem(_toString(channel.title), url, image=image)
  380. xbmcplugin.endOfDirectory(_handle_, updateListing=False, cacheToDisc=False)
  381.  
  382.  
  383. def listContext(what, ID, page):
  384. xbmcplugin.setContent(_handle_, "episodes")
  385. programme = ivysilani.Programme(ID)
  386. l = []
  387. if what == "related":
  388. l = programme.related(page)
  389. elif what == "episodes":
  390. l = programme.episodes(page)
  391. elif what == "bonuses":
  392. l = programme.bonuses(page)
  393. if page > 1:
  394. addDirectoryItem('[B]<< ' + _lang_(30007) + '[/B]',
  395. _baseurl_ + "?" + what + "=" + ID + "&page=" + str(page - 1), image=_previous_)
  396. for item in l:
  397. plot = None
  398. if hasattr(item, "synopsis") and item.synopsis:
  399. plot = item.synopsis
  400. addDirectoryItem(item.title, _baseurl_ + "?play=" + item.ID, ID=item.ID, related=True, plot=plot,
  401. image=item.imageURL)
  402. if len(l) == ivysilani.PAGE_SIZE:
  403. addDirectoryItem('[B]' + _lang_(30006) + ' >>[/B]',
  404. _baseurl_ + "?" + what + "=" + ID + "&page=" + str(page + 1), image=_next_)
  405. _setViewMode("Media info")
  406. xbmcplugin.endOfDirectory(_handle_, updateListing=(page > 1), cacheToDisc=False)
  407.  
  408.  
  409. def _sendError(params, exc_type, exc_value, exc_traceback):
  410. status = "no status"
  411. try:
  412. conn = httplib.HTTPSConnection('script.google.com')
  413. req_data = urllib.urlencode(
  414. {'addon': _scriptname_, 'version': _version_, 'params': _toString(params), 'type': exc_type,
  415. 'value': exc_value,
  416. 'traceback': _toString(traceback.format_exception(exc_type, exc_value, exc_traceback))})
  417. headers = {"Content-type": "application/x-www-form-urlencoded"}
  418. conn.request(method='POST', url='/macros/s/AKfycbyZfKhi7A_6QurtOhcan9t1W0Tug-F63_CBUwtfkBkZbR2ysFvt/exec',
  419. body=req_data, headers=headers)
  420. resp = conn.getresponse()
  421. while resp.status >= 300 and resp.status < 400:
  422. location = resp.getheader('Location')
  423. o = urlparse(location, allow_fragments=True)
  424. host = o.netloc
  425. conn = httplib.HTTPSConnection(host)
  426. url = o.path + "?" + o.query
  427. conn.request(method='GET', url=url)
  428. resp = conn.getresponse()
  429. if resp.status >= 200 and resp.status < 300:
  430. resp_body = resp.read()
  431. json_body = json.loads(resp_body)
  432. status = json_body['status']
  433. if status == 'ok':
  434. return True
  435. else:
  436. logErr(status)
  437. except:
  438. pass
  439. logErr(status)
  440. return False
  441.  
  442.  
  443. def get_params():
  444. param = []
  445. paramstring = sys.argv[2]
  446. if len(paramstring) >= 2:
  447. params = sys.argv[2]
  448. cleanedparams = params.replace('?', '')
  449. if (params[len(params) - 1] == '/'):
  450. params = params[0:len(params) - 2]
  451. pairsofparams = cleanedparams.split('&')
  452. param = {}
  453. for i in range(len(pairsofparams)):
  454. splitparams = {}
  455. splitparams = pairsofparams[i].split('=')
  456. if (len(splitparams)) == 2:
  457. param[splitparams[0]] = splitparams[1]
  458. return param
  459.  
  460.  
  461. def assign_params(params):
  462. for param in params:
  463. try:
  464. globals()[param] = urllib.unquote_plus(params[param])
  465. except:
  466. pass
  467.  
  468.  
  469. menu = None
  470. play = None
  471. play_live = None
  472. genre = None
  473. letter = None
  474. date = None
  475. channel = None
  476. related = None
  477. episodes = None
  478. bonuses = None
  479. skip_auto = None
  480. force_quality = None
  481. page = 1
  482. params = get_params()
  483. assign_params(params)
  484. page = int(page)
  485.  
  486. try:
  487. if play:
  488. skip_auto = (skip_auto is not None and skip_auto != "0")
  489. playable = selectLiveChannel(play)
  490. if not playable:
  491. if _show_subtitles_:
  492. playable = ivysilani.Programme(play, subtitles_path=_subtitles_path_)
  493. else:
  494. playable = ivysilani.Programme(play)
  495. playPlayable(playable, skip_auto, force_quality)
  496. elif genre:
  497. for g in ivysilani.genres():
  498. if g.link == genre:
  499. listProgrammelist(g, episodes=True)
  500. _setViewMode("Media info")
  501. break
  502. elif letter:
  503. for l in ivysilani.alphabet():
  504. if _toString(l.link) == _toString(letter):
  505. listProgrammelist(l, episodes=True)
  506. _setViewMode("Media info")
  507. break
  508. elif date and channel:
  509. listProgrammelist(ivysilani.Date(date, selectLiveChannel(channel)))
  510. _setViewMode("Media info")
  511. else:
  512. if date:
  513. listChannelsForDate(date)
  514. _setViewMode('Media info 2')
  515. elif related:
  516. listContext("related", related, page)
  517. _setViewMode("Media info")
  518. elif episodes:
  519. listContext("episodes", episodes, page)
  520. _setViewMode("Media info")
  521. elif bonuses:
  522. listContext("bonuses", bonuses, page)
  523. _setViewMode("Media info")
  524. elif menu:
  525. _setViewMode('List')
  526. if menu == "live":
  527. listLiveChannels()
  528. elif menu == "byDate":
  529. listDates()
  530. elif menu == "byLetter":
  531. listAlphabet()
  532. elif menu == "byGenre":
  533. listGenres()
  534. else:
  535. for spotlight in ivysilani.SPOTLIGHTS:
  536. if spotlight.ID == menu:
  537. listProgrammelist(spotlight)
  538. break
  539. else:
  540. mainMenu()
  541. except Exception as ex:
  542. exc_type, exc_value, exc_traceback = sys.exc_info()
  543. logErr(traceback.format_exception(exc_type, exc_value, exc_traceback))
  544. found = False
  545. for wnm in well_known_error_messages:
  546. if ex.message == wnm[0]:
  547. xbmcgui.Dialog().notification(_scriptname_, _lang_(wnm[1]), xbmcgui.NOTIFICATION_ERROR)
  548. found = True
  549. if not found:
  550. _exception_log(exc_type, exc_value, exc_traceback)
  551. except Exception as ex:
  552. exc_type, exc_value, exc_traceback = sys.exc_info()
  553. _exception_log(exc_type, exc_value, exc_traceback)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement