diff --git a/build.sh b/build.sh
index 9cb9746..163b2ce 100644
--- a/build.sh
+++ b/build.sh
@@ -4,7 +4,7 @@ for d in *; do
if [ -d "$d" ]; then
echo -e "\n> $d.plug:"
cd $d
- tar -cvzf ../$d.201.tgz *
+ tar -cvzf ../$d.203.tgz *
cd ..
fi
-done
\ No newline at end of file
+done
diff --git a/tivix/main.tengo b/tivix/main.tengo
new file mode 100644
index 0000000..26c8451
--- /dev/null
+++ b/tivix/main.tengo
@@ -0,0 +1,84 @@
+url := "http://tv.tivix.co/"
+srv := import("server")
+txt := import("text")
+jsn := import("json")
+stg := import("settings")
+cat := stg.cat
+fav := cat == "*"
+cat = cat == "*" ? "" : cat
+vid := "video:resolve:" + srv.base_url + "video.tengo?str=" + string(stg.str) + "&cid="
+
+// get the page:
+r := srv.request(url + cat)
+panic(is_error(r) ? r : r.status != 200 ? r.status : undefined)
+
+// parse categories:
+c := [{label: "Избранные", action: "execute:fetch:" + srv.base_url + "set.tengo?id={ID}&cat=*", enable: !fav}]
+for m in txt.re_find("(?s)class=\"menuuuuuu\">(.+?)", r.body, 3) {
+ for i in txt.re_find("(?s).+?href=\"/(.*?)\"(.+?)>(.+?)<", m[1].text, -1) {
+ cc := {label: i[3].text, action: "execute:fetch:" + srv.base_url + "set.tengo?id={ID}&cat="+ i[1].text}
+ if !fav && len(i[2].text) > 3 {
+ cc.enable = false
+ cat = (i[1].text == "" ? "" : "{col:msx-white}") + i[3].text
+ }
+ c = append(c, cc)
+ }
+}
+
+// parse channels:
+if fav {
+ cat = "{col:msx-yellow}Избранные"
+ if r = srv.file("favs.json"); r {
+ panic(is_error(r) ? r : undefined)
+ r = jsn.decode(r)
+ panic(is_error(r) ? r : !is_array(r) ? "Wrong format of file favs.json" : undefined)
+ for i := 0; i < len(r); i++ {
+ r[i].playerLabel = r[i].headline
+ r[i].action = vid + r[i].id
+ }
+ } else { r = [] }
+} else if r = txt.re_find("(?s)class=\"all_tv\".+? 0 {
+ epg[i-1] = "{col:msx-yellow}" + epg[i-1] + "{col:msx-white}"
+ nrs.cur = i - 1
+ }
+ } else {
+ nrs.now = [epg[i].start_at, epg[i].name]
+ }
+ }
+ epg[i] = tms.time_format(epg[i].start_at, "15:04") + "{tb}" + epg[i].name
+ }
+ }
+}
+// prepare the answer:
+if fn := srv.read("now"); !is_array(epg) || len(epg) < 1 {
+ epg = fn ? {titleHeader: "Программа недоступна!"} : undefined
+ cid = fn ? ("update:content:" + cid) : "player:label:duration:{ico:sensors}"
+} else if fn {
+ epg = {live: {
+ type: "schedule", from: tms.time_unix(nrs.now[0]) * 1000, to: tms.time_unix(nrs.nxt[0]) * 1000,
+ titleHeader: "{ico:add}{col:msx-white}{progress:time:hh:mm} " + nrs.now[1],
+ titleFooter: "{ico:remove}{countdown:time:hh:mm} " + nrs.nxt[1],
+ over: {action: "execute:service:fetch:" + srv.base_url + "programme.tengo?now=true&cid=" + cid}
+ }}
+ cid = "update:content:" + cid
+} else {
+ if nrs.cur < 0 {
+ epg = append(["{col:msx-yellow}...{col:msx-white}"], epg...)
+ } else if l := len(epg) - 10; l > 0 && nrs.cur > 0 {
+ epg = epg[nrs.cur < l ? nrs.cur : l:]
+ }
+ tuf := tms.time_unix(nrs.now[0])
+ tut := tms.time_unix(nrs.nxt[0])
+ epg = {actions: [
+ {action: "trigger:player:execute:service:fetch:" + srv.base_url + "progress.tengo?b=" + tuf + "&e=" + tut + "&cid=" + cid},
+ {action: "player:info:text:" + txt.join(epg, "{br}")},
+ {action: "player:label:position:{VALUE}{tb}{col:msx-white}" + nrs.now[1]},
+ {action: "player:label:duration:{VALUE}"},
+ {action: "player:video:position:" + string(tms.time_unix(now) - tuf)},
+ {action: "player:video:duration:" + string(tut - tuf)}
+ ]}
+ cid = "data"
+}
+// answer:
+srv.write(jsn.encode({response: {status: 200, data: {action: cid, data: epg}}}))
\ No newline at end of file
diff --git a/tivix/progress.tengo b/tivix/progress.tengo
new file mode 100644
index 0000000..a6c3cc0
--- /dev/null
+++ b/tivix/progress.tengo
@@ -0,0 +1,13 @@
+s := import("server")
+t := import("times")
+b := s.read("b")
+e := s.read("e")
+panic(b == "" || e == "" ? 400 : undefined)
+b = int(b)
+e = int(e)
+n := t.time_unix(t.now())
+a := "player:video:position:" + string(n - b)
+if n > e {
+ a = "execute:service:fetch:" + s.base_url + "programme.tengo?cid=" + s.read("cid")
+}
+s.write("{\"response\":{\"status\":200,\"data\":{\"action\":\"" + a + "\"}}}")
diff --git a/tivix/set.tengo b/tivix/set.tengo
new file mode 100644
index 0000000..462c3a8
--- /dev/null
+++ b/tivix/set.tengo
@@ -0,0 +1,42 @@
+srv := import("server")
+jsn := import("json")
+stg := import("settings")
+rtn := {response: {status: 200, data: {action: "reload:content"}}}
+if r := srv.read("str"); r {
+ stg.set(int(r, 0))
+ rtn.response.data.action = "[back|reload:content]"
+} else if r = srv.read("cat"); is_string(r) {
+ stg.set(r)
+ rtn.response.data.action = "[back|reload:content]"
+} else if c := srv.read("cid"); c {
+ ch := false
+ if r = srv.file(stg.fav); r {
+ panic(is_error(r) ? r : undefined)
+ r = jsn.decode(r)
+ }
+ r = is_array(r) ? r : []
+ l := len(r)
+ for i := 0; i < l; i++ {
+ if r[i].id == c {
+ splice(r, i, 1)
+ i = l
+ ch = true
+ }
+ }
+ if t := srv.read("ttl"); t {
+ r = append(r, {id: c, headline: t, image: srv.read("img")})
+ ch = true
+ rtn.response.data.action = "success:" + t + " добавлен в {col:msx-yellow}избранные"
+ }
+ if ch {
+ r = jsn.encode(r)
+ panic(is_error(r) ? r : undefined)
+ srv.file(stg.fav, r)
+ }
+} else {
+ rtn = {type: "list", headline: "Видео:", extension: "Tivix", template: {enumerate: false, type: "button", layout: "0,0,8,1"}, items: []}
+ for i, n in stg.hls {
+ rtn.items = append(rtn.items, {label: n, action: "execute:fetch:" + srv.base_url + "set.tengo?id={ID}&str=" + string(i)})
+ }
+}
+srv.write(jsn.encode(rtn))
diff --git a/tivix/settings.tengo b/tivix/settings.tengo
new file mode 100644
index 0000000..06688ae
--- /dev/null
+++ b/tivix/settings.tengo
@@ -0,0 +1,22 @@
+s := import("server")
+i := s.read("id") || "*"
+p := s.memory() || {}
+if !is_map(p[i]) { p[i] = {cat: "", str: 0} }
+h := ["прямой HLS", "проксировать HLS"]
+if s.settings.ffmpeg() { h = append(h, "конвертировать в MPEGTS") }
+export {
+ fav: "favs.json",
+ cat: p[i].cat,
+ str: p[i].str,
+ hls: h,
+ set: func(arg) {
+ r := false
+ if r = is_string(arg); r {
+ p[i].cat = arg
+ } else if r = is_int(arg); r {
+ p[i].str = arg > 0 && arg < len(h) ? arg : 0
+ }
+ if r { s.memory(p) }
+ return r
+ }
+}
\ No newline at end of file
diff --git a/tivix/video.tengo b/tivix/video.tengo
new file mode 100644
index 0000000..12ea26b
--- /dev/null
+++ b/tivix/video.tengo
@@ -0,0 +1,29 @@
+srv := import("server")
+txt := import("text")
+cid := srv.read("cid")
+panic(cid ? undefined : 400)
+url := "http://tv.tivix.co/"
+
+b := srv.request(url + cid + ".html")
+panic(is_error(b) ? b : b.status != 200 ? b.status : undefined)
+
+b = txt.re_find("(?s)firstIpProtect.+?'(.+?)'.+?secondIpProtect.+?'(.+?)'.+?portProtect.+?'(.+?)'.+?new Playerjs.+?file.*?:.*?\"(.+?)\"", b.body, 1)[0][1:]
+
+b[3] = txt.trim_prefix(b[3].text, "#2")
+for i := txt.last_index(b[3], "//"); i > -1; i = txt.last_index(b[3], "//"){
+ b [3]= b[3][:i] + b[3][i+50:]
+}
+b[3] = import("base64").decode(b[3])
+
+b = txt.replace(txt.replace(txt.replace(b[3], "{v3}", b[2].text, 1), "{v2}", b[1].text, 1), "{v1}", b[0].text, 1)
+
+if s := int(srv.read("str"), 0); s == 2 {
+ b = srv.settings.ffmpeg(b, ["-referer", url], ["-c", "copy"])
+ panic(b == "" ? "ffmpeg is not set" : undefined)
+} else if s == 1 {
+ b = "http://" + srv.host + "/proxy.m3u8?header=Referer%3A" + srv.encode_uri(url) + "&link=" + srv.encode_uri(b)
+} else {
+ r := srv.request(b, {header: {Referer: url}})
+ panic(is_error(r) ? r : r.status == 200 ? undefined : r.status)
+}
+srv.write("{\"response\":{\"status\":200,\"data\":{\"url\":\"", srv.settings.player(b), "\"}}}")
diff --git a/torlook/find.tengo b/torlook/find.tengo
new file mode 100644
index 0000000..c4277e4
--- /dev/null
+++ b/torlook/find.tengo
@@ -0,0 +1,42 @@
+srv := import("server")
+txt := import("text")
+jsn := import("json")
+url := "https://torlook.info/"
+stg := srv.memory()
+stg = is_array(stg) && len(stg) == 4 ? stg : ["seeders", false, false, false]
+its := []
+panic(srv.method != "POST" ? 400 : undefined)
+fnd := jsn.decode(srv.read())
+panic(is_error(fnd) ? fnd : !is_map(fnd) || !is_string(fnd.data) ? 400 : undefined)
+fnd = fnd.data
+r := srv.request(
+ url + "?cinema=on&s=" + srv.encode_uri(fnd) + "&sort=" + stg[0] + (stg[1] ? "&forced=on" : ""),
+ {header: {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"}}
+)
+panic(is_error(r) ? r : r.status != 200 ? r.status : undefined)
+if r = txt.re_find("(?s)webResult.+?item.+?(.+?).+?(.+?)<.+?class=\"size\">(.+?)<.+?class=\"date\">(.+?)<.+?class=\"arrow-up\".+?>(.+?)<.+?data-src=\"(.+?)\"", r.body, -1); is_array(r) {
+ for i in r { its = append(its, {
+ headline: txt.re_replace("<.+?>", i[1].text, ""),
+ titleFooter: i[3].text + "{tb}{ico:msx-white:attach-file}" + txt.replace(i[4].text, " ", " ", 1) +
+ "{tb}{ico:msx-white:calendar-today} " + i[5].text + "{tb}{ico:msx-white:arrow-upward} " + i[6].text,
+ data: url + srv.encode_uri(i[7].text, true)
+ })}
+} else {
+ its = append(its, {label: "{dic:message:playlist_empty|Empty}", icon: "msx-yellow:warning", extensionIcon: "msx-white:refresh", action: "reload:content"})
+}
+
+srv.write(jsn.encode({response: {status: 200, data: {action: "content:data", data:{
+ type: "list", headline: "Torlook", extension: "{ico:search}{col:msx-white}" + fnd, cache: false, compress: true, items: its, flag: "FIND",
+ template: {type: "control", layout: "0,0," + (stg[2] ? "8" : "16") + ",2", action: "execute:" + srv.base_url + "magnet.tengo?"},
+ header: {items:[
+ {type: "control", icon: "arrow-back-ios", label: "TOP-50", action: "close:FIND", layout: "0,0,3,1"},
+ {
+ type: "control", icon: "search", extensionIcon: "keyboard", layout: "3,0,10,1",
+ id: "search", label: fnd, action: "execute:http://" + srv.host + "/msx/input",
+ data: {action: "[cleanup|close:FIND|execute:" + srv.base_url + "find.tengo]", headline: "Torlook:", value: fnd}
+ },{
+ type: "button", icon: "tune", iconSize: "small", layout: "13,0,3,1",
+ action: "execute:info:dictionary:" + srv.base_url + "set.tengo?find=" + srv.encode_uri(fnd), data: undefined
+ }
+ ]}
+}}}}))
\ No newline at end of file
diff --git a/torlook/magnet.tengo b/torlook/magnet.tengo
new file mode 100644
index 0000000..e8de893
--- /dev/null
+++ b/torlook/magnet.tengo
@@ -0,0 +1,15 @@
+srv := import("server")
+jsn := import("json")
+
+panic(srv.method != "POST" ? 400 : undefined)
+u := srv.read()
+u = jsn.decode(u)
+panic(is_error(u) ? u : undefined)
+u = u.data || ""
+panic(u == "" ? 400 : undefined)
+
+u = srv.request(u, {header: {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36"}})
+panic(is_error(u) ? u : u.status == 200 ? undefined : u.status)
+u = import("text").re_find("(?s)\"(.+?)
.+?torstat.+?(.+?)<", r.body, -1); is_array(r) {
+ for i in r {
+ b := i[2].text
+ i = txt.re_find("href=\"/(.+?)\">(.+?)<", i[1].text, 2)
+ i = i[len(i) > 1 && org ? 1 : 0]
+ its = append(its, {label: i[2].text, extensionLabel: b, data: srv.decode_uri(i[1].text)})
+ }
+} else {
+ its = append(its, {label: "{dic:message:playlist_empty|Empty}", icon: "msx-yellow:warning", extensionIcon: "msx-white:refresh", action: "reload:content"})
+}
+
+srv.write(import("json").encode({
+ type: "list", headline: "Torlook", extension: "TOP-50 (kinopoisk)", cache: false, compress: true, items: its,
+ ready: {action: "execute:info:dictionary:" + srv.base_url + "trans.tengo"},
+ template: {type: "control", icon: "search", layout: "0,0,16,1", action: "execute:" + srv.base_url + "find.tengo"},
+ header: {items:[
+ {
+ type: "control", icon: "title", layout: "0,0,3,1", action: "execute:" + srv.base_url + "set.tengo", data: 3,
+ label: org ? "{txt:msx-white-soft:Рус} {ico:toggle-on} Origin" : "Рус {ico:toggle-off} {txt:msx-white-soft:Origin}"
+ },{
+ type: "control", icon: "search", extensionIcon: "keyboard", layout: "3,0,10,1",
+ id: "search", label: "Torrents search", action: "execute:http://" + srv.host + "/msx/input",
+ data: {action: "[cleanup|execute:" + srv.base_url + "find.tengo]", headline: "Torlook:"}
+ },{
+ type: "button", icon: "tune", iconSize: "small", layout: "13,0,3,1",
+ action: "execute:info:dictionary:" + srv.base_url + "set.tengo", data: undefined
+ }
+ ]}
+}))
\ No newline at end of file
diff --git a/torlook/manifest.json b/torlook/manifest.json
new file mode 100644
index 0000000..04b6b09
--- /dev/null
+++ b/torlook/manifest.json
@@ -0,0 +1,5 @@
+{
+ "Label": "Torlook",
+ "Image": "{BASE_URL}tor.svg",
+ "Torrent": true
+}
\ No newline at end of file
diff --git a/torlook/set.tengo b/torlook/set.tengo
new file mode 100644
index 0000000..20a0df1
--- /dev/null
+++ b/torlook/set.tengo
@@ -0,0 +1,51 @@
+srv := import("server")
+jsn := import("json")
+stg := srv.memory()
+stg = is_array(stg) && len(stg) == 4 ? stg : ["seeders", false, false, false]
+if srv.method == "POST" {
+ b := jsn.decode(srv.read())
+ panic(is_error(b) ? b : undefined)
+ rtn := {response: {status: 200, data: {action: "reload:panel"}}}
+ if b.info {
+ ru := b.info.dictionary && is_string(b.info.dictionary.name) ? b.info.dictionary.name[:3] : ""
+ f := srv.read("find")
+ f = f ? srv.encode_uri(f) : ""
+ rtn.response.data.action = "panel:" +srv.base_url + "set.tengo?find=" + f + (ru == "Rus" || ru == "Ukr" ? "&ru" : "")
+ } else if is_string(b.data) {
+ stg[0] = b.data
+ srv.memory(stg)
+ } else if b = int(b.data, 0); b > 0 && b < len(stg) {
+ stg[b] = !stg[b]
+ srv.memory(stg)
+ if b == 3 { rtn.response.data.action = "reload:content" }
+ }
+ srv.write(jsn.encode(rtn))
+} else {
+ ru := is_string(srv.read("ru"))
+ f := srv.read("find")
+ srv.write(jsn.encode({
+ type: "list", headline: ru ? "Параметры поиска:" : "Search properties:", extension: "Torlook",
+ template: {enumerate: false, type: "control", layout: "0,0,8,1", action: "execute:" + srv.base_url + "set.tengo"},
+ items: [
+ {
+ icon: "remove-red-eye", label: ru ? "представление результатов:" : "results view:", data: 2,
+ extensionLabel: "{ico:" + (stg[2] ? "" : "msx-white:") + "splitscreen} {ico:msx-white:toggle-o" + (stg[2] ? "n" : "ff") + "} {ico:" + (stg[2] ? "msx-white:" : "") + "grid-view}"
+ },{
+ icon: "sort", label: ru ? "сортировать по сидам" : "order by seeders", data: "seeders",
+ extensionIcon: stg[0] == "seeders" ? "msx-white:radio-button-on" : "radio-button-off"
+ },{
+ icon: "sort", label: ru ? "сортировать по дате" : "order by date", data: "date",
+ extensionIcon: stg[0] == "date" ? "msx-white:radio-button-on" : "radio-button-off"
+ },{
+ icon: "sort", label: ru ? "сортировать по размеру" : "order by size", data: "size",
+ extensionIcon: stg[0] == "size" ? "msx-white:radio-button-on" : "radio-button-off"
+ },{
+ icon: "manage-search", label: ru ? "форсированный поиск" : "forced search", data: 1,
+ extensionIcon: stg[1] ? "msx-white:check-box" : "check-box-outline-blank"
+ },{
+ type: "button", label: "{dic:label:apply|Apply}", data: f,
+ action: "[cleanup|close:FIND|execute:" + srv.base_url + "find.tengo]", enable: f ? true : false
+ }
+ ]
+ }))
+}
diff --git a/torlook/tor.svg b/torlook/tor.svg
new file mode 100644
index 0000000..1621b90
--- /dev/null
+++ b/torlook/tor.svg
@@ -0,0 +1,18 @@
+
+
diff --git a/torlook/trans.tengo b/torlook/trans.tengo
new file mode 100644
index 0000000..06e5439
--- /dev/null
+++ b/torlook/trans.tengo
@@ -0,0 +1,11 @@
+srv := import("server")
+jsn := import("json")
+rtn := {response: {status: 200, data: {action: "[]"}}}
+if srv.method == "POST" {
+ if l := jsn.decode(srv.read()); !is_error(l) && is_map(l) && is_map(l.info) && is_map(l.info.dictionary) && is_string(l.info.dictionary.name) {
+ if l = l.info.dictionary.name[:3]; l == "Rus" || l == "Ukr" {
+ rtn.response.data = {action: "update:content:search", data: {label: "Поиск торрентов"}}
+ }
+ }
+}
+srv.write(jsn.encode(rtn))
\ No newline at end of file