m3u8 proxy for shortcut.lv streams

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