#!/usr/bin/env python
# coding=utf8
#
# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
#
import sys, os, os.path, re, sys
import urllib,urllib2,urlparse
#from xml.sax.saxutils import unescape,escape
from urllib import quote, unquote
import datetime
import HTMLParser
import json
from SourceBase import SourceBase, stream_type
import util
from util import unescape
from collections import OrderedDict
import ssl
if "_create_unverified_context" in dir(ssl):
ssl._create_default_https_context = ssl._create_unverified_context
user_agent = "Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; da-dk) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/7534.48.3"
headers2dict = lambda h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
h = HTMLParser.HTMLParser()
class Source(SourceBase):
def __init__(self,cfg_path=None):
self.name = "ltc"
self.title = "Shortcut.lv (lattelecom.tv)"
self.img = "shortcut.png"
self.desc = "Shortcut.lv (lattelecom.tv) satura skatīšanās"
self.token = "" # manstv.lattelecom.tv
self.session_id = "" # www.shortcut.lv
self.api_url = "https://manstv.lattelecom.tv/api/v1.4/get/"
self.api_url2 = "https://www.shortcut.lv/"
self.headers = headers2dict("""
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.2; SM-G900FD Build/KOT49H)
Host: manstv.lattelecom.tv
Connection: Keep-Alive
""")
self.headers2 = headers2dict("""
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
Accept-Language: en-US,en;q=0.8
""")
self.headers3 = headers2dict("""
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:60.0) Gecko/20100101 Firefox/60.0
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
""")
self.channels = None
### specific service info ###
self.ch = []
self.ch2 = []
self.ch_id={}
self.ch_id2={}
self.ch_name={}
self.epg=[]
self.epg_id={}
self.epg_id2={}
self.epg_date={}
self.epg_ch={}
self.epgdates = []
self.today = datetime.date.today()
self.today2 = self.today.strftime("%d.%m.%Y")
cur_directory = os.path.dirname(os.path.abspath(__file__))
if not cfg_path: cfg_path = cur_directory
self.config_file = os.path.join(cfg_path,self.name+".cfg")
self.options = OrderedDict([("user","lietotajs"),("password","parole")])
self.options_read()
def get_content(self, data):
print "[ltc] get_content:", data
source, data, path, plist, clist, params, qs = self.parse_data(data)
content=[]
content.append(("..return", "back","back.png","Return back"))
if clist=="home":
content.extend([
("TV tiešraides", "ltc::tiesraide","","TV tiešraides"),
("TV arhīvs", "ltc::arhivs","","TV arhīvs atseviškiem kanāliem"),
("Bērnu", "ltc::videonoma/bernu","","Videonomas bērnu filmas un seriāli"),
("Filmas", "ltc::videonoma/filmas","","Videonomas filmas"),
("Premiere filmas", "ltc::videonoma/premiere","","Videonomas premiere filmas"),
("Seriāli", "ltc::videonoma/series","","Videonomas seriāli"),
("360 Play", "ltc::videonoma/360play","","Videonomas lattelecom saturs"), # TODO
#("Videonoma", "ltc::videonoma","","Filmas (arī Priemiere) un seriāli"),
("Meklēt filmas", "ltc::viss/search/?cat=movies&q={0}","","Meklēt filmu sadaļa"),
("Meklēt seriālus", "ltc::viss/search/?cat=series&q={0}","", "Meklēt seriālu sadaļā"),
#("Meklēt TV arhīvā", "ltc::viss/search/?cat=archive&q={0}","", "Meklēt TV arhīvā"),
#("Meklēt TV arhīvā", "ltc::search/{0}","","Meklēt TV arhīvā"), #TODO
])
return content
### Meklēt TV (1.4 API)
elif clist == "search": #TODO vod/search/{q}
#r = self.call("vod/"+data)
return content
### Meklēsana video (www )###
elif path == 'viss/search/': #TODO vod/search/{q}
r = self.call2(data)
if "cat=movies" in data:
result = re.findall(r'class="forward-link" href="/([^"]+)/">(
(\w+)
)*([^<]+)([^<]+)<', r, re.DOTALL)
elif "cat=series" in data:
result = re.findall(r'class="forward-link" href="/([^"]+)/">(
(\w+)
)*
([^<]+)
([^<]+)<', r, re.DOTALL)
else:
result = re.findall(r'class="forward-link" href="/([^"]+)/">(
(\w+)
)*
([^<]+)
([^<]+)<', r, re.DOTALL)
for item in result:
title1 = item[4]
title2 = item[5]
if title1 <> title2:
title = "%s ~ %s" % (title1, title2)
if item[1]:
title = title + "[J]" if item[2] == "Jaunums" else title + "[P]"
data2 = item[0]
if re.search("e\d+$", data2):
data2 += "?series"
img = "https://www.shortcut.lv" + item[3]
desc = title
content.append((title,self.name+"::"+data2,img,desc))
return content
### Tiešraides kanānālu saraksts ###
elif data=="tiesraide":
#r = self.call2(data)
#m = re.search("var xprs_ides_array = (.+);", r, re.MULTILINE)
#if m:
# js=json.loads(m.group(1))
#else:
# raise Exception("Error reading channel list")
r = self.call2("program-snippet.json")
try:
js = json.loads(r)
except:
js = {}
for item in self.get_channels():
if item["live"]=='0':continue
title = item["name"]
data2 = "content/live-streams/%s?include=quality"%item["id"]
if item["xprs_id"] in js:
epg = js[item["xprs_id"]]
desc = "%s - %s (%s-%s)"%(title,epg[0]["t"],epg[0]["hs"],epg[0]["he"])
title = desc
img = "https://www.shortcut.lv" + epg[0]["p"]
#img = "https://manstv.shortcut.lv/"+ item['broadcast_default_picture']
else:
img = "https://manstv.shortcut.lv/"+ item['broadcast_default_picture']
desc = title
content.append((title,self.name+"::"+data2,img,desc))
return content
### TV arhīva sākums ###
elif data=="archive" or data=="arhivs":
#self.get_epg()
content.extend([
("Archive - categories", "ltc::archive/categories","","TV live archive by categories"),
("Archive - channels", "ltc::archive/channels","","TV live archive by channels"),
#("Archive - dates", "ltc::archive/dates","","TV live archive by dates"),
])
return content
### Arhīva kategorijas
elif data=="archive/categories":
#https://manstv.lattelecom.tv/api/v1.3/get/archive/records/?filter[category]=13&limit=10&until_id=1458681019238
#https://manstv.lattelecom.tv/api/v1.3/get/archive/categories/
r = self.call(data)
for item in r["items"]:
title = item["name"]
data2 = "archive/records?filter[category]=%s&limit=40"%item["id"]
img = "https://manstv.lattelecom.tv/"+ item['image']
desc = title
content.append((title,self.name+"::"+data2,img,desc))
return content
### Arhīva kategoriju video
elif "archive/records" in data:
#https://manstv.lattelecom.tv/api/v1.3/get/archive/records/?filter[category]=13&limit=10&until_id=1458681019238
#https://manstv.lattelecom.tv/api/v1.3/get/archive/categories/
r = self.call(data)
for i,item in enumerate(r["items"]):
#if not item["is_archive"]==u"1":continue # TODO jānočeko, kurs no atributiem apzīmē, ka ir arhīvs
if not self.epg_id.has_key(item["id"]):
item["time_start2"] = datetime.datetime.fromtimestamp(int(item["unix_start"]))
item["time_stop2"] = datetime.datetime.fromtimestamp(int(item["unix_stop"]))
item["date"]=item["time_start2"].strftime("%Y-%m-%d")
self.epg.append(item)
index = self.epg.index(item)
self.epg_id[item["id"]]=index
if not item["date"] in self.epg_date:
self.epg_date[item["date"]]=[]
self.epg_date[item["date"]].append(index)
if not item["channel_id"] in self.epg_ch:
self.epg_ch[item["channel_id"]]=[]
self.epg_ch[item["channel_id"]].append(index)
item = self.get_epg_id(item["id"])
ch = self.get_channel_by_id2(item["channel_id"])
ch_name = ch["name"] if ch else item["channel_id"]
title = u"%s (%s-%s)"%(item["title"], item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"))
#data2 = "archive/get-stream/%s?channelid=%s"%(item["id"],ch["id"])
data2 = "content/record-streams/%s?include=quality"%item["id"]
img = "https://manstv.lattelecom.tv/"+ item["url"]
desc = u"%s - %s\n%s %s-%s\n%s\n%s"%(ch_name,item["title"], item["date"], item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"),
item["category1"],item["description"])
content.append((title,self.name+"::"+data2,img,desc))
if "until_id" in data:
data2 = re.sub("until_id=\d+","until_id="+item["id"],data)
else:
data2 = data + "&until_id=%s"%item["id"]
content.append(("Next page",self.name+"::"+data2,"next.png","Go to next page"))
return content
### Arhīva kanānālu saraksts
elif data=="archive/channels":
for item in self.get_channels():
if not item["is_archive"]==u"1":continue
title = item["name"]
data2 = "archive/channel/%s?date=%s"%(item["id"],self.today.strftime("%Y-%m-%d"))
img = "https://manstv.lattelecom.tv/"+ item['broadcast_default_picture']
desc = title
content.append((title,self.name+"::"+data2,img,desc))
return content
### Arhīva kanānāla video saraksta
elif "archive/channel/" in data:
chid = path.split("/")[2]
for item in self.get_epg_date(qs["date"],chid):
if item["is_archive"]=='0':continue
if item["time_stop2"] > datetime.datetime.now(): continue
ch = self.get_channel_by_id2(item["channel_id"])
ch_name = ch["name"] if ch else item["channel_id"]
#title = u"[%s %s-%s] %s - %s"%(item["date"],item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"),ch_name,item["title"])
title = u"%s (%s-%s)"%(item["title"], item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"))
#data2 = "archive/get-stream/%s?channelid=%s"%(item["id"],ch["id"])
data2 = "content/record-streams/%s?include=quality"%item["id"]
img = "https://manstv.lattelecom.tv/"+ item["url"]
desc = u"%s - %s\n%s %s-%s\n%s\n%s"%(ch_name,item["title"], item["date"], item["time_start2"].strftime("%H:%M"),item["time_stop2"].strftime("%H:%M"),
item["category1"],item["description"])
content.append((title,self.name+"::"+data2,img,desc))
#date2=datetime.datetime.strptime(qs["date"], '%Y-%m-%d').date()-datetime.timedelta(days=1)
date2 = datetime.date(*tuple(map(int, qs["date"].split("-")))) - datetime.timedelta(days=1)
date2 = date2.strftime("%Y-%m-%d")
if "date=" in data:
data2 = re.sub("date=[\d-]+","date="+date2,data)
else:
data2 = data + "&date=%s"%date2
content.append(("Previous day (%s)"%date2,self.name+"::"+data2,"","Go previous day"))
return content
### Arhīva datumi
elif clist=="arhivs" and len(data.split("/"))==2: # TODO - pasreiz nestrada
ch = data.split("/")[1]
r= self.call(data)
m = re.search('class="spac no_select">([^<]+)', r, re.IGNORECASE)
if m:
ch_name = m.group(1)
else:
ch_name = ""
today = datetime.date.today()
for i in range(7):
date = today-datetime.timedelta(i)
title = ch_name + " - " + date.strftime("%d.%m.%Y")
data2 = "%s/%s"%(data,date.strftime("%Y-%m-%d"))
img = ""
desc = title
content.append((title,self.name+"::"+data2,img,desc))
return content
### Arhīva dienas raidijumi
elif clist=="arhivs" and len(data.split("/"))==3: # TODO - nestrādā
ch = data.split("/")[1]
date = data.split("/")[2]
r= self.call(data)
m = re.search('class="spac no_select">([^<]+)', r, re.IGNORECASE)
if m:
ch_name = m.group(1)
else:
ch_name = ""
for item in re.findall('(?i)href="/([^"]+?)" id="" class="archive_programm_a">
([^<]+)
([^<]+)', r):
title = "%s - %s"%(item[1],item[2])
data2 = item[0]
img = ""
desc = "%s (%s)\n%s"%(ch_name,date,title)
content.append((title,self.name+"::"+data2,img,desc))
return content
### Videonoma galvenā (vecā, vairs nestrada filtri)
elif data=="videonoma":
content.extend([
("Filmas - jaunākās", "ltc::videonoma?page=0&genre=all_movies&sorts=laiks&cnt=40&clear=true&filter={}","https://www.shortcut.lv/media/features/2013-12-17/aa3b_videonoma_dropdown_filmas.png","Jaunākās filmas"),
("Filmas - pēc nosaukuma", "ltc::videonoma?page=0&genre=all_movies&sorts=title&cnt=40&clear=true&filter={}","https://www.shortcut.lv/media/features/2013-12-17/aa3b_videonoma_dropdown_filmas.png","Filmas pēc nosaukuma"),
("Filmas - latviski", 'ltc::videonoma?page=0&genre=all_movies&sorts=laiks&cnt=40&clear=true&filter={"valoda":["lv"]}',"https://www.shortcut.lv/media/features/2013-12-17/aa3b_videonoma_dropdown_filmas.png","Filmas latviešu valodā"),
("Filmas - pēc reitinga", "ltc::videonoma?page=0&genre=all_movies&sorts=imbd&cnt=40&clear=true&filter={}","https://www.shortcut.lv/media/features/2013-12-17/aa3b_videonoma_dropdown_filmas.png","Filmas pēc IMBD reitinga"),
("Filmas bērniem - jaunākās", "ltc::videonoma?page=0&genre=3&sorts=laiks&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_berniem.png","Jaunākie bernu video"),
("Filmas bērniem - pēc nosaukuma", "ltc::videonoma?page=0&genre=3&sorts=title&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_berniem.png","Bērnu video pēc nosaukuma"),
("Filmas bērniem - latviski", 'ltc::videonoma?page=0&genre=3&sorts=laiks&cnt=40&clear=true&filter={"valoda":[\"lv\"]}',"https://www.shortcut.lv/images/redesign/videonoma_dropdown_berniem.png","Bērnu video latviski"),
("Filmas bērniem - pēc reitinga", "ltc::videonoma?page=0&genre=3&sorts=imbd&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_berniem.png","Bērnu video pēc IMBD reitinga"),
("Sērijas - jaunākās", "ltc::videonoma?page=0&genre=27&sorts=laiks&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Jaunākās sērijas"),
("Sērijas - pēc nosaukuma", "ltc::videonoma?page=0&genre=27&sorts=title&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Sērijas pēc pēc nosaukuma"),
("Sērijas animācijas - jaunākās", "ltc::videonoma?page=0&genre=27&sorts=laiks&cnt=40&clear=true&filter={\"zanrs\":[\"201\"]}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Animācijas serijas"),
("Sērijas animācijas - pēc nosaukuma", "ltc::videonoma?page=0&genre=27&sorts=title&cnt=40&clear=true&filter={\"zanrs\":[\"201\"]}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Animācijas serijas"),
("Sērijas ģimenes - jaunākās", "ltc::videonoma?page=0&genre=27&sorts=laiks&cnt=40&clear=true&filter={\"zanrs\":[\"195\"]}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Animācijas serijas"),
("Sērijas ģimenes - pēc nosaukuma", "ltc::videonoma?page=0&genre=27&sorts=title&cnt=40&clear=true&filter={\"zanrs\":[\"195\"]}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Animācijas serijas"),
("Sērijas latviski - jaunākās", 'ltc::videonoma?page=0&genre=27&sorts=laiks&cnt=40&clear=true&filter={"valoda":["lv"]}',"https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Sērijas latviski"),
("Sērijas latviski - pēc nosaukuma", 'ltc::videonoma?page=0&genre=27&sorts=title&cnt=40&clear=true&filter={"valoda":["lv"]}',"https://www.shortcut.lv/images/redesign/videonoma_dropdown_raidijumi.png","Sērijas latviski"),
("Koncerti - jaunākie", "ltc::videonoma?page=0&genre=19&sorts=laiks&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_koncerti.png","Jaunākie koncerti"),
("Koncerti - pēc nosaukuma", "ltc::videonoma?page=0&genre=19&sorts=title&cnt=40&clear=true&filter={}","https://www.shortcut.lv/images/redesign/videonoma_dropdown_koncerti.png","Koncerti pēc pēc nosaukuma"),
])
return content
### Videonomas saraksti (vecie, vairs nestrādā filtri)
elif path == "videonoma":
url = "https://www.shortcut.lv/movies-snippet.json"+params
r = self._http_request(url,headers=self.headers2)
if not r:
return content
js = json.loads(r,"utf8")
if not r:
return content
for item in js["movies"]:
if not item["title"]:
continue
title = item["title"].encode("utf8")
data2 = item["url"][1:].encode("utf8")
if data2[-1]=="/": data2=data2[:-1]
if "/raidijumi/" in data2:
data2 += "?series" # TODO
img = "https://www.shortcut.lv"+item["image"].encode("utf8")
desc = "%s\n%s"%(title,item["genre"].encode("utf8"))
if "is_premium" in item and item["is_premium"]:
title = title + " [P]"
desc = desc + "\nPremium"
content.append((title,self.name+"::"+data2,img,desc))
m = re.search("page=(\d+)",data)
if m:
page = int(m.group(1))
data2 = re.sub("page=\d+","page=%s"%(page+1),data)
content.append(("Next page",self.name+"::"+data2,"next.png","Go to next page"))
return content
### Filmas galvenā ###
elif data == "videonoma/filmas":
content.extend([
("Aktuālās", "ltc::viss/actual_films","","Nesen pievienotas filmas"),
("Komēdijas", "ltc::viss/comedy","","Komēdijas"),
("Detektīvi", "ltc::viss/crime","","Detektivi"),
("Ģimenes", "ltc::viss/family","","Ģimenes filmas"),
("Asa sižeta", "ltc::viss/action","","Asa sižeta filmas"),
("Romantika", "ltc::viss/romance","","Romantiskās filmas"),
("Piedzīvojumu", "ltc::viss/adventure","","Piedzivojumu filmas"),
("Supervaroņi", "ltc::viss/superheros","","Supervaroņu filmas"),
("Fantastika", "ltc::viss/scifi","","Fantastikas filmas"),
("Dokumentalās", "ltc::viss/documentaries","","Dokumentalās filmas"),
("Šausmu", "ltc::viss/horror","","Šausmu filmas"),
("Retro", "ltc::viss/retro_films","","Retro filmas"),
("Koncerti un karaoke", "ltc::viss/concerts_karaoke","","Koncerti un filmas"),
])
### Sērijas galvenā ###
elif data == "videonoma/series":
content.extend([
("Aktuālie seriāli", "ltc::viss/actual_series?series","","Nesen pievienotie seriāli"),
("Aktuālie šovi", "ltc::viss/actual_series?series","","Nesen pievienotie TV šovi"),
("Populārākie seriāli", "ltc::viss/popular_series?series","","Populārākie seriāli"),
("Dokumentalie seriāli", "ltc::viss/documentary?series","","Dokumentalie seriāli"),
("Izklaides pārraides", "ltc::viss/entertainment?series","","Izklaides pārraides"),
("Detektivseriāli", "ltc::viss/Crime_series?series","","Detektivseriāli"),
("Dramas seriāli", "ltc::viss/drama_series?series","","Dramas seriāli"),
("Par dabu", "ltc::viss/nature?series","","Seriāli par dabu"),
("Gardēžiem", "ltc::viss/gourmets?series","","Seriāli gardēžiem"),
("Mistērija", "ltc::viss/mystery_series?series","","Mistērijas seriāli"),
("Oriģinālsaturs", "ltc::viss/originals_series?series","","Oriģinālsatura seriāli"),
("Klasika", "ltc::viss/classic?series","","Klasika"),
])
### Bērnu galvenā ###
elif data == "videonoma/bernu":
content.extend([
("Nesen pievienotais", "ltc::viss/actual_kid","","Nesen pievienotais bernu saturs"),
("Bērnu Premiere", "ltc::viss/kids_premiere","","Bērnu Premiere saturs"),
("Multfilmas", "ltc::viss/animation2","","Multfilmas"),
("Bērnu seriāli", "ltc::viss/kids_series?series","","Bērnu seriāli"),
("Ģimenes filmas", "ltc::viss/family","","Ģimenes filmas"),
("Multfilmas latviski", "ltc::viss/animation_lv","","Multfilmas latviski"),
("Retro multfilmas", "ltc::viss/retro_animation","","Retro multfilmas"),
("Latviešu multfilmas", "ltc::viss/animation","","Latviešu multfilmas"),
("Raidijumi berniem", "ltc::viss/kids_events","","Raidijumi berniem"),
])
### Filmas premiere galvenā ###
elif data == "videonoma/premiere":
content.extend([
("Aktuālās Premiere filmas", "ltc::viss/actual_premiere","","Nesen pievienotās Premiere filmas"),
("Tikko no kinoteātra", "ltc::viss/just_from_cinema","","Filmas tikko no kinoteātra"),
("Bērnu Premiere", "ltc::viss/kids_premiere","","Bērnu Premiere saturs"),
("Komēdijas Premiere", "ltc::viss/comedy_premiere","","Premiere komēdijas filmas"),
("Detektivi Premiere", "ltc::viss/crime_premiere","","Premiere detektivfilmas"),
("Piedzīvojumu Premiere", "ltc::viss/adventure_premiere","","Premiere piedzivojumu filmas"),
("Fantastika Premiere", "ltc::viss/scifi_premiere","","Premiere fantastikas filmas"),
("Šausmu Premiere", "ltc::viss/horror_premiere","","Premiere šausmu filmas"),
])
### 360 Play galvenā ###
elif data == "videonoma/360play":
content.extend([
("Viss", "ltc::viss/bezmaksas?series","","Viss bezmaksas saturs"),
("360TV", "ltc::viss/360_free?series","","360TV bezmaksas saturs"),
("Red Bull", "ltc::viss/Red_bull?series","","Red Bull bezmaksas saturs"),
])
r = self.call
### Videonomas saraksti ###
elif plist[0] == "viss" or "load_more" in data:
#content.append(("Videonomas saraksts", "", "", ""))
if "viss" in data:
r = self.call2(data)
m = re.search('(.+?)
', r, re.DOTALL)
html = m.group(1) if m else ""
else:
url = self.api_url2 + path
params = data.split("?")[1]
r = self._http_request(url, params, headers=self.headers3 )
js = json.loads(r)
html = js["data"] if "data" in r else ""
result = re.findall("
", html, re.DOTALL)
for it in result:
title1 = re.search('
(.+?)<', it, re.DOTALL).group(1)
title2 = re.search('
(.+?)<', it, re.DOTALL).group(1)
if title1 <> title2:
title = "%s ~ %s" % (title1, title2)
else:
title = title1
img = self.api_url2 + re.search('img src="(.+?)"', it).group(1)
data2 = re.search('href="/(.+?)/"', it).group(1)
if "?series" in data or re.search("e\d+$", data2):
data2 += "?series"
if "Jaunums" in it:
title += " [J]"
if "Premiere" in it:
title += " [P]"
desc = title
content.append((title,self.name+"::"+data2,img,desc))
if not "end-reached-box" in r:
if "load_more" in data:
page = int(qs["pack"])
data2 = re.sub("pack=\d+","pack=%s"%(page+1),data)
else:
section = re.search('data-section="(\d+)"', r).group(1)
data2 = "load_more.json?pack=1§ion=%s" % section
content.append(("Next page",self.name+"::"+data2,"next.png","Go to next page"))
return content
### Sērijas
elif clist=="videonoma" and (params=="?series" or "season_nr" in qs):
url = "https://www.shortcut.lv/"+path
r = self._http_request(url,headers=self.headers2)
if not r:
return content
m = re.search(r'data-movieid=\d+>
([^<]+)
]+>([^<]+)<', r)
if m:
title1 = unescape(m.group(1))
title2 = unescape(m.group(2))
else:
m = re.search('
', r, re.IGNORECASE)
title1 = title2 = unescape(m.group(1)) if m else "Video"
if 'episode_switcher_title' in r:
set1 = title1.replace("\xe2\x80\x93", "-")
if " - " in set1:
set1 = set1.split(" - ")[0]
set2 = title2.replace("\xe2\x80\x93", "-")
if " - " in set2:
set2 = set2.split(" - ")[0]
if set1 <> set2:
raidijums = "%s ~ %s" % (set1, set2)
else:
raidijums = set1
else:
m = re.search('
([^<]+)
', r)
raidijums = m.group(1) if m else "Series"
img0 = re.search('
', r).group(1) if re.search('
', r) else ""
m = re.search('season_choice', r)
# Ir sezonas
if m:
result = re.findall(r"""season_choice\(.+?'epizode','([^']*)',[^,]+,'(\d+)',[^,]+,[^,]+\)">([^<]+)<""", r, re.MULTILINE)
if not result:
raise Exception("No seasons find!")
vid = result[0][0]
if not "season_nr" in qs: # Sezonu saraksts
for s,it in enumerate(result):
title = "%s - %s" % (raidijums, it[2])
data2 = path+"?season_nr=%s"%(it[1])
img = img0
desc = title
content.append((title, self.name + "::" + data2, img, desc))
#return content
else: # Sezonas epizožu saraksts
if not "season_nr" in qs:
qs["season_nr"]="0"
# https://www.shortcut.lv/api/episode-loader-design17/0?chunk_size=4&sorting=epizode&series_id=dora_the_explorer
# https://www.shortcut.lv/api/episode-loader-design17/3?chunk_size=4&sorting=epizode&series_id=dora_the_explorer&movie_id=10161&z360tv=&is_active_season=false HTTP/1.1
# https://www.shortcut.lv/api/episode-loader-design17/3?chunk_size=4&sorting=epizode&series_id=dora_the_explorer
url = "https://www.shortcut.lv/api/episode-loader-design17/%s?chunk_size=4&sorting=epizode&series_id=%s" % (qs["season_nr"], vid)
r = self._http_request(url,headers=self.headers2)
try:
js = json.loads(r)
except:
raise Exception("Error getting episode list")
result = re.findall(r'class="" href="([^"]+)".+?image:url\(([^ \)]+)\); ">
([^<]+)
([^<]+)
', js["data"])
for item in result:
title = "%s - %s (%s)"%(raidijums,item[2],item[3])
data2 = item[0][1:]
img = "https://www.shortcut.lv"+item[1]
desc = title
content.append((title,self.name+"::"+data2,img,desc))
#return content
# Nav sezonu
else:
result = re.findall(r'class="" href="([^"]+)".+?image:url\(([^ \)]+)\).+?class="episode_titlez_design17">([^<]+)
([^<]+)
', r)
for item in result:
title = "%s - %s(%s)"%(raidijums,item[2],item[3])
data2 = item[0][1:]
img = "https://www.shortcut.lv"+item[1]
desc = title
content.append((title,self.name+"::"+data2,img,desc))
#return content
if not result: # nav ne epizožu, atgriež pats sevi bez ?series
title = desc = raidijums
img = img0
data2 = path
content.append((title,self.name+"::"+data2,img,desc))
return content
### Videonomas video
elif clist=="videonoma" and len(data.split("/"))> 2:
ch = data.split("/")[1]
video_id=data[data.find("/")+1:]
#video_id=data.split("/")[-1]
if not self.is_logedin2():
if not self.login2():
content=("Can not login\nPlease check lattelecom.tv username/password in\n/usr/lib/enigma2/python/Plugins/Extensions/sources/ltc.cfg file","","","No stream found. Please check lattelecom.tv username/password in sources/ltc.cfg file ")
return content
data2 = self.get_noma_url(video_id)
if not data2:
content=("No stream found for '%s'"%data,"","","No stream found")
return content
r = self.call2(data)
m = re.search('
', r, re.IGNORECASE)
if m:
title = m.group(1)
else:
title = ""
desc = title
content = (title,data2,"",desc)
return content
return content
def get_streams(self, data):
print "[ltc] get_streams:", data
if not self.is_video(data):
return []
source, data, path, plist, clist, params, qs = self.parse_data(data)
#if "::" in data: data = data.split("::")[1]
### Video nomas strīmus pagaidām dabu no mājas lapas TODO
if data.split("/")[0]=="videonoma" and len(data.split("/"))>1:
#video_id=data.split("/")[-1]
streams = self.get_stream_url2(data)
else:
if not self.is_logedin():
if not self.login():
return []
if plist[1] == "catchup":
start = int(qs["start"]) + 1
#url = "https://manstv.lattelecom.tv/api/v1.7/get/content/epgs/?filter[channel]=101&filter[utFrom]=1551551500&include=channel&page[size]=40page[number]=1"
data2 = "content/epgs/?filter[channel]=%s&filter[utFrom]=%s&filter[utTo]=%s&include=channel&page[size]=40page[number]=1" % (plist[2], start, start )
r2 = self.call(data2)
if "data" in r2:
epgid = r2["data"][0]["id"]
else:
return []
data = "ltc::content/record-streams/%s?include=quality" % epgid
source, data, path, plist, clist, params, qs = self.parse_data(data)
r = self.call(data)
if not r: return []
if "errors" in r:
return []
self.refresh_token()
token = "&auth_token=app_%s"%(self.token)
vid = data.split("/")[2].split("?")[0]
vtype = data.split("/")[1]
if vtype == "live-streams":
ch = self.get_channel_by_id(vid)
offset = "%2B03%3A00" # TODO - vajag aktuālo laika nobidi no GMS
data2 = "tv/epg-live/%s/?offset=%s"%(ch["xprs_id"],offset)
r2 = self.call(data2)
if r2 and r2["items"]:
title = r2["items"][0]["title"].encode("utf8")
t1 = datetime.datetime.fromtimestamp(int(r2["items"][0]["unix_start"])).strftime('%H:%M')
t2 = datetime.datetime.fromtimestamp(int(r2["items"][0]["unix_stop"])).strftime('%H:%M')
title = "%s (%s-%s)"%(title,t1,t2)
img = "https://manstv.lattelecom.tv/cache/" + r2["items"][0]["url"]
desc = r2["items"][0]["description"]
else:
title = ch["name"]
desc = title
img = ""
elif vtype == "record-streams":
epg = self.get_epg_id(vid)
if epg:
title = epg["title"].encode("utf8")
t1 = datetime.datetime.fromtimestamp(int(epg["unix_start"])).strftime('%H:%M')
t2 = datetime.datetime.fromtimestamp(int(epg["unix_stop"])).strftime('%H:%M')
date = epg["date"]
#title = "%s [%s %s-%s]"%(title,date,t1,t2)
desc = title + "\n" + epg["description"].encode("utf8")
img = epg["img"].encode("utf8") if "img" in epg else ""
else:
title = desc = data
img = ""
streams = []
for s in r["data"]:
stream = util.item()
stream["url"]=(s["attributes"]["stream-url"]+token.encode("utf8")).encode("utf8")
stream["name"]=title
stream["desc"]=desc
stream["img"] = img
stream["type"]="hls"
m=re.search(".+_(\w\w)_(\w\w)\.\w+",s["id"])
if m:
stream["quality"]=m.group(2).encode("utf8")
stream["lang"]=m.group(1).encode("utf8")
streams.append(stream)
### TODO - sakārtot sarakstu, lai pirmais ir labakais video
qlist = ["???","lq","mq","hq","hd"]
llist = ["fr","en","ru","lv"]
for s in streams:
lv = llist.index(s["lang"])*10 if s["lang"] in llist else 0
qv=qlist.index(s["quality"]) if s["quality"] in qlist else 0
s["order"] = lv+qv
streams = sorted(streams,key=lambda item: item["order"],reverse=True)
return streams
def is_video(self,data):
if "::" in data:
data = data.split("::")[1]
cmd = data.split("/")
if "get-stream" in data:
return True
elif cmd[0] in ("content") and cmd[1] in ("live-streams","record-streams","vod-streams", "catchup"):
return True
elif cmd[0]=="arhivs" and len(cmd)==4:
return True
elif cmd[0]=="videonoma" and len(cmd) >= 3 and not "?" in data:
return True
else:
return False
def get_channels(self):
if self.ch:
return self.ch
if not self.check_logedin():
self.login() # citādi nerāda TV3, LNT, TV6
r= self.call("tv/channels")
self.ch=[]
for i,item in enumerate(r["items"]):
self.ch.append(item)
self.ch_id[item["id"]]=i
self.ch_id2[item["xprs_id"]]=i
self.ch_name[item["name"]]=i
return self.ch
def get_channel_by_id(self,chid):
if not self.ch:
self.get_channels()
if not self.ch:
return None
return self.ch[self.ch_id[chid]] if self.ch_id.has_key(chid) else None
def get_channel_by_id2(self,chid):
if not self.ch:
self.get_channels()
if not self.ch:
return None
return self.ch[self.ch_id2[chid]] if self.ch_id2.has_key(chid) else None
def get_channels2(self):
if self.ch2:
return self.ch2
r= self.call2("tiesraide")
self.ch2=[]
for item in re.findall(r'
([^<]+)
]+>([^<]+)<', r)
if m:
title1 = unescape(m.group(1))
title2 = unescape(m.group(2))
else:
m = re.search('
', r, re.IGNORECASE)
title1 = title2 = unescape(m.group(1)) if m else "Video"
nfo["title"] = title1
if not title1 == title2:
nfo["originaltitle"] = title2
if nfo["originaltitle"] and not nfo["title"]:
nfo["title"] = nfo["originaltitle"]
if 'episode_switcher_title' in r:
set1 = title1.replace("\xe2\x80\x93", "-")
if " - " in set1:
set1 = set1.split(" - ")[0]
set2 = title2.replace("\xe2\x80\x93", "-")
if " - " in set2:
set2 = set2.split(" - ")[0]
if set1 <> set2:
nfo["set"] = "%s ~ %s" % (set1, set2)
m = re.search(r"
(S(\d+)E(\d+))<", r, re.IGNORECASE | re.DOTALL)
if m:
#nfo["title"] = nfo["title"] + " (%s)" % m.group(1)
#nfo["originaltitle"] = nfo["originaltitle"] + " (%s)" % m.group(1)
nfo["season"] = m.group(2)
nfo["episode"] = m.group(2)
nfo["thumb"] = tt('
Gads<.+?content">([^<]+)<', r, "")
nfo["runtime"] = tt('movie-informatio-title">Garums<.+?content">([^<]+)<', r, "")
nfo["quality"] = tt('movie-informatio-title">Kvalitāte<.+?content">([^<]+)<', r, "")
nfo["genre"]=tt('movie-informatio-title">Žanrs<.+?content">([^<]+)<', r, "")
nfo["director"] = tt('movie-informatio-title">Režisor.<.+?content">([^<]+)<', r, "")
nfo["actor"] = tt2('class="movie-informatio-content actors">([^<]+)<', r, "")
nfo["language"] = tt2('movie-informatio-title">Valodas*<.+?content">([^<]+)<', r, "")
nfo["subtitles"] = tt2('movie-informatio-title">Subtitri<.+?content">([^<]+)<', r, "")
nfo["plot"] = tt('class="movie-informatio-content introduction">([^<]+)<', r, "")
nfo["tagline"] = nfo["plot"]
return nfo
def get_stream_url2(self,data):
video_id=data[data.find("/")+1:]
if not self.is_logedin2():
if not self.login2():
return []
#data2 = self.get_noma_url(video_id)
nfo = self.get_info2(data)
title = util.nfo2title(nfo)
desc = util.nfo2desc(nfo)
img = nfo["thumb"]
#xml = util.nfo2xml(nfo)
url = "https://www.shortcut.lv/xmls/%s.xml"%video_id
headers = self.headers2
headers["Cookie"] = self.session_id
response = urllib2.urlopen(urllib2.Request(url, headers=headers))
r = response.read()
servers = re.findall("(?s)
([^<]+)", r)
streams_xml = re.findall('
(mp4:\w+(\w\w)_(\w\w).mp4)',r)
if not streams_xml:
raise Exception("No stream, buy movie?")
resource_id = re.search("(?s)
([^<]+)", r).group(1)
token = re.search("(?s)
([^<]+)", r).group(1)
streams=[]
captions = []
llist = ["fr","en","ru","lv"]
for s in re.findall('
([^<]+)', r, re.DOTALL):
sub = {}
sub["url"] = s[1]
sub["lang"] = s[0]
sub["name"] = "captions (vtt)"
sub["type"] = "vtt"
sub["order"] = llist.index(sub["lang"])*10 if sub["lang"] in llist else 0
captions.append(sub)
captions = sorted(captions,key=lambda item: item["order"],reverse=True)
for s in streams_xml:
for server in servers:
stream = util.item()
server2 = self.load_balancer(server)
url = "http://%s/mobile-vod/%s/playlist.m3u8?resource_id=%s&auth_token=%s"%(server2,s[0],resource_id,token)
# TODO Engima2 gstreamer vajag lai padod playlist nevis chunklist
# r3 = self._http_request(url)
# sss = re.findall(r"#EXT-X-STREAM-INF:.*?BANDWIDTH=(\d+).*?\n(.+?)$", r3, re.IGNORECASE | re.MULTILINE)
# if sss:
# url2 = sss[0][1]
# stream["headers"] = {"Referer":url}
# if url2.startswith("http"):
# url = url2
# else:
# url = util.hls_base(url)+url2
stream["url"]=url
stream["lang"]=s[1]
stream["quality"]=s[2]
stream["name"]= unescape(title)
stream["desc"]= unescape(desc)
stream["img"] = img
stream["nfo"] = {"movie":nfo}
stream["type"]="hls" #stream_type(url)
stream["subs"] = []
for c in captions:
c2= c.copy()
#c2["url"] ="http://%s/mobile-vod/%s/%s?resource_id=%s&auth_token=%s"%(server2,s[0],c["url"],resource_id,token)
c2["url"] ="http://%s/mobile-vod/%s/%s"%(server2,s[0],c["url"])
stream["subs"].append(c2)
pass
streams.append(stream)
break # TODO ņem tikai pirmo serveri, varētu pārbaudit, kurš no tiem strādā, kurš ne
return streams
#data = {}
#data["server"] = re.findall("(?s)
([^<]+)", r)[1]
#data["language"]=re.findall('(?s)
', r)
#data["language"]="lv" if "lv" in data["language"] else "ru" if "ru" in data["language"] else "en"
#data["qs"]=re.findall('(?s)([^<]+)', r)
#data["qs"]=dict(data["qs"])
#qs = data["qs"].keys()
#data["quality"] = "hd" if "hd" in qs else "hq" if "hq" in qs else "mhq" if "mhq" in qs else "lq"
#data["mp4"] = data["qs"][data["quality"]]
#data["token"] = re.search("(?s)([^<]+)", r).group(1)
#data["resource_id"]=re.search("(?s)([^<]+)", r).group(1)
#data["server"]=self.load_balancer(data["server"])
#data["hls"] = "http://%s/mobile-vod/%s/playlist.m3u8?resource_id=%s&auth_token=%s"%(data["server"],data["mp4"],data["resource_id"],data["token"])
##data["hls"]="http://%s/mobile-vod/mp4:%s/playlist.m3u8?resource_id=%s&auth_token=app_%s"%(data["server"],data["mp4"],data["resource_id"],data["token"])
### wwww.shortcut.lv izsaukumi
def login2(self,user="",password=""):
"""Login in to site, create session cookies"""
if not user: user=self.options["user"]
if not password: password = self.options["password"]
url0 = "https://www.shortcut.lv"
class NoRedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_302(self, req, fp, code, msg, headers):
infourl = urllib.addinfourl(fp, headers, req.get_full_url())
infourl.status = code
infourl.code = code
return infourl
http_error_300 = http_error_302
http_error_301 = http_error_302
http_error_303 = http_error_302
http_error_307 = http_error_302
# Dabūjam sesijas id un url_gif, kas redirektējas uz auth_url
headers = headers2dict("""
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
DNT: 1
Connection: keep-alive
""")
response = urllib2.urlopen(urllib2.Request(url0, headers=headers))
session_id = response.headers["set-cookie"].split(";")[0]
html = response.read()
url_gif = url0 + re.search('(/auth/\d+\.gif)', html).group(1)
# Dabūtjam auth_url
headers = headers2dict("""
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-US,en;q=0.5
DNT: 1
Referer: https://www.shortcut.lv/
""")
headers["Cookie"] = session_id
urllib2.install_opener(urllib2.build_opener(NoRedirectHandler()))
response = urllib2.urlopen(urllib2.Request(url_gif, headers=headers))
if response.code == 302:
url_auth = response.headers["location"]
else:
self.error = u"auth.gif nenostrādāja"
raise Exception(u"auth.gif nenostrādāja")
#return False
# Pierakstāmies iekš auth.lattelecom.lv
headers = headers2dict("""
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: image/png,image/*;q=0.8,*/*;q=0.5
Accept-Language: en-US,en;q=0.5
DNT: 1
Referer: https://www.shortcut.lv/
""")
response = urllib2.urlopen(urllib2.Request(url_auth, headers=headers))
if not response.code == 302:
self.error = u"pierakstīšanās auth.lattelecom.lv nenostrādāja"
return False
#raise "pierakstīšanās auth.lattelecom.lv nenostrādāja"
# Mēģinam ielogoties
headers = headers2dict("""
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
Accept: text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
DNT: 1
X-Requested-With: XMLHttpRequest
Referer: https://www.shortcut.lv/
""")
headers["Cookie"] = session_id
#data = "login=yes&email=%s&passw=%s"%(user,password)
url = "https://www.shortcut.lv/login.json?callback=jQuery111303344749731668816_1463817318435&username=%s&password=%s&captcha=&sid=&_="%(user,password)
req = urllib2.Request(url, headers=headers)
response = urllib2.urlopen(req)
#with open("auth.htm","w") as f: f.write(response.read())
if not response.code == 200:
#self.error = u"kļūda ielogojoties"
raise Exception(u"kļūda ielogojoties")
html = response.read()
if not '"success":true' in html:
err = re.search('"error":"(.+?)"',html).group(1) if re.search('"error":"(.+?)"',html) else ""
raise Exception(u"Kļūda ielogojoties - %s"%err.decode("utf8"))
self.session_id = session_id
self.headers2["Cookie"] = "%s; "%(self.session_id)
self.error = ""
return True
def check_logedin2(self):
if not self.session_id:
return False
else:
url = "https://www.shortcut.lv/profils"
response = urllib2.urlopen(urllib2.Request(url, headers=self.headers2))
if response.code == 200:
return True
else:
self.session_id = ""
return False
def is_logedin2(self):
if self.session_id:
return True
else:
return False
def load_balancer(self,server,streams=[]):
headers = headers2dict("""
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
X-Requested-With: ShockwaveFlash/21.0.0.242
""")
url = "http://%s/loadbalancer"%server
response = urllib2.urlopen(urllib2.Request(url, headers=headers))
r = response.read()
statuss = re.search("(\d+)",r).group(1)
edge = re.search("([^<>]+)",r).group(1)
return edge
def test_hls(self,url):
headers = headers2dict("""
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
""")
try:
response = urllib2.urlopen(urllib2.Request(url, headers=headers))
except Exception as ex:
print "hls failed: %s %s"%(ex.getcode(),url)
return False
if response.code == 200:
html = response.read()
url0 = re.search("(http://[^/]+/)",url).group(1)
chunklist = re.search("(chunklist.+)",html).group(1).strip()
url2 = url.split('/')[:-1]
url2 ="/".join(url2)+"/"+chunklist
try:
response2 = urllib2.urlopen(urllib2.Request(url2, headers=headers))
except Exception as ex:
print "hls chunk failed: %s %s"%(ex.getcode(),url2)
return False
if response2.code == 200:
return True
else:
return False
else:
return False
if __name__ == "__main__":
sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
import run
source = Source()
data= sys.argv[1] if len(sys.argv)>1 else source.name+"::home"
run.run(source, data)
sys.exit()
c.get_info2(sys.argv[1])
if len(sys.argv)>1 and not "ltc::" in sys.argv[1]:
vid = vid2 = sys.argv[1]
password = sys.argv[2]
print "login - %s"%c.login("ivars777",password)
#vid = "1069"
#vid = "1462566072086"
#channelid="101"
#vid = "1350462656767"
#data = c.get_stream_url(vid,"vod")
#call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",data["stream"]])
#pass
print "login2 - %s"%c.login2("ivars777",password)
#vid2 = "animation/ultimate_avengers_ii"
#vid2 = "animation/ice_age"
#vid2 = "tiesraide/ltv1"
#vid2 = "arhivs/1456521417815"
streams = c.get_stream_url2(vid2)
stream = streams[-1]
print
#for s in data:
#call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",stream["url"]])
cmd = ["ffplay.exe",
"-headers","Referer:%s"%(quote(stream["headers"]["Referer"])),
"-headers","Connection:Keep-Alive",
stream["url"]]
print " ".join(cmd)
call(cmd)
pass
else:
if len(sys.argv)>1:
data= sys.argv[1]
else:
data = "ltc::home"
content = c.get_content(data)
for item in content:
print item
#cat = api.get_categories(country)
#chan = api.get_channels("lv")
#prog = api.get_programs(channel=6400)
#prog = api.get_programs(category=55)
#seas = api.get_seasons(program=6453)
#str = api.get_streams(660243)
#res = api.get_videos(802)
#formats = api.getAllFormats()
#det = api.detailed("1516")
#vid = api.getVideos("13170")
pass