Enigma2 plugin to to play various online streams (mostly Latvian).

iptvtools.py 37KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141
  1. # -*- coding: utf-8 -*-
  2. #
  3. # IPTV Tools
  4. #
  5. # $Id$
  6. #
  7. #
  8. ###################################################
  9. # LOCAL import
  10. ###################################################
  11. ###################################################
  12. ###################################################
  13. # FOREIGN import
  14. ###################################################
  15. from Components.config import config
  16. from Tools.Directories import resolveFilename, fileExists, SCOPE_PLUGINS, SCOPE_CONFIG
  17. from enigma import eConsoleAppContainer
  18. from Components.Language import language
  19. from time import sleep as time_sleep, time
  20. from urllib2 import Request, urlopen, URLError, HTTPError
  21. from datetime import datetime
  22. import urllib
  23. import urllib2
  24. import traceback
  25. import re
  26. import sys
  27. import os
  28. import stat
  29. import codecs
  30. try: import json
  31. except: import simplejson as json
  32. ###################################################
  33. def GetNice(pid=None):
  34. nice = 0
  35. if None == pid:
  36. pid = 'self'
  37. filePath = '/proc/%s/stat' % pid
  38. try:
  39. with open(filePath, 'r') as f:
  40. data = f.read()
  41. data = data.split(' ')[19]
  42. nice = int(data)
  43. except:
  44. printExc()
  45. return nice
  46. def E2PrioFix(cmd):
  47. if config.plugins.iptvplayer.plarform.value in ('mipsel', 'armv7', 'armv5t'):
  48. return 'nice -n %d %s' % (GetNice()+2, cmd)
  49. else:
  50. return cmd
  51. def GetDefaultLang(full=False):
  52. if full:
  53. try: defaultLanguage = language.getActiveLanguage()
  54. except:
  55. printExc()
  56. defaultLanguage = 'en_EN'
  57. else:
  58. try: defaultLanguage = language.getActiveLanguage().split('_')[0]
  59. except:
  60. printExc()
  61. defaultLanguage = 'en'
  62. return defaultLanguage
  63. def GetPolishSubEncoding(filePath):
  64. encoding = 'utf-8'
  65. # Method provided by @areq: http://forum.dvhk.to/showpost.php?p=5367956&postcount=5331
  66. try:
  67. f = open(filePath)
  68. sub = f.read()
  69. f.close()
  70. iso = 0
  71. for i in (161, 166, 172, 177, 182, 188):
  72. iso += sub.count(chr(i))
  73. win = 0
  74. for i in (140, 143, 156, 159, 165, 185):
  75. win += sub.count(chr(i))
  76. utf = 0
  77. for i in (195, 196, 197):
  78. utf += sub.count(chr(i))
  79. if win > utf and win > iso:
  80. encoding = "CP1250"
  81. elif utf > iso and utf > win:
  82. encoding = "utf-8"
  83. else:
  84. encoding = "iso-8859-2"
  85. printDBG("IPTVExtMoviePlayer _getEncoding iso[%d] win[%d ] utf[%d] -> [%s]" % (iso, win, utf, encoding))
  86. except:
  87. printExc()
  88. return encoding
  89. def MapUcharEncoding(encoding):
  90. ENCODING_MAP = {'X-MAC-CYRILLIC':"MAC-CYRILLIC"}
  91. printDBG("MapUcharEncoding in encoding[%s]" % encoding)
  92. try: encoding = ENCODING_MAP.get(encoding.strip().upper(), encoding.strip())
  93. except: printExc()
  94. printDBG("MapUcharEncoding out encoding[%s]" % encoding)
  95. return encoding
  96. class eConnectCallbackObj:
  97. OBJ_ID = 0
  98. OBJ_NUM = 0
  99. def __init__(self, obj=None, connectHandler=None):
  100. eConnectCallbackObj.OBJ_ID += 1
  101. eConnectCallbackObj.OBJ_NUM += 1
  102. self.objID = eConnectCallbackObj.OBJ_ID
  103. printDBG("eConnectCallbackObj.__init__ objID[%d] OBJ_NUM[%d]" % (self.objID, eConnectCallbackObj.OBJ_NUM))
  104. self.connectHandler = connectHandler
  105. self.obj = obj
  106. def __del__(self):
  107. eConnectCallbackObj.OBJ_NUM -= 1
  108. printDBG("eConnectCallbackObj.__del__ objID[%d] OBJ_NUM[%d] " % (self.objID, eConnectCallbackObj.OBJ_NUM))
  109. try:
  110. if 'connect' not in dir(self.obj):
  111. if 'get' in dir(self.obj):
  112. self.obj.get().remove(self.connectHandler)
  113. else:
  114. self.obj.remove(self.connectHandler)
  115. else:
  116. del self.connectHandler
  117. except:
  118. printExc()
  119. self.connectHandler = None
  120. self.obj = None
  121. def eConnectCallback(obj, callbackFun, withExcept=False):
  122. try:
  123. if 'connect' in dir(obj):
  124. return eConnectCallbackObj(obj, obj.connect(callbackFun))
  125. else:
  126. if 'get' in dir(obj):
  127. obj.get().append(callbackFun)
  128. else:
  129. obj.append(callbackFun)
  130. return eConnectCallbackObj(obj, callbackFun)
  131. except:
  132. printExc("eConnectCallback")
  133. return eConnectCallbackObj()
  134. class iptv_system:
  135. '''
  136. Calling os.system is not recommended, it may fail due to lack of memory,
  137. please use iptv_system instead, this should be used as follow:
  138. self.handle = iptv_system("cmd", callBackFun)
  139. there is need to have reference to the obj created by iptv_system,
  140. other ways behaviour is undefined
  141. iptv_system must be used only inside MainThread context, please see
  142. iptv_execute class from asynccall module which is dedicated to be
  143. used inside other threads
  144. '''
  145. def __init__(self, cmd, callBackFun=None):
  146. printDBG("iptv_system.__init__ ---------------------------------")
  147. self.callBackFun = callBackFun
  148. self.console = eConsoleAppContainer()
  149. if None != self.callBackFun:
  150. self.console_appClosed_conn = eConnectCallback(self.console.appClosed, self._cmdFinished)
  151. self.console_stdoutAvail_conn = eConnectCallback(self.console.stdoutAvail, self._dataAvail)
  152. self.outData = ""
  153. self.console.execute( E2PrioFix( cmd ) )
  154. def terminate(self, doCallBackFun=False):
  155. self.kill(doCallBackFun)
  156. def kill(self, doCallBackFun=False):
  157. if None != self.console:
  158. if None != self.callBackFun:
  159. self.console_appClosed_conn = None
  160. self.console_stdoutAvail_conn = None
  161. else:
  162. doCallBackFun = False
  163. self.console.sendCtrlC()
  164. self.console = None
  165. if doCallBackFun:
  166. self.callBackFun(-1, self.outData)
  167. self.callBackFun = None
  168. def _dataAvail(self, data):
  169. if None != data:
  170. self.outData += data
  171. def _cmdFinished(self, code):
  172. printDBG("iptv_system._cmdFinished code[%r]---------------------------------" % code)
  173. self.console_appClosed_conn = None
  174. self.console_stdoutAvail_conn = None
  175. self.console = None
  176. self.callBackFun(code, self.outData)
  177. self.callBackFun = None
  178. def __del__(self):
  179. printDBG("iptv_system.__del__ ---------------------------------")
  180. def IsHttpsCertValidationEnabled():
  181. return config.plugins.iptvplayer.httpssslcertvalidation.value
  182. def GetAvailableIconSize(checkAll=True):
  183. iconSizes = [config.plugins.iptvplayer.IconsSize.value]
  184. if checkAll:
  185. iconSizes.extend(['135', '120', '100'])
  186. confirmedIconSize = 0
  187. for size in iconSizes:
  188. try:
  189. file = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/PlayerSelector/marker{0}.png').format(int(size) + 45)
  190. if fileExists(file):
  191. confirmedIconSize = int(size)
  192. break
  193. except:
  194. printExc()
  195. return confirmedIconSize
  196. #############################################################
  197. # returns the directory path where specified resources are
  198. # stored, in the future, it can be changed in the config
  199. #############################################################
  200. def GetLogoDir(file = ''):
  201. return resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/logos/') + file
  202. def GetPyScriptCmd(name):
  203. cmd = ''
  204. baseName = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/scripts/') + name
  205. if fileExists(baseName + '.py'):
  206. baseName += '.py'
  207. elif fileExists(baseName + '.pyo'):
  208. baseName += '.pyo'
  209. if baseName != '':
  210. for item in ['python', 'python2.7', 'python2.6']:
  211. pyPath = Which(item)
  212. if '' != pyPath:
  213. cmd = '%s %s' % (pyPath, baseName)
  214. break
  215. return cmd
  216. def GetUchardetPath():
  217. return config.plugins.iptvplayer.uchardetpath.value
  218. def GetCookieDir(file = ''):
  219. cookieDir = '/tmp/'
  220. tmpDir = config.plugins.iptvplayer.SciezkaCache.value + '/cookies/'
  221. try:
  222. if os.path.isdir(tmpDir) or mkdirs(tmpDir):
  223. cookieDir = tmpDir
  224. except:
  225. printExc()
  226. return cookieDir + file
  227. def GetTmpDir(file = ''):
  228. path = config.plugins.iptvplayer.NaszaTMP.value
  229. path = path.replace('//', '/')
  230. try: mkdirs(path)
  231. except: printExc()
  232. return path + '/' + file
  233. def CreateTmpFile(filename, data=''):
  234. sts = False
  235. filePath = GetTmpDir(filename)
  236. try:
  237. with open(filePath, 'w') as f:
  238. f.write(data)
  239. sts = True
  240. except:
  241. printExc()
  242. return sts, filePath
  243. def GetCacheSubDir(dir, file = ''):
  244. path = config.plugins.iptvplayer.SciezkaCache.value + "/" + dir
  245. path = path.replace('//', '/')
  246. try: mkdirs(path)
  247. except: printExc()
  248. return path + '/' + file
  249. def GetSearchHistoryDir(file = ''):
  250. return GetCacheSubDir('SearchHistory', file)
  251. def GetFavouritesDir(file = ''):
  252. return GetCacheSubDir('IPTVFavourites', file)
  253. def GetSubtitlesDir(file = ''):
  254. return GetCacheSubDir('Subtitles', file)
  255. def GetMovieMetaDataDir(file = ''):
  256. return GetCacheSubDir('MovieMetaData', file)
  257. def GetIPTVDMImgDir(file = ''):
  258. return resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/') + file
  259. def GetIconDir(file = ''):
  260. return resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/icons/') + file
  261. def GetBinDir(file = '', platform=None):
  262. if None == platform: platform = config.plugins.iptvplayer.plarform.value
  263. return resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/bin/') + platform + '/' + file
  264. def GetPluginDir(file = ''):
  265. return resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/') + file
  266. def GetSkinsDir(path = ''):
  267. return resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/skins/') + path
  268. def GetConfigDir(path = ''):
  269. return resolveFilename(SCOPE_CONFIG, path)
  270. def IsExecutable(fpath):
  271. try:
  272. if '' != Which(fpath): return True
  273. except: printExc()
  274. return False
  275. def Which(program):
  276. try:
  277. def is_exe(fpath):
  278. return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
  279. fpath, fname = os.path.split(program)
  280. if fpath:
  281. if is_exe(program):
  282. return program
  283. else:
  284. for path in os.environ["PATH"].split(os.pathsep):
  285. path = path.strip('"')
  286. exe_file = os.path.join(path, program)
  287. if is_exe(exe_file):
  288. return exe_file
  289. except: printExc()
  290. return ''
  291. #############################################################
  292. # class used to auto-select one link when video has several
  293. # links with different qualities
  294. #############################################################
  295. class CSelOneLink():
  296. def __init__(self, listOfLinks, getQualiyFun, maxRes):
  297. self.listOfLinks = listOfLinks
  298. self.getQualiyFun = getQualiyFun
  299. self.maxRes = maxRes
  300. def _cmpLinks(self, item1, item2):
  301. val1 = self.getQualiyFun(item1)
  302. val2 = self.getQualiyFun(item2)
  303. if val1 < val2: ret = -1
  304. elif val1 > val2: ret = 1
  305. else: ret = 0
  306. return ret
  307. def _cmpLinksBest(self, item1, item2):
  308. return -1 * self._cmpLinks(item1, item2)
  309. def getBestSortedList(self):
  310. printDBG('getBestSortedList')
  311. sortList = self.listOfLinks[::-1]
  312. sortList.sort( self._cmpLinksBest )
  313. retList = []
  314. tmpList = []
  315. for item in sortList:
  316. linkRes = self.getQualiyFun( item )
  317. if linkRes <= self.maxRes:
  318. retList.append(item)
  319. else:
  320. tmpList.insert(0, item)
  321. retList.extend(tmpList)
  322. return retList
  323. def getSortedLinks(self, defaultFirst=True):
  324. printDBG('getSortedLinks defaultFirst[%r]' % defaultFirst)
  325. sortList = self.listOfLinks[::-1]
  326. sortList.sort( self._cmpLinks )
  327. if len(self.listOfLinks) < 2 or None == self.maxRes:
  328. return self.listOfLinks
  329. defIdx = -1
  330. for idx in range(len(sortList)):
  331. linkRes = self.getQualiyFun( sortList[idx] )
  332. printDBG("=============== getOneLink [%r] res[%r] maxRes[%r]" % (sortList[idx], linkRes, self.maxRes))
  333. if linkRes <= self.maxRes:
  334. defIdx = idx
  335. printDBG('getOneLink use format %d/%d' % (linkRes, self.maxRes) )
  336. if defaultFirst and -1 < defIdx:
  337. item = sortList[defIdx]
  338. del sortList[defIdx]
  339. sortList.insert(0, item)
  340. return sortList
  341. def getOneLink(self):
  342. printDBG('getOneLink start')
  343. tab = self.getSortedLinks()
  344. if len(tab) == 0:
  345. return tab
  346. return [ tab[0] ]
  347. # end CSelOneLink
  348. #############################################################
  349. # prints debugs on screen or to the file
  350. #############################################################
  351. # debugs
  352. def printDBG( DBGtxt ):
  353. try:
  354. from Components.config import config
  355. DBG = config.plugins.iptvplayer.debugprint.value
  356. except:
  357. #nie zainicjowany modul Config, sprawdzamy wartosc bezposredio w pliku
  358. DBG=''
  359. file = open(resolveFilename(SCOPE_CONFIG, "settings"))
  360. for line in file:
  361. if line.startswith('config.plugins.iptvplayer.debugprint=' ) :
  362. DBG=line.split("=")[1].strip()
  363. break
  364. #print DBG
  365. if DBG == '':
  366. return
  367. elif DBG == 'console':
  368. print(DBGtxt)
  369. elif DBG == 'debugfile':
  370. try:
  371. f = open('/hdd/iptv.dbg', 'a')
  372. f.write(DBGtxt + '\n')
  373. f.close
  374. except:
  375. print("======================EXC printDBG======================")
  376. print("printDBG(I): %s" % traceback.format_exc())
  377. print("========================================================")
  378. try:
  379. msg = '%s' % traceback.format_exc()
  380. f = open('/tmp/iptv.dbg', 'a')
  381. f.write(DBGtxt + '\n')
  382. f.close
  383. except:
  384. print("======================EXC printDBG======================")
  385. print("printDBG(II): %s" % traceback.format_exc())
  386. print("========================================================")
  387. #####################################################
  388. # get host list based on files in /hosts folder
  389. #####################################################
  390. def GetHostsList(fromList=True, fromHostFolder=True):
  391. printDBG('getHostsList begin')
  392. HOST_PATH = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/hosts/')
  393. BLOCKED_MARKER = '_blocked_'
  394. lhosts = []
  395. def __isHostNameValid(hostName):
  396. if len(hostName) > 4 and BLOCKED_MARKER not in hostName and hostName.startswith("host"):
  397. return True
  398. return False
  399. if fromHostFolder:
  400. try:
  401. fileList = os.listdir( HOST_PATH )
  402. for wholeFileName in fileList:
  403. # separate file name and file extension
  404. fileName, fileExt = os.path.splitext(wholeFileName)
  405. nameLen = len( fileName )
  406. if fileExt in ['.pyo', '.pyc', '.py'] and nameLen > 4 and __isHostNameValid(fileName):
  407. if fileName[4:] not in lhosts:
  408. lhosts.append( fileName[4:] )
  409. printDBG('getHostsList add host with fileName: "%s"' % fileName[4:])
  410. printDBG('getHostsList end')
  411. lhosts.sort()
  412. except:
  413. printDBG('GetHostsList EXCEPTION')
  414. # when new option to remove not enabled host is enabled
  415. # on list should be also host which are not normally in
  416. # the folder, so we will read first predefined list
  417. if fromList:
  418. try:
  419. sts, data = ReadTextFile(HOST_PATH + '/list.txt')
  420. if sts:
  421. data = data.split('\n')
  422. for item in data:
  423. line = item.strip()
  424. if __isHostNameValid(line):
  425. if line[4:] not in lhosts:
  426. lhosts.append( line[4:] )
  427. printDBG('getHostsList add host from list.txt hostName: "%s"' % line[4:])
  428. except:
  429. printExc()
  430. return lhosts
  431. def GetEnabledHostsList():
  432. hostsList = GetHostsList(fromList=True, fromHostFolder=True)
  433. enabledHostsList = []
  434. for hostName in hostsList:
  435. if IsHostEnabled(hostName):
  436. enabledHostsList.append(hostName)
  437. return enabledHostsList
  438. def SortHostsList(hostsList):
  439. hostsList = list(hostsList)
  440. hostsOrderList = GetHostsOrderList()
  441. sortedList = []
  442. for item in hostsOrderList:
  443. if item in hostsList:
  444. sortedList.append(item)
  445. hostsList.remove(item)
  446. sortedList.extend(hostsList)
  447. return sortedList
  448. def SaveHostsOrderList(list, fileName="iptvplayerhostsorder"):
  449. printDBG('SaveHostsOrderList begin')
  450. fname = GetConfigDir(fileName)
  451. try:
  452. f = open(fname, 'w')
  453. for item in list:
  454. f.write(item + '\n')
  455. f.close()
  456. except:
  457. printExc()
  458. def GetHostsOrderList(fileName="iptvplayerhostsorder"):
  459. printDBG('GetHostsOrderList begin')
  460. fname = GetConfigDir(fileName)
  461. list = []
  462. try:
  463. with open(fname, 'r') as f:
  464. content = f.readlines()
  465. for item in content:
  466. item = item.strip()
  467. if len(item): list.append(item)
  468. except:
  469. printExc()
  470. return list
  471. def GetSkinsList():
  472. printDBG('getSkinsList begin')
  473. skins = []
  474. SKINS_PATH = resolveFilename(SCOPE_PLUGINS, 'Extensions/IPTVPlayer/skins/')
  475. fileList = os.listdir( SKINS_PATH )
  476. for filename in fileList: skins.append((filename, filename))
  477. skins.sort()
  478. skins.insert(0,("Default", "Default"))
  479. printDBG('getSkinsList end')
  480. return skins
  481. def IsHostEnabled( hostName ):
  482. hostEnabled = False
  483. try:
  484. exec('if config.plugins.iptvplayer.host' + hostName + '.value: hostEnabled = True')
  485. except:
  486. hostEnabled = False
  487. return hostEnabled
  488. ##############################################################
  489. # check if we have enough free space
  490. # if required == None return free space instead of comparing
  491. # default unit = MB
  492. ##############################################################
  493. def FreeSpace(katalog, requiredSpace, unitDiv=1024*1024):
  494. try:
  495. s = os.statvfs(katalog)
  496. freeSpace = s.f_bfree * s.f_frsize # all free space
  497. if 512 > (freeSpace / (1024 * 1024)):
  498. freeSpace = s.f_bavail * s.f_frsize
  499. freeSpace = freeSpace / unitDiv
  500. except:
  501. printExc()
  502. freeSpace = -1
  503. printDBG("FreeSpace freeSpace[%s] requiredSpace[%s] unitDiv[%s]" % (freeSpace, requiredSpace, unitDiv))
  504. if None == requiredSpace:
  505. return freeSpace
  506. else:
  507. if freeSpace >= requiredSpace:
  508. return True
  509. else:
  510. return False
  511. def IsValidFileName(name, NAME_MAX=255):
  512. prohibited_characters = ['/', "\000", '\\', ':', '*', '<', '>', '|', '"']
  513. if isinstance(name, basestring) and (1 <= len(name) <= NAME_MAX):
  514. for it in name:
  515. if it in prohibited_characters:
  516. return False
  517. return True
  518. return False
  519. def RemoveDisallowedFilenameChars(name, replacment='.'):
  520. prohibited_characters = ['/', "\000", '\\', ':', '*', '<', '>', '|', '"']
  521. for item in prohibited_characters:
  522. name = name.replace(item, replacment).replace(replacment+replacment, replacment)
  523. return name
  524. def touch(fname, times=None):
  525. try:
  526. with open(fname, 'a'):
  527. os.utime(fname, times)
  528. return True
  529. except:
  530. printExc()
  531. return False
  532. def mkdir(newdir):
  533. """ Wrapper for the os.mkdir function
  534. returns status instead of raising exception
  535. """
  536. try:
  537. os.mkdir(newdir)
  538. sts = True
  539. msg = 'Katalog "%s" został utworzony poprawnie.' % newdir
  540. except:
  541. sts = False
  542. msg = 'Katalog "%s" nie może zostać utworzony.' % newdir
  543. printExc()
  544. return sts,msg
  545. def mkdirs(newdir):
  546. """ Create a directory and all parent folders.
  547. Features:
  548. - parent directories will be created
  549. - if directory already exists, then do nothing
  550. - if there is another filsystem object with the same name, raise an exception
  551. """
  552. printDBG('mkdirs: "%s"' % newdir)
  553. try:
  554. if os.path.isdir(newdir):
  555. pass
  556. elif os.path.isfile(newdir):
  557. raise OSError("cannot create directory, file already exists: '%s'" % newdir)
  558. else:
  559. head, tail = os.path.split(newdir)
  560. if head and not os.path.isdir(head) and not os.path.ismount(head) and not os.path.islink(head):
  561. mkdirs(head)
  562. if tail:
  563. os.mkdir(newdir)
  564. return True
  565. except:
  566. printExc('!!!!!!!!!! EXCEPTION mkdirs["%s"]' % newdir)
  567. return False
  568. def rm(fullname):
  569. try:
  570. os.remove(fullname)
  571. return True
  572. except: printExc()
  573. return False
  574. def rmtree(path, ignore_errors=False, onerror=None):
  575. """Recursively delete a directory tree.
  576. If ignore_errors is set, errors are ignored; otherwise, if onerror
  577. is set, it is called to handle the error with arguments (func,
  578. path, exc_info) where func is os.listdir, os.remove, or os.rmdir;
  579. path is the argument to that function that caused it to fail; and
  580. exc_info is a tuple returned by sys.exc_info(). If ignore_errors
  581. is false and onerror is None, an exception is raised.
  582. """
  583. if ignore_errors:
  584. def onerror(*args):
  585. pass
  586. elif onerror is None:
  587. def onerror(*args):
  588. raise
  589. try:
  590. if os.path.islink(path):
  591. # symlinks to directories are forbidden, see bug #1669
  592. raise OSError("Cannot call rmtree on a symbolic link")
  593. except OSError:
  594. onerror(os.path.islink, path)
  595. # can't continue even if onerror hook returns
  596. return
  597. names = []
  598. try:
  599. names = os.listdir(path)
  600. except os.error, err:
  601. onerror(os.listdir, path)
  602. for name in names:
  603. fullname = os.path.join(path, name)
  604. try:
  605. mode = os.lstat(fullname).st_mode
  606. except os.error:
  607. mode = 0
  608. if stat.S_ISDIR(mode):
  609. rmtree(fullname, ignore_errors, onerror)
  610. else:
  611. try:
  612. os.remove(fullname)
  613. except os.error, err:
  614. onerror(os.remove, fullname)
  615. try:
  616. os.rmdir(path)
  617. except os.error:
  618. onerror(os.rmdir, path)
  619. def DownloadFile(url, filePath):
  620. printDBG('DownloadFile [%s] from [%s]' % (filePath, url) )
  621. try:
  622. downloadFile = urllib2.urlopen(url)
  623. output = open(filePath, 'wb')
  624. output.write(downloadFile.read())
  625. output.close()
  626. try:
  627. iptv_system('sync')
  628. except:
  629. printExc('DownloadFile sync exception')
  630. return True
  631. except:
  632. try:
  633. if os.path.exists(filePath):
  634. os.remove(filePath)
  635. return False
  636. except:
  637. printExc()
  638. return False
  639. ########################################################
  640. # For icon manager
  641. ########################################################
  642. def GetLastDirNameFromPath(path):
  643. path = os.path.normcase(path)
  644. if path[-1] == '/':
  645. path = path[:-1]
  646. dirName = path.split('/')[-1]
  647. return dirName
  648. def GetIconDirBaseName():
  649. return '.iptvplayer_icons_'
  650. def CheckIconName(name):
  651. #check if name is correct
  652. if 36 == len(name) and '.jpg' == name[-4:]:
  653. try:
  654. tmp = int(name[:-4], 16)
  655. return True
  656. except:
  657. pass
  658. return False
  659. def GetNewIconsDirName():
  660. return "%s%f" % (GetIconDirBaseName(), float(time()))
  661. def CheckIconsDirName(path):
  662. dirName = GetLastDirNameFromPath(path)
  663. baseName = GetIconDirBaseName()
  664. if dirName.startswith(baseName):
  665. try:
  666. test = float(dirName[len(baseName):])
  667. return True
  668. except:
  669. pass
  670. return False
  671. def GetIconsDirs(basePath):
  672. iconsDirs = []
  673. try:
  674. list = os.listdir(basePath)
  675. for item in list:
  676. currPath = os.path.join(basePath, item)
  677. if os.path.isdir(currPath) and not os.path.islink(currPath) and CheckIconsDirName(item):
  678. iconsDirs.append(item)
  679. except:
  680. printExc()
  681. return iconsDirs
  682. def GetIconsFilesFromDir(basePath):
  683. iconsFiles = []
  684. if CheckIconsDirName(basePath):
  685. try:
  686. list = os.listdir(basePath)
  687. for item in list:
  688. currPath = os.path.join(basePath, item)
  689. if os.path.isfile(currPath) and not os.path.islink(currPath) and CheckIconName(item):
  690. iconsFiles.append(item)
  691. except:
  692. printExc()
  693. return iconsFiles
  694. def GetCreationIconsDirTime(fullPath):
  695. try:
  696. dirName = GetLastDirNameFromPath(fullPath)
  697. baseName = GetIconDirBaseName()
  698. return float(dirName[len(baseName):])
  699. except:
  700. return None
  701. def GetCreateIconsDirDeltaDateInDays(fullPath):
  702. ret = -1
  703. createTime = GetCreationIconsDirTime(fullPath)
  704. if None != createTime:
  705. try:
  706. currTime = datetime.now()
  707. modTime = datetime.fromtimestamp(createTime)
  708. deltaTime = currTime - modTime
  709. ret = deltaTime.days
  710. except:
  711. printExc()
  712. return ret
  713. def RemoveIconsDirByPath(path):
  714. printDBG("RemoveIconsDirByPath[%s]" % path)
  715. RemoveAllFilesIconsFromPath(path)
  716. try:
  717. os.rmdir(path)
  718. except:
  719. printExc('RemoveIconsDirByPath dir[%s] is not empty' % path)
  720. def RemoveOldDirsIcons(path, deltaInDays='7'):
  721. deltaInDays = int(deltaInDays)
  722. try:
  723. iconsDirs = GetIconsDirs(path)
  724. for item in iconsDirs:
  725. currDir = os.path.join(path, item)
  726. delta = GetCreateIconsDirDeltaDateInDays(currDir) # we will check only directory date
  727. if delta >= 0 and deltaInDays >= 0 and delta >= deltaInDays:
  728. RemoveIconsDirByPath(currDir)
  729. except:
  730. printExc()
  731. def RemoveAllFilesIconsFromPath(path):
  732. printDBG( "RemoveAllFilesIconsFromPath" )
  733. try:
  734. list = os.listdir(path)
  735. for item in list:
  736. filePath = os.path.join(path, item)
  737. if CheckIconName(item) and os.path.isfile(filePath):
  738. printDBG( 'RemoveAllFilesIconsFromPath img: ' + filePath )
  739. try:
  740. os.remove(filePath)
  741. except:
  742. printDBG( "ERROR while removing file %s" % filePath )
  743. except:
  744. printExc('ERROR: in RemoveAllFilesIconsFromPath')
  745. def RemoveAllDirsIconsFromPath(path, old=False):
  746. if old:
  747. RemoveAllFilesIconsFromPath(path)
  748. else:
  749. try:
  750. iconsDirs = GetIconsDirs(path)
  751. for item in iconsDirs:
  752. currDir = os.path.join(path, item)
  753. RemoveIconsDirByPath(currDir)
  754. except:
  755. printExc()
  756. def formatBytes(bytes, precision = 2):
  757. import math
  758. units = ['B', 'KB', 'MB', 'GB', 'TB']
  759. bytes = max(bytes, 0);
  760. if bytes:
  761. pow = math.log(bytes)
  762. else:
  763. pow = 0
  764. pow = math.floor(pow / math.log(1024))
  765. pow = min(pow, len(units) - 1)
  766. bytes /= math.pow(1024, pow);
  767. return ("%s%s" % (str(round(bytes, precision)),units[int(pow)]))
  768. def remove_html_markup(s, replacement=''):
  769. tag = False
  770. quote = False
  771. out = ""
  772. for c in s:
  773. if c == '<' and not quote:
  774. tag = True
  775. elif c == '>' and not quote:
  776. tag = False
  777. out += replacement
  778. elif (c == '"' or c == "'") and tag:
  779. quote = not quote
  780. elif not tag:
  781. out = out + c
  782. return re.sub('&\w+;', ' ',out)
  783. class CSearchHistoryHelper():
  784. TYPE_SEP = '|--TYPE--|'
  785. def __init__(self, name, storeTypes=False):
  786. printDBG('CSearchHistoryHelper.__init__')
  787. self.storeTypes = storeTypes
  788. try:
  789. printDBG('CSearchHistoryHelper.__init__ name = "%s"' % name)
  790. self.PATH_FILE = GetSearchHistoryDir(name + ".txt")
  791. except:
  792. printExc('CSearchHistoryHelper.__init__ EXCEPTION')
  793. def getHistoryList(self):
  794. printDBG('CSearchHistoryHelper.getHistoryList from file = "%s"' % self.PATH_FILE)
  795. historyList = []
  796. try:
  797. file = codecs.open(self.PATH_FILE, 'r', 'utf-8', 'ignore')
  798. for line in file:
  799. value = line.replace('\n', '').strip()
  800. if len(value) > 0:
  801. try: historyList.insert(0, value.encode('utf-8', 'ignore'))
  802. except: printExc()
  803. file.close()
  804. except:
  805. printExc()
  806. return []
  807. orgLen = len(historyList)
  808. # remove duplicates
  809. # last 50 searches patterns are stored
  810. historyList = historyList[:config.plugins.iptvplayer.search_history_size.value]
  811. uniqHistoryList = []
  812. for i in historyList:
  813. if i not in uniqHistoryList:
  814. uniqHistoryList.append(i)
  815. historyList = uniqHistoryList
  816. # save file without duplicates
  817. if orgLen > len(historyList):
  818. self._saveHistoryList(historyList)
  819. # now type also can be stored
  820. #################################
  821. newList = []
  822. for histItem in historyList:
  823. fields = histItem.split(self.TYPE_SEP)
  824. if 2 == len(fields):
  825. newList.append({'pattern':fields[0], 'type':fields[1]})
  826. elif self.storeTypes:
  827. newList.append({'pattern':fields[0]})
  828. if len(newList) > 0:
  829. return newList
  830. #################################
  831. return historyList
  832. def addHistoryItem(self, itemValue, itemType = None):
  833. printDBG('CSearchHistoryHelper.addHistoryItem to file = "%s"' % self.PATH_FILE)
  834. try:
  835. if config.plugins.iptvplayer.search_history_size.value > 0:
  836. file = codecs.open(self.PATH_FILE, 'a', 'utf-8', 'replace')
  837. value = itemValue
  838. if None != itemType:
  839. value = value + self.TYPE_SEP + itemType
  840. file.write(value + '\n')
  841. printDBG('Added pattern: "%s"' % itemValue)
  842. file.close
  843. except:
  844. printExc('CSearchHistoryHelper.addHistoryItem EXCEPTION')
  845. def _saveHistoryList(self, list):
  846. printDBG('CSearchHistoryHelper._saveHistoryList to file = "%s"' % self.PATH_FILE)
  847. try:
  848. file = open( self.PATH_FILE, 'w' )
  849. l = len(list)
  850. for i in range( l ):
  851. file.write( list[l - 1 -i] + '\n' )
  852. file.close
  853. except:
  854. printExc('CSearchHistoryHelper._saveHistoryList EXCEPTION')
  855. @staticmethod
  856. def saveLastPattern(pattern):
  857. filePath = GetSearchHistoryDir("pattern")
  858. sts = False
  859. try:
  860. file = codecs.open(filePath, 'w', 'utf-8', 'replace')
  861. file.write(pattern)
  862. file.close
  863. sts = True
  864. except:
  865. printExc()
  866. return sts
  867. @staticmethod
  868. def loadLastPattern():
  869. filePath = GetSearchHistoryDir("pattern")
  870. return ReadTextFile(filePath)
  871. # end CSearchHistoryHelper
  872. def ReadTextFile(filePath, encode='utf-8', errors='ignore'):
  873. sts, ret = False, ''
  874. try:
  875. file = codecs.open(filePath, 'r', encode, errors)
  876. ret = file.read().encode(encode, errors)
  877. file.close()
  878. sts = True
  879. except:
  880. printExc()
  881. return sts, ret
  882. def WriteTextFile(filePath, text, encode='utf-8', errors='ignore'):
  883. sts = False
  884. try:
  885. file = codecs.open(filePath, 'w', encode, errors)
  886. file.write(text)
  887. file.close()
  888. sts = True
  889. except:
  890. printExc()
  891. return sts
  892. class CFakeMoviePlayerOption():
  893. def __init__(self, value, text):
  894. self.value = value
  895. self.text = text
  896. def getText(self):
  897. return self.text
  898. class CMoviePlayerPerHost():
  899. def __init__(self, hostName):
  900. self.filePath = GetCacheSubDir('MoviePlayer', hostName + '.json')
  901. self.activePlayer = {} # {buffering:True/False, 'player':''}
  902. self.load()
  903. def __del__(self):
  904. self.save()
  905. def load(self):
  906. sts, ret = False, ''
  907. try:
  908. if not os.path.isfile(self.filePath):
  909. sts = True
  910. else:
  911. file = codecs.open(self.filePath, 'r', 'utf-8', 'ignore')
  912. ret = file.read().encode('utf-8', 'ignore')
  913. file.close()
  914. activePlayer = {}
  915. ret = json.loads(ret)
  916. activePlayer['buffering'] = ret['buffering']
  917. activePlayer['player'] = CFakeMoviePlayerOption(ret['player']['value'].encode('utf-8'), ret['player']['text'].encode('utf-8'))
  918. self.activePlayer = activePlayer
  919. sts = True
  920. except: printExc()
  921. return sts, ret
  922. def save(self):
  923. sts = False
  924. try:
  925. if {} == self.activePlayer and os.path.isfile(self.filePath):
  926. os.remove(self.filePath)
  927. else:
  928. data = {}
  929. data['buffering'] = self.activePlayer['buffering']
  930. data['player'] = {'value':self.activePlayer['player'].value, 'text':self.activePlayer['player'].getText()}
  931. data = json.dumps(data).encode('utf-8')
  932. file = codecs.open(self.filePath, 'w', 'utf-8', 'replace')
  933. file.write(data)
  934. file.close
  935. sts = True
  936. except: printExc()
  937. return sts
  938. def get(self, key, defval):
  939. return self.activePlayer.get(key, defval)
  940. def set(self, activePlayer):
  941. self.activePlayer = activePlayer
  942. def byteify(input):
  943. if isinstance(input, dict):
  944. return dict([(byteify(key), byteify(value)) for key, value in input.iteritems()])
  945. elif isinstance(input, list):
  946. return [byteify(element) for element in input]
  947. elif isinstance(input, unicode):
  948. return input.encode('utf-8')
  949. else:
  950. return input
  951. def printExc(msg=''):
  952. printDBG("===============================================")
  953. printDBG(" EXCEPTION ")
  954. printDBG("===============================================")
  955. msg = msg + ': \n%s' % traceback.format_exc()
  956. printDBG(msg)
  957. printDBG("===============================================")
  958. def GetIPTVPlayerVerstion():
  959. try: from Plugins.Extensions.IPTVPlayer.version import IPTV_VERSION
  960. except: IPTV_VERSION="XX.YY.ZZ"
  961. return IPTV_VERSION
  962. def GetShortPythonVersion():
  963. return "%d.%d" % (sys.version_info[0], sys.version_info[1])
  964. def GetVersionNum(ver):
  965. try:
  966. if None == re.match("[0-9]+\.[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]", ver): raise Exception("Wrong version!")
  967. return int(ver.replace('.', ''))
  968. except:
  969. printExc('Version[%r]' % ver)
  970. return 0
  971. def GetE2OptionsFromFile(filePath):
  972. options = []
  973. try:
  974. if fileExists(filePath):
  975. with open(filePath, 'r') as f:
  976. data = f.read().strip()
  977. data = data.split(' ')
  978. for item in data:
  979. opt = item.strip()
  980. if '' != opt:
  981. options.append(opt)
  982. else:
  983. printDBG('GetE2OptionsFromFile file[%s] not exists' % filePath)
  984. except:
  985. printExc()
  986. return options
  987. def SetE2OptionByFile(filePath, value):
  988. sts = False
  989. try:
  990. with open(filePath, 'w') as f:
  991. data = f.write(value)
  992. sts = True
  993. except:
  994. printExc()
  995. return sts
  996. def GetE2VideoAspectChoices():
  997. tab = GetE2OptionsFromFile('/proc/stb/video/aspect_choices')
  998. # workaround for some STB
  999. # reported here: https://gitlab.com/iptvplayer-for-e2/iptvplayer-for-e2/issues/30
  1000. staticTab = ["4:3", "16:9", "any"]
  1001. if len(tab) < 2 and GetE2VideoAspect() in staticTab:
  1002. tab = staticTab
  1003. return tab
  1004. def GetE2VideoAspect():
  1005. options = GetE2OptionsFromFile('/proc/stb/video/aspect')
  1006. if 1 == len(options): return options[0]
  1007. return None
  1008. def SetE2VideoAspect(value):
  1009. return SetE2OptionByFile('/proc/stb/video/aspect', value)
  1010. def GetE2VideoPolicyChoices(num=''):
  1011. return GetE2OptionsFromFile('/proc/stb/video/policy%s_choices' % num)
  1012. def GetE2VideoPolicy(num=''):
  1013. options = GetE2OptionsFromFile('/proc/stb/video/policy'+num)
  1014. if 1 == len(options): return options[0]
  1015. return None
  1016. def SetE2VideoPolicy(value, num=''):
  1017. return SetE2OptionByFile('/proc/stb/video/policy'+num, value)
  1018. def GetE2AudioCodecMixChoices(codec):
  1019. return GetE2OptionsFromFile('/proc/stb/audio/%s_choices' % codec)
  1020. def GetE2AudioCodecMixOption(codec):
  1021. options = GetE2OptionsFromFile('/proc/stb/audio/%s' % codec)
  1022. if 1 == len(options): return options[0]
  1023. return None
  1024. def SetE2AudioCodecMixOption(value, codec):
  1025. return SetE2OptionByFile('/proc/stb/audio/%s' % codec, value)