m3u8 proxy for shortcut.lv streams

ltcproxy.py 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  1. #!/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. Shortcut.lv proxy server
  5. usage: %s start|stop|restart|manualstart [options]
  6. -p PORT - port number
  7. -s WSGI_SERVER - wsgi server - wsgiref,cheroot,mtwsgi,waitress...
  8. -d - debug printout
  9. -r - remote debug mode (ptvsd)"""
  10. __version__ = "0.1b"
  11. import os, sys, time
  12. import urllib,urlparse, urllib2, requests
  13. from urllib import unquote, quote
  14. import re, json
  15. import ConfigParser, getopt
  16. import arrow
  17. from diskcache import Cache
  18. import daemonize
  19. import bottle
  20. from bottle import Bottle, hook, response, route, request, run
  21. cunicode = lambda s: s.decode("utf8") if isinstance(s, str) else s
  22. cstr = lambda s: s.encode("utf8") if isinstance(s, unicode) else s
  23. headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
  24. headers0 = headers2dict("""
  25. User-Agent: Shortcut.lv v2.9.1 / Dalvik/1.6.0 (Linux; U; Android 4.4.2; SM-G900FD Build/KOT49H)
  26. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
  27. """)
  28. url0 = "https://manstv.lattelecom.tv/api/v1.7/get/content/"
  29. cur_directory = os.path.dirname(os.path.realpath(__file__))
  30. cache_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "cache")
  31. if not os.path.exists(cache_dir):
  32. os.mkdir(cache_dir)
  33. CFG_FILE = "ltcproxy.cfg" # TODO - iespēja uzdot kā parametru
  34. config = ConfigParser.ConfigParser()
  35. proxy_cfg_file = os.path.join(cur_directory, CFG_FILE)
  36. DEBUG = False
  37. PORT_NUMBER = 8881
  38. REDIRECT = False
  39. CACHE = True
  40. KEY = ["0000","00000"]
  41. SERVER = "wsgiref"
  42. WORKERS = 10
  43. LTC_USER = "user"
  44. LTC_PASSWORD = "password"
  45. if not os.path.exists(proxy_cfg_file):
  46. config.add_section("ltcproxy")
  47. config.set("ltcproxy", "debug", DEBUG)
  48. config.set("ltcproxy", "port", PORT_NUMBER)
  49. config.set("ltcproxy", "redirect", REDIRECT)
  50. config.set("ltcproxy", "cache", CACHE)
  51. config.set("ltcproxy", "key", " ".join(KEY))
  52. config.set("ltcproxy", "wsgi", SERVER)
  53. config.set("ltcproxy", "workers", WORKERS)
  54. config.set("ltcproxy", "ltc_user", LTC_USER)
  55. config.set("ltcproxy", "ltc_password", LTC_PASSWORD)
  56. config.write(open(proxy_cfg_file, "w"))
  57. else:
  58. config.read(proxy_cfg_file)
  59. DEBUG = config.getboolean("ltcproxy", "debug")
  60. PORT_NUMBER = config.getint("ltcproxy", "port")
  61. REDIRECT = config.getboolean("ltcproxy", "redirect")
  62. CACHE = config.getboolean("ltcproxy", "cache")
  63. KEY = config.get("ltcproxy", "key").split(" ")
  64. SERVER = config.get("ltcproxy", "wsgi")
  65. WORKERS = config.getint("ltcproxy", "workers")
  66. LTC_USER = config.get("ltcproxy", "ltc_user")
  67. LTC_PASSWORD = config.get("ltcproxy", "ltc_password")
  68. s = Cache(cache_dir)
  69. app = Bottle()
  70. token = None
  71. ########################################################################################
  72. @app.hook('before_request')
  73. def set_globals():
  74. global s, headers0, token
  75. key = request.path.split("/")[1]
  76. if not key in KEY:
  77. print "Error: Wrong key - %s"% key
  78. raise bottle.HTTPError(500, "Wrong key")
  79. s = Cache(cache_dir)
  80. if "token" in s and s["token"]:
  81. token = s["token"]
  82. else:
  83. token = login(LTC_USER, LTC_PASSWORD)
  84. if token:
  85. s.set("token", token, expire=3600*24*1) # pēc 1d ekspirejas
  86. print "** %s: token=%s" % (request.remote_addr,token)
  87. else:
  88. print "Can not login %s/%s"%(LTC_USER, LTC_PASSWORD)
  89. raise bottle.HTTPError(500, "Can not login")
  90. # @app.route('/playstream/<url:re:.*>')
  91. ### Live playlist ###
  92. @app.route("/<key>/live/<ch>/")
  93. def get_live(key, ch):
  94. global s, token, headers0
  95. path0, rest = hls_split(request.url)
  96. response.content_type = "application/x-mpegURL" # r.headers["content-type"] # 'application/vnd.apple.mpegurl' # application/x-mpegURL
  97. if "c"+ch in s:
  98. stream_url2 = s["c"+ch]
  99. mediaid = s["m"+ch]
  100. print "** %s: serving live playlist for %s (%s) from cache" % (request.remote_addr,path0,mediaid )
  101. else:
  102. stream_url2, mediaid = refresh_live_chunklist_url(ch)
  103. print "** %s: getting ive playlist for %s (%s)" % (request.remote_addr,path0,mediaid )
  104. stream_url2 += token
  105. if REDIRECT:
  106. bottle.redirect(stream_url2, 307)
  107. for i in range(3):
  108. r2 = requests.get(stream_url2,headers=headers0)
  109. if r2.status_code == 200:
  110. break
  111. time.sleep(1)
  112. else:
  113. print "Error %s getting live chunklist %s"% (r2.status_code,stream_url2)
  114. raise bottle.HTTPError(r2.status_code)
  115. return r2.content
  116. ### Live TS chunk ###
  117. @app.route("/<key>/live/<ch>/<tail>")
  118. def get_live_chunk(key, ch, tail):
  119. global s, token, headers0
  120. path0, rest = hls_split(request.url)
  121. chid = re.search("resource_id=c-(\\w+)",rest).group(1)
  122. chunkid = re.search("(\d+)\.ts", request.url).group(1)
  123. path2 = ch + "/" + chunkid
  124. if CACHE and path2 in s:
  125. print "** %s: serving live ts %s from cache" % (request.remote_addr,path2)
  126. f = s.get(path2, read=True)
  127. response.headers["Content-Type"] = s[path2+"@"] #'video/MP2T'
  128. response.headers["Content-Length"] = s[path2+"#"]
  129. while True:
  130. chunk = f.read(8192)
  131. if not chunk:
  132. break
  133. yield chunk
  134. else: # no cache
  135. if ch in s:
  136. stream_url = s[ch]
  137. mediaid= s["m"+ch]
  138. else:
  139. refresh_live_chunklist_url(ch)
  140. if ch in s:
  141. stream_url = s[ch]
  142. mediaid= s["m"+ch]
  143. else:
  144. print "No stream_url %s in cache" % path0
  145. raise bottle.HTTPError(500)
  146. base0, rest0 = hls_base(stream_url)
  147. rest2 = "media_%s_%s.ts?resource_id=c-%s&auth_token=app_" % (mediaid, chunkid, chid)
  148. url = base0 + rest2 + token
  149. url2 = hls_base(stream_url)[0] + rest
  150. headers = dict(request.headers)
  151. del headers["Host"]
  152. # headers["Authorization"] = "Bearer " + token
  153. print "** %s: getting live ts from %s(%s)- %s" % (request.remote_addr, path2, mediaid,url[:40])
  154. if DEBUG:
  155. print "=== Request headers ==="
  156. print_headers(headers)
  157. r = requests.get(url, stream=True, headers=headers0)
  158. if r.status_code <> 200:
  159. r = requests.get(url, stream=True, headers=headers0) # try once more
  160. if r.status_code <> 200:
  161. # Refresh chunklist
  162. print "## %s: Refreshing chunklist/mediaid for live channel %s" %(request.remote_addr, ch)
  163. chunklist_url, mediaid = refresh_live_chunklist_url(ch)
  164. rest2 = "media_%s_%s.ts?resource_id=c-%s&auth_token=app_" % (mediaid, chunkid, chid)
  165. url = base0 + rest2 + token
  166. url2 = chunklist_url + token
  167. print "** %s: getting live ts from %s(%s)- %s" % (request.remote_addr, path2, mediaid,url[:40])
  168. r = requests.get(url, stream=True, headers=headers0)
  169. if r.status_code <> 200:
  170. print "Error %s opening stream \n%s" %(r.status_code,url)
  171. print url2
  172. raise bottle.HTTPError(r.status_code, "Error opening stream "+url)
  173. content = ""
  174. response.content_type = r.headers["content-type"] # 'application/vnd.apple.mpegurl' #
  175. # response.headers.clear()
  176. for k in r.headers:
  177. response.headers[k] = r.headers[k]
  178. if DEBUG:
  179. print "=== Response headers ==="
  180. print_headers(response.headers)
  181. for chunk in r.iter_content(chunk_size=8192):
  182. if chunk:
  183. content += chunk
  184. yield chunk
  185. if len(content) <> int(r.headers["content-length"]):
  186. print "Content length problem"
  187. if CACHE:
  188. s.set(path2, content, expire=3600, read=True)
  189. s.set(path2+"#", len(content), expire=3600, read=True)
  190. s.set(path2+"@", r.headers["Content-Type"], expire=3600, read=True)
  191. ### Archive playlist ###
  192. @app.route("/<key>/live/<ch>/<ts>/")
  193. def get_archive(key, ch, ts):
  194. global s, token, headers0
  195. path0, rest = hls_split(request.url)
  196. start = int(ts) + 60 * 5
  197. epg = get_epg(ch, start)
  198. print "** %s: getting archive playlist for channel %s" % (request.remote_addr,path0)
  199. if epg:
  200. epgid = epg["id"]
  201. epg_start = int(epg["attributes"]["unix-start"])
  202. epg_stop = int(epg["attributes"]["unix-stop"])
  203. epg_title = epg["attributes"]["title"]
  204. else:
  205. print "EPG not found"
  206. raise bottle.HTTPError(500, "EPG not found")
  207. stream_url = epg_get_stream_url(epgid)
  208. if REDIRECT:
  209. bottle.redirect(stream_url, 307)
  210. # Getting chunklist
  211. stream_url2, mediaid = refresh_epg_chunklist_url(stream_url)
  212. r2 = requests.get(stream_url2)
  213. if r2.status_code <> 200:
  214. print "Error %s getting archive chunklist %s"% (r2.status_code,stream_url2)
  215. raise bottle.HTTPError(r2.status_code)
  216. result = re.findall(r"#EXTINF:([\d\.]+),\n(.+)", r2.content)
  217. ll = 0
  218. i = 0
  219. for chunk_len, chunk_url in result:
  220. ll += float(chunk_len)
  221. if ll > (start - epg_start):
  222. break
  223. i += 1
  224. result2 =result[i:]
  225. content = re.search("(^.+?)#EXTINF", r2.content, re.DOTALL).group(1)
  226. for chunk_len, chunk_url in result2:
  227. content += "#EXTINF:%s,\n" % chunk_len
  228. content += chunk_url + "\n"
  229. content += "#EXT-X-ENDLIST"
  230. response.content_type = r2.headers["content-type"] # 'application/vnd.apple.mpegurl' #
  231. return content
  232. def live_get_stream_url(ch):
  233. global s, token, headers0
  234. if ch in s:
  235. stream_url = s[ch]
  236. stream_url += token
  237. else:
  238. # Getting live stream url
  239. url = url0 + "live-streams/%s?include=quality&auth_token=app_%s" % (ch, token)
  240. headers = headers0.copy()
  241. headers["Authorization"] = "Bearer " + token
  242. r = requests.get(url, headers=headers)
  243. if r.status_code <> 200:
  244. print "Error getting epg stream url "+url
  245. raise bottle.HTTPError(r.status_code, "Error getting epg stream url "+url)
  246. js = json.loads(r.content)
  247. stream_url = js["data"][0]["attributes"]["stream-url"]
  248. stream_url0 = stream_url.replace(token, "")
  249. s.set(ch, stream_url0, expire=3600*24*7, read=False)
  250. return str(stream_url)
  251. def epg_get_stream_url(epgid):
  252. global s, token, headers0
  253. if epgid in s:
  254. stream_url = s[epgid]
  255. stream_url += token
  256. else:
  257. # Getting epg stream url
  258. url = url0 + "record-streams/%s?include=quality&auth_token=app_%s" % (epgid, token)
  259. headers = headers0.copy()
  260. headers["Authorization"] = "Bearer " + token
  261. r = requests.get(url, headers=headers)
  262. if r.status_code <> 200:
  263. print "Error getting epg stream url "+url
  264. raise bottle.HTTPError(r.status_code, "Error getting epg stream url "+url)
  265. js = json.loads(r.content)
  266. stream_url = js["data"][0]["attributes"]["stream-url"]
  267. stream_url0 = stream_url.replace(token, "")
  268. s.set(epgid, stream_url0, expire=3600*24*7, read=False)
  269. return str(stream_url)
  270. def refresh_live_chunklist_url(ch):
  271. global s, token, headers0
  272. stream_url = live_get_stream_url(ch)
  273. r = requests.get(stream_url)
  274. if r.status_code <> 200:
  275. print "Error %s getting live chunklist %s"% (r.status_code,stream_url)
  276. raise bottle.HTTPError(r.status_code)
  277. chid = re.search("resource_id=c\\-(\\w+)",stream_url).group(1)
  278. rest2 = re.search("chunklist.+$", r.content).group(0).replace(token,"")
  279. mediaid = re.search("chunklist_(.+?)\\.m3u8",rest2).group(1)
  280. base2 = hls_base(stream_url)[0]
  281. stream_url2 = base2 + rest2 # chunlist url
  282. s.set("m"+ch, mediaid, expire=3600*24*7, read=False)
  283. s.set("c"+ch, stream_url2, expire=3600*24*7, read=False)
  284. return stream_url2,mediaid
  285. def refresh_epg_chunklist_url(stream_url):
  286. global s, token, headers0
  287. r = requests.get(stream_url)
  288. if r.status_code <> 200:
  289. print "Error %s getting archive chunklist %s"% (r.status_code,stream_url)
  290. raise bottle.HTTPError(r.status_code)
  291. epgid = re.search("resource_id=a-(\\d+)",stream_url).group(1)
  292. rest2 = re.search("chunklist.+$", r.content).group(0)
  293. mediaid = re.search("chunklist_(.+?)\\.m3u8",rest2).group(1)
  294. s.set("m"+epgid, mediaid, expire=3600*24*7, read=False)
  295. base2 = hls_base(stream_url)[0]
  296. stream_url2 = base2 + rest2 # chunlist url
  297. return stream_url2,mediaid
  298. ### Archive ts chunk ###
  299. @app.route("/<key>/live/<ch>/<ts>/<tail>")
  300. def get_archive_chunk(key, ch, ts, tail):
  301. global s, token, headers0
  302. path0, rest = hls_split(request.url)
  303. epgid = re.search("resource_id=a-(\\d+)",rest).group(1)
  304. chunkid = re.search("(\\d+)\\.ts", rest).group(1)
  305. path2 = epgid + "/" + chunkid
  306. if CACHE and path2 in s:
  307. print "** %s: serving archive ts from cache %s" % (request.remote_addr,path2)
  308. f = s.get(path2, read=True)
  309. response.headers["Content-Type"] = s[path2+"@"] #'video/MP2T'
  310. response.headers["Content-Length"] = s[path2+"#"]
  311. while True:
  312. chunk = f.read(8192)
  313. if not chunk:
  314. break
  315. yield chunk
  316. else: # No cache
  317. stream_url = epg_get_stream_url(epgid)
  318. if "m"+epgid in s:
  319. mediaid= s["m"+epgid]
  320. else:
  321. chunklist_url, mediaid = refresh_epg_chunklist_url(stream_url)
  322. base0, rest0 = hls_base(stream_url)
  323. #media_w76603200_0.ts?resource_id=a-6559656352477&auth_token=app_
  324. rest2 = "media_%s_%s.ts?resource_id=a-%s&auth_token=app_" % (mediaid, chunkid, epgid)
  325. url = base0 + rest2 + token
  326. print "** %s: getting archive ts from %s(%s) - %s" % (request.remote_addr,path2, mediaid, rest2[:rest2.index("?")])
  327. #print url
  328. headers = dict(request.headers)
  329. del headers["Host"]
  330. # headers["Authorization"] = "Bearer " + token
  331. r = requests.get(url, stream=True, headers=headers)
  332. if r.status_code <> 200:
  333. r = requests.get(url, stream=True, headers=headers) # try once more
  334. if r.status_code <> 200:
  335. # Refresh chunklist
  336. print "## %s: Refreshing chunklist/mediaid for epg %s" %(request.remote_addr, epgid)
  337. chunklist_url, mediaid = refresh_epg_chunklist_url(stream_url)
  338. rest2 = "media_%s_%s.ts?resource_id=a-%s&auth_token=app_" % (mediaid, chunkid, epgid)
  339. url = base0 + rest2 + token
  340. print "** %s: getting archive ts from %s(%s) - %s" % (request.remote_addr, path2, mediaid, rest2[:rest2.index("?")])
  341. r = requests.get(url, stream=True, headers=headers0)
  342. if r.status_code <> 200:
  343. print "Error %s opening stream \n%s" %(r.status_code,url)
  344. raise bottle.HTTPError(r.status_code, "Error opening stream "+url)
  345. content = ""
  346. response.content_type = r.headers["content-type"] # 'application/vnd.apple.mpegurl' #
  347. # response.headers.clear()
  348. for k in r.headers:
  349. response.headers[k] = r.headers[k]
  350. if DEBUG:
  351. print_headers(response.headers)
  352. for chunk in r.iter_content(chunk_size=8192):
  353. if chunk:
  354. content += chunk
  355. yield chunk
  356. if CACHE:
  357. path2 = epgid + "/" + chunkid
  358. s.set(path2, content, expire=3600, read=True)
  359. s.set(path2+"#", len(content), expire=3600, read=True)
  360. s.set(path2+"@", r.headers["Content-Type"], expire=3600, read=True)
  361. @app.route("/<key>/vod/<ch>/")
  362. def get_vod(key, ch):
  363. global s, token, headers0
  364. path0, rest = hls_split(request.url)
  365. if path0 in s:
  366. stream_url = s[path0] + token
  367. print "** %s: getting vod to %s from cache (%s)" % (request.remote_addr, path0)
  368. else:
  369. url = url0 + "vod-streams/%s?include=language,subtitles,quality &auth_token=app_%s" % (ch, token)
  370. headers = headers0.copy()
  371. headers["Authorization"] = "Bearer " + token
  372. r = requests.get(url, headers=headers)
  373. if r.status_code <> 200:
  374. raise bottle.HTTPError(r.status_code, "Error opening stream "+url)
  375. js = json.loads(r.content)
  376. stream_url = js["data"][0]["attributes"]["stream-url"]
  377. stream_url0 = stream_url.replace(token, "")
  378. s.set(path0, stream_url0, expire=3600*24*7, read=False)
  379. print "** %s: changing vod to %s (%s)" % (request.remote_addr, path0)
  380. if True: # REDIRECT:
  381. bottle.redirect(stream_url, 307)
  382. r = requests.get(stream_url)
  383. if r.status_code <> 200:
  384. raise bottle.HTTPError(r.status_code)
  385. response.content_type = r.headers["content-type"] # 'application/vnd.apple.mpegurl' #
  386. return r.content
  387. def get_epg(ch, start):
  388. url = url0 + "epgs/?filter[channel]=%s&filter[utFrom]=%s&filter[utTo]=%s&include=channel&page[size]=40page[number]=1" % (ch, start, start )
  389. r = requests.get(url)
  390. if r.status_code <> 200:
  391. raise bottle.HTTPError(500, "EPG not found")
  392. js = json.loads(r.content)
  393. if "data" in js:
  394. for epg in js["data"]:
  395. if int(epg["id"]) < 0:
  396. continue
  397. else:
  398. break
  399. return epg
  400. else:
  401. return None
  402. ####################################################################
  403. # Run WSGI server
  404. def start(server,port):
  405. print "*** Starting ltcproxy ***"
  406. print "LTC_USER: %s"% LTC_USER
  407. options = {}
  408. if server == "mtwsgi":
  409. import mtwsgi
  410. server = mtwsgi.MTServer
  411. options = {"thread_count": WORKERS,}
  412. run(app=app,server=server, host='0.0.0.0',
  413. port=port,
  414. reloader=False,
  415. quiet=False,
  416. plugins=None,
  417. debug=True,
  418. config=None,
  419. **options)
  420. def login(user,password):
  421. """Login in to site, get token"""
  422. # Dabūjam tokenu
  423. url = "https://manstv.lattelecom.tv/api/v1.7/post/user/users/%s" % user
  424. params = "uid=5136baee57505694&password=%s&" % (password)
  425. headers = headers2dict("""
  426. User-Agent: Shortcut.lv v2.9.1 / Dalvik/1.6.0 (Linux; U; Android 4.4.2; SM-G900FD Build/KOT49H)
  427. Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  428. Host: manstv.lattelecom.tv
  429. """ )
  430. try:
  431. r = urllib2.Request(url, data=params, headers=headers)
  432. u = urllib2.urlopen(r)
  433. content = u.read()
  434. u.close()
  435. except Exception as ex:
  436. return None
  437. if r and "token" in content:
  438. token = re.search('"token":"(.+?)"', content).group(1)
  439. return token
  440. else:
  441. return False
  442. def refresh_token(token):
  443. """Refresh"""
  444. url = "https://manstv.lattelecom.tv/api/v1.7/post/user/refresh-token/"
  445. params = "uid=5136baee57505694&token=%s&" % (token)
  446. headers = headers2dict("""
  447. User-Agent: Shortcut.lv v2.9.1 / Dalvik/1.6.0 (Linux; U; Android 4.4.2; SM-G900FD Build/KOT49H)
  448. Content-Type: application/x-www-form-urlencoded; charset=UTF-8
  449. Host: manstv.lattelecom.tv
  450. """ )
  451. try:
  452. r = urllib2.Request(url, data=params, headers=headers)
  453. u = urllib2.urlopen(r)
  454. content = u.read()
  455. u.close()
  456. except Exception as ex:
  457. return None
  458. if r and "token" in content:
  459. token2 = re.search('"token":"(.+?)"', content).group(1)
  460. return token2
  461. else:
  462. return False
  463. def print_headers(headers):
  464. for h in headers:
  465. print "%s: %s"%(h,headers[h])
  466. def del_headers(headers0,tags):
  467. headers = headers0.copy()
  468. for t in tags:
  469. if t in headers:
  470. del headers[t]
  471. if t.lower() in headers:
  472. del headers[t.lower()]
  473. return headers
  474. def hls_split(url):
  475. pp = urlparse.urlsplit(url)
  476. path0 = pp.path[:pp.path.rindex("/")+1]
  477. path0 = path0[path0.index("/", 1):]
  478. rest = pp.path[pp.path.rindex("/")+1:] + "?" + pp.query
  479. return path0, rest
  480. def hls_base(url):
  481. base = url.split("?")[0]
  482. base = "/".join(base.split("/")[0:-1])+ "/"
  483. rest = url.replace(base, "")
  484. return base, rest
  485. #########################################################################################
  486. if __name__ == '__main__':
  487. # 1561839586
  488. # get_epg("101", 1561839586)
  489. try:
  490. opts, args = getopt.gnu_getopt(sys.argv[1:], "p:s:dr", ["port=","server=","--debug"])
  491. except getopt.GetoptError as err:
  492. print str(err)
  493. print str(__doc__)
  494. sys.exit(2)
  495. opts = dict(opts)
  496. if not len(args):
  497. print str(__doc__)
  498. sys.exit(2)
  499. if "-r" in opts:
  500. print "Enabling remote debuging (ptvsd)"
  501. import ptvsd
  502. ptvsd.enable_attach(address = ('0.0.0.0', 5678),redirect_output=False)
  503. if "-d" in opts:
  504. print "Enabling debuging mode (more output)"
  505. DEBUG = True
  506. pid = "/var/run/ltcproxy.pid"
  507. daemon = daemonize.Daemon(start, pid)
  508. server = opts["-s"] if "-s" in opts else SERVER
  509. port = opts["-p"] if "-p" in opts else PORT_NUMBER
  510. if "start" == args[0]:
  511. s.clear()
  512. daemon.start(server,port)
  513. daemon.is_running()
  514. elif "stop" == args[0]:
  515. daemon.stop()
  516. elif "restart" == args[0]:
  517. s.clear()
  518. daemon.restart()
  519. daemon.is_running()
  520. elif "manualstart" == args[0]:
  521. s.clear()
  522. start(server,port)
  523. elif "status" == args[0]:
  524. daemon.is_running()
  525. else:
  526. print "Unknown command"
  527. print str(__doc__)
  528. sys.exit(2)
  529. sys.exit(0)