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

enigma2_api.py 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. # coding: utf-8
  2. """
  3. Enigma2 handling objects
  4. (c)Ivars 2013-2015, v0.2
  5. """
  6. import sys, os, os.path
  7. from urllib import quote, unquote
  8. from record3 import Rec
  9. class DBServices(object):
  10. """Dreambox services, stored in lamedb (E2)/services(E1) file handling class"""
  11. def __init__(self,service_path=None,enigma=2):
  12. self.enigma = enigma
  13. if not service_path:
  14. service_path = "enigma2" if sys.platform=="win32" else "/etc/enigma2"
  15. self.service_path = service_path
  16. #print service_path
  17. if self.enigma == 2:
  18. if not "ftp:" in service_path:
  19. self.service_fname= os.path.join(service_path,"lamedb")
  20. self.bouquets_fname = os.path.join(service_path, "bouquets.tv")
  21. else:
  22. sep = "" if service_path[-1]=="//" else "//"
  23. self.service_fname= service_path+sep+"lamedb"
  24. self.bouquets_fname = service_path+sep+"bouquets.tv"
  25. else: # ENIGMA === "1":
  26. self.service_fname = os.path.join(service_path,"services")
  27. self.bouquets_fname = os.path.join(service_path, "userbouquets.tv.epl")
  28. #print self.service_fname
  29. self.services = []
  30. self.index_sref= {}
  31. self.index_chid = {}
  32. self.index_name = {}
  33. self.index_provider = {}
  34. self.bouquets = []
  35. self.bouquets_services = {}
  36. self.transp = []
  37. self.tp_index_tpid = {}
  38. self.tp_index_pic ={}
  39. self._load_services()
  40. self._load_bouquets()
  41. def _load_services(self):
  42. #tpref - lamedb/transponders
  43. # NS:TSID:ONID
  44. # s FREQ:SR:POLAR:FREC:49:2:0
  45. # X X X
  46. # D D D D
  47. # lref - lamedb/services
  48. # SID:NS:TSID:ONID:STYPE:UNUSED(channelnumber in enigma1)
  49. # 0 1 2 3 4 5
  50. # X X X X D D
  51. # wref - bouquets/picon
  52. # REFTYPE:FLAGS:STYPE:SID:TSID:ONID:NS:PARENT_SID:PARENT_TSID:UNUSED
  53. # 0 1 2 3 4 5 6 7 8 9
  54. # D D X X X X X X X X
  55. f_services = open(self.service_fname,"r") if not self.service_fname[0:4] == "ftp:" else urllib2.urlopen(self.service_fname)
  56. line = f_services.readline()
  57. if not "eDVB services" in line:
  58. raise Exception("no correct lamedb file")
  59. line = f_services.readline()
  60. # Read transponders
  61. i = 0
  62. while True:
  63. line = f_services.readline()
  64. if "end" in line: break
  65. tp = Rec()
  66. #tp = {}
  67. ff = line.strip().split(":")
  68. tp["ns"] = ns = pos_str2int(ff[0])
  69. tp["tsid"] = tsid = int(ff[1],16)
  70. tp["onid"] = onid = int(ff[2],16)
  71. line = f_services.readline()
  72. tp["params"] = params = line.strip().split(" ")[1]
  73. ff = params.split(":")
  74. tp["freq"] = freq = int(ff[0][:-3])
  75. tp["polar"] = polar = int(ff[2])
  76. tp["tpid"] = tpid = (ns,tsid,onid)
  77. self.transp.append(tp)
  78. self.tp_index_tpid[tpid] = i
  79. self.tp_index_pic[(ns,freq,polar)] = i
  80. line = f_services.readline()
  81. i += 1
  82. # Reading services
  83. i= 0
  84. line = f_services.readline()
  85. while True:
  86. line = f_services.readline()
  87. if line[0:3] == "end": break
  88. if not line: break
  89. rec = Rec()
  90. #rec = {}
  91. rec["lref"] = line.lower().strip().decode("utf-8")
  92. line = f_services.readline()
  93. #line = line.replace('\xc2\x87', '').replace('\xc2\x86', '')
  94. #line = decode_charset(line)
  95. line = line.decode("utf-8")
  96. rec["name"] = line.strip()
  97. line = f_services.readline()
  98. provider = ""
  99. caid=[]
  100. for p in line.split(","):
  101. if p[0:2].lower() == "p:":
  102. provider = p[2:].strip()
  103. elif p[0:2].lower() == "c:":
  104. caid.append(p[2:].strip())
  105. if provider == "":
  106. provider = "unknown"
  107. rec["provider"] = provider.decode("utf-8")
  108. rec["sref"] = lref2sref(rec["lref"])
  109. r = lref_parse(rec["lref"])
  110. rec["stype"] = r["stype"]
  111. rec["chid"] = (r["sid"],r["tsid"],r["onid"])
  112. rec["caid"] = caid
  113. self.services.append(rec)
  114. self.index_sref[rec["sref"]] = i
  115. self.index_chid[rec["chid"]] = i
  116. name = rec["name"].lower()
  117. if not self.index_name.has_key(name): self.index_name[name] = []
  118. self.index_name[name].append(i)
  119. provider = rec["provider"].lower()
  120. if not self.index_provider.has_key(provider): self.index_provider[provider] = []
  121. self.index_provider[provider].append(i)
  122. i += 1
  123. f_services.close()
  124. def _load_bouquets(self):
  125. f_bouquets = open(self.bouquets_fname,"r") if not self.bouquets_fname[0:4] == "ftp:" else urllib2.urlopen(self.bouquets_fname)
  126. self.bouquets=Rec()
  127. for line in f_bouquets.readlines():
  128. if line[0:9] == "#SERVICE:":
  129. if self.enigma==1:
  130. bn = line.strip().split("/")
  131. else:
  132. bn = line.strip().split(":")
  133. bfn = bn[-1]
  134. bid = bfn.split(".")[1]
  135. ### Process one bouquet file ###
  136. bouq = Rec()
  137. bouq.bid = bid
  138. bouq.name = ""
  139. bouq.services=[]
  140. #fb = open(self.fname,"r") if not self.fname[0:4] == "ftp:" else urllib2.urlopen(self.fname)
  141. fb = open(os.path.join(self.service_path,bfn))
  142. i= 0
  143. line = fb.readline()
  144. while True:
  145. if line[0:5] == "#NAME":
  146. bouq.name = line.strip()[6:].decode("utf8")
  147. elif line[0:8] == "#SERVICE":
  148. sref = line.strip()[9:]
  149. s = sref_parse(sref)
  150. s["sref"] = sref
  151. if s["flags"] == 64:
  152. s["type"] = "marker"
  153. line = fb.readline()
  154. if line[0:12] =='#DESCRIPTION':
  155. s["name"] = line [13:].strip().decode("utf8")
  156. else: continue
  157. elif s["url"]: # IPTV stream
  158. s["type"] = "stream"
  159. s["sref"] = ":".join(s["sref"].split(":")[0:10])+":"
  160. line = fb.readline()
  161. if line[0:12] =='#DESCRIPTION':
  162. s["name"] = line [13:].strip().decode("utf8")
  163. else: continue
  164. bouq.services.append(s)
  165. line = fb.readline()
  166. if not line: break
  167. fb.close()
  168. self.bouquets[bid] = bouq
  169. f_bouquets.close()
  170. def _load_bouquets2(self):
  171. f_bouquets = open(self.bouquets_fname,"r") if not self.bouquets_fname[0:4] == "ftp:" else urllib2.urlopen(self.bouquets_fname)
  172. for line in f_bouquets.readlines():
  173. if line[0:9] == "#SERVICE:":
  174. if self.enigma==1:
  175. bn = line.strip().split("/")
  176. else:
  177. bn = line.strip().split(":")
  178. bfn = bn[-1]
  179. bid = bfn.split(".")[1]
  180. bouq = Bouquet(bid, self.service_path)
  181. self.bouquets.append(bouq)
  182. f_bouquets.close()
  183. def create_bouqet(self,bid,name):
  184. fname = "userbouquet.%s.tv"%bid
  185. f_bouquets = open(self.bouquets_fname,"r") if not self.bouquets_fname[0:4] == "ftp:" else urllib2.urlopen(self.bouquets_fname)
  186. lines = f_bouquets.read().strip()
  187. f_bouquets.close()
  188. if not fname in lines:
  189. lines += "\n#SERVICE: 1:7:1:0:0:0:0:0:0:0:%s\n"%fname
  190. f_bouquets = open(self.bouquets_fname,"w")
  191. f_bouquets.write(lines)
  192. f_bouquets.close()
  193. with open(os.path.join(self.service_path,fname), 'w') as f:
  194. f.write("#NAME %s"%name.encode("utf8"))
  195. pass
  196. def get_bouquets(self):
  197. if not self.bouquets:
  198. self._load_bouquets()
  199. return self.bouquets
  200. def get_bouquet_services(self,bn):
  201. if not self.bouquets:
  202. self._load_bouquets()
  203. return self.bouquets[bn].services
  204. #----------------------------------------------------------------------
  205. def save_bouquet(self,bn):
  206. """Save bouquet to file"""
  207. fn = "userbouquet.%s.tv"%bn
  208. fb = open(os.path.join(self.service_path,fn),"w")
  209. fb.write("#NAME %s\n"%self.bouquets[bn].name.encode("utf8"))
  210. for s in self.bouquets[bn].services:
  211. if s.type=="marker":
  212. fb.write("#SERVICE %s\n"%s.sref)
  213. fb.write("#DESCRIPTION %s\n"%s.name.encode("utf8"))
  214. elif s.type == "stream":
  215. fb.write("#SERVICE %s%s:%s\n"%(s.sref,quote(s.url),s.name.encode("utf8")))
  216. fb.write("#DESCRIPTION %s\n"%s.name.encode("utf8"))
  217. else:
  218. fb.write("#SERVICE %s\n"%s.sref)
  219. fb.close()
  220. def get_service_by_sref(self,sref):
  221. return self.services[self.index_sref[sref]] if self.index_sref.has_key(sref) else None
  222. def get_service_by_chid(self,chid):
  223. return self.services[self.index_chid[chid]] if self.index_chid.has_key(chid) else None
  224. def get_service_by_name(self,name):
  225. return [self.services[i] for i in self.index_name[name]] if name in self.index_name else None
  226. def get_service_by_provider(self,provider):
  227. return [self.services[i] for i in self.index_provider[provider]] if provider in self.index_privider else Non
  228. def get_transp_by_tpid(self,tpid):
  229. return self.transp[self.tp_index_tpid[tpid]] if self.tp_index_tpid.has_key(tpid) else None
  230. def get_transp_by_pic(self,picid):
  231. return self.transp[self.tp_index_pic[picid]] if self.tp_index_pic.has_key(picid) else None
  232. def find_sref(ns,freq,polar,sid):
  233. "Find service reference according to given parameters"
  234. tp = services.get_transp_by_pic((ns,freq,polar))
  235. if tp:
  236. serv = self.services.get_service_by_chid((sid,tp["tsid"],tp["onid"]))
  237. if serv:
  238. return serv["sref"]
  239. return ""
  240. ########################################################################
  241. class Bouquet(object):
  242. """Bouquet file object"""
  243. #----------------------------------------------------------------------
  244. def __init__(self, bid, service_path=None):
  245. """Constructor"""
  246. if not service_path:
  247. service_path = "enigma2" if sys.platform=="win32" else "/etc/enigma2"
  248. self.service_path = service_path
  249. self.bid = bid
  250. if not "ftp:" in service_path:
  251. self.fname = os.path.join(service_path, "userbouquet.%s.tv"%self.bid)
  252. else:
  253. sep = "" if service_path[-1]=="//" else "//"
  254. self.fname = os.path.join(service_path, "userbouquet.%s.tv"%self.bid)
  255. self.load()
  256. #----------------------------------------------------------------------
  257. def load(self):
  258. """Load bouquet from file"""
  259. self.services=[]
  260. fb = open(self.fname,"r") if not self.fname[0:4] == "ftp:" else urllib2.urlopen(self.fname)
  261. i= 0
  262. line = fb.readline()
  263. while True:
  264. if line[0:5] == "#NAME":
  265. self.name = line.strip()[6:].decode("utf8")
  266. elif line[0:8] == "#SERVICE":
  267. sref = line.strip()[9:]
  268. s = sref_parse(sref)
  269. s["sref"] = sref
  270. if s["flags"] == 64:
  271. s["type"] = "marker"
  272. line = fb.readline()
  273. if line[0:12] =='#DESCRIPTION':
  274. s["name"] = line [13:].strip().decode("utf8")
  275. else: continue
  276. elif s["url"]: # IPTV stream
  277. s["type"] = "stream"
  278. s["sref"] = ":".join(s["sref"].split(":")[0:10])
  279. line = fb.readline()
  280. if line[0:12] =='#DESCRIPTION':
  281. s["name"] = line [13:].strip().decode("utf8")
  282. else: continue
  283. self.services.append(s)
  284. line = fb.readline()
  285. if not line: break
  286. fb.close()
  287. def decode_charset(s):
  288. u = None
  289. if isinstance(s,unicode):
  290. return s
  291. charset_list=('iso-8859-4','iso-8859-1','iso-8859-2''iso-8859-15')
  292. for charset in charset_list:
  293. try:
  294. u=unicode(s,charset,"strict")
  295. except:
  296. pass
  297. else:
  298. break
  299. if u == None:
  300. raise Error, "CHARSET ERROR while decoding lamedb. Aborting !"
  301. else:
  302. return(u)
  303. # lref - lamedb/services
  304. # SID:NS:TSID:ONID:STYPE:UNUSED(channelnumber in enigma1)
  305. # 0 1 2 3 4 5
  306. # X X X X D D
  307. #
  308. # sref bouquets/picon
  309. # REFTYPE:FLAGS:STYPE:SID:TSID:ONID:NS:PARENT_SID:PARENT_TSID:UNUSED
  310. # 0 1 2 3 4 5 6 7 8 9
  311. # D D X X X X X X X X
  312. def lref2sref(s):
  313. "Converts service refefence from lamedb format to bouquets/picon (standard) format"
  314. f = s.split(":")
  315. sid = int(f[0],16)
  316. ns = int(f[1], 16)
  317. tsid = int(f[2],16)
  318. onid = int(f[3],16)
  319. stype = int(f[4])
  320. s2 = "1:0:%X:%X:%X:%X:%X:0:0:0:" % (stype,sid,tsid,onid,ns)
  321. return s2
  322. def lref_parse(s):
  323. "Parse lamedb/service string, return dictionary of items"
  324. f = s.split(":")
  325. #r = {}
  326. r = Rec()
  327. r["sid"] = int(f[0],16)
  328. r["ns"] = int(f[1], 16)
  329. r["tsid"] = int(f[2],16)
  330. r["onid"] = int(f[3],16)
  331. r["stype"] = int(f[4])
  332. return r
  333. def sref2lref(s):
  334. "Converts service refefence from bouquets/picon (standard) format to lamedb format"
  335. f = s.split(":")
  336. reftype = int(f[0])
  337. flags = int(f[1])
  338. stype = int(f[2],16)
  339. sid = int(f[3],16)
  340. tsid = int(f[4],16)
  341. onid = int(f[5],16)
  342. ns = int(f[6],16)
  343. s2 = "%04x:%08x:%04x:%04x:%i:0" % (sid,ns,tsid,onid,stype)
  344. return s2
  345. def sref_parse(s):
  346. "Parse service refefence string , return dictionary of items"
  347. f = s.split(":")
  348. #r = {}
  349. r = Rec()
  350. r["reftype"] = int(f[0])
  351. r["flags"] = int(f[1])
  352. r["stype"] = int(f[2],16)
  353. r["sid"] = int(f[3],16)
  354. r["tsid"] = int(f[4],16)
  355. r["onid"] = int(f[5],16)
  356. r["ns"] = int(f[6],16)
  357. r["url"] = unquote(f[10]) if len(f)>10 else ""
  358. return r
  359. pos_int2str = lambda pos_num: "%04x0000"%pos_num
  360. pos_str2int = lambda pos: int(pos[0:4],16)
  361. def decode_charset(s):
  362. u = None
  363. charset_list = ('utf-8','iso-8859-1','iso-8859-2','iso-8859-15')
  364. for charset in charset_list:
  365. try:
  366. u = unicode(s,charset,"strict")
  367. except:
  368. pass
  369. else:
  370. break
  371. if u == None:
  372. print("CHARSET ERROR while decoding string")
  373. sys.exit(1)
  374. else:
  375. return(u)
  376. import UserDict
  377. if __name__ == "__main__":
  378. #print "** Starting..."
  379. #sys.exit(main(sys.argv))
  380. e2 = DBServices()
  381. #e2.save_buquet("english")
  382. e2.create_bouqet("test", "Tests")
  383. pass