Ivars 7 gadus atpakaļ
revīzija
722b19aa96
52 mainītis faili ar 16948 papildinājumiem un 0 dzēšanām
  1. 95
    0
      addon.py
  2. 22
    0
      addon.xml
  3. 3
    0
      changelog.md
  4. 92
    0
      kmake.bat
  5. 6
    0
      make_links.bat
  6. 1522
    0
      project.wpr
  7. 34
    0
      readme.md
  8. Binārs
      release/plugin.video.playstream-0.1.2.zip
  9. 0
    0
      resources/__init__.py
  10. Binārs
      resources/icon.png
  11. 5
    0
      resources/language/English/strings.xml
  12. 215
    0
      resources/lib/ContentSources.py
  13. 0
    0
      resources/lib/__init__.py
  14. 6281
    0
      resources/lib/demjson.py
  15. 141
    0
      resources/lib/resolver.py
  16. 31
    0
      resources/lib/resolvers/__init__.py
  17. 209
    0
      resources/lib/resolvers/aadecode.py
  18. 95
    0
      resources/lib/resolvers/hdgo.py
  19. 234
    0
      resources/lib/resolvers/hqqresolver.py
  20. 94
    0
      resources/lib/resolvers/kapnob.py
  21. 95
    0
      resources/lib/resolvers/kodik.py
  22. 109
    0
      resources/lib/resolvers/openload3.py
  23. 347
    0
      resources/lib/resolvers/youtuberesolver.py
  24. 149
    0
      resources/lib/sources/SourceBase.py
  25. 404
    0
      resources/lib/sources/YouTubeVideoUrl.py
  26. 0
    0
      resources/lib/sources/__init__.py
  27. 209
    0
      resources/lib/sources/cinemalive.py
  28. 99
    0
      resources/lib/sources/config.py
  29. 3
    0
      resources/lib/sources/euronews.cfg
  30. 287
    0
      resources/lib/sources/euronews.py
  31. 336
    0
      resources/lib/sources/filmix.py
  32. 272
    0
      resources/lib/sources/filmon.py
  33. 4
    0
      resources/lib/sources/iplayer.cfg
  34. 524
    0
      resources/lib/sources/iplayer.py
  35. 261
    0
      resources/lib/sources/jsinterp.py
  36. 3
    0
      resources/lib/sources/ltc.cfg
  37. 1018
    0
      resources/lib/sources/ltc.py
  38. 230
    0
      resources/lib/sources/movieplace.py
  39. 279
    0
      resources/lib/sources/mtgplay.py
  40. 212
    0
      resources/lib/sources/play24.py
  41. 305
    0
      resources/lib/sources/replay.py
  42. 230
    0
      resources/lib/sources/serialguru.py
  43. 108
    0
      resources/lib/sources/streams.cfg
  44. 828
    0
      resources/lib/sources/swfinterp.py
  45. 4
    0
      resources/lib/sources/tvdom.cfg
  46. 277
    0
      resources/lib/sources/tvdom.py
  47. 4
    0
      resources/lib/sources/ustvnow.cfg
  48. 176
    0
      resources/lib/sources/ustvnow.py
  49. 5
    0
      resources/lib/sources/viaplay.cfg
  50. 478
    0
      resources/lib/sources/viaplay.py
  51. 603
    0
      resources/lib/util.py
  52. 10
    0
      run.py

+ 95
- 0
addon.py Parādīt failu

@@ -0,0 +1,95 @@
1
+import os,os.path,sys, urllib
2
+from xbmcswift2 import Plugin, ListItem
3
+from xbmcswift2 import xbmc, xbmcgui, xbmcplugin
4
+from resources.lib import ContentSources, util
5
+
6
+plugin = Plugin()
7
+sources = ContentSources.ContentSources(os.path.join(os.path.dirname(__file__),"resources","lib","sources"))
8
+prefix = ""
9
+
10
+@plugin.route(".+" )
11
+def main():
12
+    global prefix
13
+    prefix = "%s://%s/"%(plugin.request.scheme,plugin.request.netloc)
14
+    data = plugin.request.url.replace(prefix,"")
15
+    data = urllib.unquote(data)
16
+    if not data:
17
+        data = "config::home"
18
+    if sources.is_video(data):
19
+        try:
20
+            streams = sources.get_streams(data)
21
+        except Exception,e:
22
+            plugin.notify(str(e),"",10000)
23
+            return None
24
+        if streams:
25
+            return play_video(streams)
26
+        else:
27
+            plugin.notify("No streams found!",10000)
28
+            return None
29
+    else:
30
+        if "{0}" in data:
31
+            q = plugin.keyboard(default=None, heading=None, hidden=False)
32
+            data = data.format(q)
33
+        try:
34
+            items = get_list(data)
35
+        except Exception,e:
36
+            plugin.notify(str(e),"")
37
+            return None
38
+        return items
39
+
40
+def get_list(data):
41
+    content = sources.get_content(data)
42
+    items = []
43
+    for item in content:
44
+        if item[1] == "back": continue
45
+        title = item[0].decode("utf8")
46
+        data2 = prefix+item[1]
47
+        is_playable = True if  sources.is_video(item[1]) else False
48
+        img = item[2]
49
+        desc = item[3].decode("utf8")
50
+        items.append({
51
+            "label": title,
52
+            "path": data2,
53
+            "thumbnail":img,
54
+            "info":{"plot":desc},
55
+            "is_playable":is_playable
56
+        })
57
+    return items
58
+
59
+def play_video(streams):
60
+    stream = streams[0]
61
+    subfiles = []
62
+    print "play_video ",stream["url"]
63
+    if "subs" in stream and stream["subs"]:
64
+        for sub in stream["subs"]:
65
+            suburl = sub["url"]
66
+            subs = util.Captions(suburl)
67
+            srt = subs.get_srt()
68
+            subfile = plugin.temp_fn("subtitles.srt")
69
+            subfile = os.path.join(os.path.dirname(__file__),sub["lang"]+".srt")
70
+            f = open(subfile, "w")
71
+            f.write(srt)
72
+            # TODO nestrada uz ltc.lv subtititliem!
73
+            # import codecs
74
+            #f = codecs.open(subfile, 'w', "utf-8-sig")
75
+            #f.write(srt.decode("utf8"))
76
+            f.close()
77
+            subfiles.append(subfile)
78
+    item = ListItem(label=stream["name"], thumbnail=stream["img"], path=stream["url"])
79
+    item.set_info("video",{"plot":stream["desc"]})
80
+    item.set_is_playable(True)
81
+
82
+    item = plugin._listitemify(item)
83
+    item.set_played(True)
84
+    succeeded = True
85
+    xbmcplugin.setResolvedUrl(plugin.handle, succeeded, item.as_xbmc_listitem())
86
+
87
+    #plugin.play_video(item)
88
+    for subfile in subfiles:
89
+        print "Add subtitle file - ", subfile
90
+        plugin._add_subtitles(subfile)
91
+        #break # TODO multipe subtitles?
92
+    return [item]
93
+
94
+if __name__ == '__main__':
95
+    plugin.run()

+ 22
- 0
addon.xml Parādīt failu

@@ -0,0 +1,22 @@
1
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+<addon id="plugin.video.playstream" name="PlayStream" version="0.1.2" provider-name="ivars777">
3
+  <requires>
4
+    <import addon="xbmc.python" version="2.1.0"/>
5
+    <import addon="script.module.xbmcswift2" version="2.4.0" />
6
+    <import addon="script.module.requests" />
7
+    <import addon="script.module.simplejson" />
8
+  </requires>
9
+  <extension point="xbmc.python.pluginsource" library="addon.py">
10
+    <provides>video</provides>
11
+  </extension>
12
+  <extension point="xbmc.addon.metadata">
13
+    <platform>all</platform>
14
+    <language></language>
15
+    <summary>Play online streams from various sites (mostly Latvian)</summary>
16
+    <description>Play online streams from various sites:
17
+    - replay.lv
18
+    - skaties.lv
19
+    - shortcut.lv
20
+    </description>
21
+  </extension>
22
+</addon>

+ 3
- 0
changelog.md Parādīt failu

@@ -0,0 +1,3 @@
1
+**0.1.2** (12.02.2016):
2
+- sākotnējā, eksperimentālā versija
3
+

+ 92
- 0
kmake.bat Parādīt failu

@@ -0,0 +1,92 @@
1
+@echo off
2
+:=== Parameters ===
3
+
4
+if ()==(%1%) (
5
+    set ver=0.1.2
6
+	rem echo Please provide version
7
+	rem pause
8
+	rem GOTO:EOF
9
+) else (
10
+    set ver=%1
11
+)
12
+
13
+set prog=PlayStream
14
+set pack_name=plugin.video.playstream
15
+set desc=Play online streams from various sources, mostly Latvian
16
+
17
+set ipk_dir=ipkg\
18
+set release_dir=release\
19
+set repo_dir=..\repo\
20
+set feed_dir=w:\repo\
21
+
22
+set AR=\MinGW\bin\ar.exe
23
+set TAR=\MinGW\msys\1.0\bin\tar.exe
24
+rem set ZIP=\Program Files (x86)\Gow\bin\zip.exe
25
+
26
+:=== data files ===
27
+if exist %pack_name% rm -r -f "%pack_name%""
28
+mkdir "%pack_name%""
29
+if not exist %release_dir% mkdir %release_dir%
30
+if not exist %repo_dir% mkdir %repo_dir%
31
+if not exist  %repo_dir%%pack_name% mkdir  %repo_dir%%pack_name%
32
+if not exist  %release_dir% mkdir %release_dir%
33
+
34
+for %%f in (
35
+readme.md
36
+changelog.md
37
+addon.xml
38
+addon.py
39
+icon.png
40
+resources\__init__.py
41
+resources\icon.png
42
+resources\language\English\*
43
+resources\lib\__init__.py
44
+resources\lib\ContentSources.py
45
+resources\lib\resolver.py
46
+resources\lib\util.py
47
+resources\lib\demjson.py
48
+resources\lib\sources\__init__.py
49
+resources\lib\sources\SourceBase.py
50
+resources\lib\sources\cinemalive.py
51
+resources\lib\sources\config.py
52
+resources\lib\sources\euronews.py
53
+resources\lib\sources\filmix.py
54
+resources\lib\sources\filmon.py
55
+resources\lib\sources\iplayer.py
56
+resources\lib\sources\movieplace.py
57
+resources\lib\sources\ltc.py
58
+resources\lib\sources\mtgplay.py
59
+resources\lib\sources\play24.py
60
+resources\lib\sources\replay.py
61
+resources\lib\sources\serialguru.py
62
+resources\lib\sources\tvdom.py
63
+resources\lib\sources\ustvnow.py
64
+resources\lib\sources\viaplay.py
65
+resources\lib\sources\YouTubeVideoUrl.py
66
+resources\lib\sources\jsinterp.py
67
+resources\lib\sources\swfinterp.py
68
+resources\lib\sources\streams.cfg
69
+resources\lib\resolvers\__init__.py
70
+resources\lib\resolvers\aadecode.py
71
+resources\lib\resolvers\hqqresolver.py
72
+resources\lib\resolvers\openload3.py
73
+resources\lib\resolvers\hdgo.py
74
+resources\lib\resolvers\kapnob.py
75
+resources\lib\resolvers\kodik.py
76
+resources\lib\resolvers\youtuberesolver.py
77
+) do echo f| xcopy %%f %pack_name%\%%f
78
+
79
+if exist  %release_dir%%pack_name%-%ver%.zip rm %release_dir%%pack_name%-%ver%.zip
80
+rem zip  -r %release_dir%%pack_name%-%ver%.zip %pack_name%
81
+"C:\Program Files\WinRAR\winrar.exe" a -afzip -r %release_dir%%pack_name%-%ver%.zip plugin.video.playstream
82
+copy  addon.xml  %repo_dir%%pack_name%\addon.xml /Y
83
+copy  %release_dir%%pack_name%-%ver%.zip  %repo_dir%%pack_name%\%pack_name%-%ver%.zip /Y
84
+python -c "import hashlib; print hashlib.md5(open(r'%repo_dir%%pack_name%\%pack_name%-%ver%.zip','r').read()).hexdigest()" >%repo_dir%%pack_name%\%pack_name%-%ver%.zip.md5
85
+
86
+git add %release_dir%%pack_name%-%ver%.zip
87
+
88
+pushd  %repo_dir%..
89
+call update_repo.bat
90
+xcopy /s /y repo %feed_dir%
91
+popd
92
+

+ 6
- 0
make_links.bat Parādīt failu

@@ -0,0 +1,6 @@
1
+mklink /h resources\lib\ContentSources.py \Data\Programming\enigma2\PlayStream2\ContentSources.py
2
+mklink /h resources\lib\util.py \Data\Programming\enigma2\PlayStream2\util.py
3
+mklink /h resources\lib\resolver.py \Data\Programming\enigma2\PlayStream2\resolver.py
4
+mklink /h resources\lib\demjson.py \Data\Programming\enigma2\PlayStream2\demjson.py
5
+mklink /j resources\lib\sources \Data\Programming\enigma2\PlayStream2\sources
6
+mklink /j resources\lib\resolvers \Data\Programming\enigma2\PlayStream2\resolvers

+ 1522
- 0
project.wpr
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 34
- 0
readme.md Parādīt failu

@@ -0,0 +1,34 @@
1
+PlayStream
2
+==========
3
+
4
+Kodi plugin to to play various online streams (mostly Latvian).
5
+Stream sources are in  subfolder "resources/lib/sources", and can be added/customized
6
+Currently implemented:
7
+- Main menu and manual stream definition in sources/streams.cfg file
8
+- **replay.lsm.lv** media portal content (Latvian TV)
9
+- **skaties.lv** media portal content (MTG media portal Latvian version), other countries MTG contents are available through customizing main menu (country=xx)
10
+- **lattelecom.tv(shortcut.lv)** media portal content
11
+- **play24.lv** media portal content
12
+- **viaplay.lv**
13
+- **cinemalive.tv**
14
+- **movieplace.lv**
15
+- **dom.tv**
16
+- **BBC iPlayer**
17
+- **Euronews**
18
+- **filmon.tv** media portal content
19
+- **ustvnow.tv**
20
+- **serialguru.ru**
21
+- **filmix.net**
22
+
23
+---
24
+Copyright (c) 2016 ivars777 (ivars777@gmail.com)
25
+Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
26
+Used fragments of code from
27
+- enigma2-plugin-tv3play by Taapat (https://github.com/Taapat/enigma2-plugin-tv3play)
28
+- Kodi plugin script.module.stream.resolver (https://github.com/kodi-czsk/script.module.stream.resolver)
29
+- enigma2-plugin-youtube by Taapat (https://github.com/Taapat/enigma2-plugin-youtube), originally from https://github.com/rg3/youtube-dl/blob/master/youtube_dl
30
+
31
+
32
+
33
+
34
+

Binārs
release/plugin.video.playstream-0.1.2.zip Parādīt failu


+ 0
- 0
resources/__init__.py Parādīt failu


Binārs
resources/icon.png Parādīt failu


+ 5
- 0
resources/language/English/strings.xml Parādīt failu

@@ -0,0 +1,5 @@
1
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
2
+<strings>
3
+  <!-- Plugin name -->
4
+  <string id="30000">PlayStream</string>
5
+</strings>

+ 215
- 0
resources/lib/ContentSources.py Parādīt failu

@@ -0,0 +1,215 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+
9
+import sys,os,re
10
+import glob
11
+sys.path.insert(0,os.path.dirname(os.path.abspath(__file__)))
12
+from  sources.SourceBase import stream_type
13
+import util
14
+
15
+
16
+class ContentSources(object):
17
+    """Wrapper for content sources plugin"""
18
+
19
+    #----------------------------------------------------------------------
20
+    def __init__(self, plugin_path):
21
+        self.plugins = {}
22
+        self.error_content = [("..atpakaļ", "back", None, "Kļūda, atgriezties atpakaļ")]
23
+        sys.path.insert(0, plugin_path)
24
+        #for f in os.listdir(plugin_path):
25
+        #for f in next(os.walk(plugin_path))[2]:
26
+        print "ContentSources: Importing sources from "+plugin_path
27
+        files = glob.glob(os.path.join(plugin_path,"*.py"))
28
+        for f in files:
29
+            fname, ext = os.path.splitext(f)
30
+            fname = os.path.split(fname)[1]
31
+            if fname == "__init__": continue
32
+            if ext == '.py':
33
+                mod = __import__(fname)
34
+                reload(mod)
35
+                if "Source" in dir(mod):
36
+                    self.plugins[fname] = mod.Source()
37
+                    print fname+ " imported"
38
+                else:
39
+                    pass
40
+                    #print fname+ "skipped"
41
+        sys.path.pop(0)
42
+        if not "config" in self.plugins:
43
+            raise Exception("Problem importing content sources")
44
+        cfg = self.plugins["config"]
45
+        for pl in self.plugins.keys():
46
+            found = False
47
+            for lst in cfg.get_lists():
48
+                for item in cfg.lists[lst]:
49
+                    if item[1].split("::")[0]==pl:
50
+                        found = True
51
+                        break
52
+                    if found: break
53
+            if not found:
54
+                title = self.plugins[pl].title if "title" in dir(self.plugins[pl]) else pl
55
+                img = self.plugins[pl].img if "img" in dir(self.plugins[pl]) else ""
56
+                desc = self.plugins[pl].desc if "desc" in dir(self.plugins[pl]) else title
57
+                cfg.add_item("home",(title,"%s::home"%pl,img,desc))
58
+                cfg.write_streams()
59
+
60
+    def get_content(self,data):
61
+        source = data.split("::")[0]
62
+        if source in self.plugins:
63
+            content = self.plugins[source].get_content(data)
64
+            if content:
65
+                if isinstance(content,list):
66
+                    for i,item in enumerate(content):
67
+                        item2=[]
68
+                        for el in item:
69
+                            if isinstance(el,unicode):
70
+                                el = el.encode("utf8")
71
+                            item2.append(el)
72
+                        content[i]=tuple(item2)
73
+                else:
74
+                    item2=[]
75
+                    for el in content:
76
+                        if isinstance(el,unicode):
77
+                            el = el.encode("utf8")
78
+                        item2.append(el)
79
+                    content=tuple(item2)
80
+                return content
81
+            else:
82
+                return self.error_content
83
+        else:
84
+            return self.error_content
85
+
86
+    def get_streams(self,data):
87
+        if stream_type(data):
88
+            if "::" in data:
89
+                data = data.split("::")[1]
90
+            content = self.get_content(data)
91
+            stream = util.item()
92
+            stream["name"] = data
93
+            stream["url"] = data
94
+            stream["type"] = stream_type(data)
95
+            #stream["img"] = ""
96
+            #stream["desc"] = ""
97
+            return[stream]
98
+
99
+        if not self.is_video(data):
100
+            return []
101
+        source = data.split("::")[0]
102
+        if source in self.plugins:
103
+            streams = self.plugins[source].get_streams(data)
104
+            for s in streams:
105
+                for k in s:
106
+                    if isinstance(s[k],unicode):
107
+                        s[k] = s[k].encode("utf8")
108
+            return streams
109
+        else:
110
+            return []
111
+
112
+    def stream_type(self,data):
113
+        return stream_type(data)
114
+
115
+    def is_video(self,data):
116
+        if self.stream_type(data):
117
+            return True
118
+        source = data.split("::")[0]
119
+        if source in self.plugins:
120
+            return self.plugins[source].is_video(data)
121
+        else:
122
+            return False
123
+
124
+    def options_read(self,source):
125
+        if source in self.plugins:
126
+            options = self.plugins[source].options_read()
127
+            if options:
128
+                return options
129
+            else:
130
+                return None
131
+        else:
132
+            return None
133
+
134
+    def options_write(self,source,options):
135
+        if source in self.plugins:
136
+            return self.plugins[source].options_write(options)
137
+        else:
138
+            return None
139
+
140
+if __name__ == "__main__":
141
+
142
+    sources = ContentSources("sources")
143
+    if len(sys.argv)>1:
144
+        data= sys.argv[1]
145
+    else:
146
+        data = "config::home"
147
+
148
+    #options = sources.options_read("ltc")
149
+    #print options
150
+    history = []
151
+    cur = ("Home",data,None,None)
152
+    content = sources.get_content(cur[1])
153
+
154
+    exit_loop = False
155
+    while True:
156
+        print
157
+        for i,item in enumerate(content):
158
+            s = "%i: %s - %s %s %s "%(i+1,item[0],item[1],item[2],item[3])
159
+            print s #.encode(sys.stdout.encoding,"replace")
160
+
161
+        while True:
162
+            a = raw_input("Enter numeber, q for exit: ")
163
+            if a in ("q","Q","x","X"):
164
+                exit_loop = True
165
+                print "Exiting"
166
+                break
167
+            try:
168
+                n = int(a)
169
+                break
170
+            except:
171
+                print "Not number!"
172
+        if exit_loop: break
173
+        cur2 = content[n-1]
174
+
175
+        data0 = cur2[1].split("::")[1] if "::" in cur2[1] else cur2[1]
176
+        if not data0:
177
+            pass
178
+
179
+        elif cur2[1] == "back":
180
+            cur = history.pop()
181
+        elif sources.is_video(cur2[1]):
182
+            if sources.stream_type(cur2[1]):
183
+                stream = util.item()
184
+                stream["url"] = cur2[1]
185
+                stream["name"] = cur2[0]
186
+                streams = [stream]
187
+            else:
188
+                streams = sources.get_streams(cur2[1])
189
+                try:
190
+                    streams = sources.get_streams(cur2[1])
191
+                except Exception as e:
192
+                    print str(e)
193
+                    streams = []
194
+            if streams:
195
+                util.play_video(streams)
196
+            else:
197
+                print "**No stream to play - %s "%(
198
+                    cur2[1])
199
+                raw_input("Press any key")
200
+            #import os
201
+            #os.system('"c:\Program Files (x86)\VideoLAN\VLC\vlc.exe" "%s"'%cur2[1])
202
+
203
+        else:
204
+            if "{0}" in cur2[1]:
205
+                a = raw_input("Enter value:")
206
+                cur2 = (cur2[0],cur2[1].format(a),cur2[2],cur2[3])
207
+            history.append(cur)
208
+            cur = cur2
209
+        try:
210
+            content = sources.get_content(cur[1])
211
+        except Exception as e:
212
+            print str(e)
213
+            raw_input("Continue?")
214
+
215
+

+ 0
- 0
resources/lib/__init__.py Parādīt failu


+ 6281
- 0
resources/lib/demjson.py
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 141
- 0
resources/lib/resolver.py Parādīt failu

@@ -0,0 +1,141 @@
1
+# *      Copyright (C) 2011 Libor Zoubek
2
+# *      Modified by ivars777
3
+# *      Based in code from https://github.com/kodi-czsk/script.module.stream.resolver
4
+# *
5
+# *
6
+# *  This Program is free software; you can redistribute it and/or modify
7
+# *  it under the terms of the GNU General Public License as published by
8
+# *  the Free Software Foundation; either version 2, or (at your option)
9
+# *  any later version.
10
+# *
11
+# *  This Program is distributed in the hope that it will be useful,
12
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+# *  GNU General Public License for more details.
15
+# *
16
+# *  You should have received a copy of the GNU General Public License
17
+# *  along with this program; see the file COPYING.  If not, write to
18
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
+# *  http://www.gnu.org/copyleft/gpl.html
20
+# *
21
+# */
22
+# Based in code from https://github.com/kodi-czsk/script.module.stream.resolver
23
+
24
+import re
25
+import traceback
26
+
27
+import util
28
+import sys,os
29
+#sys.path.insert(0,os.path.dirname(os.path.abspath(__file__)))
30
+server_path = "resolvers"
31
+sys.path.append(os.path.join(os.path.dirname(__file__), server_path))
32
+
33
+RESOLVERS = []
34
+util.debug('%s searching for modules' % __name__)
35
+
36
+for module in os.listdir(os.path.join(os.path.dirname(__file__), server_path)):
37
+    if module == '__init__.py' or module[-3:] != '.py':
38
+        continue
39
+    module = module[:-3]
40
+    #exec 'import %s' % module
41
+    #resolver = eval(module)
42
+    resolver = __import__(module)
43
+    #reload(resolver)
44
+
45
+    if not hasattr(resolver, 'resolve'):
46
+        continue
47
+    print 'found %s %s' % (resolver, dir(resolver))
48
+    #util.debug('found %s %s' % (resolver, dir(resolver)))
49
+    if not hasattr(resolver, '__priority__'):
50
+        resolver.__priority__ = 0
51
+    RESOLVERS.append(resolver)
52
+    del module
53
+RESOLVERS = sorted(RESOLVERS, key=lambda m: -m.__priority__)
54
+
55
+
56
+def resolve(url):
57
+    """
58
+        resolves given url by asking all resolvers
59
+
60
+        returns None if no resolver advised to be able to resolve this url
61
+        returns False if resolver did his job, but did not return any value (thus failed)
62
+        returns Array of resolved objects in positive usecase
63
+    """
64
+    url = util.decode_html(url)
65
+    util.info('Resolving ' + url)
66
+    resolver = _get_resolver(url)
67
+    value = None
68
+    if resolver is None:
69
+        return []
70
+    util.info('Using resolver \'%s\'' % str(resolver.__name__));
71
+    value = resolver.resolve(url)
72
+    if not value:
73
+        return []
74
+    default = util.item()
75
+    for i in value:
76
+        i["resolver"] = resolver.__name__
77
+        if 'name' not in i.keys():
78
+            i['name'] = resolver.__name__
79
+        i['surl'] = url
80
+        for key in default.keys():
81
+            if key not in i.keys():
82
+                i[key] = default[key]
83
+        if "|" in i["url"]:
84
+            headers = i["url"].split("|")[1]
85
+            i["url"]=i["url"].split("|")[0]
86
+            for h in headers.split("&"):
87
+                if "=" in h:
88
+                    i["headers"][h.split("=")[0]] = h.split("=")[1]
89
+
90
+    return sorted(value, key=lambda i: i['quality'], reverse=True)
91
+
92
+
93
+def _get_resolver(url):
94
+    util.debug('Get resolver for ' + url)
95
+    for r in RESOLVERS:
96
+        util.debug('querying %s' % r)
97
+        if r.supports(url):
98
+            return r
99
+
100
+def can_resolve(url):
101
+    """ Returns true if we are able to resolve stream by given URL """
102
+    return _get_resolver(url) is not None
103
+
104
+
105
+if __name__ == "__main__":
106
+
107
+    from subprocess import call
108
+    #url = "http://hqq.tv/player/embed_player.php?vid=235238210241210222228241233208212245&autoplay=no"
109
+    #url = "http://hqq.tv/player/embed_player.php?vid=243221241234244238208213206212211231&autoplay=no"
110
+    url = "http://hqq.tv/player/embed_player.php?vid=208231211231207221227243206206221244&autoplay=no"
111
+    #url = "https://openload.co/embed/TMthIdpy4PI/"
112
+    #url = "https://www.youtube.com/watch?v=Tx1K51_F99o"
113
+    #url = "https://www.youtube.com/watch?v=8BkcX7O1890"
114
+    #url = "https://www.youtube.com/watch?v=Se07R8SYsg0"
115
+    #url = "https://kinostok.tv/embed/731f3437e3c53104dd56d04039a0b15a"
116
+    #url = "http://vk.com/video_ext.php?oid=246066565&id=169244575&hash=d430ab0e76c9f7a1&hd=3"
117
+    #url ="https://openload.co/embed/rPMXJYPTkw4/"
118
+    #url = "https://openload.co/embed/bE7WfZ-vz_A/"
119
+    #url = "https://openload.co/embed/bE7WfZ/"
120
+    #url = "https://openload.co/embed/OuskaKyC2GU/"
121
+    url = "http://hqq.tv/player/embed_player.php?vid=235238210241210222228241233208212245&autoplay=no"
122
+    url = "https://hqq.tv/player/embed_player.php?vid=235242211228257255206246241253244213194271217261258"
123
+    #url = "https://openload.co/embed/rmNcP-0QopE/"
124
+    #url = "https://openload.co/embed/gpLF6Grzy80/"
125
+    #url = "https://openload.co/embed/oQLXcU1ITAY/"
126
+    #url = "http://hqq.tv/player/embed_player.php?vid=245208228234224222241224221239207212&autoplay=no"
127
+    url = "https://goo.gl/yMTzqf"
128
+    url = "http://cdn.kapnob.ru/video/5e67c8b1ad018ffa/iframe"
129
+    url = "http://kodik.cc/video/10830/4269a802d1a9d9bdc53fe38488d53a52/720p"
130
+    streams = resolve(url)
131
+    if not streams:
132
+        print "No streams found"
133
+        sys.exit()
134
+
135
+    for s in streams:
136
+        print s
137
+
138
+    print streams[0]["url"]
139
+    util.play_video(streams)
140
+    ##call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",streams[0]["url"]])
141
+    pass

+ 31
- 0
resources/lib/resolvers/__init__.py Parādīt failu

@@ -0,0 +1,31 @@
1
+#/*
2
+# *      Copyright (C) 2011 Libor Zoubek
3
+# *
4
+# *
5
+# *  This Program is free software; you can redistribute it and/or modify
6
+# *  it under the terms of the GNU General Public License as published by
7
+# *  the Free Software Foundation; either version 2, or (at your option)
8
+# *  any later version.
9
+# *
10
+# *  This Program is distributed in the hope that it will be useful,
11
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+# *  GNU General Public License for more details.
14
+# *
15
+# *  You should have received a copy of the GNU General Public License
16
+# *  along with this program; see the file COPYING.  If not, write to
17
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18
+# *  http://www.gnu.org/copyleft/gpl.html
19
+# *
20
+# */
21
+
22
+
23
+##########################################################3
24
+# all resolvers modules in this directory must have following methods:
25
+
26
+# __name__ - name of the resolver module - can override module filename
27
+# def supports(url) - returns true iff resolver is able to resolve url to stream otherwise false
28
+# def resolve(url) - returns array of all hashmaps that were resolved
29
+#   - if resolving fails, nothing is returned
30
+#   - a hash MUST contain key 'url' - it's value is stream URL
31
+#   - optional keys are 'subs' (link to subtitle), 'quality' (quality string like '240p' or just 'HD'

+ 209
- 0
resources/lib/resolvers/aadecode.py Parādīt failu

@@ -0,0 +1,209 @@
1
+#-*- coding: utf-8 -*-
2
+#
3
+# author : Djeman
4
+# Updated by Shani-08 (https://github.com/Shani-08/ShaniXBMCWork2)
5
+
6
+import re
7
+
8
+class AADecoder(object):
9
+    def __init__(self, aa_encoded_data):
10
+        self.encoded_str = aa_encoded_data.replace('/*´∇`*/','')
11
+
12
+        self.b = ["(c^_^o)", "(゚Θ゚)", "((o^_^o) - (゚Θ゚))", "(o^_^o)",
13
+                  "(゚ー゚)", "((゚ー゚) + (゚Θ゚))", "((o^_^o) +(o^_^o))", "((゚ー゚) + (o^_^o))",
14
+                  "((゚ー゚) + (゚ー゚))", "((゚ー゚) + (゚ー゚) + (゚Θ゚))", "(゚Д゚) .゚ω゚ノ", "(゚Д゚) .゚Θ゚ノ",
15
+                  "(゚Д゚) ['c']", "(゚Д゚) .゚ー゚ノ", "(゚Д゚) .゚Д゚ノ", "(゚Д゚) [゚Θ゚]"]
16
+
17
+    def is_aaencoded(self):
18
+        idx = self.encoded_str.find("゚ω゚ノ= /`m´)ノ ~┻━┻   //*´∇`*/ ['_']; o=(゚ー゚)  =_=3; c=(゚Θ゚) =(゚ー゚)-(゚ー゚); ")
19
+        if idx == -1:
20
+            return False
21
+
22
+        if self.encoded_str.find("(゚Д゚)[゚o゚]) (゚Θ゚)) ('_');", idx) == -1:
23
+            return False
24
+
25
+        return True
26
+
27
+    def base_repr(self, number, base=2, padding=0):
28
+        digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
29
+        if base > len(digits):
30
+            base = len(digits)
31
+
32
+        num = abs(number)
33
+        res = []
34
+        while num:
35
+            res.append(digits[num % base])
36
+            num //= base
37
+        if padding:
38
+            res.append('0' * padding)
39
+        if number < 0:
40
+            res.append('-')
41
+        return ''.join(reversed(res or '0'))
42
+
43
+    def decode_char(self, enc_char, radix):
44
+        end_char = "+ "
45
+        str_char = ""
46
+        while enc_char != '':
47
+            found = False
48
+
49
+            if not found:
50
+                for i in range(len(self.b)):             
51
+                    enc_char=enc_char.replace(self.b[i], str(i))
52
+                
53
+                startpos=0
54
+                findClose=True
55
+                balance=1
56
+                result=[]
57
+                if enc_char.startswith('('):
58
+                    l=0
59
+                    
60
+                    for t in enc_char[1:]:
61
+                        l+=1
62
+                        if findClose and t==')':
63
+                            balance-=1;
64
+                            if balance==0:
65
+                                result+=[enc_char[startpos:l+1]]
66
+                                findClose=False
67
+                                continue
68
+                        elif not findClose and t=='(':
69
+                            startpos=l
70
+                            findClose=True
71
+                            balance=1
72
+                            continue
73
+                        elif t=='(':
74
+                            balance+=1
75
+                 
76
+
77
+                if result is None or len(result)==0:
78
+                    return ""
79
+                else:
80
+                    
81
+                    for r in result:
82
+                        value = self.decode_digit(r, radix)
83
+                        if value == "":
84
+                            return ""
85
+                        else:
86
+                            str_char += value
87
+                            
88
+                    return str_char
89
+
90
+            enc_char = enc_char[len(end_char):]
91
+
92
+        return str_char
93
+
94
+        
95
+              
96
+    def decode_digit(self, enc_int, radix):
97
+
98
+        rr = '(\(.+?\)\))\+'
99
+        rerr=enc_int.split('))+')
100
+        v = ''
101
+        
102
+        #new mode
103
+
104
+        for c in rerr:
105
+            
106
+            if len(c)>0:
107
+                if c.strip().endswith('+'):
108
+                    c=c.strip()[:-1]
109
+
110
+                startbrackets=len(c)-len(c.replace('(',''))
111
+                endbrackets=len(c)-len(c.replace(')',''))
112
+                    
113
+                if startbrackets>endbrackets:
114
+                    c+=')'*startbrackets-endbrackets
115
+                    
116
+                c = c.replace('!+[]','1')
117
+                c = c.replace('-~','1+')
118
+                c = c.replace('[]','0')
119
+                    
120
+                v+=str(eval(c))
121
+                    
122
+        return v
123
+         
124
+        mode = 0
125
+        value = 0
126
+
127
+        while enc_int != '':
128
+            found = False
129
+            for i in range(len(self.b)):
130
+                if enc_int.find(self.b[i]) == 0:
131
+                    if mode == 0:
132
+                        value += i
133
+                    else:
134
+                        value -= i
135
+                    enc_int = enc_int[len(self.b[i]):]
136
+                    found = True
137
+                    break
138
+
139
+            if not found:
140
+                return ""
141
+
142
+            enc_int = re.sub('^\s+|\s+$', '', enc_int)
143
+            if enc_int.find("+") == 0:
144
+                mode = 0
145
+            else:
146
+                mode = 1
147
+
148
+            enc_int = enc_int[1:]
149
+            enc_int = re.sub('^\s+|\s+$', '', enc_int)
150
+
151
+        return self.base_repr(value, radix)
152
+
153
+    def decode(self):
154
+
155
+        self.encoded_str = re.sub('^\s+|\s+$', '', self.encoded_str)
156
+
157
+        # get data
158
+        pattern = (r"\(゚Д゚\)\[゚o゚\]\+ (.+?)\(゚Д゚\)\[゚o゚\]\)")
159
+        result = re.search(pattern, self.encoded_str, re.DOTALL)
160
+        if result is None:
161
+            print "AADecoder: data not found"
162
+            return False
163
+
164
+        data = result.group(1)
165
+
166
+        # hex decode string
167
+        begin_char = "(゚Д゚)[゚ε゚]+"
168
+        alt_char = "(o゚ー゚o)+ "
169
+
170
+        out = ''
171
+
172
+        while data != '':
173
+            # Check new char
174
+            if data.find(begin_char) != 0:
175
+                print "AADecoder: data not found"
176
+                return False
177
+
178
+            data = data[len(begin_char):]
179
+
180
+            # Find encoded char
181
+            enc_char = ""
182
+            if data.find(begin_char) == -1:
183
+                enc_char = data
184
+                data = ""
185
+            else:
186
+                enc_char = data[:data.find(begin_char)]
187
+                data = data[len(enc_char):]
188
+
189
+            
190
+            radix = 8
191
+            # Detect radix 16 for utf8 char
192
+            if enc_char.find(alt_char) == 0:
193
+                enc_char = enc_char[len(alt_char):]
194
+                radix = 16
195
+
196
+            str_char = self.decode_char(enc_char, radix)
197
+            
198
+            if str_char == "":
199
+                print "no match :  "
200
+                print  data + "\nout = " + out + "\n"
201
+                return False
202
+            
203
+            out += chr(int(str_char, radix))
204
+
205
+        if out == "":
206
+            print "no match : " + data
207
+            return False
208
+
209
+        return out

+ 95
- 0
resources/lib/resolvers/hdgo.py Parādīt failu

@@ -0,0 +1,95 @@
1
+# -*- coding: UTF-8 -*-
2
+# /*
3
+# *      Copyright (C) 2016 ivars777
4
+# *
5
+# *
6
+# *  This Program is free software; you can redistribute it and/or modify
7
+# *  it under the terms of the GNU General Public License as published by
8
+# *  the Free Software Foundation; either version 2, or (at your option)
9
+# *  any later version.
10
+# *
11
+# *  This Program is distributed in the hope that it will be useful,
12
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+# *  GNU General Public License for more details.
15
+# *
16
+# *  You should have received a copy of the GNU General Public License
17
+# *  along with this program; see the file COPYING.  If not, write to
18
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
+# *  http://www.gnu.org/copyleft/gpl.html
20
+# *
21
+# */
22
+
23
+import re,os,sys
24
+import json
25
+try:
26
+    import util
27
+except:
28
+    pp = os.path.dirname(os.path.abspath(__file__))
29
+    sys.path.insert(0,os.sep.join(pp.split(os.sep)[:-1]))
30
+    import util
31
+import urllib2
32
+import requests
33
+#from aadecode import AADecoder
34
+
35
+if __name__ <> "__main__":
36
+    __name__ = 'hqq'
37
+
38
+def supports(url):
39
+    m = re.search(r"https?://hdgo\.\w+/(.+?)$", url, re.DOTALL)
40
+    if m:
41
+        return True
42
+    else:
43
+        return False
44
+
45
+def resolve(url):
46
+    HTTP_HEADER = {
47
+        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0',
48
+        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
49
+        'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
50
+        'Accept-Encoding': 'none',
51
+        'Accept-Language': 'en-US,en;q=0.8',
52
+        'Referer': url}  # 'Connection': 'keep-alive'
53
+    streams = []
54
+    m = re.search(r"https?://hdgo\.\w+/(.+?)$", url, re.DOTALL)
55
+    vid=m.group(1)
56
+    url2 = "http://couber.be/"+vid
57
+    r = requests.get(url2,headers=HTTP_HEADER)
58
+    if r.status_code <> 200:
59
+        return streams
60
+    m = re.search('<iframe src="([^"]+)"', r.content, re.DOTALL)
61
+    if not m: return streams
62
+    url3 = m.group(1)
63
+    HTTP_HEADER["Rererer"] = url2
64
+    r = requests.get(url3,headers=HTTP_HEADER)
65
+    m = re.search(r"else{\s+setFlash\('([^']+)'\);", r.content, re.DOTALL)
66
+    if not m: return streams
67
+    q = ["1080p","720p","480p","360p"]
68
+    for i,ss in enumerate(m.group(1).split(",")):
69
+        s = ss.split(" or ")
70
+        if not s[0]: continue
71
+        stream = util.item()
72
+        stream["url"] = s[0]
73
+        stream["name"] = s[0]
74
+        stream["quality"] = q[i]
75
+        streams.append(stream)
76
+    return streams
77
+
78
+
79
+if __name__ == "__main__":
80
+
81
+    from subprocess import call
82
+    url = "http://hdgo.cc/video/t/Qrz0riUvA65GtkTpDvmlD9TBOn56HSm2/127280/"
83
+    url = "http://hdgo.cc/video/t/Qrz0riUvA65GtkTpDvmlD9TBOn56HSm2/34879/"
84
+    streams = resolve(url)
85
+    if not streams:
86
+        print "No streams found"
87
+        sys.exit()
88
+    for s in streams:
89
+        print s
90
+    util.play_video(streams)
91
+
92
+
93
+    #print streams[0]["url"]    
94
+    #call([r"gst-launch-1.0.exe",'uri="%s""'%streams[0]["url"]])
95
+    pass

+ 234
- 0
resources/lib/resolvers/hqqresolver.py Parādīt failu

@@ -0,0 +1,234 @@
1
+# -*- coding: UTF-8 -*-
2
+# *  GNU General Public License for more details.
3
+# *
4
+# *
5
+# *  You should have received a copy of the GNU General Public License
6
+# *  along with this program; see the file COPYING.  If not, write to
7
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
8
+# *  http://www.gnu.org/copyleft/gpl.html
9
+# *
10
+# *
11
+# *  based on https://gitorious.org/iptv-pl-dla-openpli/ urlresolver
12
+# */
13
+from StringIO import StringIO
14
+import json
15
+import re
16
+import base64
17
+import urllib
18
+import sys,os
19
+
20
+try:
21
+    import util
22
+except:
23
+    pp = os.path.dirname(os.path.abspath(__file__))
24
+    sys.path.insert(0, os.sep.join(pp.split(os.sep)[:-1]))
25
+    import util
26
+import requests
27
+
28
+__author__ = 'ivars777'
29
+if __name__ <> "__main__":
30
+    __name__ = 'hqq'
31
+
32
+
33
+def supports(url):
34
+    #return False
35
+    return _regex(url) is not None
36
+
37
+
38
+def _decode(data):
39
+    def O1l(string):
40
+        ret = ""
41
+        i = len(string) - 1
42
+        while i >= 0:
43
+            ret += string[i]
44
+            i -= 1
45
+        return ret
46
+
47
+    def l0I(string):
48
+        enc = ""
49
+        dec = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
50
+        i = 0
51
+        while True:
52
+            h1 = dec.find(string[i])
53
+            i += 1
54
+            h2 = dec.find(string[i])
55
+            i += 1
56
+            h3 = dec.find(string[i])
57
+            i += 1
58
+            h4 = dec.find(string[i])
59
+            i += 1
60
+            bits = h1 << 18 | h2 << 12 | h3 << 6 | h4
61
+            o1 = bits >> 16 & 0xff
62
+            o2 = bits >> 8 & 0xff
63
+            o3 = bits & 0xff
64
+            if h3 == 64:
65
+                enc += unichr(o1)
66
+            else:
67
+                if h4 == 64:
68
+                    enc += unichr(o1) + unichr(o2)
69
+                else:
70
+                    enc += unichr(o1) + unichr(o2) + unichr(o3)
71
+            if i >= len(string):
72
+                break
73
+        return enc
74
+
75
+    escape = re.search("var _escape=\'([^\']+)", l0I(O1l(data))).group(1)
76
+    return escape.replace('%', '\\').decode('unicode-escape')
77
+
78
+
79
+def _decode2(file_url):
80
+    def K12K(a, typ='b'):
81
+        codec_a = ["G", "L", "M", "N", "Z", "o", "I", "t", "V", "y", "x", "p", "R", "m", "z", "u",
82
+                   "D", "7", "W", "v", "Q", "n", "e", "0", "b", "="]
83
+        codec_b = ["2", "6", "i", "k", "8", "X", "J", "B", "a", "s", "d", "H", "w", "f", "T", "3",
84
+                   "l", "c", "5", "Y", "g", "1", "4", "9", "U", "A"]
85
+        if 'd' == typ:
86
+            tmp = codec_a
87
+            codec_a = codec_b
88
+            codec_b = tmp
89
+        idx = 0
90
+        while idx < len(codec_a):
91
+            a = a.replace(codec_a[idx], "___")
92
+            a = a.replace(codec_b[idx], codec_a[idx])
93
+            a = a.replace("___", codec_b[idx])
94
+            idx += 1
95
+        return a
96
+
97
+    def _xc13(_arg1):
98
+        _lg27 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
99
+        _local2 = ""
100
+        _local3 = [0, 0, 0, 0]
101
+        _local4 = [0, 0, 0]
102
+        _local5 = 0
103
+        while _local5 < len(_arg1):
104
+            _local6 = 0
105
+            while _local6 < 4 and (_local5 + _local6) < len(_arg1):
106
+                _local3[_local6] = _lg27.find(_arg1[_local5 + _local6])
107
+                _local6 += 1
108
+            _local4[0] = ((_local3[0] << 2) + ((_local3[1] & 48) >> 4))
109
+            _local4[1] = (((_local3[1] & 15) << 4) + ((_local3[2] & 60) >> 2))
110
+            _local4[2] = (((_local3[2] & 3) << 6) + _local3[3])
111
+
112
+            _local7 = 0
113
+            while _local7 < len(_local4):
114
+                if _local3[_local7 + 1] == 64:
115
+                    break
116
+                _local2 += chr(_local4[_local7])
117
+                _local7 += 1
118
+            _local5 += 4
119
+        return _local2
120
+
121
+    return _xc13(K12K(file_url, 'e'))
122
+
123
+
124
+def resolve(url):
125
+    m = _regex(url)
126
+    if m:
127
+        headers = {'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
128
+                   'Content-Type': 'text/html; charset=utf-8'}
129
+        if "goo.gl" in url:
130
+            data = util.request(url, headers)
131
+            player_url = re.search("var ppage = '(.+?)'",data).group(1)
132
+            player_url = urllib.unquote(player_url)
133
+        else:
134
+            vid = m.group('vid')
135
+            player_url = "http://hqq.tv/player/embed_player.php?vid=%s&autoplay=no" % vid
136
+            data = util.request(player_url, headers)
137
+        b64enc = re.search('base64([^\"]+)', data, re.DOTALL)
138
+        b64dec = b64enc and base64.decodestring(b64enc.group(1))
139
+        enc = b64dec and re.search("\'([^']+)\'", b64dec).group(1)
140
+        if enc:
141
+            data = re.findall('<input name="([^"]+?)" [^>]+? value="([^"]+?)">', _decode(enc))
142
+            post_data = {}
143
+            for idx in range(len(data)):
144
+                post_data[data[idx][0]] = data[idx][1]
145
+            data = util.post(player_url, post_data, headers)
146
+            b64enc = re.search('base64([^\"]+)', data, re.DOTALL)
147
+            b64dec = b64enc and base64.decodestring(b64enc.group(1))
148
+            enc = b64dec and re.search("\'([^']+)\'", b64dec).group(1)
149
+            if enc:
150
+                data = re.findall('<input name="([^"]+?)" [^>]+? value="([^"]*)">', _decode(enc))
151
+                post_data = {}
152
+                for idx in range(len(data)):
153
+                    post_data[data[idx][0]] = data[idx][1]
154
+                data = urllib.unquote(util.request("http://hqq.tv/sec/player/embed_player.php?" +
155
+                                                   urllib.urlencode(post_data), headers))
156
+                server_1 = re.search("server_1: (\w+)",data).group(1)
157
+                link_1 = re.search("link_1: (\w+)",data).group(1)
158
+                vid_server = re.search(r'var\s*%s\s*=\s*"([^"]*?)"'%server_1, data)
159
+                vid_link = re.search(r'var\s*%s\s*=\s*"([^"]*?)"'%link_1, data)
160
+                at = re.search(r'var\s*at\s*=\s*"([^"]*?)"', data)
161
+                vid = re.search('vid: "([^"]+)"',data)
162
+                sub_url = re.search('sub:"(.+?)"',data).group(1) if re.search('sub:"(.+?)"',data) else ""
163
+                subs_lang = re.search('sublangs:"(.+?)"',data).group(1) if re.search('sub:"(.+?)"',data) else ""
164
+                if sub_url:
165
+                    subs=[{"url":sub_url,'name':subs_lang,"lang":subs_lang}]
166
+                else:
167
+                    subs = []
168
+                if vid_server and vid_link and at:
169
+                    get_data = {'server_1': vid_server.group(1),
170
+                                'link_1': vid_link.group(1),
171
+                                'at': at.group(1),
172
+                                'adb': '0/',
173
+                                'b':'1',
174
+                                'vid': vid.group(1)}
175
+                    # X-Requested-With: XMLHttpRequest
176
+                    headers["X-Requested-With"] = "XMLHttpRequest"
177
+                    html = util.request("http://hqq.tv/player/get_md5.php?"+urllib.urlencode(get_data), headers)
178
+                    data = json.load(StringIO(html))
179
+                    if 'file' in data:
180
+                        file_url = _decode2(data['file'])
181
+                        file_url = re.sub(r'\?socket=?$', '.mp4.m3u8',file_url)
182
+                        stream  = {
183
+                            'url': file_url,
184
+                            'name': file_url,
185
+                            'subs':subs,
186
+                            'quality': 'hqq',
187
+                            'resolver': 'hqq',
188
+                            "headers":{"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/47.0.2526.70 Mobile/13C71 Safari/601.1.46"}
189
+                        }
190
+                        return [stream]
191
+    return []
192
+
193
+
194
+def _regex(url):
195
+    # https://goo.gl/yMTzqf
196
+    match = re.search("(hqq|netu)\.tv/watch_video\.php\?v=(?P<vid>[0-9A-Z]+)", url)
197
+    if match:
198
+        return match
199
+    match = re.search(r'(hqq|netu)\.tv/player/embed_player\.php\?vid=(?P<vid>[0-9A-Za-z]+)', url)
200
+    if match:
201
+        return match
202
+    match = re.search(r'(hqq|netu)\.tv/player/hash\.php\?hash=\d+', url)
203
+    if match:
204
+        match = re.search(r'var\s+vid\s*=\s*\'(?P<vid>[^\']+)\'', urllib.unquote(util.request(url)))
205
+        if match:
206
+            return match
207
+    # https://goo.gl/yMTzqf
208
+    match = re.search("(goo)\.gl/(?P<vid>[\w]+)", url)
209
+    if match:
210
+        return match
211
+
212
+    b64enc = re.search(r'data:text/javascript\;charset\=utf\-8\;base64([^\"]+)', url)
213
+    b64dec = b64enc and base64.decodestring(b64enc.group(1))
214
+    enc = b64dec and re.search(r"\'([^']+)\'", b64dec).group(1)
215
+    if enc:
216
+        decoded = _decode(enc)
217
+        match = re.search(r'<input name="vid"[^>]+? value="(?P<vid>[^"]+?)">', decoded)
218
+        if re.search(r'<form(.+?)action="[^"]*(hqq|netu)\.tv/player/embed_player\.php"[^>]*>',
219
+                     decoded) and match:
220
+            return match
221
+    return None
222
+
223
+if __name__ == "__main__":
224
+
225
+    url = "http://hqq.tv/player/embed_player.php?vid=nYAKgzBAf7ll"
226
+    streams = resolve(url)
227
+    if not streams:
228
+        print "No streams found"
229
+        sys.exit()
230
+    for s in streams:
231
+        print s
232
+    print streams[0]["url"]
233
+    util.play_video(streams)
234
+    pass

+ 94
- 0
resources/lib/resolvers/kapnob.py Parādīt failu

@@ -0,0 +1,94 @@
1
+# -*- coding: UTF-8 -*-
2
+# /*
3
+# *      Copyright (C) 2016 Ivars777
4
+# *
5
+# *
6
+# *  This Program is free software; you can redistribute it and/or modify
7
+# *  it under the terms of the GNU General Public License as published by
8
+# *  the Free Software Foundation; either version 2, or (at your option)
9
+# *  any later version.
10
+# *
11
+# *  This Program is distributed in the hope that it will be useful,
12
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+# *  GNU General Public License for more details.
15
+# *
16
+# *  You should have received a copy of the GNU General Public License
17
+# *  along with this program; see the file COPYING.  If not, write to
18
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
+# *  http://www.gnu.org/copyleft/gpl.html
20
+# *
21
+# */
22
+
23
+import re,os,sys
24
+import json
25
+try:
26
+    import util
27
+except:
28
+    pp = os.path.dirname(os.path.abspath(__file__))
29
+    sys.path.insert(0,os.sep.join(pp.split(os.sep)[:-1]))
30
+    import util
31
+import requests
32
+
33
+__author__ = 'ivars777'
34
+if __name__ <> "__main__":
35
+    __name__ = 'kapnob'
36
+
37
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
38
+headers = headers2dict("""
39
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
40
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
41
+Accept-Language: en-US,en;q=0.5
42
+""")
43
+
44
+
45
+def supports(url):
46
+    return True if "kapnob.ru" in url else False
47
+
48
+def resolve(url):
49
+    HTTP_HEADER = {
50
+        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0',
51
+        'Referer': url}  # 'Connection': 'keep-alive'
52
+    stream = util.item()
53
+    data = requests.get(url,headers = HTTP_HEADER).content
54
+    m = re.search(r'subtitles: \[\s+{\s+src: "(.+?)",\s+label: "(.+?)",\s+language: "(.+?)"', data, re.DOTALL)
55
+    if m:
56
+        sub = {}
57
+        sub["url"] = m.group(1)
58
+        sub["name"] = m.group(2)
59
+        sub["lang"] = m.group(3)
60
+        sub["type"] = "srt"
61
+        stream["subs"]=[sub]
62
+
63
+    video_token = re.search("video_token: '(.+?)'",data).group(1)
64
+    content_type = re.search("content_type: '(.+?)'",data).group(1)
65
+    mw_key = re.search("mw_key: '(.+?)'",data).group(1)
66
+    mw_domain_id = re.search("mw_domain_id: (\d+)",data).group(1)
67
+    uuid = re.search("uuid: '(.+?)'",data).group(1)
68
+    params = "video_token=%s&content_type=%s&mw_key=%s&mw_pid=&mw_domain_id=%s&ad_attr=0&debug=false&uuid=%s"%(
69
+        video_token,content_type,mw_key,mw_domain_id,uuid)
70
+    headers = headers2dict("""
71
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
72
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
73
+X-Iframe-Option: Direct
74
+X-Requested-With: XMLHttpRequest
75
+""")
76
+    data = requests.post("http://cdn.kapnob.ru/sessions/new_session", data=params,headers=headers).content
77
+    js = json.loads(data)
78
+    stream["url"] = js["mans"]["manifest_m3u8"]
79
+    stream["name"]= stream["url"]
80
+    return [stream]
81
+
82
+
83
+if __name__ == "__main__":
84
+
85
+    url = "http://cdn.kapnob.ru/video/5e67c8b1ad018ffa/iframe"
86
+    streams = resolve(url)
87
+    if not streams:
88
+        print "No streams found"
89
+        sys.exit()
90
+    for s in streams:
91
+        print s
92
+    print streams[0]["url"]    
93
+    util.play_video(streams)
94
+    pass

+ 95
- 0
resources/lib/resolvers/kodik.py Parādīt failu

@@ -0,0 +1,95 @@
1
+# -*- coding: UTF-8 -*-
2
+# /*
3
+# *      Copyright (C) 2016 Ivars777
4
+# *
5
+# *
6
+# *  This Program is free software; you can redistribute it and/or modify
7
+# *  it under the terms of the GNU General Public License as published by
8
+# *  the Free Software Foundation; either version 2, or (at your option)
9
+# *  any later version.
10
+# *
11
+# *  This Program is distributed in the hope that it will be useful,
12
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+# *  GNU General Public License for more details.
15
+# *
16
+# *  You should have received a copy of the GNU General Public License
17
+# *  along with this program; see the file COPYING.  If not, write to
18
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
+# *  http://www.gnu.org/copyleft/gpl.html
20
+# *
21
+# */
22
+
23
+import re,os,sys
24
+import json
25
+try:
26
+    import util
27
+except:
28
+    pp = os.path.dirname(os.path.abspath(__file__))
29
+    sys.path.insert(0,os.sep.join(pp.split(os.sep)[:-1]))
30
+    import util
31
+import requests
32
+
33
+__author__ = 'ivars777'
34
+if __name__ <> "__main__":
35
+    __name__ = 'kodik'
36
+
37
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
38
+headers0 = headers2dict("""
39
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
40
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
41
+Upgrade-Insecure-Requests: 1
42
+DNT: 1
43
+Connection: keep-alive
44
+Upgrade-Insecure-Requests: 1
45
+Cache-Control: max-age=0
46
+
47
+""")
48
+
49
+
50
+def supports(url):
51
+    return True if "kodik.cc" in url else False
52
+
53
+def resolve(url):
54
+    global headers0
55
+    streams = []
56
+    try:
57
+        r = requests.get(url,headers=headers0)
58
+    except:
59
+        return []
60
+    if r.status_code<>200:
61
+        return []
62
+    data = r.content
63
+    hash = re.search('hash: "(.+?)"',data).group(1)
64
+    vid = re.search('id: "(.+?)"',data).group(1)
65
+    quality = re.search('quality: "(.+?)"',data).group(1)
66
+    params = "domain=&url=&type=database&hash=%s&id=%s&quality=%s"%(hash,vid,quality)
67
+    headers = headers2dict("""
68
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
69
+Accept: application/json, text/javascript, */*; q=0.01
70
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
71
+X-Requested-With: XMLHttpRequest
72
+Referer: %s
73
+"""%url)
74
+    data = requests.post("http://kodik.cc/get-video", data=params,headers=headers).content
75
+    js = json.loads(data)
76
+    for st in js["qualities"]:
77
+        stream = util.item()
78
+        stream["url"] = js["qualities"][st]["src"]
79
+        stream["quality"]=int(st)
80
+        stream["name"]= stream["url"]
81
+        streams.append(stream)
82
+    return streams
83
+
84
+if __name__ == "__main__":
85
+
86
+    url = "http://kodik.cc/video/10830/4269a802d1a9d9bdc53fe38488d53a52/720p"
87
+    streams = resolve(url)
88
+    if not streams:
89
+        print "No streams found"
90
+        sys.exit()
91
+    for s in streams:
92
+        print s
93
+    print streams[0]["url"]    
94
+    util.play_video(streams)
95
+    pass

+ 109
- 0
resources/lib/resolvers/openload3.py Parādīt failu

@@ -0,0 +1,109 @@
1
+# -*- coding: UTF-8 -*-
2
+# /*
3
+# *      Copyright (C) 2015 Lubomir Kucera
4
+# *
5
+# *
6
+# *  This Program is free software; you can redistribute it and/or modify
7
+# *  it under the terms of the GNU General Public License as published by
8
+# *  the Free Software Foundation; either version 2, or (at your option)
9
+# *  any later version.
10
+# *
11
+# *  This Program is distributed in the hope that it will be useful,
12
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+# *  GNU General Public License for more details.
15
+# *
16
+# *  You should have received a copy of the GNU General Public License
17
+# *  along with this program; see the file COPYING.  If not, write to
18
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
+# *  http://www.gnu.org/copyleft/gpl.html
20
+# *
21
+# */
22
+
23
+import re,os,sys
24
+import json
25
+try:
26
+    import util
27
+except:
28
+    pp = os.path.dirname(os.path.abspath(__file__))
29
+    sys.path.insert(0,os.sep.join(pp.split(os.sep)[:-1]))
30
+    import util
31
+import urllib2
32
+import requests
33
+#from aadecode import AADecoder
34
+
35
+__author__ = 'Jose Riha/Lubomir Kucera'
36
+__name__ = 'openload3'
37
+
38
+
39
+def supports(url):
40
+    return re.search(r'openload\.\w+/embed/.+', url) is not None
41
+
42
+
43
+#INFO_URL = API_BASE_URL + '/streaming/info'
44
+
45
+def resolve(url):
46
+    HTTP_HEADER = {
47
+        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:39.0) Gecko/20100101 Firefox/39.0',
48
+        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
49
+        'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
50
+        'Accept-Encoding': 'none',
51
+        'Accept-Language': 'en-US,en;q=0.8',
52
+        'Referer': url}  # 'Connection': 'keep-alive'    
53
+
54
+    stream = util.item()
55
+    m = re.search('https*://openload\.\w+/embed/([^/]+)', url)
56
+    if not m:
57
+        return stream
58
+    vid=m.group(1)
59
+    url2 = "https://api.openload.co/1/streaming/get?file="+vid
60
+    r = requests.get(url2,headers=HTTP_HEADER)
61
+    try:
62
+        js = json.loads(r.content)
63
+    except:
64
+        return stream
65
+    if js["status"] <>200:
66
+        raise Exception(js["msg"])
67
+    res = js["result"]
68
+    stream["url"] = res["url"]
69
+    stream["name"]= res["url"]
70
+    ### Retrieve subtitles ####
71
+    html = requests.get(url, headers=HTTP_HEADER).content 
72
+    m = re.search('<track kind="captions" src="([^"]+)" srclang="([^"]+)" label="([^"]+)"', html)
73
+    if m:
74
+        stream["subs"] = m.group(1)
75
+        stream["lang"] = m.group(2)   
76
+
77
+    return [stream]
78
+
79
+
80
+if __name__ == "__main__":
81
+
82
+    from subprocess import call
83
+    #url = "http://hqq.tv/player/embed_player.php?vid=235238210241210222228241233208212245&autoplay=no"
84
+    #url = "http://hqq.tv/player/embed_player.php?vid=243221241234244238208213206212211231&autoplay=no"
85
+    url = "http://hqq.tv/player/embed_player.php?vid=208231211231207221227243206206221244&autoplay=no"
86
+    #url = "https://openload.co/embed/TMthIdpy4PI/"
87
+    #url = "https://www.youtube.com/watch?v=Tx1K51_F99o"
88
+    #url = "https://www.youtube.com/watch?v=8BkcX7O1890"
89
+    #url = "https://www.youtube.com/watch?v=Se07R8SYsg0"
90
+    #url = "https://kinostok.tv/embed/731f3437e3c53104dd56d04039a0b15a"
91
+    #url = "http://vk.com/video_ext.php?oid=246066565&id=169244575&hash=d430ab0e76c9f7a1&hd=3"
92
+    #url ="https://openload.co/embed/rPMXJYPTkw4/"
93
+    #url = "https://openload.co/embed/bE7WfZ-vz_A/" 
94
+    #url = "https://openload.co/embed/bE7WfZ/" 
95
+    #url = "https://openload.co/embed/OuskaKyC2GU/"
96
+    url = "http://hqq.tv/player/embed_player.php?vid=235238210241210222228241233208212245&autoplay=no"
97
+    url = "https://openload.co/embed/rmNcP-0QopE/"
98
+    url = "https://openload.co/embed/oQLXcU1ITAY/"
99
+    streams = resolve(url)
100
+    if not streams:
101
+        print "No streams found"
102
+        sys.exit()
103
+
104
+    for s in streams:
105
+        print s
106
+
107
+    print streams[0]["url"]    
108
+    call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",streams[0]["url"]])
109
+    pass

+ 347
- 0
resources/lib/resolvers/youtuberesolver.py Parādīt failu

@@ -0,0 +1,347 @@
1
+# -*- coding: UTF-8 -*-
2
+
3
+import urllib2
4
+# source from https://github.com/rg3/youtube-dl/issues/1208
5
+# removed some unnecessary debug messages..
6
+class CVevoSignAlgoExtractor:
7
+    # MAX RECURSION Depth for security
8
+    MAX_REC_DEPTH = 5
9
+
10
+    def __init__(self):
11
+        self.algoCache = {}
12
+        self._cleanTmpVariables()
13
+
14
+    def _cleanTmpVariables(self):
15
+        self.fullAlgoCode = ''
16
+        self.allLocalFunNamesTab = []
17
+        self.playerData = ''
18
+
19
+    def _jsToPy(self, jsFunBody):
20
+        pythonFunBody = jsFunBody.replace('function', 'def').replace('{', ':\n\t').replace('}', '').replace(';', '\n\t').replace('var ', '')
21
+        pythonFunBody = pythonFunBody.replace('.reverse()', '[::-1]')
22
+
23
+        lines = pythonFunBody.split('\n')
24
+        for i in range(len(lines)):
25
+            # a.split("") -> list(a)
26
+            match = re.search('(\w+?)\.split\(""\)', lines[i])
27
+            if match:
28
+                lines[i] = lines[i].replace(match.group(0), 'list(' + match.group(1) + ')')
29
+            # a.length -> len(a)
30
+            match = re.search('(\w+?)\.length', lines[i])
31
+            if match:
32
+                lines[i] = lines[i].replace(match.group(0), 'len(' + match.group(1) + ')')
33
+            # a.slice(3) -> a[3:]
34
+            match = re.search('(\w+?)\.slice\(([0-9]+?)\)', lines[i])
35
+            if match:
36
+                lines[i] = lines[i].replace(match.group(0), match.group(1) + ('[%s:]' % match.group(2)))
37
+            # a.join("") -> "".join(a)
38
+            match = re.search('(\w+?)\.join\(("[^"]*?")\)', lines[i])
39
+            if match:
40
+                lines[i] = lines[i].replace(match.group(0), match.group(2) + '.join(' + match.group(1) + ')')
41
+        return "\n".join(lines)
42
+
43
+    def _getLocalFunBody(self, funName):
44
+        # get function body
45
+        match = re.search('(function %s\([^)]+?\){[^}]+?})' % funName, self.playerData)
46
+        if match:
47
+            # return jsFunBody
48
+            return match.group(1)
49
+        return ''
50
+
51
+    def _getAllLocalSubFunNames(self, mainFunBody):
52
+        match = re.compile('[ =(,](\w+?)\([^)]*?\)').findall(mainFunBody)
53
+        if len(match):
54
+            # first item is name of main function, so omit it
55
+            funNameTab = set(match[1:])
56
+            return funNameTab
57
+        return set()
58
+
59
+    def decryptSignature(self, s, playerUrl):
60
+        playerUrl = playerUrl[:4] != 'http' and 'http:' + playerUrl or playerUrl
61
+        util.debug("decrypt_signature sign_len[%d] playerUrl[%s]" % (len(s), playerUrl))
62
+
63
+        # clear local data
64
+        self._cleanTmpVariables()
65
+
66
+        # use algoCache
67
+        if playerUrl not in self.algoCache:
68
+            # get player HTML 5 sript
69
+            request = urllib2.Request(playerUrl)
70
+            try:
71
+                self.playerData = urllib2.urlopen(request).read()
72
+                self.playerData = self.playerData.decode('utf-8', 'ignore')
73
+            except:
74
+                util.debug('Unable to download playerUrl webpage')
75
+                return ''
76
+
77
+            # get main function name
78
+            match = re.search("signature=(\w+?)\([^)]\)", self.playerData)
79
+            if match:
80
+                mainFunName = match.group(1)
81
+                util.debug('Main signature function name = "%s"' % mainFunName)
82
+            else:
83
+                util.debug('Can not get main signature function name')
84
+                return ''
85
+
86
+            self._getfullAlgoCode(mainFunName)
87
+
88
+            # wrap all local algo function into one function extractedSignatureAlgo()
89
+            algoLines = self.fullAlgoCode.split('\n')
90
+            for i in range(len(algoLines)):
91
+                algoLines[i] = '\t' + algoLines[i]
92
+            self.fullAlgoCode = 'def extractedSignatureAlgo(param):'
93
+            self.fullAlgoCode += '\n'.join(algoLines)
94
+            self.fullAlgoCode += '\n\treturn %s(param)' % mainFunName
95
+            self.fullAlgoCode += '\noutSignature = extractedSignatureAlgo( inSignature )\n'
96
+
97
+            # after this function we should have all needed code in self.fullAlgoCode
98
+            try:
99
+                algoCodeObj = compile(self.fullAlgoCode, '', 'exec')
100
+            except:
101
+                util.debug('decryptSignature compile algo code EXCEPTION')
102
+                return ''
103
+        else:
104
+            # get algoCodeObj from algoCache
105
+            util.debug('Algo taken from cache')
106
+            algoCodeObj = self.algoCache[playerUrl]
107
+
108
+        # for security alow only flew python global function in algo code
109
+        vGlobals = {"__builtins__": None, 'len': len, 'list': list}
110
+
111
+        # local variable to pass encrypted sign and get decrypted sign
112
+        vLocals = { 'inSignature': s, 'outSignature': '' }
113
+
114
+        # execute prepared code
115
+        try:
116
+            exec(algoCodeObj, vGlobals, vLocals)
117
+        except:
118
+            util.debug('decryptSignature exec code EXCEPTION')
119
+            return ''
120
+
121
+        util.debug('Decrypted signature = [%s]' % vLocals['outSignature'])
122
+        # if algo seems ok and not in cache, add it to cache
123
+        if playerUrl not in self.algoCache and '' != vLocals['outSignature']:
124
+            util.debug('Algo from player [%s] added to cache' % playerUrl)
125
+            self.algoCache[playerUrl] = algoCodeObj
126
+
127
+        # free not needed data
128
+        self._cleanTmpVariables()
129
+
130
+        return vLocals['outSignature']
131
+
132
+    # Note, this method is using a recursion
133
+    def _getfullAlgoCode(self, mainFunName, recDepth=0):
134
+        if self.MAX_REC_DEPTH <= recDepth:
135
+            util.debug('_getfullAlgoCode: Maximum recursion depth exceeded')
136
+            return
137
+
138
+        funBody = self._getLocalFunBody(mainFunName)
139
+        if '' != funBody:
140
+            funNames = self._getAllLocalSubFunNames(funBody)
141
+            if len(funNames):
142
+                for funName in funNames:
143
+                    if funName not in self.allLocalFunNamesTab:
144
+                        self.allLocalFunNamesTab.append(funName)
145
+                        util.debug("Add local function %s to known functions" % mainFunName)
146
+                        self._getfullAlgoCode(funName, recDepth + 1)
147
+
148
+            # conver code from javascript to python
149
+            funBody = self._jsToPy(funBody)
150
+            self.fullAlgoCode += '\n' + funBody + '\n'
151
+        return
152
+
153
+decryptor = CVevoSignAlgoExtractor()
154
+
155
+'''
156
+   YouTube plugin for XBMC
157
+    Copyright (C) 2010-2012 Tobias Ussing And Henrik Mosgaard Jensen
158
+
159
+    This program is free software: you can redistribute it and/or modify
160
+    it under the terms of the GNU General Public License as published by
161
+    the Free Software Foundation, either version 3 of the License, or
162
+    (at your option) any later version.
163
+
164
+    This program is distributed in the hope that it will be useful,
165
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
166
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
167
+    GNU General Public License for more details.
168
+
169
+    You should have received a copy of the GNU General Public License
170
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
171
+'''
172
+
173
+import sys
174
+import urllib
175
+import cgi
176
+import simplejson as json
177
+
178
+
179
+class YoutubePlayer(object):
180
+    fmt_value = {
181
+            5: "240p",
182
+            18: "360p",
183
+            22: "720p",
184
+            26: "???",
185
+            33: "???",
186
+            34: "360p",
187
+            35: "480p",
188
+            37: "1080p",
189
+            38: "720p",
190
+            43: "360p",
191
+            44: "480p",
192
+            45: "720p",
193
+            46: "520p",
194
+            59: "480",
195
+            78: "400",
196
+            82: "360p",
197
+            83: "240p",
198
+            84: "720p",
199
+            85: "520p",
200
+            100: "360p",
201
+            101: "480p",
202
+            102: "720p",
203
+            120: "hd720",
204
+            121: "hd1080"
205
+            }
206
+
207
+    # YouTube Playback Feeds
208
+    urls = {}
209
+    urls['video_stream'] = "http://www.youtube.com/watch?v=%s&safeSearch=none"
210
+    urls['embed_stream'] = "http://www.youtube.com/get_video_info?video_id=%s"
211
+    urls['video_info'] = "http://gdata.youtube.com/feeds/api/videos/%s"
212
+
213
+    def __init__(self):
214
+        pass
215
+
216
+    def removeAdditionalEndingDelimiter(self, data):
217
+        pos = data.find("};")
218
+        if pos != -1:
219
+            data = data[:pos + 1]
220
+        return data
221
+
222
+    def extractFlashVars(self, data, assets):
223
+        flashvars = {}
224
+        found = False
225
+
226
+        for line in data.split("\n"):
227
+            if line.strip().find(";ytplayer.config = ") > 0:
228
+                found = True
229
+                p1 = line.find(";ytplayer.config = ") + len(";ytplayer.config = ") - 1
230
+                p2 = line.rfind(";")
231
+                if p1 <= 0 or p2 <= 0:
232
+                    continue
233
+                data = line[p1 + 1:p2]
234
+                break
235
+        data = self.removeAdditionalEndingDelimiter(data)
236
+
237
+        if found:
238
+            data = json.loads(data)
239
+            if assets:
240
+                flashvars = data["assets"]
241
+            else:
242
+                flashvars = data["args"]
243
+        return flashvars
244
+
245
+    def scrapeWebPageForVideoLinks(self, result, video):
246
+        links = {}
247
+        flashvars = self.extractFlashVars(result, 0)
248
+        if not flashvars.has_key(u"url_encoded_fmt_stream_map"):
249
+            return links
250
+
251
+        if flashvars.has_key(u"ttsurl"):
252
+            video[u"ttsurl"] = flashvars[u"ttsurl"]
253
+        if flashvars.has_key("title"):
254
+            video["title"] = flashvars["title"]
255
+
256
+        for url_desc in flashvars[u"url_encoded_fmt_stream_map"].split(u","):
257
+            url_desc_map = cgi.parse_qs(url_desc)
258
+            if not (url_desc_map.has_key(u"url") or url_desc_map.has_key(u"stream")):
259
+                continue
260
+
261
+            key = int(url_desc_map[u"itag"][0])
262
+            url = u""
263
+            if url_desc_map.has_key(u"url"):
264
+                url = urllib.unquote(url_desc_map[u"url"][0])
265
+            elif url_desc_map.has_key(u"conn") and url_desc_map.has_key(u"stream"):
266
+                url = urllib.unquote(url_desc_map[u"conn"][0])
267
+                if url.rfind("/") < len(url) - 1:
268
+                    url = url + "/"
269
+                url = url + urllib.unquote(url_desc_map[u"stream"][0])
270
+            elif url_desc_map.has_key(u"stream") and not url_desc_map.has_key(u"conn"):
271
+                url = urllib.unquote(url_desc_map[u"stream"][0])
272
+
273
+            if url_desc_map.has_key(u"sig"):
274
+                url = url + u"&signature=" + url_desc_map[u"sig"][0]
275
+            elif url_desc_map.has_key(u"s"):
276
+                sig = url_desc_map[u"s"][0]
277
+                flashvars = self.extractFlashVars(result, 1)
278
+                js = flashvars[u"js"]
279
+                url = url + u"&signature=" + self.decrypt_signature(sig, js)
280
+
281
+            links[key] = url
282
+
283
+        return links
284
+
285
+    def decrypt_signature(self, s, js):
286
+        return decryptor.decryptSignature(s, js)
287
+
288
+
289
+    def extractVideoLinksFromYoutube(self, url, videoid, video):
290
+        result = util.request(self.urls[u"video_stream"] % videoid)
291
+        links = self.scrapeWebPageForVideoLinks(result, video)
292
+        if len(links) == 0:
293
+            util.error(u"Couldn't find video url- or stream-map.")
294
+        return links
295
+# /*
296
+# *      Copyright (C) 2011 Libor Zoubek
297
+# *
298
+# *
299
+# *  This Program is free software; you can redistribute it and/or modify
300
+# *  it under the terms of the GNU General Public License as published by
301
+# *  the Free Software Foundation; either version 2, or (at your option)
302
+# *  any later version.
303
+# *
304
+# *  This Program is distributed in the hope that it will be useful,
305
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
306
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
307
+# *  GNU General Public License for more details.
308
+# *
309
+# *  You should have received a copy of the GNU General Public License
310
+# *  along with this program; see the file COPYING.  If not, write to
311
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
312
+# *  http://www.gnu.org/copyleft/gpl.html
313
+# *
314
+# */
315
+import re, util, urllib
316
+__name__ = 'youtube'
317
+
318
+
319
+def supports(url):
320
+    return not _regex(url) == None
321
+
322
+def resolve(url):
323
+    m = _regex(url)
324
+    if not m == None:
325
+        player = YoutubePlayer()
326
+        video = {'title':'žádný název'}
327
+        index = url.find('&')  # strip out everytihing after &
328
+        if index > 0:
329
+            url = url[:index]
330
+        links = player.extractVideoLinksFromYoutube(url, m.group('id'), video)
331
+        resolved = []
332
+        for q in links:
333
+            if q in player.fmt_value.keys():
334
+                quality = player.fmt_value[q]
335
+                item = {}
336
+                item['name'] = __name__
337
+                item['url'] = links[q]
338
+                item['quality'] = quality
339
+                item['surl'] = url
340
+                item['subs'] = ''
341
+                item['title'] = video['title']
342
+                item['fmt'] = q
343
+                resolved.append(item)
344
+        return resolved
345
+
346
+def _regex(url):
347
+    return re.search('www\.youtube\.com/(watch\?v=|v/|embed/)(?P<id>.+?)(\?|$|&)', url, re.IGNORECASE | re.DOTALL)

+ 149
- 0
resources/lib/sources/SourceBase.py Parādīt failu

@@ -0,0 +1,149 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+
9
+import urllib2, urllib
10
+import datetime, re, sys,os
11
+import requests
12
+from collections import OrderedDict
13
+import ConfigParser
14
+try:
15
+    import util
16
+except:
17
+    parent = os.path.dirname(os.path.abspath(__file__))
18
+    parent = os.sep.join(parent.split(os.sep)[:-1])
19
+    sys.path.insert(0,parent)
20
+    import util
21
+
22
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
23
+
24
+class SourceBase(object):
25
+    """Stream source base class"""
26
+
27
+    def __init__(self,country="lv"):
28
+        self.name = "name"
29
+        self.title = "Title"
30
+        self.img = ""
31
+        self.desc = ""
32
+        self.options = OrderedDict()
33
+        self.config_file = ""
34
+        self.url = "http://www.bbb.com/"
35
+        self.headers = headers2dict("""
36
+User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
37
+""")
38
+
39
+    def login(self,user="",password=""):
40
+        return False
41
+
42
+    def logout(self):
43
+        return True
44
+
45
+    def get_content(self,data):
46
+        ### To be overriden in child class
47
+        return [("..atpakaļ","back",None,"Kļūda, atgriezties atpakaļ")]
48
+
49
+    def is_video(self,data):
50
+        ### To be overriden in child class
51
+        return False
52
+
53
+    def get_streams(self,data):
54
+        ### Normally to be overrided in child class
55
+
56
+        if not self.is_video(data):
57
+            return []
58
+        content = self.get_content(data)
59
+        stream = util.item()
60
+        stream["name"] = content[0].encode("utf8") if isinstance(content[0],unicode) else content[0]
61
+        stream["url"] = content[1].encode("utf8") if isinstance(content[1],unicode) else content[1]
62
+        stream["img"] = content[2].encode("utf8") if isinstance(content[2],unicode) else content[2]
63
+        stream["desc"] = content[3].encode("utf8") if isinstance(content[3],unicode) else content[3]
64
+        stream["type"] = stream_type(content[1]).encode("utf8")
65
+        return[stream]
66
+
67
+    def options_read(self):
68
+        if not ("options" in dir(self) and self.options): # process options only if self.options defined, self.config_file should be defined too
69
+            return None
70
+        config = ConfigParser.ConfigParser()
71
+        if os.path.exists(self.config_file):
72
+            config.read(self.config_file)
73
+            self.options = OrderedDict(config.items(self.name))
74
+        else:
75
+            self.options_write(self.options)
76
+        return self.options
77
+
78
+    def options_write(self,options):
79
+        config = ConfigParser.ConfigParser()
80
+        config.add_section(self.name)
81
+        for k in options.keys():
82
+            config.set(self.name, k,options[k])
83
+        with open(self.config_file,"w") as f:
84
+            config.write(f)
85
+        self.options = OrderedDict(config.items(self.name))
86
+
87
+    def call(self, data,params=None,headers=None,lang=""):
88
+        if not headers: headers = self.headers
89
+        url = self.url+data
90
+        result = self._http_request(url,params,headers=headers)
91
+        return result
92
+
93
+    def call_json(self, data,params=None,headers=None,lang=""):
94
+        result = self.call(url,params,headers=headers)
95
+        if result:
96
+            result = json.loads(content)
97
+            return result
98
+        else:
99
+            raise "No data returned"
100
+
101
+    def _http_request(self, url,params = None, headers=None):
102
+        if not headers:
103
+            headers = self.headers if "headers" in dir(self) else headers2dict("User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0")
104
+        try:
105
+            if params:
106
+                r = requests.post(url, data=params, headers=headers)
107
+            else:
108
+                r = requests.get(url, headers=headers)
109
+            return r.content
110
+        except Exception as ex:
111
+            if "read" in ex:
112
+                content = ex.read()
113
+            else:
114
+                content = None
115
+            return content
116
+
117
+    @staticmethod
118
+    def stream_type(data):
119
+        return stream_type(data)
120
+
121
+    @staticmethod
122
+    def parse_data(data):
123
+        if "::" in data:
124
+            source = data.split("::")[0]
125
+            data = data.split("::")[1]
126
+        else:
127
+            source = ""
128
+        path = data.split("?")[0]
129
+        plist = path.split("/")
130
+        clist = plist[0]
131
+        params = data[data.find("?"):] if "?" in data else ""
132
+        qs = dict(map(lambda x:x.split("="),re.findall("\w+=\w+",params)))
133
+        return source,data,path,plist,clist,params,qs
134
+
135
+def stream_type(data):
136
+    if "::" in data:
137
+        data = data.split("::")[1]
138
+    data = data.lower()
139
+    m = re.search(r"^(\w+)://", data)
140
+    prefix = m.group(1) if m else ""
141
+    if prefix in ("http","https") and "m3u8" in data:
142
+        return "hls"
143
+    elif prefix == "http":
144
+        return "http"
145
+    else:
146
+        return prefix
147
+
148
+if __name__ == "__main__":
149
+    pass

+ 404
- 0
resources/lib/sources/YouTubeVideoUrl.py Parādīt failu

@@ -0,0 +1,404 @@
1
+# -*- coding: UTF-8 -*-
2
+# This video extraction code based on youtube-dl: https://github.com/rg3/youtube-dl
3
+
4
+import codecs
5
+import json
6
+import re
7
+
8
+from urllib import urlencode
9
+from urllib2 import urlopen, URLError
10
+import sys
11
+
12
+#from Components.config import config
13
+
14
+#from . import sslContext
15
+sslContext = None
16
+if sys.version_info >= (2, 7, 9):
17
+	try:
18
+		import ssl
19
+		sslContext = ssl._create_unverified_context()
20
+	except:
21
+		pass 
22
+from jsinterp import JSInterpreter
23
+from swfinterp import SWFInterpreter
24
+
25
+
26
+PRIORITY_VIDEO_FORMAT = []
27
+maxResolution =  '22'
28
+
29
+
30
+def createPriorityFormats():
31
+	global PRIORITY_VIDEO_FORMAT,maxResolution
32
+	PRIORITY_VIDEO_FORMAT = []
33
+	use_format = False
34
+	for itag_value in ['38', '37', '96', '22', '95', '120',
35
+		'35', '94', '18', '93', '5', '92', '132', '17']:
36
+		if itag_value == maxResolution: #config.plugins.YouTube.maxResolution.value:
37
+			use_format = True
38
+		if use_format:
39
+			PRIORITY_VIDEO_FORMAT.append(itag_value)
40
+
41
+createPriorityFormats()
42
+
43
+IGNORE_VIDEO_FORMAT = [
44
+		'43',  # webm
45
+		'44',  # webm
46
+		'45',  # webm
47
+		'46',  # webm
48
+		'100',  # webm
49
+		'101',  # webm
50
+		'102'  # webm
51
+	]
52
+
53
+
54
+def uppercase_escape(s):
55
+	unicode_escape = codecs.getdecoder('unicode_escape')
56
+	return re.sub(
57
+		r'\\U[0-9a-fA-F]{8}',
58
+		lambda m: unicode_escape(m.group(0))[0],
59
+		s)
60
+
61
+
62
+def compat_urllib_parse_unquote(string, encoding='utf-8', errors='replace'):
63
+	if string == '':
64
+		return string
65
+	res = string.split('%')
66
+	if len(res) == 1:
67
+		return string
68
+	if encoding is None:
69
+		encoding = 'utf-8'
70
+	if errors is None:
71
+		errors = 'replace'
72
+	# pct_sequence: contiguous sequence of percent-encoded bytes, decoded
73
+	pct_sequence = b''
74
+	string = res[0]
75
+	for item in res[1:]:
76
+		try:
77
+			if not item:
78
+				raise ValueError
79
+			pct_sequence += item[:2].decode('hex')
80
+			rest = item[2:]
81
+			if not rest:
82
+				# This segment was just a single percent-encoded character.
83
+				# May be part of a sequence of code units, so delay decoding.
84
+				# (Stored in pct_sequence).
85
+				continue
86
+		except ValueError:
87
+			rest = '%' + item
88
+		# Encountered non-percent-encoded characters. Flush the current
89
+		# pct_sequence.
90
+		string += pct_sequence.decode(encoding, errors) + rest
91
+		pct_sequence = b''
92
+	if pct_sequence:
93
+		# Flush the final pct_sequence
94
+		string += pct_sequence.decode(encoding, errors)
95
+	return string
96
+
97
+
98
+def _parse_qsl(qs, keep_blank_values=False, strict_parsing=False,
99
+			encoding='utf-8', errors='replace'):
100
+	qs, _coerce_result = qs, unicode
101
+	pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')]
102
+	r = []
103
+	for name_value in pairs:
104
+		if not name_value and not strict_parsing:
105
+			continue
106
+		nv = name_value.split('=', 1)
107
+		if len(nv) != 2:
108
+			if strict_parsing:
109
+				raise ValueError("bad query field: %r" % (name_value,))
110
+			# Handle case of a control-name with no equal sign
111
+			if keep_blank_values:
112
+				nv.append('')
113
+			else:
114
+				continue
115
+		if len(nv[1]) or keep_blank_values:
116
+			name = nv[0].replace('+', ' ')
117
+			name = compat_urllib_parse_unquote(
118
+				name, encoding=encoding, errors=errors)
119
+			name = _coerce_result(name)
120
+			value = nv[1].replace('+', ' ')
121
+			value = compat_urllib_parse_unquote(
122
+				value, encoding=encoding, errors=errors)
123
+			value = _coerce_result(value)
124
+			r.append((name, value))
125
+	return r
126
+
127
+
128
+def compat_parse_qs(qs, keep_blank_values=False, strict_parsing=False,
129
+					encoding='utf-8', errors='replace'):
130
+	parsed_result = {}
131
+	pairs = _parse_qsl(qs, keep_blank_values, strict_parsing,
132
+					encoding=encoding, errors=errors)
133
+	for name, value in pairs:
134
+		if name in parsed_result:
135
+			parsed_result[name].append(value)
136
+		else:
137
+			parsed_result[name] = [value]
138
+	return parsed_result
139
+
140
+
141
+class YouTubeVideoUrl():
142
+
143
+	def _download_webpage(self, url):
144
+		""" Returns a tuple (page content as string, URL handle) """
145
+		try:
146
+			if sslContext:
147
+				urlh = urlopen(url, context = sslContext)
148
+			else:
149
+				urlh = urlopen(url)
150
+		except URLError, e:
151
+			#raise Exception(e.reason)
152
+			return ""
153
+		return urlh.read()
154
+
155
+	def _search_regex(self, pattern, string):
156
+		"""
157
+		Perform a regex search on the given string, using a single or a list of
158
+		patterns returning the first matching group.
159
+		"""
160
+		mobj = re.search(pattern, string, 0)
161
+		if mobj:
162
+			# return the first matching group
163
+			return next(g for g in mobj.groups() if g is not None)
164
+		else:
165
+			raise Exception('Unable extract pattern from string!')
166
+
167
+	def _decrypt_signature(self, s, player_url):
168
+		"""Turn the encrypted s field into a working signature"""
169
+
170
+		if player_url is None:
171
+			raise Exception('Cannot decrypt signature without player_url!')
172
+
173
+		if player_url[:2] == '//':
174
+			player_url = 'https:' + player_url
175
+		try:
176
+			func = self._extract_signature_function(player_url)
177
+			return func(s)
178
+		except:
179
+			raise Exception('Signature extraction failed!')
180
+
181
+	def _extract_signature_function(self, player_url):
182
+		id_m = re.match(
183
+			r'.*?-(?P<id>[a-zA-Z0-9_-]+)(?:/watch_as3|/html5player(?:-new)?|/base)?\.(?P<ext>[a-z]+)$',
184
+			player_url)
185
+		if not id_m:
186
+			raise Exception('Cannot identify player %r!' % player_url)
187
+		player_type = id_m.group('ext')
188
+		code = self._download_webpage(player_url)
189
+		if player_type == 'js':
190
+			return self._parse_sig_js(code)
191
+		elif player_type == 'swf':
192
+			return self._parse_sig_swf(code)
193
+		else:
194
+			raise Exception('Invalid player type %r!' % player_type)
195
+
196
+	def _parse_sig_js(self, jscode):
197
+		funcname = self._search_regex(r'\.sig\|\|([a-zA-Z0-9$]+)\(', jscode)
198
+		jsi = JSInterpreter(jscode)
199
+		initial_function = jsi.extract_function(funcname)
200
+		return lambda s: initial_function([s])
201
+
202
+	def _parse_sig_swf(self, file_contents):
203
+		swfi = SWFInterpreter(file_contents)
204
+		TARGET_CLASSNAME = 'SignatureDecipher'
205
+		searched_class = swfi.extract_class(TARGET_CLASSNAME)
206
+		initial_function = swfi.extract_function(searched_class, 'decipher')
207
+		return lambda s: initial_function([s])
208
+
209
+	def _extract_from_m3u8(self, manifest_url):
210
+		url_map = {}
211
+
212
+		def _get_urls(_manifest):
213
+			lines = _manifest.split('\n')
214
+			urls = filter(lambda l: l and not l.startswith('#'), lines)
215
+			return urls
216
+
217
+		manifest = self._download_webpage(manifest_url)
218
+		formats_urls = _get_urls(manifest)
219
+		for format_url in formats_urls:
220
+			itag = self._search_regex(r'itag/(\d+?)/', format_url)
221
+			url_map[itag] = format_url
222
+		return url_map
223
+
224
+	def _get_ytplayer_config(self, webpage):
225
+		# User data may contain arbitrary character sequences that may affect
226
+		# JSON extraction with regex, e.g. when '};' is contained the second
227
+		# regex won't capture the whole JSON. Yet working around by trying more
228
+		# concrete regex first keeping in mind proper quoted string handling
229
+		# to be implemented in future that will replace this workaround (see
230
+		# https://github.com/rg3/youtube-dl/issues/7468,
231
+		# https://github.com/rg3/youtube-dl/pull/7599)
232
+		patterns = [
233
+			r';ytplayer\.config\s*=\s*({.+?});ytplayer',
234
+			r';ytplayer\.config\s*=\s*({.+?});',
235
+		]
236
+		for pattern in patterns:
237
+			config = self._search_regex(pattern, webpage)
238
+			if config:
239
+				return json.loads(uppercase_escape(config))
240
+
241
+	def extract(self, video_id):
242
+		url = 'https://www.youtube.com/watch?v=%s&gl=US&hl=en&has_verified=1&bpctr=9999999999' % video_id
243
+
244
+		# Get video webpage
245
+		video_webpage = self._download_webpage(url)
246
+		if not video_webpage:
247
+			#raise Exception('Video webpage not found!')
248
+			return ""
249
+
250
+		# Attempt to extract SWF player URL
251
+		mobj = re.search(r'swfConfig.*?"(https?:\\/\\/.*?watch.*?-.*?\.swf)"', video_webpage)
252
+		if mobj is not None:
253
+			player_url = re.sub(r'\\(.)', r'\1', mobj.group(1))
254
+		else:
255
+			player_url = None
256
+
257
+		# Get video info
258
+		embed_webpage = None
259
+		if re.search(r'player-age-gate-content">', video_webpage) is not None:
260
+			age_gate = True
261
+			# We simulate the access to the video from www.youtube.com/v/{video_id}
262
+			# this can be viewed without login into Youtube
263
+			url = 'https://www.youtube.com/embed/%s' % video_id
264
+			embed_webpage = self._download_webpage(url)
265
+			data = urlencode({
266
+				'video_id': video_id,
267
+				'eurl': 'https://youtube.googleapis.com/v/' + video_id,
268
+				'sts': self._search_regex(r'"sts"\s*:\s*(\d+)', embed_webpage),
269
+			})
270
+			video_info_url = 'https://www.youtube.com/get_video_info?' + data
271
+			video_info_webpage = self._download_webpage(video_info_url)
272
+			video_info = compat_parse_qs(video_info_webpage)
273
+		else:
274
+			age_gate = False
275
+			video_info = None
276
+			# Try looking directly into the video webpage
277
+			ytplayer_config = self._get_ytplayer_config(video_webpage)
278
+			if ytplayer_config:
279
+				args = ytplayer_config['args']
280
+				if args.get('url_encoded_fmt_stream_map'):
281
+					# Convert to the same format returned by compat_parse_qs
282
+					video_info = dict((k, [v]) for k, v in args.items())
283
+
284
+			if not video_info:
285
+				# We also try looking in get_video_info since it may contain different dashmpd
286
+				# URL that points to a DASH manifest with possibly different itag set (some itags
287
+				# are missing from DASH manifest pointed by webpage's dashmpd, some - from DASH
288
+				# manifest pointed by get_video_info's dashmpd).
289
+				# The general idea is to take a union of itags of both DASH manifests (for example
290
+				# video with such 'manifest behavior' see https://github.com/rg3/youtube-dl/issues/6093)
291
+				for el_type in ['&el=info', '&el=embedded', '&el=detailpage', '&el=vevo', '']:
292
+					video_info_url = (
293
+						'https://www.youtube.com/get_video_info?&video_id=%s%s&ps=default&eurl=&gl=US&hl=en'
294
+						% (video_id, el_type))
295
+					video_info_webpage = self._download_webpage(video_info_url)
296
+					video_info = compat_parse_qs(video_info_webpage)
297
+					if 'token' in video_info:
298
+						break
299
+		if 'token' not in video_info:
300
+			if 'reason' in video_info:
301
+				print '[YouTubeVideoUrl] %s' % video_info['reason'][0]
302
+			else:
303
+				print '[YouTubeVideoUrl] "token" parameter not in video info for unknown reason'
304
+
305
+		# Start extracting information
306
+		if 'conn' in video_info and video_info['conn'][0][:4] == 'rtmp':
307
+			url = video_info['conn'][0]
308
+		elif len(video_info.get('url_encoded_fmt_stream_map', [''])[0]) >= 1 or \
309
+			len(video_info.get('adaptive_fmts', [''])[0]) >= 1:
310
+			encoded_url_map = video_info.get('url_encoded_fmt_stream_map', [''])[0] + \
311
+				',' + video_info.get('adaptive_fmts', [''])[0]
312
+			if 'rtmpe%3Dyes' in encoded_url_map:
313
+				raise Exception('rtmpe downloads are not supported, see https://github.com/rg3/youtube-dl/issues/343')
314
+
315
+			# Find the best format from our format priority map
316
+			encoded_url_map = encoded_url_map.split(',')
317
+			url_map_str = None
318
+			# If format changed in config, recreate priority list
319
+			if PRIORITY_VIDEO_FORMAT[0] != maxResolution: #config.plugins.YouTube.maxResolution.value:
320
+				createPriorityFormats()
321
+			for our_format in PRIORITY_VIDEO_FORMAT:
322
+				our_format = 'itag=' + our_format
323
+				for encoded_url in encoded_url_map:
324
+					if our_format in encoded_url and 'url=' in encoded_url:
325
+						url_map_str = encoded_url
326
+						break
327
+				if url_map_str:
328
+					break
329
+			# If anything not found, used first in the list if it not in ignore map
330
+			if not url_map_str:
331
+				for encoded_url in encoded_url_map:
332
+					if 'url=' in encoded_url:
333
+						url_map_str = encoded_url
334
+						for ignore_format in IGNORE_VIDEO_FORMAT:
335
+							ignore_format = 'itag=' + ignore_format
336
+							if ignore_format in encoded_url:
337
+								url_map_str = None
338
+								break
339
+					if url_map_str:
340
+						break
341
+			if not url_map_str:
342
+				url_map_str = encoded_url_map[0]
343
+
344
+			url_data = compat_parse_qs(url_map_str)
345
+			url = url_data['url'][0]
346
+			if 'sig' in url_data:
347
+				url += '&signature=' + url_data['sig'][0]
348
+			elif 's' in url_data:
349
+				encrypted_sig = url_data['s'][0]
350
+				ASSETS_RE = r'"assets":.+?"js":\s*("[^"]+")'
351
+
352
+				jsplayer_url_json = self._search_regex(ASSETS_RE,
353
+					embed_webpage if age_gate else video_webpage)
354
+				if not jsplayer_url_json and not age_gate:
355
+					# We need the embed website after all
356
+					if embed_webpage is None:
357
+						embed_url = 'https://www.youtube.com/embed/%s' % video_id
358
+						embed_webpage = self._download_webpage(embed_url)
359
+					jsplayer_url_json = self._search_regex(ASSETS_RE, embed_webpage)
360
+
361
+				player_url = json.loads(jsplayer_url_json)
362
+				if player_url is None:
363
+					player_url_json = self._search_regex(
364
+						r'ytplayer\.config.*?"url"\s*:\s*("[^"]+")',
365
+						video_webpage)
366
+					player_url = json.loads(player_url_json)
367
+
368
+				signature = self._decrypt_signature(encrypted_sig, player_url)
369
+				url += '&signature=' + signature
370
+			if 'ratebypass' not in url:
371
+				url += '&ratebypass=yes'
372
+		elif video_info.get('hlsvp'):
373
+			url = None
374
+			manifest_url = video_info['hlsvp'][0]
375
+			url_map = self._extract_from_m3u8(manifest_url)
376
+
377
+			# Find the best format from our format priority map
378
+			for our_format in PRIORITY_VIDEO_FORMAT:
379
+				if url_map.get(our_format):
380
+					url = url_map[our_format]
381
+					break
382
+			# If anything not found, used first in the list if it not in ignore map
383
+			if not url:
384
+				for url_map_key in url_map.keys():
385
+					if url_map_key not in IGNORE_VIDEO_FORMAT:
386
+						url = url_map[url_map_key]
387
+						break
388
+			if not url:
389
+				url = url_map.values()[0]
390
+		else:
391
+			#raise Exception('No supported formats found in video info!')
392
+			return ""
393
+
394
+		return str(url)
395
+
396
+if __name__ == "__main__":
397
+
398
+	#yt = YouTubeVideoUrl()
399
+	if len(sys.argv)>1:
400
+		video_id= sys.argv[1]
401
+	else:
402
+		video_id = "2rlTF6HiMGg"
403
+	e = YouTubeVideoUrl().extract(video_id)
404
+	print e

+ 0
- 0
resources/lib/sources/__init__.py Parādīt failu


+ 209
- 0
resources/lib/sources/cinemalive.py Parādīt failu

@@ -0,0 +1,209 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+import urllib2, urllib
13
+import datetime, re, sys,os
14
+import ConfigParser
15
+from SourceBase import SourceBase
16
+#from collections import OrderedDict
17
+import os
18
+
19
+#sys.path.insert(0,os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 
20
+from resolver import resolve
21
+import util
22
+
23
+
24
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
25
+import HTMLParser
26
+h = HTMLParser.HTMLParser()
27
+    
28
+class Source(SourceBase):
29
+    
30
+    def __init__(self,country=""):
31
+        self.name = "cinemalive"
32
+        self.title = "cinemalive.tv"
33
+        self.img = "picons/cinemalive.png" #"https://cinemalive.tv/assets/img/logo.png"
34
+        self.desc = "cinemalive.tv satura skatīšanās"
35
+        self.country=country
36
+        self.headers = headers2dict("""
37
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
38
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8,application/json
39
+""")
40
+        self.headers2 = headers2dict("""
41
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.116 Safari/537.36
42
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
43
+Accept-Language: en-US,en;q=0.8
44
+""")
45
+        self.url = "https://cinemalive.tv/"
46
+        #self.login()
47
+        
48
+            
49
+    ######### Entry point ########
50
+    def get_content(self, data):
51
+        print "[cinemalive] get_content:", data
52
+        source,data,path,plist,clist,params,qs = self.parse_data(data)     
53
+        content=[]
54
+        content.append(("..return", "back","","Return back"))
55
+        
56
+        if clist=="home":
57
+            content.extend([
58
+                ("Search", "cinemalive::scripts/search.php?search={0}","","Search"),            
59
+                ("Filmas latviski - visas", "cinemalive::filmaslatviski/visas/lapa/1","","Filmas latviski - visas"),
60
+                ("Filmas angliski", "cinemalive::home_en","","Filmas angliski"),
61
+                ("Filmas latviski - jaunākās", "cinemalive::filmaslatviski/jaunakas/lapa/1","","Filmas latviski - jaunākās"),
62
+                ("Filmas latviski - vertētākās", "cinemalive::filmaslatviski/vertetakas/lapa/1","","Filmas latviski - vērtētākās"),
63
+                ("Filmas latviski - skatitakās", "cinemalive::filmaslatviski/skatitakas/lapa/1","","Filmas latviski - skatītākās"),
64
+            ])
65
+            r = self.call("filmaslatviski")
66
+            for item in re.findall(r'<li class="nav-submenu-item"><a href="/([\w/]+)">(.+?)</a></li>', r):
67
+                title = "Filmas latviski - "+item[1]
68
+                data2 = item[0]+"/lapa/1"
69
+                img = self.img
70
+                desc = title
71
+                content.append((title,self.name+"::"+data2,img,desc))      
72
+            return content
73
+
74
+        elif clist=="home_en":
75
+            content.extend([
76
+                ("Search", "cinemalive::scripts/search.php?search={0}","","Search"),            
77
+                ("Movies English - all", "cinemalive::moviesenglish/all/page/1","","Movies English - all"),
78
+                ("Movies Latvian", "cinemalive::home","","Filmas latviski"),
79
+                ("Movies English - newest", "cinemalive::moviesenglish/newestmovies/page/1","","Movies English - newest"),
80
+                ("Movies English - top rated", "cinemalive::moviesenglish/toprated/page/1","","Movies English - top rated"),
81
+                ("Movies English - most watched", "cinemalive::moviesenglish/mostwatched/page/1","","Movies English - most watched"),
82
+            ])
83
+            r = self.call("moviesenglish")
84
+            for item in re.findall(r'<li class="nav-submenu-item"><a href="/([\w/]+)">(.+?)</a></li>', r):
85
+                title = "Movies English - "+item[1]
86
+                data2 = item[0]+"/page/1"
87
+                img = self.img
88
+                desc = title
89
+                content.append((title,self.name+"::"+data2,img,desc))      
90
+            return content
91
+
92
+    
93
+        elif "search.php" in data:
94
+            
95
+            r=self.call(path,params=params[1:],headers=self.headers2)
96
+            result = re.findall(r'<div class="results.+?<a href="https://cinemalive\.tv/(.+?)">.+?<img src="(.+?)".+?<span style="color:#bcbcbc">([^<]+)</span> <span style="color:#5a606d;font-size:12px;">([^<]+)</span><br/>.+?<p class="dec" style="font-size:12px; color:#777;line-height:14px;">([^<]+)</p>', r, re.DOTALL)            
97
+            for item in result:
98
+                title = item[2]
99
+                title0 = re.sub(" \(\d+\)","",title)
100
+                if title0 == item[3]:
101
+                    title = title+" [EN]"
102
+                else:
103
+                    title = title + "/"+ item[3]+" [LV]"
104
+                title = util.unescape(title)
105
+                data2 = item[0]
106
+                img = item[1].replace("xs.","sm.")
107
+                desc = util.unescape(item[4])
108
+                content.append((title,self.name+"::"+data2,img,desc))            
109
+            return content
110
+
111
+        elif clist in ("filmaslatviski","moviesenglish"):
112
+            r = self.call(data)
113
+            if not r:
114
+                return content
115
+            result = re.findall(r'<div class="base-used">.+?<a href="https://cinemalive.tv/([^"]+)">.+?<img class="img-thumbnail" src="/([^"]+)" alt="([^"]+)"/>.+?<p class="year">(\d+)</p>', r, re.DOTALL)
116
+            for item in result:
117
+                title = item[2] + " (%s)"%item[3]
118
+                data2 = item[0]
119
+                img = "https://cinemalive.tv/"+item[1]
120
+                title = util.unescape(title)
121
+                desc = title
122
+                content.append((title,self.name+"::"+data2,img,desc)) 
123
+            m = re.search(r"""<a href='https://cinemalive\.tv/([^']+)' style="border-right:none;">»</a>""", r, re.DOTALL)
124
+            if m:
125
+                data2 = m.group(1)
126
+                content.append(("Next page",self.name+"::"+data2,self.img,"Next page"))                                  
127
+            return content      
128
+         
129
+        else:
130
+            return content                            
131
+              
132
+    def is_video(self,data):
133
+        source,data,path,plist,clist,params,qs = self.parse_data(data)        
134
+        if clist=="movie":
135
+            return True
136
+        else:
137
+            return False
138
+                        
139
+    def get_streams(self, data):
140
+        print "[cinemalive] get_streams:", data
141
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
142
+        r = self.call(path)
143
+        if not r:
144
+            return []
145
+        streams = []
146
+        title0 = re.search("<title>([^<]+)</title>", r).group(1)
147
+        lang = "LV" if "Filma Online Latviski" in title0 else "EN"
148
+        title = title0.replace(" - Filma Online Latviski","").replace(" - Movie Online English HD","")
149
+        desc = re.search('<p class="plot">(.+?)</p>', r).group(1)
150
+        img = "http://cinemalive.tv"+re.search('<img src="(.+?)" class="img-thumbnail"', r).group(1)
151
+        
152
+        m = re.search(r'<video id=.+?<source src="([^"]+\.mp4)"', r, re.DOTALL)
153
+        if m:
154
+            s = util.item()
155
+            s["url"] = m.group(1)
156
+            s["name"] = util.unescape(title)
157
+            s["desc"] = util.unescape(desc)
158
+            s["img"] = img
159
+            s["type"] = self.stream_type(s["url"])
160
+            s["lang"] = lang 
161
+            return [s]
162
+        
163
+        #m = re.search('<div class="viboom-overroll"><iframe src="([^"]+)"', r)
164
+        #if m:
165
+        result = re.findall('<div id="video_container"><iframe src="(.+?)"', r)
166
+        if result:
167
+            streams = resolve(result[0])
168
+            for s in streams:
169
+                s["name"] = util.unescape(title)
170
+                s["desc"] = util.unescape(desc)
171
+                s["img"] = img
172
+                s["type"] = self.stream_type(s["url"])
173
+                s["lang"] = lang
174
+            if len(result)>1:
175
+                lang2 = "EN" if lang=="LV" else "LV"
176
+                streams2 = resolve(result[1])
177
+                for s in streams2:
178
+                    s["name"] = util.unescape(title)
179
+                    s["desc"] = util.unescape(desc)
180
+                    s["img"] = img
181
+                    s["type"]= self.stream_type(s["url"])
182
+                    s["lang"] = lang2
183
+                    streams.append(s)  
184
+            return streams
185
+        else:
186
+            return []
187
+
188
+                    
189
+if __name__ == "__main__":
190
+    country= "lv"
191
+    c = Source(country)
192
+    if len(sys.argv)>1:
193
+        data= sys.argv[1]
194
+    else:
195
+        data = "home"
196
+    content = c.get_content(data)
197
+    for item in content:
198
+        print item
199
+    #cat = api.get_categories(country)
200
+    #chan = api.get_channels("lv")
201
+    #prog = api.get_programs(channel=6400)
202
+    #prog = api.get_programs(category=55)
203
+    #seas = api.get_seasons(program=6453)
204
+    #str = api.get_streams(660243)
205
+    #res = api.get_videos(802)
206
+    #formats = api.getAllFormats()
207
+    #det = api.detailed("1516")
208
+    #vid = api.getVideos("13170")
209
+    pass

+ 99
- 0
resources/lib/sources/config.py Parādīt failu

@@ -0,0 +1,99 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+import os.path,re
9
+import collections
10
+from SourceBase import SourceBase
11
+
12
+os.path.dirname(os.path.abspath(__file__))
13
+class Source(SourceBase):
14
+    
15
+    def __init__(self,country="lv"):
16
+        self.name = "config"
17
+        self.country=country
18
+        cur_directory = os.path.dirname(os.path.abspath(__file__))
19
+        self.streams_file = os.path.join(cur_directory,"streams.cfg")
20
+        self.lists = collections.OrderedDict()
21
+        self.read_streams()
22
+         
23
+    def get_content(self, data):
24
+        self.read_streams()
25
+        if "::" in data:
26
+            data = data.split("::")[1]
27
+        if not data in self.lists:
28
+            return []
29
+        return self.lists[data]
30
+
31
+    def is_video(self,data):
32
+        return False
33
+    
34
+    def read_streams(self):
35
+        for line in open(self.streams_file,"r"):
36
+            r = re.search("^\[(\w+)\]", line)
37
+            if r:
38
+                name = r.group(1)
39
+                self.lists[name] = []
40
+            else:
41
+                if len(line)<10 or line[0] in ("#"): continue
42
+                items = tuple(line.strip().split("|"))
43
+                if len(items)<2:
44
+                    continue
45
+                self.lists[name].append(items)
46
+                
47
+    def write_streams(self):
48
+        f = open(self.streams_file,"w")
49
+        for l in self.lists.keys():
50
+            f.write("[%s]\n"%l)
51
+            for item in self.lists[l]:
52
+                f.write("%s|%s|%s|%s\n"%(item[0],item[1],item[2],item[3]))
53
+            f.write("\n")
54
+        f.close()
55
+    
56
+    def get_lists(self):
57
+        return self.lists.keys()
58
+    
59
+    def get_list_items(self,name):
60
+        return self.lists[name]
61
+    
62
+    def add_list(self,name):
63
+        if not name in self.lists.keys():
64
+            self.lists[name] = []
65
+            
66
+    def del_list(self,name):
67
+        if name in self.lists.keys():
68
+            del self.lists[name]
69
+            
70
+    def add_item(self,name,item,pos=None):
71
+        if name in self.lists.keys():
72
+            if pos==None:
73
+                self.lists[name].append(item)
74
+            else:
75
+                self.lists[name].insert(pos,item)
76
+                
77
+    def del_item(self,name,pos):
78
+        self.lists[name].pop(pos)
79
+    
80
+    def replace_item(self,name,item,pos):
81
+        self.lists[name][pos]=item
82
+            
83
+                           
84
+if __name__ == "__main__":
85
+    c = Source()
86
+    content = c.get_content("home")
87
+    for item in content: print item
88
+    #c.del_item("home",0)
89
+    #c.del_list("favorites")
90
+    
91
+    #c.add_item("home",("My Streams","config::favorites","","Mani saglabātie TV kanāli un video"),0)
92
+    c.replace_item("home",("My Streams","config::my_streams","default","Mani saglabātie TV kanāli un video"),0)
93
+    #c.add_list("favorites")
94
+    #c.add_item("favorites",("..return","back","","Atgriezties atpakaļ"))    
95
+    #c.add_item("favorites",("LTV1","http://streamltv.cloudy.services/ltv/LTV02.smil/playlist.m3u8","picons/latvia1.png", "Latvijas televīzijas 1.kanāls"))
96
+    
97
+    c.write_streams()
98
+    for item in content: print item
99
+    

+ 3
- 0
resources/lib/sources/euronews.cfg Parādīt failu

@@ -0,0 +1,3 @@
1
+[euronews]
2
+language = en
3
+

+ 287
- 0
resources/lib/sources/euronews.py Parādīt failu

@@ -0,0 +1,287 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import urllib2, urllib
14
+import datetime, time,re, sys,os
15
+from collections import OrderedDict
16
+from SourceBase import SourceBase
17
+import util
18
+
19
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
20
+import HTMLParser
21
+h = HTMLParser.HTMLParser()
22
+
23
+class Source(SourceBase):
24
+
25
+    def __init__(self,language="en"):
26
+        self.name = "euronews"
27
+        self.title = "Euronews"
28
+        self.img = "http://pbs.twimg.com/profile_images/732665354242150400/tZsCnjuh_400x400.jpg"
29
+        self.desc = "Euronews live and archive"
30
+        self.headers = headers2dict("""
31
+User-Agent: Euronews/4.0.126
32
+Content-Type: application/json
33
+Connection: keep-alive
34
+        """)
35
+        #self.language=language
36
+        cur_directory = os.path.dirname(os.path.abspath(__file__))
37
+        self.config_file = os.path.join(cur_directory,self.name+".cfg")
38
+        self.options = OrderedDict([("language","en")])
39
+        self.options_read()
40
+        self.vid={"1": "News", "2": "European Affairs", "3": "Lifestyle", "4": "Knowledge"}
41
+        self.languages = []
42
+        try:
43
+            self.get_languages()
44
+        except:
45
+            pass
46
+
47
+    def login(self,user="",password=""):
48
+        return True
49
+
50
+    def get_content(self, data):
51
+        print "[%s] get_content:"%self.name, data
52
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
53
+        #lang = qs["lang"] if "lang" in qs else self.language
54
+        lang = self.options["language"]
55
+        if not lang in self.get_languages():
56
+            raise Exception("Not valid default language - '%s'"%lang)
57
+
58
+        content=[]
59
+        content.append(("..return", "back","","Return back"))
60
+
61
+        if clist=="home":
62
+            content.extend([
63
+                ("Search", "euronews::content/getSearch?lang=%s&byPage=40&page=1&text={0}"%lang,self.img,"Top stories timeline"),
64
+                ("Live stream", "euronews::live?lang=%s"%lang,self.img,"Euronews live stream"),
65
+                ("Just in", "euronews::content/getTimeline?lang=%s&byPage=40&page=1"%lang,self.img,"News timeline"),
66
+                ("Top stories", "euronews::content/getTopStories?lang=%s"%lang,self.img,"Top stories timeline"),
67
+                ("Category - News", "euronews::content/getVertical?lang=%s&byPage=40&page=1&vId=1"%lang,self.img,"Category - News"),
68
+                ("Category - European Affairs", "euronews::content/getVertical?lang=%s&byPage=40&page=1&vId=2"%lang,self.img,"Category - European Affairs"),
69
+                ("Category - Lifestyle", "euronews::content/getVertical?lang=%s&byPage=40&page=1&vId=3"%lang,self.img,"Category - Lifestyle"),
70
+                ("Category - Knowledge", "euronews::content/getVertical?lang=%s&byPage=40&page=1&vId=4"%lang,self.img,"Category - Knowledge"),
71
+                ("Latest programs", "euronews::content/getLatestPrograms?lang=%s&byPage=40&page=1"%lang,self.img,"Latest programs"),
72
+                ("Programs list", "euronews::content/getPrograms?lang=%s"%lang,self.img,"Programs list"),
73
+             ])
74
+            return content
75
+
76
+
77
+        ### Video arhīvs ###
78
+        elif clist=="content":
79
+            if "lang" in qs:
80
+                del qs["lang"]
81
+            params = json.dumps(qs)
82
+
83
+            req = '{"methodName":"content.%s","apiKey":"androidPhoneEuronews-1.0","params":%s,"language":"%s"}'%(plist[1],params,lang)
84
+            r = self.call(req)
85
+            if not r:
86
+                return content
87
+            lst = r["timeline"] if "timeline" in r else\
88
+                r["topstorieslist"] if "topstorieslist" in r else\
89
+                r["programs"] if "programs" in r else\
90
+                r["programDetailsList"] if "programDetailsList" in r else\
91
+                r["programlist"] if "programlist" in r else\
92
+                r["articlelist"] if "articlelist" in r else\
93
+                r["verticals"] if "verticals" in r else\
94
+                []
95
+            if not lst:
96
+                return content
97
+
98
+            for item in lst:
99
+                if plist[1] in ("getTimeline"):
100
+                    article = item["article"]
101
+                    atype = item["type"]
102
+                    #if item["type"] == "wire":
103
+                        #continue # TODO
104
+                else:
105
+                    article = item
106
+                    atype = "article"
107
+                if plist[1]=="getPrograms":
108
+                    title = article["title"]
109
+                    id = article["pId"]
110
+                    desc = title
111
+                    img = "http://static.euronews.com/articles/programs/533x360_%s"%article["img"]
112
+                    data2 = "content/getProgramDetails?lang=%s&byPage=40&page=1&pId=%s"%(lang,id)
113
+                    content.append((title,self.name+"::"+data2,img,desc))
114
+                else:
115
+                    title = article["title"] if "title" in article else article["text"] if "text" in article else "No title"
116
+                    if atype <> "article":
117
+                        title = "[%s] %s"%(atype,title)
118
+                    atime = datetime.datetime.fromtimestamp(int(article["uts"]))
119
+                    #atime = datetime.datetime.fromtimestamp(int(article["uts"])-time.altzone)
120
+                    atime = atime.strftime("%Y-%m-%d %H:%M")
121
+                    vert = self.vid[article["vId"]] if "vId" in article else ""
122
+                    ptitle = article["pTitle"] if "pTitle" in article else ""
123
+                    id = article["id"]
124
+                    desc = "%s\n%s\n%s %s"%(title,atime,vert,ptitle)
125
+                    img = "http://static.euronews.com/articles/%s/399x225_%s.jpg"%(id,id)
126
+                    if not atype in ("breakingnews","wire"):
127
+                        data2 = "content/getArticle?lang=%s&id=%s"%(lang,id)
128
+                    else:
129
+                        data2 = ""
130
+                    content.append((title,self.name+"::"+data2,img,desc))
131
+            if "page=" in data:
132
+                data2 = re.sub("page=\d+","page=%s"%(int(qs["page"])+1),data)
133
+                content.append(("Next page",self.name+"::"+data2,self.img,"Next page"))
134
+            return content
135
+
136
+
137
+    def is_video(self,data):
138
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
139
+        if path == "live":
140
+            return True
141
+        elif clist=="content" and plist[1]=="getArticle":
142
+            return True
143
+        else:
144
+            return False
145
+
146
+    def get_streams(self, data):
147
+        print "[euronews] get_streams:", data
148
+        if not self.is_video(data):
149
+            return []
150
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
151
+        #lang = qs["lang"] if "lang" in qs else self.language
152
+        lang = self.options["language"]
153
+        if not lang in self.get_languages():
154
+            raise Exception("Not valid default language - '%s'"%lang)
155
+
156
+        streams = []
157
+
158
+        if path == "live":
159
+            url = "http://www.euronews.com/api/watchlive.json"
160
+            r = self._http_request(url)
161
+            try:
162
+                js = json.loads(r)
163
+                url = js["url"]
164
+            except:
165
+                raise Exception("No live stream found")
166
+            r = self._http_request(url)
167
+            try:
168
+                js = json.loads(r)
169
+                if not js["status"]=="ok":
170
+                    raise Exception("No live stream found")
171
+            except:
172
+                raise Exception("No live stream found")
173
+
174
+            slist = js["primary"]
175
+
176
+            for l in slist:
177
+                stream = util.item()
178
+                stream["url"]=slist[l]["hls"]
179
+                stream["lang"]=l
180
+                stream["quality"]="variant"
181
+                stream["name"]="Euronews live [%s]"%l
182
+                stream["desc"]=stream["name"]
183
+                stream["type"]="hls" #stream_type(url)
184
+                streams.append(stream)
185
+
186
+        elif clist=="content" and plist[1] == "getArticle":
187
+            if "lang" in qs:
188
+                del qs["lang"]
189
+            languages = self.get_languages()
190
+            for lang in languages:
191
+                id = qs["id"]
192
+                req = '{"methodName":"content.getArticle","apiKey":"androidPhoneEuronews-1.0","params":{"id":"%s"},"language":"%s"}'%(id,lang)
193
+                r = self.call(req)
194
+                if not r:
195
+                    raise Exception("No live stream found")
196
+                if not "articlelist" in r:
197
+                    msg = r["label"] if "label" in r else "No article finde"
198
+                    raise Exception(msg)
199
+                article = r["articlelist"]
200
+                stream = util.item()
201
+                stream["url"]=article["videoUri"] if "videoUri" in article else ""
202
+                if not stream["url"]:
203
+                    return []
204
+                stream["lang"]=lang
205
+                stream["quality"]="?"
206
+                stream["name"]= article["title"]
207
+                stream["desc"]=article["text"] if "text" in article else article["title"]
208
+                stream["type"]="http" #stream_type(url)
209
+                streams.append(stream)
210
+
211
+        else:
212
+            raise Exception("No live stream found")
213
+
214
+        ### TODO - sakārtot sarakstu, lai pirmais ir labakais video
215
+        qlist = ["???","lq","mq","hq","hd","variant"]
216
+        llist = ["fr","en","ru","lv"]
217
+        for s in streams:
218
+            if s["lang"]==self.options["language"]:
219
+                s["order"] = 10000
220
+                continue
221
+            lv = llist.index(s["lang"])*10 if s["lang"] in llist else 0
222
+            qv=qlist.index(s["quality"]) if s["quality"] in qlist else 0
223
+            s["order"] = lv+qv
224
+        streams = sorted(streams,key=lambda item: item["order"],reverse=True)
225
+        return streams
226
+    def get_languages(self):
227
+        if self.languages: return self.languages
228
+        url = "http://www.euronews.com/api/watchlive.json"
229
+        r = self._http_request(url)
230
+        try:
231
+            js = json.loads(r)
232
+            url = js["url"]
233
+        except:
234
+            raise Exception("Can not get languages list")
235
+        r = self._http_request(url)
236
+        try:
237
+            js = json.loads(r)
238
+            if not js["status"]=="ok":
239
+                raise Exception("Can not get languages list")
240
+        except:
241
+            raise Exception("Can not get languages list")
242
+
243
+        slist = js["primary"]
244
+        self.languages=slist.keys()
245
+        return self.languages
246
+
247
+    def call(self, data,params = None, headers=None):
248
+        if not headers: headers = self.headers
249
+        #if not lang: lang = self.country
250
+        url = "http://api.euronews.com/ipad/"
251
+        headers = headers2dict("""
252
+User-Agent: Euronews/4.0.126
253
+Content-Type: multipart/form-data, boundary=AaB03xBounDaRy; charset=UTF-8
254
+Host: api.euronews.com
255
+Connection: Keep-Alive
256
+        """)
257
+        params = """
258
+--AaB03xBounDaRy
259
+content-disposition: form-data; name=request
260
+
261
+%s
262
+--AaB03xBounDaRy--
263
+"""%data
264
+        content = self._http_request(url, params, headers)
265
+        if content:
266
+            try:
267
+                result = json.loads(content)
268
+                return result
269
+            except Exception, ex:
270
+                return None
271
+        else:
272
+            return None
273
+
274
+
275
+if __name__ == "__main__":
276
+    language= "en"
277
+    c = Source(language)
278
+    data = '{"methodName":"content.getTimeline","apiKey":"androidPhoneEuronews-1.0","params":{"page":"1","byPage":"30"},"language":"en"}'
279
+    r = c.call(data)
280
+    if len(sys.argv)>1:
281
+        data= sys.argv[1]
282
+    else:
283
+        data = "home"
284
+    content = c.get_content(data)
285
+    for item in content:
286
+        print item
287
+    pass

+ 336
- 0
resources/lib/sources/filmix.py Parādīt failu

@@ -0,0 +1,336 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import urllib2, urllib
14
+import datetime, re, sys,os
15
+import ConfigParser
16
+from SourceBase import SourceBase
17
+import base64
18
+from collections import OrderedDict
19
+import sys
20
+try:
21
+    import util
22
+except:
23
+    sys.path.insert(0,'..')
24
+    import util
25
+
26
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
27
+
28
+class Source(SourceBase):
29
+
30
+    def __init__(self,country=""):
31
+        self.name = "filmix"
32
+        self.title = "filmix.me"
33
+        self.img = "http://cs5324.vk.me/g33668783/a_903fcc63.jpg"
34
+        self.desc = "filmix.me satura skatīšanās"
35
+        self.country=country
36
+        self.headers = headers2dict("""
37
+Host: filmix.me
38
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
39
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
40
+Accept-Language: en-US,en;q=0.5
41
+""")
42
+        self.headers2 = headers2dict("""
43
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
44
+X-Requested-With: XMLHttpRequest
45
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
46
+""")
47
+        self.url = "https://filmix.me/"
48
+        #self.login()
49
+
50
+    def login(self,user="",password=""):
51
+        return True
52
+
53
+    def get_content(self, data):
54
+        print "[filmix] get_content:", data
55
+        source, data, path, plist, clist, params, qs = self.parse_data(data)
56
+        content=[]
57
+        content.append(("..return", "back","","Return back"))
58
+
59
+        if clist=="home":
60
+            content.extend([
61
+                ("Search", "filmix::search/{0}","","Search"),
62
+                ("Movies", "filmix::movies","","Movies"),
63
+                ("Series", "filmix::series","","TV Series"),
64
+                ("Cartoons", "filmix::cartoons","","Cartoons"),
65
+            ])
66
+            return content
67
+
68
+        #elif clist=="search":
69
+            # TODO
70
+            #return content
71
+
72
+        elif data in ("movies","series","cartoons"):
73
+            r = self.call("")
74
+            r = r.decode("cp1251").encode("utf8")
75
+            if data == "movies":
76
+                sname = "Фильмы"
77
+            elif data=="series":
78
+                sname = "Сериалы"
79
+            else:
80
+                sname = "Мультфильмы"
81
+            # <span class="menu-title">Фильмы</span>
82
+            m = re.search('<span class="menu-title">%s</span>(.+?)<li>\s+?<span'%sname, r, re.DOTALL|re.UNICODE)
83
+            if not m: return content
84
+            r2 = m.group(1)
85
+            result = re.findall(r'<a .*?href="https://filmix\.me/([^"]+)".*?>([^<]+)</', r2, re.DOTALL)
86
+            for item in result:
87
+                if "catalog" in item[0]: continue
88
+                title = item[1]
89
+                data2 = item[0]
90
+                img = self.img
91
+                desc = title
92
+                content.append((title,self.name+"::"+data2,img,desc))
93
+            return content
94
+
95
+        ## Seriāls
96
+        elif clist=="play":
97
+            r = self.call(path)
98
+            r = r.decode("cp1251").encode("utf8")
99
+            title = title0 = util.unescape(re.search("titlePlayer = '([^']+)'", r, re.DOTALL).group(1))
100
+            m = re.search('<meta itemprop="thumbnailUrl" content="([^"]+)',r,re.DOTALL)
101
+            img = m.group(1) if m else self.img
102
+            m = re.search('<meta itemprop="duration" content="([^"]+)" />', r, re.DOTALL)
103
+            duration = "(%s)"%m.group(1) if m else ""
104
+            m = re.search('<p itemprop="description"[^>]+>([^<]+)<', r, re.DOTALL)
105
+            desc = desc0 =  util.unescape(m.group(1).strip()) if m else ""
106
+            vid = plist[-1]
107
+            js = self.get_movie_info(vid)
108
+            pl_link = js["message"]["translations"]["flash"].values()[0] # TODO process several players
109
+            pl_link = self.decode_uppod_text(pl_link)
110
+            js = self._http_request(pl_link)
111
+            js = self.decode_uppod_text(js)
112
+            js = json.loads(js)
113
+            if "s" in qs:
114
+                s = int(qs["s"])
115
+                for i,ep in enumerate(js["playlist"][s-1]["playlist"]):
116
+                    title = title0+" - "+js["playlist"][s-1]["playlist"][i]["comment"].encode("utf8")
117
+                    serie = js["playlist"][s-1]["playlist"][i]["comment"].encode("utf8")
118
+                    data2 = data+"&e=%s"%(i+1)
119
+                    desc = serie +"\n"+desc0
120
+                    content.append((title,self.name+"::"+data2,img,desc))
121
+            else:
122
+                for i,ep in enumerate(js["playlist"]):
123
+                    title = title0 +" - "+js["playlist"][i]["comment"].encode("utf8")
124
+                    serie = js["playlist"][i]["comment"].encode("utf8")
125
+                    data2 = data+"?s=%s"%(i+1)
126
+                    desc = serie +"\n"+desc0
127
+                    content.append((title,self.name+"::"+data2,img,desc))
128
+            return content
129
+            #r = self._http_request(url)
130
+
131
+
132
+        ### saraksts ###
133
+        else:
134
+            r = self.call(data)
135
+            r = r.decode("cp1251").encode("utf8")
136
+            for r2 in re.findall('<article class="shortstory line".+?</article>', r, re.DOTALL):
137
+                m = re.search(r'<a href="https://filmix\.me/play/(\d+)" class="watch icon-play">', r2, re.DOTALL)
138
+                if not m: continue
139
+                vid = m.group(1)
140
+                data2 = "play/%s"%vid
141
+                #title = re.search('itemprop="name">([^<]+)</div>', r2, re.DOTALL).group(1)
142
+                title = re.search('itemprop="name" content="([^"]+)"', r2, re.DOTALL).group(1)
143
+                m = re.search('itemprop="alternativeHeadline" content="([^"]+)"', r2, re.DOTALL)
144
+                if m:
145
+                    title = title + "/"+m.group(1)
146
+                m = re.search('<img src="([^"]+.jpg)"', r2, re.DOTALL)
147
+                img = "http://filmix.me"+m.group(1) if m else self.img
148
+                m = re.search(r'<a itemprop="copyrightYear".+?>(\d+)<', r2, re.DOTALL)
149
+                if m:
150
+                    year = m.group(1) if m else ""
151
+                    title = "%s (%s)"%(title,year)
152
+                title = util.unescape(title)
153
+                genre = re.findall('<a itemprop="genre"[^>]+?">([^<]+)</a>', r2, re.DOTALL)
154
+                genre = ",".join(genre)
155
+                m = re.search('<p itemprop="description">([^<]+)</p>', r2, re.DOTALL)
156
+                desc0 = util.unescape(m.group(1)) if m else ""
157
+                m = re.search('<div class="quality">([^<]+)</div>', r2, re.DOTALL)
158
+                quality = m.group(1) if m else ""
159
+                actors = re.findall('itemprop="actor">([^<]+)<', r2, re.DOTALL)
160
+                actors = ",".join(actors)
161
+                desc="%s\n%s\n%s\n%s\n%s"%(title,genre,desc0,actors,quality)
162
+                content.append((title,self.name+"::"+data2,img,desc))
163
+            if '<div class="navigation">' in r:
164
+                m = re.search(r'href="https://filmix\.me/([^"]+)" class="next icon-arowRight btn-tooltip"', r, re.DOTALL)
165
+                if m:
166
+                    data2 = m.group(1)
167
+                else:
168
+                    m = re.search("/page/(\d)+",data)
169
+                    if m:
170
+                        page = int(m.group(1))+1
171
+                        data2 = re.sub("/page/(\d)+", "/page/%s"%page, data)
172
+                    else:
173
+                        data2 = data + "/page/2"
174
+                content.append(("Next page",self.name+"::"+data2,self.img,"Next page"))
175
+
176
+            return content
177
+
178
+    def is_video(self,data):
179
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
180
+        if clist == "play" and "s=" in data and "e=" in data:
181
+            return True
182
+        elif clist=="play" and not params:
183
+            r = self.call(path)
184
+            #r = r.decode("cp1251").encode("utf8")
185
+            m = re.search('itemprop="contentUrl" content="(.+?)"', r, re.IGNORECASE | re.DOTALL)
186
+            if not m:
187
+                raise Exception("Can not find video link")
188
+                #return False
189
+            video_link = m.group(1)
190
+            if video_link=='{video-link}':
191
+                return False
192
+            else:
193
+                return True
194
+        else:
195
+            return False
196
+
197
+    def get_streams(self, data):
198
+        print "[filmix] get_streams:", data
199
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
200
+
201
+        r = self.call(path)
202
+        if not r:
203
+            return []
204
+        streams = []
205
+        r = r.decode("cp1251").encode("utf8")
206
+        title = title0 = util.unescape(re.search("titlePlayer = '([^']+)'", r, re.DOTALL).group(1))
207
+        m = re.search('<meta itemprop="thumbnailUrl" content="([^"]+)',r,re.DOTALL)
208
+        img = m.group(1) if m else self.img
209
+        m = re.search('<meta itemprop="duration" content="([^"]+)" />', r, re.DOTALL)
210
+        duration = "(%s)"%m.group(1) if m else ""
211
+        m = re.search('<p itemprop="description"[^>]+>([^<]+)<', r, re.DOTALL)
212
+        desc = desc0 =  util.unescape(m.group(1).strip()) if m else ""
213
+        m = re.search('itemprop="contentUrl" content="(.+?)"', r, re.IGNORECASE | re.DOTALL)
214
+        if not m:
215
+        #    #raise Exception("Can not find video link")
216
+            return []
217
+        video_link = m.group(1)
218
+        series = True if video_link == '{video-link}' else False
219
+        vid = plist[1]
220
+        js = self.get_movie_info(vid)
221
+        if js["message"]["translations"]["flash"]:
222
+            video_link = js["message"]["translations"]["flash"].values()[0].encode("utf8")
223
+            video_link = self.decode_uppod_text(video_link)
224
+            lang = js["message"]["translations"]["flash"].keys()[0].encode("utf8") # TODO process several players/streams
225
+        else:
226
+            return []
227
+
228
+        if not series : # Filma
229
+            url0 = video_link
230
+            streams2 = self.get_streams2(url0)
231
+            for st in streams2:
232
+                stream = util.item()
233
+                stream["url"]=st[1]
234
+                stream["lang"]=lang
235
+                stream["quality"]=st[0]
236
+                stream["name"]= title
237
+                stream["desc"]=desc
238
+                streams.append(stream)
239
+            return streams
240
+
241
+        else: # Seriāls
242
+            pl_link = video_link
243
+            js = self._http_request(pl_link)
244
+            js = self.decode_uppod_text(js)
245
+            js = json.loads(js)
246
+            if "s" in qs and "e" in qs:
247
+                s = int(qs["s"])
248
+                e = int(qs["e"])
249
+                serie = js["playlist"][s-1]["playlist"][e-1]["comment"].encode("utf8")
250
+                title = title0+" - "+ serie
251
+                url0 = js["playlist"][s-1]["playlist"][e-1]["file"].encode("utf8")
252
+                streams2 = self.get_streams2(url0)
253
+                for st in streams2:
254
+                    stream = util.item()
255
+                    stream["url"]=st[1]
256
+                    stream["lang"]=lang
257
+                    stream["quality"]=st[0]
258
+                    stream["name"]= title
259
+                    stream["desc"]=desc
260
+                    streams.append(stream)
261
+                return streams
262
+
263
+    def call(self, data,params=None,headers=None,lang=""):
264
+        if not headers: headers = self.headers
265
+        url = self.url+data
266
+        result = self._http_request(url,params,headers=headers)
267
+        return result
268
+
269
+    def get_movie_info(self,vid):
270
+        headers = headers2dict("""
271
+    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:50.0) Gecko/20100101 Firefox/50.0
272
+    Accept: application/json, text/javascript, */*; q=0.01
273
+    Accept-Language: en-US,en;q=0.5
274
+    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
275
+    X-Requested-With: XMLHttpRequest
276
+    Referer: https://filmix.me/play/%s
277
+    """%vid )
278
+        post_data = {"post_id":vid}
279
+        r = util.post("https://filmix.me/api/movies/player_data", data=post_data, headers = headers)
280
+        if not r:
281
+            raise Exception("Can not get movie info")
282
+            #return []
283
+        js = json.loads(r)
284
+        return js
285
+
286
+    def decode_uppod_text(self, text):
287
+        Client_codec_a = ["l", "u", "T", "D", "Q", "H", "0", "3", "G", "1", "f", "M", "p", "U", "a", "I", "6", "k", "d", "s", "b", "W", "5", "e", "y", "="]
288
+        Client_codec_b = ["w", "g", "i", "Z", "c", "R", "z", "v", "x", "n", "N", "2", "8", "J", "X", "t", "9", "V", "7", "4", "B", "m", "Y", "o", "L", "h"]
289
+        text = text.replace("\n", "").strip()
290
+        for i in range(len(Client_codec_a)):
291
+            char1 = Client_codec_b[i]
292
+            char2 = Client_codec_a[i]
293
+            text = text.replace(char1, "___")
294
+            text = text.replace(char2, char1)
295
+            text = text.replace("___", char2)
296
+        result = base64.b64decode(text)
297
+        print result
298
+        return result
299
+
300
+    def get_streams2(self,url0):
301
+        m = re.search("\[([\d,]+)]",url0)
302
+        if not m:
303
+            return [("?",url0)]
304
+        res = m.group(1)
305
+        streams=[]
306
+        for res in res.split(","):
307
+            if not res: continue
308
+            url=re.sub("\[[\d,]+]",res,url0)
309
+            streams.append((res,url))
310
+        return streams
311
+
312
+
313
+if __name__ == "__main__":
314
+
315
+    c = Source()
316
+    #s = "ZnVuY3Rpb24gc2VuZE1lc3NhZ2U2MDc3ODkoZSl7dmFyIGg9bWdfd3M2MDc3ODkub25tZXNzYWdlOyBtZ193czYwNzc4OS5yZWFkeVN0YXRlPT1tZ193czYwNzc4OS5DTE9TRUQmJihtZ193czYwNzc4OT1uZXcgV2ViU29ja2V0KG1nX3dzNjA3Nzg5X2xvY2F0aW9uKSksbWdfd3M2MDc3ODkub25tZXNzYWdlPWgsd2FpdEZvclNvY2tldENvbm5lY3Rpb242MDc3ODkobWdfd3M2MDc3ODksZnVuY3Rpb24oKXttZ193czYwNzc4OS5zZW5kKGUpfSl9ZnVuY3Rpb24gd2FpdEZvclNvY2tldENvbm5lY3Rpb242MDc3ODkoZSx0KXtzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7cmV0dXJuIDE9PT1lLnJlYWR5U3RhdGU/dm9pZChudWxsIT10JiZ0KCkpOnZvaWQgd2FpdEZvclNvY2tldENvbm5lY3Rpb242MDc3ODkoZSx0KX0sNSl9OyB2YXIgbWdfd3M2MDc3ODlfbG9jYXRpb24gPSAid3NzOi8vd3NwLm1hcmtldGdpZC5jb20vd3MiOyBtZ193czYwNzc4OSA9IG5ldyBXZWJTb2NrZXQobWdfd3M2MDc3ODlfbG9jYXRpb24pLCBtZ193czYwNzc4OS5vbm1lc3NhZ2UgPSBmdW5jdGlvbiAodCkge3Bvc3RNZXNzYWdlKHQuZGF0YSk7fSwgb25tZXNzYWdlID0gZnVuY3Rpb24oZSl7c2VuZE1lc3NhZ2U2MDc3ODkoZS5kYXRhKX0="
317
+
318
+    #txt = c.decode_uppod_text(s)
319
+    if len(sys.argv)>1:
320
+        data= sys.argv[1]
321
+    else:
322
+        data = "home"
323
+    content = c.get_content(data)
324
+    for item in content:
325
+        print item
326
+    #cat = api.get_categories(country)
327
+    #chan = api.get_channels("lv")
328
+    #prog = api.get_programs(channel=6400)
329
+    #prog = api.get_programs(category=55)
330
+    #seas = api.get_seasons(program=6453)
331
+    #str = api.get_streams(660243)
332
+    #res = api.get_videos(802)
333
+    #formats = api.getAllFormats()
334
+    #det = api.detailed("1516")
335
+    #vid = api.getVideos("13170")
336
+    pass

+ 272
- 0
resources/lib/sources/filmon.py Parādīt failu

@@ -0,0 +1,272 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import urllib2, urllib
14
+import datetime, re, sys
15
+from SourceBase import SourceBase
16
+
17
+API_URL = 'http://www.filmon.com/'
18
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
19
+#User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
20
+headers0 = headers2dict("""
21
+User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/47.0.2526.70 Mobile/13C71 Safari/601.1.46
22
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
23
+Accept-Language: en-US,en;q=0.5
24
+Accept-Encoding: deflate
25
+Connection: keep-alive
26
+""")
27
+import HTMLParser
28
+h = HTMLParser.HTMLParser()
29
+
30
+class Source(SourceBase):
31
+
32
+    def __init__(self,country="lv"):
33
+        self.name = "filmon"
34
+        self.title = "FilmOn"
35
+        self.img = "http://behindthegloves.com/wp-content/uploads/2016/01/FilmOn-logo1.jpg"
36
+        self.desc = "FilmOn portāla satura skatīšanās"
37
+        self.headers = headers0
38
+
39
+        self.country=country
40
+        self.jstv = None
41
+        self.session_key = None
42
+        self.cookie = None
43
+
44
+    def get_content(self, data):
45
+        print "[filmon] get_content:", data
46
+        if "::" in data:
47
+            data = data.split("::")[1] 
48
+        path = data.split("?")[0]
49
+        clist = path.split("/")[0]
50
+        params = data[data.find("?"):] if "?" in data else ""
51
+        qs = dict(map(lambda x:x.split("="),re.findall("\w+=\w+",params)))
52
+        lang = qs["lang"] if "lang" in qs else self.country
53
+
54
+        if not self.jstv:
55
+            self.jstv = self.get_tv_channels()
56
+        #if not self.session_key: # TODO izskatās, ka strādā bez, vismaz ja nelogojas iekšā,  jānočeko
57
+        #    html = self._http_request("http://www.filmon.com/api/init")
58
+        #    js = json.loads(html)
59
+        #    self.session_key = js["session_key"]
60
+
61
+        content=[]
62
+        content.append(("..return", "back","","Return back"))
63
+
64
+        if clist=="home":
65
+            content.extend([
66
+                ("Live streams", "filmon::tv","","TV live streams"),
67
+                ("Video on demand", "filmon::vod","","Last videos"),
68
+            ])
69
+            return content
70
+
71
+        ### TV Groups ###
72
+        elif clist in ("tv","home"):
73
+            for gr in self.jstv:
74
+                title = gr["name"].encode("utf8")
75
+                data2 = "group?id=%s"%gr["id"]
76
+                img = gr["logo_148x148_uri"].encode("utf8")
77
+                desc = gr["description"].encode("utf8")
78
+                content.append((title,self.name+"::"+data2,img,desc))
79
+            return content
80
+
81
+        ### TV group channels ###
82
+        elif clist=="group":
83
+            if "id" in qs:
84
+                group_id = qs["id"] 
85
+            else:
86
+                return content
87
+            group = None
88
+            for gr in self.jstv:
89
+                if gr["id"]==group_id:
90
+                    group = gr
91
+                    break
92
+            if not group:
93
+                return content
94
+            for ch in group["channels"]:
95
+                title = ch["title"].encode("utf8")
96
+                data2 = "channel?id=%s"%ch["id"]
97
+                img = ch["big_logo"].encode("utf8")
98
+                desc = ch["description"].encode("utf8") if ch["description"] else title
99
+                content.append((title,self.name+"::"+data2,img,desc))
100
+            return content
101
+
102
+        ### TV Channel ###
103
+        elif clist == "channel" or clist == "video":
104
+            if "id" in qs:
105
+                ch_id = qs["id"] 
106
+            else:
107
+                return ("No stream found %s"%data,"","","No stream found")
108
+            ch = self.get_tv_channel_info(ch_id)
109
+            if ch["now_playing"]:
110
+                current_event = ch["now_playing"]["programme_name"] if "programme_name" in ch["now_playing"] else ""
111
+            else:
112
+                current_event = ""
113
+            title = u"%s - %s"%(ch["title"],current_event)
114
+            title = title.encode("utf8")
115
+            if current_event:
116
+                desc = ch["now_playing"]["programme_description"].encode("utf8")
117
+            else:
118
+                desc = title
119
+            data2 = ""
120
+            for t in ("SD","HD"):
121
+                for s in ch["streams"]:
122
+                    if s["name"]==t:
123
+                        data2 = s["url"].encode("utf8")
124
+                        break
125
+                if data2: break
126
+            return (title,data2,"",desc)
127
+
128
+        ### VOD genres ###
129
+        elif path in ("vod","vod/genres"):
130
+            data = "vod/genres"
131
+            js = self.call(data)
132
+            for gr in js["response"]:
133
+                title = gr["name"].encode("utf8")
134
+                data2 = "vod/search?genre=%s&max_results=30&no_episode=true&start_index=0"%(gr["slug"].encode("utf8"))
135
+                img = gr["images"][0]["url"].encode("utf8")
136
+                desc = gr["description"].encode("utf8") if gr["description"] else title
137
+                content.append((title,self.name+"::"+data2,img,desc))
138
+            return content           
139
+
140
+        ### VOD genre videos ###
141
+        elif path == "vod/search":
142
+            js = self.call(data)
143
+            for vid in js["response"]:
144
+                title = vid["title"].encode("utf8")
145
+                if vid["type"]=="series":
146
+                    title = "[Series] "+title
147
+                data2 = "vod/movie?id=%s&type=%s"%(vid["id"],vid["type"].encode("utf8"))
148
+                img = "http://static.filmon.com/assets/"+vid["poster"]["couchdb_url"].encode("utf8")
149
+                desc = vid["description"].encode("utf8") if vid["description"] else title
150
+                content.append((title,self.name+"::"+data2,img,desc))
151
+            start_index = int(qs["start_index"]) if "start_index" in qs else 0
152
+            if start_index+js["total"]<js["total_found"]:
153
+                start_index += 30
154
+                data2 = re.sub("start_index=\d+","start_index=%s"%start_index,data) if "start_index" in qs else data +"&start_index=30"
155
+                content.append(("Next page",self.name+"::"+data2,"","Next page"))                                            
156
+            return content
157
+
158
+        ### VOD video sigle/series ###
159
+        elif path == "vod/movie":
160
+            js = self.call(data)
161
+            if js["response"]["type"] == "series":
162
+                ids = ",".join(js["response"]["episodes"])
163
+                data2 = "vod/movies?ids=%s"%ids
164
+                js2 = self.call(data2)
165
+                for vid in js2["response"]:
166
+                    title = vid["title"].encode("utf8")
167
+                    if vid["type"]=="series":
168
+                        title = "[Series] "+title
169
+                    data2 = "vod/movie?id=%s&type=%s"%(vid["id"],vid["type"].encode("utf8"))
170
+                    img = "http://static.filmon.com/assets/"+vid["poster"]["couchdb_url"].encode("utf8")
171
+                    desc = vid["description"].encode("utf8") if vid["description"] else title
172
+                    content.append((title,self.name+"::"+data2,img,desc))
173
+                return content
174
+            else:
175
+                title = js["response"]["title"].encode("utf8")
176
+                desc = js["response"]["description"].encode("utf8") if js["response"]["description"] else title
177
+                data2 = js["response"]["streams"]["low"]["url"].encode("utf8")
178
+                return (title,data2,"",desc)
179
+
180
+    def is_video(self,data):
181
+        if "::" in data:
182
+            data = data.split("::")[1]
183
+        cmd = data.split("?")
184
+        if cmd[0] in ("video","channel"):
185
+            return True
186
+        elif cmd[0] == "vod/movie" and "type=movie" in data:
187
+            return True
188
+        else:
189
+            return False
190
+
191
+    def call(self, data,headers=headers0,lang=""):
192
+        if not lang: lang = self.country
193
+        url = "http://www.filmon.com/api/" + data
194
+        #if not "?" in url: url += "?session_key=%s"%self.session_key
195
+        #if not "session_key=" in url: url += "&session_key=%s"%self.session_key
196
+        #print "[TVPlay Api] url: ",url
197
+        result = []
198
+        content = self._http_request(url)
199
+        if content:
200
+            try:
201
+                result = json.loads(content)
202
+            except Exception, ex:
203
+                return None
204
+        return result
205
+
206
+    #----------------------------------------------------------------------
207
+    def get_tv_channel_info(self,id):
208
+        url = "http://www.filmon.com/ajax/getChannelInfo"
209
+        headers = headers2dict("""
210
+Host: www.filmon.com
211
+User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:41.0) Gecko/20100101 Firefox/41.0
212
+Accept: application/json, text/javascript, */*; q=0.01
213
+Accept-Language: en-US,en;q=0.5
214
+Accept-Encoding: deflate
215
+DNT: 1
216
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
217
+X-Requested-With: XMLHttpRequest
218
+Referer: http://www.filmon.com/tv/live
219
+Connection: keep-alive
220
+Pragma: no-cache
221
+Cache-Control: no-cache
222
+""")
223
+        headers["Cookie"] = self.cookie
224
+        data = "channel_id=%s&quality=low"%id
225
+        response = urllib2.urlopen(urllib2.Request(url, headers=headers,data=data))
226
+        html =  response.read()
227
+        js = json.loads(html)
228
+        return js
229
+
230
+    #----------------------------------------------------------------------
231
+    def get_tv_channels(self):
232
+        """Get tv channels list"""
233
+        headers = headers2dict("""
234
+Host: www.filmon.com
235
+User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:41.0) Gecko/20100101 Firefox/41.0
236
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
237
+Accept-Language: en-US,en;q=0.5
238
+Accept-Encoding: deflate
239
+DNT: 1
240
+Connection: keep-alive
241
+    """)
242
+
243
+        url = "http://www.filmon.com/tv"
244
+        response = urllib2.urlopen(urllib2.Request(url, headers=headers))
245
+        if "set-cookie" in response.headers:
246
+            self.cookie = response.headers["set-cookie"]
247
+        html =  response.read()
248
+        s = re.search("(?i)var groups = (.*);", html).groups(1)[0]
249
+        js = json.loads(s)
250
+        return js
251
+
252
+if __name__ == "__main__":
253
+    country= "lv"
254
+    c = Source(country)
255
+    if len(sys.argv)>1:
256
+        data= sys.argv[1]
257
+    else:
258
+        data = "home"
259
+    content = c.get_content(data)
260
+    for item in content:
261
+        print item
262
+    #cat = api.get_categories(country)
263
+    #chan = api.get_channels("lv")
264
+    #prog = api.get_programs(channel=6400)
265
+    #prog = api.get_programs(category=55)
266
+    #seas = api.get_seasons(program=6453)
267
+    #str = api.get_streams(660243)
268
+    #res = api.get_videos(802)
269
+    #formats = api.getAllFormats()
270
+    #det = api.detailed("1516")
271
+    #vid = api.getVideos("13170")
272
+    pass

+ 4
- 0
resources/lib/sources/iplayer.cfg Parādīt failu

@@ -0,0 +1,4 @@
1
+[iplayer]
2
+user = ivars777@gmail.com
3
+password = kaskade7
4
+

+ 524
- 0
resources/lib/sources/iplayer.py Parādīt failu

@@ -0,0 +1,524 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+import sys, os, os.path, re, sys
9
+import urllib,urllib2
10
+from xml.sax.saxutils import unescape,escape
11
+from urllib import quote, unquote
12
+import datetime
13
+import HTMLParser
14
+import json
15
+import datetime,time
16
+from SourceBase import SourceBase, stream_type
17
+import util
18
+from collections import OrderedDict
19
+
20
+API_URL = 'https://m.lattelecom.tv/'
21
+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"
22
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
23
+h = HTMLParser.HTMLParser()
24
+
25
+class Source(SourceBase):
26
+
27
+    def __init__(self):
28
+        self.name = "iplayer"
29
+        self.title = "BBC iPlayer"
30
+        self.img = "http://www.userlogos.org/files/logos/inductiveload/BBC_iPlayer_logo.png"
31
+        self.desc = "BBC iPlayer portal content"
32
+
33
+        self.api_url = "http://ibl.api.bbci.co.uk/ibl/v1/"
34
+        self.headers = headers2dict("""
35
+User-Agent: BBCiPlayer/4.19.0.3021 (SM-G900FD; Android 4.4.2)
36
+Connection: Keep-Alive
37
+        """)
38
+        self.headers2 = headers2dict("""
39
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36
40
+Connection: Keep-Alive
41
+        """)
42
+
43
+        self.ch = []
44
+        self.ch_id={}
45
+        self.ch_id2={}
46
+        self.ch_name={}
47
+        self.logos ={
48
+            "bbc_one_london":"http://www.lyngsat-logo.com/hires/bb/bbc_one.png",
49
+            "bbc_two_england":"http://www.lyngsat-logo.com/hires/bb/bbc_two_uk.png",
50
+            "bbc_three":"http://www.lyngsat-logo.com/hires/bb/bbc_three_uk.png",
51
+            "bbc_four":"http://www.lyngsat-logo.com/hires/bb/bbc_four_uk.png",
52
+            "bbc_radio_one":"http://www.lyngsat-logo.com/hires/bb/bbc_radio1.png",
53
+            "cbbc":"http://www.lyngsat-logo.com/hires/bb/bbc_cbbc.png",
54
+            "cbeebies":"http://www.lyngsat-logo.com/hires/bb/bbc_cbeebies_uk.png",
55
+            "bbc_news24":"http://www.lyngsat-logo.com/hires/bb/bbc_news.png",
56
+            "bbc_parliament":"http://www.lyngsat-logo.com/hires/bb/bbc_parliament.png",
57
+            "bbc_alba":"http://www.lyngsat-logo.com/hires/bb/bbc_alba.png",
58
+            "s4cpbs":"http://www.lyngsat-logo.com/hires/ss/s4c_uk.png"
59
+        }
60
+        cur_directory = os.path.dirname(os.path.abspath(__file__))
61
+        self.config_file = os.path.join(cur_directory,self.name+".cfg")
62
+        self.options = OrderedDict([("user","lietotajs"),("password","parole")])
63
+        self.options_read()
64
+
65
+    def get_content(self, data):
66
+        print "[iplayer] get_content:", data
67
+        if "::" in data:
68
+            data = data.split("::")[1]
69
+        path = data.split("?")[0]
70
+        clist = path.split("/")[0]
71
+        params = data[data.find("?"):] if "?" in data else ""
72
+        qs = dict(map(lambda x:x.split("="),re.findall("\w+=[\w-]+",params)))
73
+        #lang = qs["lang"] if "lang" in qs else self.country
74
+
75
+        content=[]
76
+        content.append(("..return", "back","","Return back"))
77
+
78
+        ### Home ###
79
+        if data=="home":
80
+            content.extend([
81
+                ("Search TV", "iplayer::search/{0}","","Search in iPlayer"),
82
+                ("Live streams", "iplayer::live","","TV live streams"),
83
+                ("Channels", "iplayer::channels","","Programmes by channel/date"),
84
+                ("Categories", "iplayer::categories","","Programmes by categories"),
85
+                ("A-Z", "iplayer::a-z","","All programmes by name"),
86
+                ("Highlights", "iplayer::home/highlights","","Current highlights"),
87
+                ("Most popular", "iplayer::groups/popular/episodes?per_page=40&page=1","","Most popular programmes")
88
+            ])
89
+            return content
90
+
91
+        ### Search ###
92
+        elif clist=="search":
93
+            data_ = "search-suggest/?q=%s&rights=mobile&initial_child_count=1"%data.split("/")[1]
94
+            r = self.call(data_)
95
+            for item in r["search_suggest"]["results"]:
96
+                title,data2,img,desc = self.get_data_element(item)
97
+                content.append((title,self.name+"::"+data2,img,desc))
98
+            return content
99
+
100
+
101
+        ### Live main ###
102
+        elif data=="live":
103
+            for ch in self.get_channels():
104
+                title = ch["title"]
105
+                img = self.logos[ch["id"]] if ch["id"] in self.logos else  "http://static.bbci.co.uk/mobileiplayerappbranding/1.9/android/images/channels/tv-guide-wide-logo/layout_normal/xxhdpi/%s_tv-guide-wide-logo.png"%ch["id"]
106
+                desc = title
107
+                data2 = "live/%s"%ch["id"]
108
+                ee = self.get_epg_live(ch["id"])
109
+                desc = ee[2]
110
+                content.append((title,self.name+"::"+data2,img,desc))
111
+            return content
112
+
113
+        ### Categories ###
114
+        elif data == "categories":
115
+            r = self.call(data)
116
+            if not "categories":
117
+                raise Exception("Error reading categories")
118
+            for item in r["categories"]:
119
+                data2 = "categories/%s"%(item["id"])
120
+                title = item["title"]
121
+                desc = title
122
+                img = self.img
123
+                content.append((title,self.name+"::"+data2,img,desc))
124
+            return content
125
+
126
+        ### Catetory root ###
127
+        elif clist == "categories" and len(data.split("/"))==2:
128
+            r = self.call(data)
129
+            title = "%s - highlights"%r["category"]["title"]
130
+            content.append((title,self.name+"::"+data+"/highlights?lang=en&rights=mobile&availability=available",self.img,title))
131
+            title = "%s - recent (%s programmes, %s episodes)"%(r["category"]["title"],r["category"]["child_programme_count"],r["category"]["child_episode_count"])
132
+            content.append((title,self.name+"::"+data+"/programmes?rights=mobile&page=1&per_page=40&sort=recent&sort_direction=asc&initial_child_count=1&availability=available",self.img,title))
133
+            title = "%s - a-z (%s programmes, %s episodes)"%(r["category"]["title"],r["category"]["child_programme_count"],r["category"]["child_episode_count"])
134
+            content.append((title,self.name+"::"+data+"/programmes?rights=mobile&page=1&per_page=40&sort=title&sort_direction=asc&initial_child_count=1&availability=available",self.img,title))
135
+            return content
136
+
137
+        ### Program/episodes list ###
138
+        elif   re.search("categories/([\w\-]+)/(highlights|programmes).+",data) or\
139
+               re.search("programmes/(\w+)/episodes.+",data) or\
140
+               re.search("groups/(\w+)/episodes.+",data) or\
141
+               re.search("atoz/([\w]+)/programmes.+",data) or\
142
+               re.search("channels/(\w+)/schedule/[\d\-].+",data) or\
143
+               re.search("channels/(\w+)/programmes.+",data) or\
144
+               re.search("channels/(\w+)/highlights.+",data) or\
145
+               data == "home/highlights":
146
+            r = self.call(data)
147
+            lst = r["category_highlights"] if "category_highlights" in r else\
148
+                  r["category_programmes"] if "category_programmes" in r else\
149
+                  r["programme_episodes"] if "programme_episodes" in r else\
150
+                  r["atoz_programmes"] if "atoz_programmes" in r else\
151
+                  r["group_episodes"] if "group_episodes" in r else\
152
+                  r["schedule"] if "schedule" in r else\
153
+                  r["channel_highlights"] if "channel_highlights" in r else\
154
+                  r["channel_programmes"] if "channel_programmes" in r else\
155
+                  r["home_highlights"] if "home_highlights" in r else\
156
+                  []
157
+            if not lst:
158
+                return content
159
+            for el in lst["elements"]:
160
+                if el["type"] == "broadcast":
161
+                    if not len(el["episode"]["versions"]):continue
162
+                    title,data2,img,desc = self.get_data_element(el["episode"])
163
+                    t1 = gt(el['scheduled_start'])
164
+                    t2 = gt(el['scheduled_end'])
165
+                    title = "[%s-%s]%s"%(t1.strftime("%d.%m.%Y %H:%M"),t2.strftime("%H:%M"),title)
166
+                else:
167
+                    title,data2,img,desc = self.get_data_element(el)
168
+                content.append((title,self.name+"::"+data2,img,desc))
169
+
170
+            if "&page=" in data and lst["page"]*lst["per_page"]<lst["count"]:
171
+                data2 = re.sub("&page=\d+","&page=%s"%(lst["page"]+1),data)
172
+                content.append(("Next page",self.name+"::"+data2,self.img,"Next page"))
173
+            return content
174
+
175
+        ### A-z root ###
176
+        elif data=="a-z":
177
+            url = "http://www.bbc.co.uk/programmes/a-z/by/x/all.json?page=1"
178
+            r = self._http_request(url)
179
+            if not r:
180
+                raise Exception("Can not read %s"%s)
181
+            js = json.loads(r)
182
+            for ch in js["atoz"]["letters"]:
183
+                title = ch.upper()
184
+                desc = "Programmes beginning with %s"%title
185
+                img = self.img
186
+                data2 = "atoz/%s/programmes?rights=mobile&page=1&per_page=40&initial_child_count=1&sort=title&sort_direction=asc&availability=available"%ch
187
+                content.append((title,self.name+"::"+data2,img,desc))
188
+            return content
189
+
190
+        ###  Channels home ###
191
+        elif data=="channels":
192
+            for ch in self.get_channels():
193
+                title = ch["title"]
194
+                img = self.logos[ch["id"]] if ch["id"] in self.logos else  "http://static.bbci.co.uk/mobileiplayerappbranding/1.9/android/images/channels/tv-guide-wide-logo/layout_normal/xxhdpi/%s_tv-guide-wide-logo.png"%ch["id"]
195
+                desc = title
196
+                data2 = "channels/%s"%ch["id"]
197
+                #ee = self.get_epg_live(ch["id"])
198
+                desc = title
199
+                content.append((title,self.name+"::"+data2,img,desc))
200
+            return content
201
+
202
+        ### Channel higlihts/progrmmes/days ###
203
+        elif clist=="channels" and len(data.split("/"))==2:
204
+            r = self.call(data)
205
+            chid = data.split("/")[1]
206
+            ch = self.get_channel_by_id(chid)
207
+
208
+            # Highlights
209
+            title = ch["title"] + " - highlights"
210
+            img = "http://static.bbci.co.uk/mobileiplayerappbranding/1.9/android/images/channels/tv-guide-wide-logo/layout_normal/xxhdpi/%s_tv-guide-wide-logo.png"%ch["id"]
211
+            data2 = "channels/%s/highlights?lang=en&rights=mobile&availability=available"%ch["id"]
212
+            desc = title
213
+            content.append((title,self.name+"::"+data2,img,desc))
214
+
215
+            #AtoZ
216
+            title = ch["title"] + " - programmes AtoZ"
217
+            data2 = "channels/%s/programmes?rights=mobile&page=1&per_page=40&sort=recent&sort_direction=asc&initial_child_count=1&availability=available"%ch["id"]
218
+            desc = title
219
+            content.append((title,self.name+"::"+data2,img,desc))
220
+
221
+            day0 = datetime.date.today()
222
+            for i in range(10):
223
+                day = day0-datetime.timedelta(days=i)
224
+                days = day.strftime("%Y-%m-%d")
225
+                title = ch["title"] + " - " + days
226
+                img = "http://static.bbci.co.uk/mobileiplayerappbranding/1.9/android/images/channels/tv-guide-wide-logo/layout_normal/xxhdpi/%s_tv-guide-wide-logo.png"%ch["id"]
227
+                data2 = "channels/%s/schedule/%s?availability=available"%(ch["id"],days)
228
+                #ee = self.get_epg_live(ch["id"])
229
+                desc = title
230
+                content.append((title,self.name+"::"+data2,img,desc))
231
+            return content
232
+
233
+
234
+    def get_streams(self, data):
235
+        print "[iplayer] get_streams:", data
236
+        if "::" in data: data = data.split("::")[1]
237
+        if not self.is_video(data):
238
+            return []
239
+        cmd = data.split("/")
240
+        vid = cmd[1].split("?")[0]
241
+        if cmd[0] == "live":
242
+            title,img,desc = self.get_epg_live(vid)
243
+        else:
244
+            data_ = "episodes/%s"%vid
245
+            r = self.call(data_)
246
+            title,img,desc,vid = self.get_epg_video(vid)
247
+        url = "http://open.live.bbc.co.uk/mediaselector/5/select/version/2.0/format/json/mediaset/iptv-all/vpid/%s"%vid
248
+        print "vid=%s"%vid
249
+        print url
250
+        r = self._http_request(url) #,headers=self.headers2
251
+        if not r:
252
+            raise Exception("No streams found")
253
+        js = json.loads(r)
254
+        if "result" in js and js["result"]=="geolocation":
255
+            raise Exception("BBC iPlayer service available only from UK")
256
+        if not "media" in js:
257
+            raise Exception("No streams found")
258
+        streams = []
259
+        captions = []
260
+        for s in js["media"]:
261
+            if s["kind"] == "captions":
262
+                if s["connection"][0]["href"]:
263
+                    sub = {}
264
+                    sub["url"] = s["connection"][0]["href"].encode('utf8')
265
+                    sub["type"] = s["type"]
266
+                    sub["name"] = s["service"] if "service" in s else "captions (taff)"
267
+                    sub["lang"] = "en"
268
+                    captions.append(sub)
269
+
270
+            if s["kind"] <> "video":
271
+                continue
272
+            for c in s["connection"]:
273
+                if c["transferFormat"] <> "hls": continue
274
+                #if not (c["supplier"].startswith("mf_") or c["supplier"].startswith("ll_")) : continue # TODO ir kaut kādas VPN problēmas ar akamaihd
275
+                #if c["priority"] <> "1": continue
276
+                url=c["href"].encode("utf8")
277
+                r2 = self._http_request(url)
278
+                if not r2: continue
279
+                slist = re.findall("#EXT-X-STREAM-INF:([^\n]+)\n([^\n]+)", r2, re.DOTALL)
280
+                if not slist:
281
+                    stream = util.item()
282
+                    stream["url"]=url
283
+                    stream["name"]=title
284
+                    stream["desc"]=desc
285
+                    stream["img"]=img
286
+                    stream["type"]="hls"
287
+                    stream["quality"]=("%s %sx%s %s,%s"%(s["bitrate"],s["width"],s["height"],c["supplier"],c["priority"])).encode("utf8")
288
+                    stream["lang"]="en"
289
+                    stream["subs"]=captions
290
+                    stream["order"]=int(s["bitrate"])
291
+                    streams.append(stream)
292
+                else:
293
+                    for cc in slist:
294
+                        m = re.search("RESOLUTION=([\dx]+)",cc[0])
295
+                        resolution = m.group(1) if m else "%sx%s"%(s["width"],s["height"])
296
+                        m = re.search("BANDWIDTH=([\d]+)",cc[0])
297
+                        bitrate = m.group(1) if m else s["bitrate"]
298
+                        url2 = cc[1].encode("utf8")
299
+                        if not url2.startswith("http"):
300
+                            uu = url.split("/")[:-1]
301
+                            uu.append(url2)
302
+                            url2 = "/".join(uu)
303
+                        stream = util.item()
304
+                        stream["url"]=url2
305
+                        stream["name"]=title
306
+                        stream["desc"]=desc
307
+                        stream["img"]=img
308
+                        stream["type"]="hls"
309
+                        stream["quality"]=("%s %s %s,%s"%(bitrate,resolution,c["supplier"],c["priority"])).encode("utf8")
310
+                        stream["lang"]="en"
311
+                        stream["subs"]=captions
312
+                        stream["order"]=int(bitrate)
313
+                        streams.append(stream)
314
+        if captions:
315
+            for s in streams:
316
+                s["subs"]=captions
317
+        streams = sorted(streams,key=lambda item: item["order"],reverse=True)
318
+        return streams
319
+
320
+    def is_video(self,data):
321
+        if "::" in data:
322
+            data = data.split("::")[1]
323
+        cmd = data.split("/")
324
+        if cmd[0]=="live" and  len(cmd)==2:
325
+            return True
326
+        elif cmd[0]=="episodes" and len(cmd)==2:
327
+            return True
328
+        else:
329
+            return False
330
+
331
+    def get_data_element(self,item):
332
+        if ("programme" in item["type"] or "group" in item["type"]) and item["count"]>1:
333
+            ep = item.copy()
334
+        elif ("programme" in item["type"] or "group" in item["type"]) and item["count"]==1:
335
+            ep = item["initial_children"][0].copy()
336
+        elif item["type"] == "episode":
337
+            ep = item.copy()
338
+        elif item["type"] == "broadcast":
339
+            ep = item["episode"].copy()
340
+        else:
341
+            ep = item.copy()
342
+        title = ep["title"]
343
+        if "subtitle" in ep and ep["subtitle"]:
344
+            title = title+". "+ ep["subtitle"]
345
+        desc = ep["synopses"]["large"] if "large" in ep["synopses"] else ep["synopses"]["medium"] if "medium" in ep["synopses"] else ep["synopses"]["small"]
346
+        #TODO papildus info pie apraksta
347
+        img = ep["images"]["standard"].replace("{recipe}","512x288") if "images" in ep else self.img
348
+        if ep["type"] == "episode":
349
+            data2 = "episodes/%s"%ep["id"]
350
+        elif "programme" in ep["type"]:
351
+            data2 = "programmes/%s/episodes?per_page=40&page=1"%ep["id"]
352
+            title = "%s [%s episodes]"%(title,ep["count"])
353
+        elif "group" in ep["type"]:
354
+            data2 = "groups/%s/episodes?per_page=40&page=1"%ep["id"]
355
+            title = "%s [%s episodes]"%(title,ep["count"])
356
+        else:
357
+            data2 = "programmes/%s/episodes?per_page=40&page=1"%ep["id"]
358
+            title = "%s [%s episodes]"%(title,ep["count"])
359
+        return title,data2,img,desc
360
+
361
+    def get_epg_video(self,vid):
362
+        data = "episodes/%s"%vid
363
+        r = self.call(data)
364
+        if "episodes" in r :
365
+            ep = r["episodes"][0]
366
+            title = ep["title"]
367
+            if "subtitle" in ep:
368
+                title = title +". "+ ep["subtitle"]
369
+            title = title
370
+            desc = ep["synopses"]["medium"] if "medium" in ep["synopses"] else p["synopses"]["small"] if "small" in ep["synopses"] else title
371
+            desc = desc
372
+            ver = ep["versions"][0]
373
+            vid = ver["id"]
374
+            remaining = ver["availability"]["remaining"]["text"]
375
+            duration = ver["duration"]
376
+            first_broadcast = ver["first_broadcast"]
377
+            desc =u"%s\n%s\%s\n%s\n%s"%(title,duration,remaining,first_broadcast,desc)
378
+            img = ep["images"]["standard"].replace("{recipe}","512x288")
379
+            return title.encode("utf8"),img.encode("utf8"),desc.encode("utf8"),vid.encode("utf8")
380
+        else:
381
+            raise Exception("No video info")
382
+
383
+    def get_epg_live(self,channelid):
384
+        data = "channels/%s/highlights?live=true"%channelid
385
+        r = self.call(data)
386
+        if "channel_highlights" in r and r["channel_highlights"]["elements"][0]["id"] == "live":
387
+            epg = r["channel_highlights"]["elements"][0]["initial_children"][0].copy()
388
+            t1 = gt(epg['scheduled_start'])
389
+            t2 = gt(epg['scheduled_end'])
390
+            ep = epg["episode"]
391
+            title = ep["title"]
392
+            if "subtitle" in ep:
393
+                title = title +". "+ ep["subtitle"]
394
+            title = "%s (%s-%s)"%(title,t1.strftime("%H:%M"),t2.strftime("%H:%M"))
395
+            title = title
396
+            desc = ep["synopses"]["medium"] if "medium" in ep["synopses"] else p["synopses"]["small"] if "small" in ep["synopses"] else title
397
+            desc = desc
398
+            desc ="%s\n%s"%(title,desc)
399
+            img = ep["images"]["standard"].replace("{recipe}","512x288")
400
+            #return title,img,desc
401
+        else:
402
+            title = r["channel_highlights"]["channel"]["title"]
403
+            img = ""
404
+            desc = title
405
+
406
+        return title.encode("utf8"),img.encode("utf8"),desc.encode("utf8")
407
+
408
+    def get_channels(self):
409
+        if self.ch:
410
+            return self.ch
411
+        r= self.call("channels")
412
+        self.ch=[]
413
+        for i,item in enumerate(r["channels"]):
414
+            self.ch.append(item)
415
+            self.ch_id[item["id"]]=i
416
+            self.ch_id2[item["master_brand_id"]]=i
417
+            self.ch_name[item["title"]]=i
418
+        return self.ch
419
+
420
+    def get_channel_by_id(self,chid):
421
+        if not self.ch:
422
+            self.get_channels()
423
+        if not self.ch:
424
+            return None
425
+        return self.ch[self.ch_id[chid]] if self.ch_id.has_key(chid) else None
426
+
427
+    def get_channel_by_id2(self,chid):
428
+        if not self.ch:
429
+            self.get_channels()
430
+        if not self.ch:
431
+            return None
432
+        return self.ch[self.ch_id2[chid]] if self.ch_id2.has_key(chid) else None
433
+
434
+    def get_channel_by_name(self,name):
435
+        if not self.ch:
436
+            self.get_channels()
437
+        ch2 = self.get_channel_by_name2(name)
438
+        if not ch2:
439
+            return None
440
+        ch = self.get_channel_by_id2(ch2["id2"])
441
+        return ch
442
+
443
+
444
+    def call(self, data,params = None, headers=None):
445
+        if not headers: headers = self.headers
446
+        #if not lang: lang = self.country
447
+        url = self.api_url + data
448
+        content = self._http_request(url,params, headers)
449
+        if content:
450
+            try:
451
+                result = json.loads(content)
452
+                return result
453
+            except Exception, ex:
454
+                return None
455
+        else:
456
+            return None
457
+
458
+    def call2(self, data,params = None, headers=None):
459
+        if not headers: headers = self.headers2
460
+        #if not lang: lang = self.country
461
+        url = self.api_url2 + data
462
+        content = self._http_request(url,params, headers)
463
+        return content
464
+
465
+    def _http_request(self, url,params = None, headers=None):
466
+        if not headers: headers = self.headers
467
+        import requests
468
+        try:
469
+            r = requests.get(url, headers=headers)
470
+            return r.content
471
+
472
+        except Exception as ex:
473
+            if ex.code==403:
474
+                return ex.read()
475
+            else:
476
+                return None
477
+
478
+def gt(dt_str):
479
+    dt, _, us= dt_str.partition(".")
480
+    dt= datetime.datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S")
481
+    dt = dt - datetime.timedelta(seconds=time.altzone)
482
+    #us= int(us.rstrip("Z"), 10)
483
+    #r = dt + datetime.timedelta(microseconds=us)a
484
+    return dt
485
+
486
+if __name__ == "__main__":
487
+    c = Source()
488
+    from subprocess import call
489
+    #ch = c.get_channels()
490
+    #c.get_epg_live("bbc_two_england")
491
+
492
+    if len(sys.argv)>1 and  not "iplayer::" in sys.argv[1]:
493
+
494
+        vid = sys.argv[1]
495
+        print "login - %s"%c.login("ivars777","xxx")
496
+        vid = "1069"
497
+        vid = "1462566072086"
498
+        channelid="101"
499
+        vid = "1350462656767"
500
+        #data = c.get_stream_url(vid,"vod")
501
+        #call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",data["stream"]])
502
+        pass
503
+
504
+
505
+
506
+    else:
507
+        if len(sys.argv)>1:
508
+            data= sys.argv[1]
509
+        else:
510
+            data = "iplayer::home"
511
+        content = c.get_content(data)
512
+        for item in content:
513
+            print item
514
+        #cat = api.get_categories(country)
515
+        #chan = api.get_channels("lv")
516
+        #prog = api.get_programs(channel=6400)
517
+        #prog = api.get_programs(category=55)
518
+        #seas = api.get_seasons(program=6453)
519
+        #str = api.get_streams(660243)
520
+        #res = api.get_videos(802)
521
+        #formats = api.getAllFormats()
522
+        #det = api.detailed("1516")
523
+        #vid = api.getVideos("13170")
524
+        pass

+ 261
- 0
resources/lib/sources/jsinterp.py Parādīt failu

@@ -0,0 +1,261 @@
1
+# This code comes from youtube-dl: https://github.com/rg3/youtube-dl/blob/master/youtube_dl/jsinterp.py
2
+
3
+from __future__ import unicode_literals
4
+
5
+import json
6
+import operator
7
+import re
8
+
9
+
10
+_OPERATORS = [
11
+    ('|', operator.or_),
12
+    ('^', operator.xor),
13
+    ('&', operator.and_),
14
+    ('>>', operator.rshift),
15
+    ('<<', operator.lshift),
16
+    ('-', operator.sub),
17
+    ('+', operator.add),
18
+    ('%', operator.mod),
19
+    ('/', operator.truediv),
20
+    ('*', operator.mul),
21
+]
22
+_ASSIGN_OPERATORS = [(op + '=', opfunc) for op, opfunc in _OPERATORS]
23
+_ASSIGN_OPERATORS.append(('=', lambda cur, right: right))
24
+
25
+_NAME_RE = r'[a-zA-Z_$][a-zA-Z_$0-9]*'
26
+
27
+
28
+class JSInterpreter(object):
29
+    def __init__(self, code, objects=None):
30
+        if objects is None:
31
+            objects = {}
32
+        self.code = code
33
+        self._functions = {}
34
+        self._objects = objects
35
+
36
+    def interpret_statement(self, stmt, local_vars, allow_recursion=100):
37
+        if allow_recursion < 0:
38
+            print '[JSInterpreter] Recursion limit reached'
39
+            return None
40
+
41
+        should_abort = False
42
+        stmt = stmt.lstrip()
43
+        stmt_m = re.match(r'var\s', stmt)
44
+        if stmt_m:
45
+            expr = stmt[len(stmt_m.group(0)):]
46
+        else:
47
+            return_m = re.match(r'return(?:\s+|$)', stmt)
48
+            if return_m:
49
+                expr = stmt[len(return_m.group(0)):]
50
+                should_abort = True
51
+            else:
52
+                # Try interpreting it as an expression
53
+                expr = stmt
54
+
55
+        v = self.interpret_expression(expr, local_vars, allow_recursion)
56
+        return v, should_abort
57
+
58
+    def interpret_expression(self, expr, local_vars, allow_recursion):
59
+        expr = expr.strip()
60
+
61
+        if expr == '':  # Empty expression
62
+            return None
63
+
64
+        if expr.startswith('('):
65
+            parens_count = 0
66
+            for m in re.finditer(r'[()]', expr):
67
+                if m.group(0) == '(':
68
+                    parens_count += 1
69
+                else:
70
+                    parens_count -= 1
71
+                    if parens_count == 0:
72
+                        sub_expr = expr[1:m.start()]
73
+                        sub_result = self.interpret_expression(
74
+                            sub_expr, local_vars, allow_recursion)
75
+                        remaining_expr = expr[m.end():].strip()
76
+                        if not remaining_expr:
77
+                            return sub_result
78
+                        else:
79
+                            expr = json.dumps(sub_result) + remaining_expr
80
+                        break
81
+            else:
82
+                print '[JSInterpreter] Premature end of parens in %r' % expr
83
+                return None
84
+
85
+        for op, opfunc in _ASSIGN_OPERATORS:
86
+            m = re.match(r'''(?x)
87
+                (?P<out>%s)(?:\[(?P<index>[^\]]+?)\])?
88
+                \s*%s
89
+                (?P<expr>.*)$''' % (_NAME_RE, re.escape(op)), expr)
90
+            if not m:
91
+                continue
92
+            right_val = self.interpret_expression(
93
+                m.group('expr'), local_vars, allow_recursion - 1)
94
+
95
+            if m.groupdict().get('index'):
96
+                lvar = local_vars[m.group('out')]
97
+                idx = self.interpret_expression(
98
+                    m.group('index'), local_vars, allow_recursion)
99
+                assert isinstance(idx, int)
100
+                cur = lvar[idx]
101
+                val = opfunc(cur, right_val)
102
+                lvar[idx] = val
103
+                return val
104
+            else:
105
+                cur = local_vars.get(m.group('out'))
106
+                val = opfunc(cur, right_val)
107
+                local_vars[m.group('out')] = val
108
+                return val
109
+
110
+        if expr.isdigit():
111
+            return int(expr)
112
+
113
+        var_m = re.match(
114
+            r'(?!if|return|true|false)(?P<name>%s)$' % _NAME_RE,
115
+            expr)
116
+        if var_m:
117
+            return local_vars[var_m.group('name')]
118
+
119
+        try:
120
+            return json.loads(expr)
121
+        except ValueError:
122
+            pass
123
+
124
+        m = re.match(
125
+            r'(?P<var>%s)\.(?P<member>[^(]+)(?:\(+(?P<args>[^()]*)\))?$' % _NAME_RE,
126
+            expr)
127
+        if m:
128
+            variable = m.group('var')
129
+            member = m.group('member')
130
+            arg_str = m.group('args')
131
+
132
+            if variable in local_vars:
133
+                obj = local_vars[variable]
134
+            else:
135
+                if variable not in self._objects:
136
+                    self._objects[variable] = self.extract_object(variable)
137
+                obj = self._objects[variable]
138
+
139
+            if arg_str is None:
140
+                # Member access
141
+                if member == 'length':
142
+                    return len(obj)
143
+                return obj[member]
144
+
145
+            assert expr.endswith(')')
146
+            # Function call
147
+            if arg_str == '':
148
+                argvals = tuple()
149
+            else:
150
+                argvals = tuple([
151
+                    self.interpret_expression(v, local_vars, allow_recursion)
152
+                    for v in arg_str.split(',')])
153
+
154
+            if member == 'split':
155
+                assert argvals == ('',)
156
+                return list(obj)
157
+            if member == 'join':
158
+                assert len(argvals) == 1
159
+                return argvals[0].join(obj)
160
+            if member == 'reverse':
161
+                assert len(argvals) == 0
162
+                obj.reverse()
163
+                return obj
164
+            if member == 'slice':
165
+                assert len(argvals) == 1
166
+                return obj[argvals[0]:]
167
+            if member == 'splice':
168
+                assert isinstance(obj, list)
169
+                index, howMany = argvals
170
+                res = []
171
+                for i in range(index, min(index + howMany, len(obj))):
172
+                    res.append(obj.pop(index))
173
+                return res
174
+
175
+            return obj[member](argvals)
176
+
177
+        m = re.match(
178
+            r'(?P<in>%s)\[(?P<idx>.+)\]$' % _NAME_RE, expr)
179
+        if m:
180
+            val = local_vars[m.group('in')]
181
+            idx = self.interpret_expression(
182
+                m.group('idx'), local_vars, allow_recursion - 1)
183
+            return val[idx]
184
+
185
+        for op, opfunc in _OPERATORS:
186
+            m = re.match(r'(?P<x>.+?)%s(?P<y>.+)' % re.escape(op), expr)
187
+            if not m:
188
+                continue
189
+            x, abort = self.interpret_statement(
190
+                m.group('x'), local_vars, allow_recursion - 1)
191
+            if abort:
192
+                print '[JSInterpreter] Premature left-side return of %s in %r' % (op, expr)
193
+                return None
194
+            y, abort = self.interpret_statement(
195
+                m.group('y'), local_vars, allow_recursion - 1)
196
+            if abort:
197
+                print '[JSInterpreter] Premature right-side return of %s in %r' % (op, expr)
198
+                return None
199
+            return opfunc(x, y)
200
+
201
+        m = re.match(
202
+            r'^(?P<func>%s)\((?P<args>[a-zA-Z0-9_$,]+)\)$' % _NAME_RE, expr)
203
+        if m:
204
+            fname = m.group('func')
205
+            argvals = tuple([
206
+                int(v) if v.isdigit() else local_vars[v]
207
+                for v in m.group('args').split(',')])
208
+            if fname not in self._functions:
209
+                self._functions[fname] = self.extract_function(fname)
210
+            return self._functions[fname](argvals)
211
+
212
+        print '[JSInterpreter] Unsupported JS expression %r' % expr
213
+        return None
214
+
215
+    def extract_object(self, objname):
216
+        obj = {}
217
+        obj_m = re.search(
218
+            (r'(?:var\s+)?%s\s*=\s*\{' % re.escape(objname)) +
219
+            r'\s*(?P<fields>([a-zA-Z$0-9]+\s*:\s*function\(.*?\)\s*\{.*?\}(?:,\s*)?)*)' +
220
+            r'\}\s*;',
221
+            self.code)
222
+        fields = obj_m.group('fields')
223
+        # Currently, it only supports function definitions
224
+        fields_m = re.finditer(
225
+            r'(?P<key>[a-zA-Z$0-9]+)\s*:\s*function'
226
+            r'\((?P<args>[a-z,]+)\){(?P<code>[^}]+)}',
227
+            fields)
228
+        for f in fields_m:
229
+            argnames = f.group('args').split(',')
230
+            obj[f.group('key')] = self.build_function(argnames, f.group('code'))
231
+
232
+        return obj
233
+
234
+    def extract_function(self, funcname):
235
+        func_m = re.search(
236
+            r'''(?x)
237
+                (?:function\s+%s|[{;,]%s\s*=\s*function|var\s+%s\s*=\s*function)\s*
238
+                \((?P<args>[^)]*)\)\s*
239
+                \{(?P<code>[^}]+)\}''' % (
240
+                re.escape(funcname), re.escape(funcname), re.escape(funcname)),
241
+            self.code)
242
+        if func_m is None:
243
+            print '[JSInterpreter] Could not find JS function %r' % funcname
244
+            return None
245
+        argnames = func_m.group('args').split(',')
246
+
247
+        return self.build_function(argnames, func_m.group('code'))
248
+
249
+    def call_function(self, funcname, *args):
250
+        f = self.extract_function(funcname)
251
+        return f(args)
252
+
253
+    def build_function(self, argnames, code):
254
+        def resf(args):
255
+            local_vars = dict(zip(argnames, args))
256
+            for stmt in code.split(';'):
257
+                res, abort = self.interpret_statement(stmt, local_vars)
258
+                if abort:
259
+                    break
260
+            return res
261
+        return resf

+ 3
- 0
resources/lib/sources/ltc.cfg Parādīt failu

@@ -0,0 +1,3 @@
1
+[ltc]
2
+user=ivars777
3
+password=kaskade7

+ 1018
- 0
resources/lib/sources/ltc.py
Failā izmaiņas netiks attēlotas, jo tās ir par lielu
Parādīt failu


+ 230
- 0
resources/lib/sources/movieplace.py Parādīt failu

@@ -0,0 +1,230 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+import urllib2, urllib
13
+import datetime, re, sys,os
14
+import ConfigParser
15
+from collections import OrderedDict
16
+from SourceBase import SourceBase
17
+import resolver
18
+try:
19
+    import util
20
+except:
21
+    sys.path.insert(0,'..')
22
+    import util
23
+
24
+
25
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
26
+import HTMLParser
27
+h = HTMLParser.HTMLParser()
28
+
29
+class Source(SourceBase):
30
+
31
+    def __init__(self, country=""):
32
+        self.name = "movieplace"
33
+        self.title = "MoviePlace.lv"
34
+        self.img = "http://movieplace.lv/images/logo.png"
35
+        self.desc = "Movieplace.lv - filmas latviesu valodā"
36
+        self.headers = headers2dict("""
37
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
38
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
39
+Accept-Language: en-US,en;q=0.5
40
+""")
41
+        self.headers2 = headers2dict("""
42
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
43
+X-Requested-With: XMLHttpRequest
44
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
45
+""")
46
+        self.url = "http://movieplace.lv/"
47
+
48
+
49
+    ######### Entry point ########
50
+    def get_content(self, data):
51
+        print "[movieplace] get_content:", data
52
+        source, data, path, plist, clist, params, qs = self.parse_data(data)
53
+        content = []
54
+        content.append(("..return", "back","","Return back"))
55
+
56
+        if clist=="home":
57
+            content.extend([
58
+                ("Meklēt", "movieplace::search/?q={0}","","Meklēt"),
59
+                ("Jaunākās filmas", "movieplace::load/?page1","","Visu žanru jaunākās filmas"),
60
+                ("Jaunākie seriāli", "movieplace::dir/?page1","","Visu žanru jaunākās filmas"),
61
+                #("Top50 filmas", "movieplace::index/top_50_filmas/0-4","","Top 50 filmas"),
62
+            ])
63
+            r = self.call("load/")
64
+            #i = r.find('<div class="cat-title">Meklēt pēc žanriem</div>')
65
+            #if i<=0:
66
+            #    return content
67
+            i = 0
68
+            for item in re.findall('<a href="/([^"]+)" class="catName">([^>]+)</a>', r[i:]):
69
+                title = item[1]
70
+                data2 = item[0]+"-1"
71
+                img = self.img
72
+                desc = title
73
+                content.append((title,self.name+"::"+data2,img,desc))
74
+            return content
75
+
76
+        elif clist=="search":
77
+            # TODO
78
+            r=self.call(data)
79
+            result = re.findall('<a href="([^"]+)"> (.+?) </a></div>.+?> (.+?)</div>', r, re.DOTALL)
80
+            for item in result:
81
+                title = item[1].replace("<b>","").replace("</b>","")
82
+                data2 = item[0].replace("http://movieplace.lv/","")
83
+                img = self.img
84
+                desc = item[2].replace("<b>","").replace("</b>","")
85
+                content.append((title,self.name+"::"+data2,img,desc))
86
+            if '<span>&raquo;</span>' in r:
87
+                m = re.search("p=(\d+)",data)
88
+                if m:
89
+                    page = int(m.group(1))+1
90
+                    data2 = re.sub(r"p=\d+", r"p=%s"%page, data)
91
+                    content.append(("Next page",self.name+"::"+data2,self.img,"Next page"))
92
+            return content
93
+
94
+        # Filmu saraksti ##
95
+        elif clist in ["load","dir"] and len(plist)<=3:
96
+            if clist == "jaunakas":
97
+                r = self.call("")
98
+            else:
99
+                r = self.call(data)
100
+            #r = r.decode("cp1251").encode("utf8")
101
+            if clist == "load":
102
+                result = re.findall(r' <a href="/([^"]+)" alt="([^"]+)"><img src="/([^"]+)" title="([^"]+)">.+?<div class="years">([^<]+)</div>\s+<div class="country">([^<]+)</div>', r, re.DOTALL)
103
+            else:
104
+                result = re.findall(r' <a href="/([^"]+)" alt="([^"]+)"><img src="/([^"]+)" title="[^"]+">.+?<span>([^<]+)</span>\s*<div class="country">([^<]+)</div>', r, re.IGNORECASE | re.DOTALL)
105
+            for item in result:
106
+                title = item[1]+" [%s]"%item[4] if clist=="load" else item[1]+" / %s [%s]"%(item[3],item[4])
107
+                img = "http://movieplace.lv/"+item[2]
108
+                data2 = item[0]
109
+                desc = "%s\n%s"%(title,item[5]) if clist=="load" else title
110
+                content.append((title,self.name+"::"+data2,img,desc))
111
+            m = re.search('<[ab] class="swchItemA*1"( href="/([^"]+)" onclick="[^"]+")*><span>([^<]+)</span></[ab]> </span>', r, re.DOTALL)
112
+            if m:
113
+                if m.group(1):
114
+                    page = int(re.search("\d+$",data).group())
115
+                    page = page+1
116
+                    data2 = re.sub("\d$","%s"%page,data)
117
+                    content.append(("Next page",self.name+"::"+data2,self.img,"Next page"))
118
+            return content
119
+
120
+        ### Seriāls ###
121
+        elif clist=="dir" and len(plist)==4:
122
+            r = self.call(path)
123
+            title0 = re.search('<h2 class="title" itemprop="name">(.+?)</h2>', r, re.DOTALL).group(1)
124
+            m = re.search(r'<span>VALODA:</span> <b><em itemprop="alternativeHeadline"><a href="[^"]*" class="entAllCats">([^<]+)</a></em></b></div>\s+?<div><span>SEZONA:</span> <b>([^<]+)</b></div>', r, re.IGNORECASE | re.DOTALL)
125
+            if m:
126
+                title0 = "%s / Season %s [%s]"%(title0,m.group(2),m.group(1))
127
+            desc0 = title0
128
+            img0 = "http://movieplace.lv" + re.search('<img src="(.+?)".+?itemprop="image">', r, re.DOTALL).group(1)
129
+            #TODO
130
+            result = re.findall(r'<summary>([^<]+)</summary><iframe src="https://openload\.co/embed/[^/]+/"', r, re.DOTALL)
131
+            i = 1
132
+            for item in result:
133
+                title = title0+" - " + item
134
+                data2 = data+"?e=%s"%i
135
+                img = img0
136
+                desc = desc0
137
+                content.append((title,self.name+"::"+data2,img,desc))
138
+                i += 1
139
+            return content
140
+
141
+        ### kaut kas neparedzets ###
142
+        else:
143
+            return content
144
+
145
+    def is_video(self,data):
146
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
147
+        if clist=="dir" and len(plist) == 4 and "e"in qs: # sērija
148
+            return True
149
+        elif clist=="load" and len(plist) == 4:
150
+            return True
151
+        else:
152
+            return False
153
+
154
+    def call(self, data,params=None,headers=None,lang=""):
155
+        if not headers: headers = self.headers
156
+        url = self.url+data
157
+        result = self._http_request(url,params,headers=headers)
158
+        return result
159
+
160
+    def get_streams(self,data):
161
+        print "[movieplace] get_streams:", data
162
+        if not self.is_video(data):
163
+            return []
164
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
165
+        r = self.call(path)
166
+        if clist=="load":
167
+            m = re.search('<h2 class="title" itemprop="name">([^<]+)</h2>', r, re.DOTALL)
168
+            title = re.search('<itemprop="name">(.+?)</itemprop="name">', r, re.DOTALL).group(1)
169
+            m = re.search(r'<div role="tabpanel" class="tab-pane fade in active" id="heading-tab4">\s*(.+?)\s*</div>', r, re.DOTALL)
170
+            desc = m.group(1) if m else title
171
+            m = re.search('<meta property="og:image" content="([^"]+)" />', r, re.DOTALL)
172
+            img = m.group(1) if m else ""
173
+            rr = []
174
+            for m in re.finditer("(RU|ENG|LAT|LAT SUB)<BR( /)*>.*?>?<BR( /)*>.*?<iframe", r, re.IGNORECASE | re.DOTALL):
175
+                if len(rr)>0:
176
+                    rr[-1]["end"] = m.start()
177
+                rr.append({"lang":m.group(1),"start":m.start(),"end":len(r)})
178
+            streams = []
179
+            for m in re.finditer(r'src="(https*://(goo\.gl|songs2dl|kodik|cdn\.kapnob|hqq|openload|sv1.servkino|vidwatch|online\.kinozz).+?)"', r, re.IGNORECASE | re.DOTALL):
180
+                url = m.group(1)
181
+                lang = "?"
182
+                for rrr in rr:
183
+                    if m.start()>rrr["start"] and m.start()<rrr["end"]:
184
+                        lang = rrr["lang"]
185
+                        break
186
+                for s in resolver.resolve(url):
187
+                    s["name"] = title
188
+                    s["desc"] = desc
189
+                    s["img"] = img
190
+                    s["type"] = self.stream_type(s["url"])
191
+                    s["lang"] = lang
192
+                    streams.append(s)
193
+            return streams
194
+
195
+
196
+        elif clist=="dir" and "e" in qs: # serialā sērija
197
+            #TODO
198
+            result = re.findall(r'<summary>([^<]+)</summary><iframe src="([^"]+)"', r, re.DOTALL)
199
+            i = int(qs["s"])-1
200
+            url0 = result[i][1]
201
+            title = title + " - " + result[i][0]
202
+        else:
203
+            #iframe src="https://openload.co/embed/wlw6Vl9zwL0/"
204
+            result = re.findall(r'<iframe src="([^"]+)"', r, re.DOTALL)
205
+            if not result:
206
+                return []
207
+            url0 = result[0]
208
+        return streams
209
+
210
+if __name__ == "__main__":
211
+    country= "lv"
212
+    c = Source(country)
213
+    if len(sys.argv)>1:
214
+        data= sys.argv[1]
215
+    else:
216
+        data = "home"
217
+    content = c.get_content(data)
218
+    for item in content:
219
+        print item
220
+    #cat = api.get_categories(country)
221
+    #chan = api.get_channels("lv")
222
+    #prog = api.get_programs(channel=6400)
223
+    #prog = api.get_programs(category=55)
224
+    #seas = api.get_seasons(program=6453)
225
+    #str = api.get_streams(660243)
226
+    #res = api.get_videos(802)
227
+    #formats = api.getAllFormats()
228
+    #det = api.detailed("1516")
229
+    #vid = api.getVideos("13170")
230
+    pass

+ 279
- 0
resources/lib/sources/mtgplay.py Parādīt failu

@@ -0,0 +1,279 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+
9
+
10
+try:
11
+    import json
12
+except:
13
+    import simplejson as json
14
+#!/usr/bin/env python
15
+# coding=utf8
16
+import urllib2, urllib
17
+import datetime, re, sys
18
+from SourceBase import SourceBase
19
+
20
+API_URL = 'http://playapi.mtgx.tv/v3/'
21
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
22
+headers0 = headers2dict("""
23
+User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
24
+""")
25
+
26
+REGIONS = [
27
+    ("Latvia",None,"lv",""),
28
+    ("Estonia",None,"ee",""),
29
+    ("Lituania",None,"lt",""),
30
+    ("Sweden",None,"se",""),
31
+    ("Denmark",None,"dk",""),
32
+    ("Norway",None,"no",""),
33
+    ("Bulgaria",None,"bg","")
34
+]
35
+
36
+
37
+class Source(SourceBase):
38
+    
39
+    def __init__(self,country="lv"):
40
+        self.name = "mtgplay"
41
+        self.title = "Skaties.lv (TV3)"
42
+        self.img = "http://skaties.lv/touch-icon-192x192.png"
43
+        self.desc = "MTG skaties.lv satura skatīšanās (LNT,TV3, TV6 u.c.)"
44
+        
45
+        self.country=country
46
+        self.pic_size = "327x250" #"1000x765"
47
+        
48
+    def get_content(self, data):
49
+        print "[mtgplay] get_content:", data
50
+        if "::" in data:
51
+            data = data.split("::")[1]        
52
+        if "/" in data:
53
+            citem,cid = data.split("/")
54
+            clist = ""
55
+        else:
56
+            clist = data.split("?")[0]
57
+            qs = dict(map(lambda x:x.split("="),re.findall("\w+=\w+",data)))
58
+            citem,cid = ("","")
59
+            self.country = qs["country"] if "country" in qs else "lv"
60
+        
61
+        content=[]
62
+        content.append(("..return", "back","","Return back"))
63
+        
64
+        if clist=="home":
65
+            content.extend([
66
+                #("Search", "mtgplay::meklet?country=%s&term={0}"%self.country,"","Search videos"), ### TODO                
67
+                ("TV Live", "mtgplay::videos?country=%s&order=title&type=live"%self.country,"","TV live streams(not always available)"),
68
+                ("Last videos", "mtgplay::videos?country=%s&order=-airdate"%self.country,"","Last aired videos"),
69
+                ("Categories", "mtgplay::categories?country=%s&order=name"%self.country,"","Categories"),
70
+                ("Channels", "mtgplay::channels?country=%s&order=id"%self.country,"","TV channels"),
71
+                ("Programs by name", "mtgplay::formats?country=%s&order=-title"%self.country,"","Programs by name"),             
72
+                ("Programs by popularity", "mtgplay::formats?country=%s&order=-popularity"%self.country,"","Programs by popularity")             
73
+            ])
74
+            return content
75
+        
76
+        r = self.call(data)
77
+        if not r:
78
+            content.append(("Error", "","","Error reading '%s'"%data))
79
+            return content
80
+        
81
+        if clist:
82
+            if r["_links"].has_key("prev"):
83
+                data2 = r["_links"]["prev"]["href"].replace(API_URL,"")
84
+                content.append(("Previous page", self.name+"::"+data2.encode("utf8"),"", "Goto previous page"))
85
+                
86
+            if "_embedded" in r:
87
+                for item in r["_embedded"][clist]:
88
+                    if "title" in item:
89
+                        title = item["title"]
90
+                    elif "name" in item:
91
+                        title = item["name"]
92
+                    #data2 = self.name+"::"+"%s/%s"%(clist,item["id"]) 
93
+                    img = item["_links"]["image"]["href"].replace("{size}",self.pic_size) if "image" in item["_links"] else ""
94
+                    desc = item["summary"] if "summary" in item and item["summary"] else ""
95
+                    
96
+                    ### Video ###
97
+                    if clist=="videos":
98
+                        data2 = "videos/%s"%item["id"]                            
99
+                        summary = item["summary"] if item["summary"] else ""
100
+                        air_at = item["broadcasts"][0]["air_at"] if "broadcasts" in item and len(item["broadcasts"])>0 and "air_at" in item["broadcasts"][0] else ""
101
+                        if not air_at:
102
+                            air_at = item["publish_at"] if "publish_at" in item else ""
103
+                        air_at = air_at[0:16].replace("T"," ") if air_at else ""
104
+                        try: playable_to = item["broadcasts"][0]["playable_to"]
105
+                        except: playable_to =""
106
+                        playable_to = "(till "+playable_to[0:10].replace("T"," ")+")" if playable_to else ""
107
+                        duration = item["duration"] if "duration" in item else ""
108
+                        duration = str(datetime.timedelta(seconds=int(duration))) if duration else ""
109
+                        try:
110
+                            views = item["views"]["total"] if "views" in item and "total" in item["views"] else ""
111
+                            views = views+" views"
112
+                        except: views = ""
113
+                        desc = "Aired: %s %s\nDuration: %s %s\n\n%s"%(air_at, playable_to,duration,views,summary)
114
+                        
115
+                    ### Categories ###     
116
+                    elif clist == "categories":
117
+                        #data2 = item["_links"]["formats"]["href"].replace(API_URL,"")
118
+                        data2 = "formats?category=%s"%item["id"]
119
+                        if "country" in qs: data2 += "&country="+qs["country"]
120
+                        if "category" in qs: data2 += "&category="+qs["category"]
121
+                        if "channel" in qs: data2 += "&channel="+qs["channel"]
122
+                        data2 += "&order=title"
123
+                        
124
+                    ### Channels ###     
125
+                    elif clist == "channels":
126
+                        #data2 = item["_links"]["categories"]["href"].replace(API_URL,"")
127
+                        data2 = "categories?channel=%s"%item["id"]
128
+                        if "country" in qs: data2 += "&country="+qs["country"]
129
+                        if "category" in qs: data2 += "&category="+qs["category"]
130
+                        if "channel" in qs: data2 += "&channel="+qs["channel"]
131
+                        data2 += "&order=name"
132
+                        
133
+                    ### Formats (programs) ###     
134
+                    elif clist == "formats":
135
+                        #data2 = item["_links"]["videos"]["href"].replace(API_URL,"")
136
+                        data2 = "seasons?format=%s"%item["id"]
137
+                        #if "country" in qs: data2 += "&country="+qs["country"]
138
+                        #if "category" in qs: data2 += "&category="+qs["category"]
139
+                        #if "channel" in qs: data2 += "&channel="+qs["channel"]
140
+                        data2 += "&order=title"
141
+                        air_at = item["latest_video"]["publish_at"] if "publish_at" in item["latest_video"] else ""
142
+                        air_at = air_at[0:16].replace("T"," ") if air_at else ""
143
+                        if air_at:
144
+                            desc = "Last video: %s\n"%air_at + desc                        
145
+                        
146
+                    ### Seasons ###     
147
+                    elif clist == "seasons":
148
+                        #data2 = item["_links"]["videos"]["href"].replace(API_URL,"")
149
+                        data2 = "videos?season=%s"%item["id"]
150
+                        #if "country" in qs: data2 += "&country="+qs["country"]
151
+                        #if "category" in qs: data2 += "&category="+qs["category"]
152
+                        #if "channel" in qs: data2 += "&channel="+qs["channel"]
153
+                        data2 += "&order=title"
154
+                        
155
+                        summary = item["summary"] if "summary" in item and item["summary"] else ""
156
+                        try:
157
+                            latest_video = item["latest_video"]["publish_at"]
158
+                            latest_video = latest_video[0:16].replace("T"," ")
159
+                        except: latest_video = ""
160
+                        desc = ("%s\nLatest video: %s"%(summary,latest_video))
161
+                                      
162
+                    content.append((title.encode("utf8"),self.name+"::"+data2.encode("utf8"),img.encode("utf8"),desc.encode("utf8")))
163
+                    
164
+            if r["_links"].has_key("next"):
165
+                data2 = r["_links"]["next"]["href"].replace(API_URL,"").encode("utf8")
166
+                content.append(("Next page", self.name+"::"+data2.encode("utf8"),"","Goto next page"))
167
+                
168
+        elif citem:
169
+            item = r
170
+            if "title" in item:
171
+                title = item["title"]
172
+            elif "name" in item:
173
+                title = r["name"]
174
+            #data2 = self.name+"::"+"%s/%s"%(clist,item["id"]) 
175
+            img = item["_links"]["image"]["href"].replace("{size}",self.pic_size) if "image" in item["_links"] else ""
176
+            desc = item["summary"] if "summary" in item and item["summary"] else ""
177
+            
178
+            dd = "videos/stream/%s"%cid
179
+            r2 = self.call(dd)
180
+            if "streams" in r2 and "hls" in r2["streams"]:
181
+                data2 = r2["streams"]["hls"]
182
+                content = (title.encode("utf8"),data2.encode("utf8"),img.encode("utf8"),desc.encode("utf8"))
183
+            elif "msg" in r2:
184
+                content = (r2["msg"].encode("utf8"),"","","")
185
+            else: 
186
+                content = ("Error getting stream","","","")            
187
+            
188
+        else:
189
+            pass
190
+        return content
191
+    
192
+    def is_video(self,data):
193
+        if "::" in data:
194
+            data = data.split("::")[1]
195
+        cmd = data.split("/")
196
+        if cmd[0]=="videos":
197
+            return True
198
+        else:
199
+            return False
200
+    
201
+    def get_stream(self,id):   
202
+        dd = "videos/stream/%s"%id
203
+        r2 = self.call(dd)
204
+        if "streams" in r2 and "hls" in r2["streams"]:
205
+            data2 = r2["streams"]["hls"]
206
+        else:
207
+            data2 = ""
208
+        return data2.encode("utf8")
209
+        
210
+    def call_all(self, endpoint, params = None):
211
+        url = API_URL % (endpoint)
212
+        if params:
213
+            url += '?' + params
214
+        print "[TVPlay Api] url: ",url
215
+        result = []
216
+        while True:
217
+            content = self._http_request(url)
218
+            if content:
219
+                try:
220
+                    content = json.loads(content)
221
+                except Exception, ex:
222
+                    return {" Error " : "in call_api: %s" % ex}
223
+            else: break
224
+            if content.has_key("_embedded") and content["_embedded"].has_key(endpoint):
225
+                result.extend(content["_embedded"][endpoint])
226
+                pass
227
+            else: break
228
+            if content.has_key("_links") and content["_links"].has_key("next"):
229
+                url = content["_links"]["next"]["href"]
230
+            else: break
231
+        return result
232
+    
233
+    def call(self, data,headers=headers0):
234
+        url = API_URL + data
235
+        #print "[TVPlay Api] url: ",url
236
+        result = []
237
+        content = self._http_request(url)
238
+        if content:
239
+            try:
240
+                result = json.loads(content)
241
+            except Exception, ex:
242
+                return None
243
+        return result
244
+
245
+    def _http_request0(self, url,headers=headers0):
246
+        try:
247
+            r = urllib2.Request(url, headers=headers)
248
+            u = urllib2.urlopen(r)
249
+            content = u.read()
250
+            u.close()
251
+            return content
252
+        except Exception as ex:
253
+            if "read" in ex:
254
+                content = ex.read()
255
+            else:
256
+                content = None
257
+            return content
258
+
259
+if __name__ == "__main__":
260
+    country= "lv"
261
+    c = Source(country)
262
+    if len(sys.argv)>1:
263
+        data= sys.argv[1]
264
+    else:
265
+        data = "home"
266
+    content = c.get_content(data)
267
+    for item in content:
268
+        print item
269
+    #cat = api.get_categories(country)
270
+    #chan = api.get_channels("lv")
271
+    #prog = api.get_programs(channel=6400)
272
+    #prog = api.get_programs(category=55)
273
+    #seas = api.get_seasons(program=6453)
274
+    #str = api.get_streams(660243)
275
+    #res = api.get_videos(802)
276
+    #formats = api.getAllFormats()
277
+    #det = api.detailed("1516")
278
+    #vid = api.getVideos("13170")
279
+    pass

+ 212
- 0
resources/lib/sources/play24.py Parādīt failu

@@ -0,0 +1,212 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import urllib2, urllib
14
+import datetime, re, sys
15
+from SourceBase import SourceBase
16
+
17
+API_URL = 'http://replay.lsm.lv/'
18
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
19
+headers0 = headers2dict("""
20
+User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
21
+""")
22
+import HTMLParser
23
+h = HTMLParser.HTMLParser()
24
+    
25
+class Source(SourceBase):
26
+    
27
+    def __init__(self,country="lv"):
28
+        self.name = "play24"
29
+        self.title = "Play24.lv"
30
+        self.img = "http://play24.lv/images/play24-logo-black.png"
31
+        self.desc = "play24.lv (Riga24TV) satura skatīšanās"
32
+        
33
+        self.country=country
34
+        
35
+    def get_content(self, data):
36
+        print "[play24] get_content:", data
37
+        if "::" in data:
38
+            data = data.split("::")[1] 
39
+        path = data.split("?")[0]
40
+        clist = path.split("/")[0]
41
+        params = data[data.find("?"):] if "?" in data else ""
42
+        qs = dict(map(lambda x:x.split("="),re.findall("\w+=\w+",params)))
43
+        lang = qs["lang"] if "lang" in qs else self.country
44
+    
45
+        content=[]
46
+        content.append(("..return", "back","","Return back"))
47
+        
48
+        if clist=="home":
49
+            content.extend([
50
+                ("Live stream", "play24::tiesraide","","TV live streams"),
51
+                ("Last videos", "play24::jaunakie","","Last videos"),
52
+                ("Categories", "play24::kategorijas","","Categories"),
53
+                ("Programs", "play24::raidijumi","","Programs"),             
54
+             ])
55
+            return content
56
+  
57
+        ### Jaunākie video ###
58
+        elif clist=="jaunakie":
59
+            url = "http://play24.lv/"
60
+            r = self._http_request(url)
61
+            for item in re.findall(' <div class="top-article__image">.*?<a class="top-article__image-link" href="([^"]+)">.*?<img.+?src="([^"]+)".+?alt="([^"]+)" />.+?</picture>', r, re.DOTALL):
62
+                title = item[2]
63
+                title =  h.unescape(title.decode("utf8")).encode("utf8")
64
+                img = item[1]
65
+                data2 = item[0].replace("http://play24.lv/","")
66
+                desc = title
67
+                content.append((title,self.name+"::"+data2,img,desc))
68
+            return content
69
+                
70
+        ### Kategorijas ###
71
+        elif clist=="kategorijas":
72
+            url = "http://play24.lv/"
73
+            r = self._http_request(url)
74
+            r2 = r[r.find('<div class="footer-navigation">'):]
75
+            for item in re.findall('<a href="http://play24.lv/(kategorija/[^"]+)" class="navigation__link">([^<]+)</a>', r2, re.DOTALL):
76
+                title = item[1]
77
+                data2 = item[0]
78
+                img = ""
79
+                desc = title
80
+                content.append((title,self.name+"::"+data2,img,desc))
81
+            return content
82
+       
83
+        elif clist=="kategorija":
84
+            url = "http://play24.lv/"+data
85
+            r = self._http_request(url)
86
+            for article in re.findall(r"<article\b[^>]*>(.+?)</article>", r, re.DOTALL):
87
+                m = re.search('<a class="masonry-item__link" href="http://play24\.lv/([^"]+)">', article, re.DOTALL)
88
+                data2 = m.group(1) if m else ""
89
+                m = re.search('<img src="([^"]+)" alt="([^"]+)" />', article, re.DOTALL)
90
+                if m:
91
+                    img = m.group(1)
92
+                    title = m.group(2)
93
+                    title =  h.unescape(title.decode("utf8")).encode("utf8")
94
+                else:
95
+                    img = ""
96
+                    title = ""
97
+                m = re.search(r'<span class="masonry-item__tags">\s+<a href="([^"]+)">([^<]+)</a>.*?</span>', article, re.DOTALL)
98
+                progr = m.group(2) if m else ""
99
+                m = re.search('<span class="masonry-item__date">([^<]+)</span>', article, re.DOTALL)
100
+                date = m.group(1).strip() if m else ""
101
+                         
102
+                if date:
103
+                    title = title + " (%s %s)"%(date,progr)
104
+                desc = title + "\n%s - %s"%(progr,date)
105
+                content.append((title,self.name+"::"+data2,img,desc))
106
+            m = re.search(r'<li><a href="http://play24\.lv/([^"]+)" rel="next">&raquo;</a></li>', r, re.DOTALL)
107
+            if m:
108
+                data2 = m.group(1)
109
+                content.append(("Next page",self.name+"::"+data2,"","Next page"))                                            
110
+            return content
111
+        
112
+        ### Raidijumi (programmas)
113
+        elif clist=="raidijumi":
114
+            url = "http://play24.lv/"
115
+            r = self._http_request(url)
116
+            for item in re.findall(r'<li class="tag-box__item">.*?<a href="http://play24\.lv/(birka/[^"]+)">([^<]+)</a>.*?</li>', r, re.DOTALL):
117
+                title = item[1]
118
+                title =  h.unescape(title.decode("utf8")).encode("utf8")
119
+                data2 = item[0]
120
+                img = ""
121
+                desc = title
122
+                content.append((title,self.name+"::"+data2,img,desc))
123
+            return content
124
+
125
+        ### Programmas (video saraksts)
126
+        elif clist=="birka":
127
+            url = "http://play24.lv/"+data
128
+            r = self._http_request(url)
129
+            for item in re.findall(r'<article\b[^>]*>.+?<a class="masonry-item__link" href="http://play24.lv/([^"]+)">.*?<img src="([^"]+)" alt="([^"]+)" />.*?<span class="masonry-item__tags">.+?<a href="([^"]+)">([^<]+)</a>.*?<span class="masonry-item__date">([^<]+)</span>.*?</article>', r, re.DOTALL):
130
+                title = item[2]
131
+                title =  h.unescape(title.decode("utf8")).encode("utf8")
132
+                title = title + " (%s)"%item[5].strip()
133
+                img = item[1]
134
+                data2 = item[0]
135
+                desc = title + "\n%s - %s"%(item[4],item[5].strip())
136
+                content.append((title,self.name+"::"+data2,img,desc))
137
+            m = re.search(r'<li><a href="http://play24\.lv/([^"]+)" rel="next">&raquo;</a></li>', r, re.DOTALL)
138
+            if m:
139
+                data2 = m.group(1)
140
+                content.append(("Next page",self.name+"::"+data2,"","Next page"))                                            
141
+            return content
142
+
143
+        elif clist == "video" or clist == "tiesraide":
144
+            if clist == "video":  
145
+                url = "http://play24.lv/"+data
146
+                r = self._http_request(url)
147
+                # var ov_video_id = '59422';
148
+                m = re.search(r"var ov_video_id = '(\d+)';", r, re.DOTALL)
149
+                if m:
150
+                    id = m.group(1)
151
+                else:
152
+                    return ("No stream found %s"%data,"","","No stream found")
153
+                m = re.search('<meta name="description" content="([^"]+)" />', r, re.DOTALL)
154
+                desc = m.group(1) if m else ""
155
+                desc = h.unescape(desc.decode("utf8")).encode("utf8")
156
+                
157
+                url = "http://player.tvnet.lv/v/%s"%id
158
+            else:
159
+                url = "http://player.tvnet.lv/l/11"
160
+                desc = ""
161
+            r = self._http_request(url)
162
+            m = re.search('<h1 class="static title">.+?<a href="[^"]+">([^<]+)</a>', r, re.DOTALL)
163
+            title = m.group(1) if m else ""   
164
+            s = {}
165
+            for item in re.findall('source src="([^"]+)" data-stream="([^"]+)" data-quality="([^"]+)"', r, re.DOTALL):
166
+                s[item[1]] = (item[0],item[2])
167
+            data2 = ""
168
+            for t in ("hls","http","rtmp"):
169
+                if t in s:
170
+                    data2 = s[t][0]
171
+                    break
172
+            return (title,data2,"",desc)
173
+               
174
+    
175
+    def is_video(self,data):
176
+        if "::" in data:
177
+            data = data.split("::")[1]
178
+        cmd = data.split("/")
179
+        if cmd[0] in ("video","tiesraide"):
180
+            return True
181
+        else:
182
+            return False
183
+    
184
+    def call(self, data,headers=headers0,lang=""):
185
+        if not lang: lang = self.country
186
+        url = API_URL%lang + data
187
+        #print "[TVPlay Api] url: ",url
188
+        result = []
189
+        content = self._http_request(url)
190
+        return content
191
+
192
+if __name__ == "__main__":
193
+    country= "lv"
194
+    c = Source(country)
195
+    if len(sys.argv)>1:
196
+        data= sys.argv[1]
197
+    else:
198
+        data = "home"
199
+    content = c.get_content(data)
200
+    for item in content:
201
+        print item
202
+    #cat = api.get_categories(country)
203
+    #chan = api.get_channels("lv")
204
+    #prog = api.get_programs(channel=6400)
205
+    #prog = api.get_programs(category=55)
206
+    #seas = api.get_seasons(program=6453)
207
+    #str = api.get_streams(660243)
208
+    #res = api.get_videos(802)
209
+    #formats = api.getAllFormats()
210
+    #det = api.detailed("1516")
211
+    #vid = api.getVideos("13170")
212
+    pass

+ 305
- 0
resources/lib/sources/replay.py Parādīt failu

@@ -0,0 +1,305 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import urllib2, urllib
14
+import datetime, re, sys
15
+from SourceBase import SourceBase
16
+import util
17
+
18
+API_URL = 'http://replay.lsm.lv/%s/'
19
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
20
+headers0 = headers2dict("""
21
+User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
22
+""")
23
+import HTMLParser
24
+h = HTMLParser.HTMLParser()
25
+from YouTubeVideoUrl import YouTubeVideoUrl
26
+
27
+class Source(SourceBase):
28
+
29
+    def __init__(self,country="lv"):
30
+        self.name = "replay"
31
+        self.title = "Replay.lv (LTV)"
32
+        self.img = "http://replay.lsm.lv/apple-touch-icon.png"
33
+        self.desc = "LSM replay.lv satura skatīšanās"
34
+
35
+        self.country=country
36
+        self.pic_size = "327x250" #"1000x765"
37
+
38
+    def get_content(self, data):
39
+        print "[replay] get_content:", data
40
+        if "::" in data:
41
+            data = data.split("::")[1]
42
+        path = data.split("?")[0]
43
+        clist = path.split("/")[0]
44
+        params = data[data.find("?"):] if "?" in data else ""
45
+        qs = dict(map(lambda x:x.split("="),re.findall("\w+=\w+",params)))
46
+        lang = qs["lang"] if "lang" in qs else self.country
47
+
48
+        content=[]
49
+        content.append(("..return", "back","","Return back"))
50
+
51
+        if clist=="home":
52
+            content.extend([
53
+                ("Live streams", "replay::tiesraide","","TV live streams"),
54
+                ("Search LV", "replay::search/?term={0}&lang=lv","","Search content LV"),
55
+                ("Last videos LV", "replay::visi/jaunakie/?source=ltv&lang=lv","","Last aired videos LV"),
56
+                ("Last videos by categories LV", "replay::kategorijas/?lang=lv","","Last videos by categories LV"),
57
+                ("All programs LV", "replay::raidijumi/?type=video","","All programs by name LV"),
58
+                ("Programs by categories LV", "replay::categories?lang=lv","","All programs by categories LV"),
59
+                #("Channels", "replay::channels?language=%s"%self.country,"","TV channels"),
60
+                ("Videos by popularity LV", "replay::visi/popularie/?source=ltv&lang=lv","","Programs by popularity"),
61
+
62
+                ("Search RU", "replay::search/?term={0}&lang=ru","","Search content RU"),
63
+                ("Last videos RU", "replay::vse/novie/?source=ltv&lang=ru","","Last aired videos RU"),
64
+                ("Last videos by categories RU", "replay::kategorijas/?lang=ru","","Last videos by categories RU"),
65
+                ("All programs RU", "replay::peredachi/?lang=ru&type=video","","All programs by name"),
66
+                ("Programs by categories RU", "replay::categories?lang=ru","","Programs by categories RU")
67
+            ])
68
+            return content
69
+
70
+        ### programmu kategorijas ###
71
+        elif clist=="categories":
72
+            url = "http://replay.lsm.lv/lv/raidijumi/?lang=lv&type=video" if lang =="lv" else "http://replay.lsm.lv/ru/peredachi/?lang=ru&type=video"
73
+            r = self._http_request(url)
74
+            for item in re.findall(r'<a .+href="(\?lang=\w+&type=video&theme=\d+)">([^<]+)</a>\t', r):
75
+                title = item[1]
76
+                data2 = url.split("?")[0]+item[0]
77
+                data2 = data2.replace(API_URL%lang,"")
78
+                img = ""
79
+                desc = title
80
+                content.append((title,self.name+"::"+data2,img,desc))
81
+            return content
82
+
83
+        ### jaunāko raidijumu kategorijas ###
84
+        elif clist=="kategorijas":
85
+            url = "http://replay.lsm.lv/lv/" if lang =="lv" else "http://replay.lsm.lv/ru/"
86
+            r = self._http_request(url)
87
+            for item in re.findall(r'<a href="/(lv|ru)/kategorija/(\w+)/">.+?<i class="[^"]+"></i>.+?<span>([^<]+)</span>', r, re.DOTALL):
88
+                title = item[2]
89
+                data2 = "kategorija/%s/?lang=%s"%(item[1],item[0])
90
+                img = ""
91
+                desc = title
92
+                content.append((title,self.name+"::"+data2,img,desc))
93
+            return content
94
+
95
+        ### Tiešraides kanānālu saraksts
96
+        elif path=="tiesraide":
97
+            url = "http://replay.lsm.lv/styles/main.css"
98
+            r= self._http_request(url)
99
+            for item in re.findall(r'channel-logo--(\w+)\{background-image:url\("([^"]+\.png)"', r):
100
+                ch = item[0]
101
+                title = ch.upper()
102
+                data2 = "tiesraide/%s/"%ch
103
+                img = "http://replay.lsm.lv"+item[1]
104
+                veids = "video "if "tv" in ch else "audio"
105
+                desc = title+" tiesraide (%s)"%veids
106
+                content.append((title,self.name+"::"+data2,img,desc))
107
+            return content
108
+
109
+        ### Kanāla tiesraide
110
+        elif clist == "tiesraide" and "/" in data:
111
+            ch = data.split('/')[1]
112
+            veids = "video" if "tv" in ch else "audio"
113
+            #url = "http://replay.lsm.lv/lv/tiesraide/ltv7/"
114
+            url = "http://replay.lsm.lv/lv/tiesraide/%s/"%ch
115
+            r= self._http_request(url)
116
+
117
+            m = re.search('%s/">.+?<h5>([^<]+)+</h5>.*?<time>([^<]+)</time>'%ch, r, re.DOTALL)
118
+            tagad = m.group(1).strip() if m else ""
119
+            laiks = m.group(2).strip() if m else ""
120
+            laiks = h.unescape(laiks).encode("utf8")
121
+            m = re.search("<h1>([^<]+)</h1>", r)
122
+            title = m.group(1).strip() if m else path.split("/")[1].upper()
123
+            title = "%s - %s (%s)"%(title,tagad,laiks)
124
+
125
+            if veids == "video":
126
+                m = re.search('<div class="video"><iframe.+src="([^"]+)"', r)
127
+                if not m:
128
+                    content=("No stream found %s"%data,"","","No stream found")
129
+                    return content
130
+                url = m.group(1)
131
+                headers = headers2dict("""
132
+            User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
133
+            Referer: http://replay.lsm.lv/lv/ieraksts/ltv/70398/tiesa-runa.-lielbritanija-gatavojas-referendumam-par-tu/
134
+                    """)
135
+                r = self._http_request(url,headers=headers)
136
+
137
+                m = re.search('<div class="video-player"><iframe.+src="([^"]+)"', r)
138
+                if not m:
139
+                    content=("No stream found %s"%data,"","","No stream found")
140
+                    return content
141
+                url = m.group(1)
142
+
143
+                r = self._http_request(url,headers=headers)
144
+                m = re.search('"([^"]+m3u8[^"]+)"', r)
145
+                if not m:
146
+                    content=("No stream found %s"%data,"","","No stream found")
147
+                    return content
148
+                data2 = m.group(1).replace("\\","")
149
+
150
+            else: # audio
151
+                lrn = ch.replace("lr","")
152
+                url = "http://www.latvijasradio.lsm.lv/lv/tiesraide/?channel=%s"%lrn
153
+                r = self._http_request(url)
154
+                m = re.search('"file":"([^"]+?m3u8.*?)"', r)
155
+                if not m:
156
+                    content=("No stream found %s"%data,"","","No stream found")
157
+                    return content
158
+                data2 = m.group(1).replace("\\","")
159
+
160
+            img = ""
161
+            desc = ""
162
+            content =(title,data2,img,desc)
163
+            return content
164
+
165
+        #m = re.search(r'(\?page=\d+)" class=" paging__prev', r, re.IGNORECASE)
166
+        #if m:
167
+        #    data = re.sub("\?page=\d+", "", data)
168
+        #    data2 = data+m.group(1)
169
+        #    content.append(("Previous page",self.name+"::"+data2,"","Previous page"))
170
+
171
+        r = self.call(data, lang=lang)
172
+        if not r:
173
+            return content
174
+
175
+        if clist == "search":
176
+            #for r2 in re.findall('<article itemtype="http://schema.org/Article" itemscope class="thumbnail thumbnail--default ">(.+?)</article>', r2, re.DOTALL):
177
+            for item in re.findall('itemprop="image" data-image="([^"]+)".+?<figcaption><h5 itemprop="name"><a itemprop="url" href="([^<]+)">([^<]+)</a></h5></figcaption>', r):
178
+                title = item[2]
179
+                data2 = item[1].replace("/%s/"%lang,"")+"?lang=%s"%lang
180
+                img = "http://replay.lsm.lv" + item[0]
181
+                desc  = title
182
+                content.append((title,self.name+"::"+data2,img,desc))
183
+
184
+            #for item in re.findall('itemprop="image" data-image="([^"]+)".+?<figcaption><h4 itemprop="about"><a href="([^"]+)">([^<]+)</a></h4>.*?<h5 itemprop="name"><a itemprop="url" href="([^"]+)">([^<]+)</a></h5>.+?datetime="([^"]+)" class="thumbnail__date ">([^<]+)</time>', r2):
185
+            for item in re.findall('itemprop="image" data-image="([^"]+)".+? class="icon-(ltv|lr).+?<figcaption><h4 itemprop="about"><a href="([^"]+)">([^<]+)</a></h4>.*?<h5 itemprop="name"><a itemprop="url" href="([^"]+)">([^<]+)</a></h5>.+?datetime="([^"]+)" class="thumbnail__date ">([^<]+)</time>', r):
186
+                if item[1]=="lr":continue
187
+                title = "%s - %s (%s)"%(item[3],item[5],item[7])
188
+                data2 = item[4].replace("/%s/"%lang,"")+"?lang=%s"%lang
189
+                img = item[0].replace("https:","http:")
190
+                desc = title
191
+                content.append((title,self.name+"::"+data2,img,desc))
192
+
193
+        ### Raidijumi (programmas) ###
194
+        elif clist in ( "raidijumi","peredachi"):
195
+            for item in re.findall('<li itemprop="name"><a href="([^"]+)" itemprop="url">([^<]+)', r):
196
+            #for item in re.findall('<li itemprop="name"><a href="([^"]+)" itemprop="url">([^<]+)</a></li>', r):
197
+                title = item[1]
198
+                data2 = item[0].replace("/%s/"%lang,"")+"?lang=%s"%lang
199
+                img = ""
200
+                desc  = ""
201
+                content.append((title,self.name+"::"+data2,img,desc))
202
+
203
+        ### Raidijuma ieraksti speciālie###
204
+        elif clist in ( "visi","vse",):
205
+            for item in re.findall('(?i)<figure><a href="([^"]+)" itemprop="image" data-image="([^"]+)".+class="thumbnail__duration">([^<]+)</time></figure><figcaption><h4 itemprop="about"><a href="[^"]+">([^<]+)</a></h4>.+>([^<]+).*</h5>.+>([^<]+)</time></figcaption>', r):
206
+                title = item[3]
207
+                data2 = item[0].replace("/%s/"%lang,"")+"?lang=%s"%lang
208
+                img = item[1].replace("https:","http:")
209
+                desc  = "%s - %s\n%s"%(item[5],item[2],item[4])
210
+                content.append((title,self.name+"::"+data2,img,desc))
211
+
212
+        ### Raidijuma ieraksti (videos)
213
+        elif clist in ("raidijums","peredacha","kategorija"):
214
+            for item in re.findall('<article .+ href="([^"]+)".+image="([^"]+)".+class="thumbnail__duration">([^<]+).+">([^<]+).+class="thumbnail__date ">([^"]+)</time></figcaption></article>', r):
215
+                title = item[3]
216
+                data2 = item[0].replace("/%s/"%lang,"")+"?lang=%s"%lang
217
+                img = item[1].replace("https:","http:")
218
+                desc = "%s - %s"%(item[4],item[2])
219
+                content.append((title,self.name+"::"+data2,img,desc))
220
+
221
+        ### Ieraksts (video) ###
222
+        elif clist in ("ieraksts","statja"):
223
+            m = re.search('src="([^"]+)"></iframe>', r)
224
+            if m:
225
+                url2 = m.group(1)
226
+                headers = headers2dict("""
227
+User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
228
+Referer: http://replay.lsm.lv/lv/ieraksts/ltv/70398/tiesa-runa.-lielbritanija-gatavojas-referendumam-par-tu/
229
+            """)
230
+                r2 = self._http_request(url2,headers=headers)
231
+                m = re.search('"file":"([^"]+)', r2)
232
+                if m:
233
+                    data2 = m.group(1).replace("\\","")
234
+                    m = re.search('"idstring":"([^"]+)', r2)
235
+                    title = m.group(1) if m else ""
236
+                    title = title.decode("unicode-escape").encode("utf8")
237
+                    title = title.replace("\n","")
238
+                    img = ""
239
+                    desc = ""
240
+                    if "youtube" in data2:
241
+                        video_id = re.search(r"/watch\?v=([^&]+)",data2).group(1)
242
+                        data2 = YouTubeVideoUrl().extract(video_id)
243
+                        if not data2:
244
+                            content=("No stream found %s"%data,"","","No stream found")
245
+                            return content
246
+                    content =(title,data2,img,desc)
247
+                    return content
248
+            content=("No stream found %s"%data,"","","No stream found")
249
+            return content
250
+
251
+        m = re.search(r'href="\?([^"]+)" class=" paging__next', r)
252
+        if m:
253
+            page = int(re.search("page=(\d+)",m.group(1)).group(1))
254
+            if "page="in data:
255
+                data2 = re.sub("page=\d+","page=%i"%page,data)
256
+            else:
257
+                if "?" in data:
258
+                    data2 =data+"&page=%i"%page
259
+                else:
260
+                    data2 =data+"?page=%i"%page
261
+            content.append(("Next page",self.name+"::"+data2,"","Next page"))
262
+
263
+        return content
264
+
265
+    def is_video(self,data):
266
+        if "::" in data:
267
+            data = data.split("::")[1]
268
+        cmd = data.split("/")
269
+        if cmd[0] in ("ieraksts","statja"):
270
+            return True
271
+        elif cmd[0]=="tiesraide" and len(cmd)>1:
272
+            return True
273
+        else:
274
+            return False
275
+
276
+    def call(self, data,headers=headers0,lang=""):
277
+        if not lang: lang = self.country
278
+        url = API_URL%lang + data
279
+        #print "[TVPlay Api] url: ",url
280
+        result = []
281
+        content = self._http_request(url,headers=headers0)
282
+        return content
283
+
284
+
285
+if __name__ == "__main__":
286
+    country= "lv"
287
+    c = Source(country)
288
+    if len(sys.argv)>1:
289
+        data= sys.argv[1]
290
+    else:
291
+        data = "home"
292
+    content = c.get_content(data)
293
+    for item in content:
294
+        print item
295
+    #cat = api.get_categories(country)
296
+    #chan = api.get_channels("lv")
297
+    #prog = api.get_programs(channel=6400)
298
+    #prog = api.get_programs(category=55)
299
+    #seas = api.get_seasons(program=6453)
300
+    #str = api.get_streams(660243)
301
+    #res = api.get_videos(802)
302
+    #formats = api.getAllFormats()
303
+    #det = api.detailed("1516")
304
+    #vid = api.getVideos("13170")
305
+    pass

+ 230
- 0
resources/lib/sources/serialguru.py Parādīt failu

@@ -0,0 +1,230 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import urllib2, urllib
14
+import datetime, re, sys,os
15
+import ConfigParser
16
+from SourceBase import SourceBase
17
+
18
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
19
+import HTMLParser
20
+h = HTMLParser.HTMLParser()
21
+
22
+class Source(SourceBase):
23
+
24
+    def __init__(self,country=""):
25
+        self.name = "serialguru"
26
+        self.title = "SerialGURU.ru"
27
+        self.img = "http://serialguru.ru/images/xlogo_new.png.pagespeed.ic.0sre2_2OJN.png"
28
+        self.desc = "Serialguru.ru portāla satura skatīšanās"
29
+        self.country=country
30
+        self.headers = headers2dict("""
31
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36
32
+Referer: http://serialguru.ru/
33
+""")
34
+        self.headers2 = headers2dict("""
35
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.79 Safari/537.36
36
+X-Requested-With: XMLHttpRequest
37
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
38
+Referer: http://serialguru.ru/
39
+""")
40
+        self.url = "http://serialguru.ru/"
41
+        #self.login()
42
+
43
+    def login(self,user="",password=""):
44
+        return True
45
+
46
+    def get_content(self, data):
47
+        print "[tvdom] get_content:", data
48
+        if "::" in data:
49
+            data = data.split("::")[1]
50
+        path = data.split("?")[0]
51
+        clist = path.split("/")[0]
52
+        params = data[data.find("?"):] if "?" in data else ""
53
+        qs = dict(map(lambda x:x.split("="),re.findall("[%\w]+=\w+",params)))
54
+        lang = qs["lang"] if "lang" in qs else self.country
55
+
56
+        content=[]
57
+        content.append(("..return", "back","","Return back"))
58
+
59
+        if clist=="home":
60
+            content.extend([
61
+                ("Search", "serialguru::search/{0}","","Search content"),
62
+                ("Last", "serialguru::last","","Last series"),
63
+                ("Series", "serialguru::serials","","TV Series"),
64
+                ("Shows", "serialguru::tv","","TV Shows"),
65
+                ("Animations", "serialguru::mult","","Animation series"),
66
+
67
+                #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
68
+            ])
69
+            return content
70
+
71
+        elif data == "last":
72
+            r = self.call("")
73
+            for item in re.findall(r'<li><a href="(http://serialguru\.ru/[^"]+)"><i>([^<]+)</i>  <i>([^<]+)</i> <b>([^<]+)</b></a></li>', r, re.DOTALL):
74
+                title = item[1] + " - " + item[2]+"/"+item[3]
75
+                img = ""
76
+                data2 = item[0].replace(self.url, "")
77
+                desc = title
78
+                content.append((title, self.name+"::"+data2, img, desc))
79
+            return content
80
+
81
+        elif data=="serials":
82
+            content.extend([
83
+                ("All", "serialguru::serials?o=0&t=S","","All series"),
84
+                ("Russian", "serialguru::serials?c%5B%5D=53&c%5B%5D=61&c%5B%5D=33&c%5B%5D=42&c%5B%5D=31&o=0&t=S","","Russian countries series"),
85
+                ("English", "serialguru::serials?c%5B%5D=27&c%5B%5D=26&c%5B%5D=43&c%5B%5D=30&c%5B%5D=34&c%5B%5D=25&o=0&t=S","","English countries series"),
86
+                ("Europe", "serialguru::serials?c%5B%5D=29&c%5B%5D=66&c%5B%5D=44&c%5B%5D=28&c%5B%5D=51&c%5B%5D=65&c%5B%5D=62&c%5B%5D=40&c%5B%5D=45&c%5B%5D=68&c%5B%5D=59&c%5B%5D=39&c%5B%5D=35&c%5B%5D=47&o=0&t=S","","European countries series"),
87
+                ("Other", "serialguru::serials?c%5B%5D=36&c%5B%5D=32&c%5B%5D=67&c%5B%5D=63&c%5B%5D=60&c%5B%5D=64&c%5B%5D=38&c%5B%5D=52&c%5B%5D=41&c%5B%5D=58&c%5B%5D=57&c%5B%5D=37&c%5B%5D=50&c%5B%5D=46&o=0&t=S","","Other countries series"),
88
+                #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
89
+            ])
90
+            return content
91
+
92
+        elif data=="tv":
93
+            content.extend([
94
+                ("All", "serialguru::tv?o=0&t=S","","All series"),
95
+                ("Russian", "serialguru::tv?c%5B%5D=53&c%5B%5D=61&c%5B%5D=33&c%5B%5D=42&c%5B%5D=31&o=0&t=P","","Russian countries TV shows"),
96
+                ("English", "serialguru::tv?c%5B%5D=27&c%5B%5D=26&c%5B%5D=43&c%5B%5D=30&c%5B%5D=34&c%5B%5D=25&o=0&t=P","","English countries TV shows"),
97
+                ("Europe", "serialguru::tv?c%5B%5D=29&c%5B%5D=66&c%5B%5D=44&c%5B%5D=28&c%5B%5D=51&c%5B%5D=65&c%5B%5D=62&c%5B%5D=40&c%5B%5D=45&c%5B%5D=68&c%5B%5D=59&c%5B%5D=39&c%5B%5D=35&c%5B%5D=47&o=0&t=P","","European countries TV shows series"),
98
+                ("Other", "serialguru::tv?c%5B%5D=36&c%5B%5D=32&c%5B%5D=67&c%5B%5D=63&c%5B%5D=60&c%5B%5D=64&c%5B%5D=38&c%5B%5D=52&c%5B%5D=41&c%5B%5D=58&c%5B%5D=57&c%5B%5D=37&c%5B%5D=50&c%5B%5D=46&o=0&t=P","","Other countries TV shows"),
99
+                #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
100
+            ])
101
+            return content
102
+
103
+        elif data=="mult":
104
+            content.extend([
105
+                ("All", "serialguru::mult?o=0&t=S","","All series"),
106
+                ("Russian", "serialguru::mult?c%5B%5D=53&c%5B%5D=61&c%5B%5D=33&c%5B%5D=42&c%5B%5D=31&o=0&t=M","","Russian countries animantions"),
107
+                ("English", "serialguru::mult?c%5B%5D=27&c%5B%5D=26&c%5B%5D=43&c%5B%5D=30&c%5B%5D=34&c%5B%5D=25&o=0&t=M","","English countries animantions"),
108
+                ("Europe", "serialguru::mult?c%5B%5D=29&c%5B%5D=66&c%5B%5D=44&c%5B%5D=28&c%5B%5D=51&c%5B%5D=65&c%5B%5D=62&c%5B%5D=40&c%5B%5D=45&c%5B%5D=68&c%5B%5D=59&c%5B%5D=39&c%5B%5D=35&c%5B%5D=47&o=0&t=M","","European countries animantions"),
109
+                ("Other", "serialguru::mult?c%5B%5D=36&c%5B%5D=32&c%5B%5D=67&c%5B%5D=63&c%5B%5D=60&c%5B%5D=64&c%5B%5D=38&c%5B%5D=52&c%5B%5D=41&c%5B%5D=58&c%5B%5D=57&c%5B%5D=37&c%5B%5D=50&c%5B%5D=46&o=0&t=M","","Other countries animantions"),
110
+                #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
111
+            ])
112
+            return content
113
+
114
+        elif clist=="search":
115
+            if data.split("/")>1:
116
+                term = data.split("/")[1]
117
+            else:
118
+                return content
119
+            r = self.call("main/autocomplete?term=%s"%(term))
120
+            if r=="null":
121
+                return content
122
+            js = json.loads(r)
123
+            for item in js:
124
+                title = item["name"].encode("utf8")
125
+                data2 = item["url"].encode("utf8")
126
+                img = "http://serialguru.ru/uploads/cover/"+item["image_s"].replace("_s","")+".jpg"
127
+                rating = item["rating"].encode("utf8") if item["rating"] else ""
128
+                desc = title +"\nRating:%s (%s+/%s-)"%(rating,item["plus_cnt"].encode("utf8"),item["minus_cnt"].encode("utf8"))
129
+                content.append((title,self.name+"::"+data2,img,desc))
130
+            return content
131
+
132
+        elif path=="serials" or path=="tv" or path=="mult":
133
+            if path=="serials" and not "cat%5B%5D" in data:
134
+                #content.append(("All", "serialguru::"+data+"&cat%5B%5D=","","All series"))
135
+                categories = self.get_categories(path)
136
+                for c in categories:
137
+                    content.append((c[1], "serialguru::"+data+"&cat%5B%5D="+c[0],"",c[1]))
138
+                return content
139
+            else:
140
+                r = self.call("main/load", params[1:], headers=self.headers2)
141
+                for item in re.findall('<li><a href="([^"]+)"><div>.*?<img src="([^"]+)" alt="([^"]+)"[^<]*?><p>([^<]+)<i><span class="r">([^<]+)</span> <span class="plus">([^<]+)</span> <span class="minus">([^<]+)</span></i></p></div>([^<]+)</a></li>', r, re.DOTALL):
142
+                    title = "%s (%s)"%(item[2],item[3])
143
+                    img = item[1].replace("_s.jpg","_l.jpg")
144
+                    data2 = item[0].replace(self.url,"")
145
+                    desc = title +"\nRating:%s (%s+/%s-)"%(item[4],item[5],item[6])
146
+                    content.append((title,self.name+"::"+data2,img,desc))
147
+                page=int(re.search("o=(\d+)",data).group(1))
148
+                data2 = re.sub("o=(\d+)","o=%s"%(page+15),data)
149
+                content.append(("Next page",self.name+"::"+data2,"","Go to next page"))
150
+                return content
151
+
152
+
153
+        ### Pārraide
154
+        else:
155
+            r = self.call(clist)
156
+            title0=re.search('<h2>(.+?)</h2>',r,re.DOTALL).group(1)
157
+            m=re.search('<div class="description">(.+?)</div>',r,re.DOTALL)
158
+            desc0=m.group(1) if m else ""
159
+            desc0=desc0.replace("<p>","").replace("</p>","\n").replace('<a href="#">ПОКАЗАТЬ ПОЛНОСТЬЮ</a>',"")
160
+            desc0=title0+"\n"+desc0.strip()
161
+            img0=""
162
+            m = re.search("http://serialguru.ru/main/playlist/\d+",r)
163
+            if m:
164
+                url = m.group()
165
+            else:
166
+                raise Exception ("No stream found")
167
+            r = self._http_request(url)
168
+            js = json.loads(r,"utf8")
169
+            if not "/" in data: # sezonas
170
+                for i,item in enumerate(js["playlist"]):
171
+                    title = title0 + " - " + item["comment"].encode("utf8")
172
+                    img = img0
173
+                    data2 = "%s/%s"%(data,i)
174
+                    desc = desc0
175
+                    content.append((title,self.name+"::"+data2,img,desc))
176
+            else:
177
+                snum = int(data.split("/")[1])
178
+                title1 = js["playlist"][snum]["comment"].encode('utf8')
179
+                for i,item in enumerate(js["playlist"][snum]["playlist"]):
180
+                    title = title0 + " - " + title1+"/"+item["comment"].encode("utf8")
181
+                    img = img0
182
+                    data2 = item["file"].encode("utf8")
183
+                    desc = desc0
184
+                    content.append((title,data2,img,desc))
185
+            return content
186
+
187
+
188
+    def is_video(self,data):
189
+        if "::" in data:
190
+            data = data.split("::")[1]
191
+        if "live/view" in data:
192
+            return True
193
+        else:
194
+            return False
195
+
196
+    def get_categories(self,data):
197
+        r = self.call(data)
198
+        r2 = re.search('<td class="category">(.+?)</td>', r, re.DOTALL).group(1)
199
+        items = re.findall(r'<a href="#" data-id="(\d+)">([^<]+)</a>', r2, re.DOTALL)
200
+        return items
201
+
202
+
203
+    def call(self, data,params = None, headers=None):
204
+        if not headers: headers = self.headers
205
+        #if not lang: lang = self.country
206
+        url = self.url + data
207
+        content = self._http_request(url,params, headers)
208
+        return content
209
+
210
+if __name__ == "__main__":
211
+    country= "lv"
212
+    c = Source(country)
213
+    if len(sys.argv)>1:
214
+        data= sys.argv[1]
215
+    else:
216
+        data = "home"
217
+    content = c.get_content(data)
218
+    for item in content:
219
+        print item
220
+    #cat = api.get_categories(country)
221
+    #chan = api.get_channels("lv")
222
+    #prog = api.get_programs(channel=6400)
223
+    #prog = api.get_programs(category=55)
224
+    #seas = api.get_seasons(program=6453)
225
+    #str = api.get_streams(660243)
226
+    #res = api.get_videos(802)
227
+    #formats = api.getAllFormats()
228
+    #det = api.detailed("1516")
229
+    #vid = api.getVideos("13170")
230
+    pass

+ 108
- 0
resources/lib/sources/streams.cfg Parādīt failu

@@ -0,0 +1,108 @@
1
+[home]
2
+My TV|config::my_tv|default|Mani TV kanāli (tiešraide)
3
+My TV archive|config::my_archive|default|Mani TV arhīvu video
4
+My Video|config::my_video||Mani video
5
+My Kids|config::my_kids||Mani bērnu video
6
+My Radio|config::my_radio||Mani radio kanāli
7
+Replay.lv (LTV)|replay::home|http://replay.lsm.lv/apple-touch-icon.png|Latvijas TV tiešraides un arhīvs
8
+Skaties.lv (TV3)|mtgplay::home|http://skaties.lv/touch-icon-192x192.png|MTG kanālu (LNT,TV3, TV6 u.c.) arhīvs
9
+Shortcut (lattelecom.tv)|ltc::home|https://kursors.lv/wp-content/uploads/2016/07/Shortcut-logo.png|lattelecom TV, arhīves un video
10
+Play24.lv (Riga24TV)|play24::home|http://play24.lv/images/play24-logo-black.png|play24.lv (Riga24TV)tiešraide un arhīvs
11
+viaplay.lv|viaplay::home|https://yt3.ggpht.com/-noVdjbNR-V8/AAAAAAAAAAI/AAAAAAAAAAA/yZ9XNP5urLY/s900-c-k-no-mo-rj-c0xffffff/photo.jpg|Viaplay.lv - filmas latviešu, krievu u.c. valodās
12
+TVDom.tv|tvdom::home|https://tvdom.tv/front/assets/images/logo.png|PBK tiešraides un arhīvs
13
+BBC iPlayer|iplayer::home|http://www.userlogos.org/files/logos/inductiveload/BBC_iPlayer_logo.png|BBC live streams and arhive
14
+Euronews|euronews::home|http://pbs.twimg.com/profile_images/732665354242150400/tZsCnjuh_400x400.jpg|Euronews live streams and archive
15
+cinemalive.tv|cinemalive::home|https://cinemalive.tv/assets/img/filmas-online-latviski.jpg|cinemalive.tv - flmas  latvišu valodā
16
+MoviePlace.lv|movieplace::home||Movieplace.lv - filmas latviesu valodā
17
+Filmix.net|filmix::home|http://cs5324.vk.me/g33668783/a_903fcc63.jpg|Filmix.net - filmas krievu valodā
18
+SerialGURU.ru|serialguru::home|http://serialguru.ru/images/xlogo_new.png.pagespeed.ic.0sre2_2OJN.png|Serialguru.ru - filmas krievu valodā
19
+USTVNow|ustvnow::home|http://watch.ustvnow.com/assets/ustvnow/img/ustvnow_og_image.png|USTVNow kanālu tiešraide
20
+FilmOn|filmon::home|http://behindthegloves.com/wp-content/uploads/2016/01/FilmOn-logo1.jpg|FilmOn - tiešraides un video (dažādās valodās)
21
+MTGPlay|config::mtg|https://www.mtg.com/wp-content/uploads/2015/11/MTG-Logo-Medium-Red-PNG.png|Other countries MTG media portals content
22
+
23
+
24
+[my_tv]
25
+..return|back|default|Atgriezties atpakaļ
26
+LTV1|replay::tiesraide/ltv1/|http://replay.lsm.lv/resources/logo/large_ltv1.png|LTV1 tiesraide (video )
27
+LTV7|replay::tiesraide/ltv7/|http://replay.lsm.lv/resources/logo/large_ltv7.png|LTV7 tiesraide (video )
28
+TV3|http://wpc.11eb4.teliasoneracdn.net/8011EB4/origin1/tvplay/mtgstream2_high.stream/playlist.m3u8|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/TV3_logo.png|TV3
29
+TV3 (ltc)|ltc::content/live-streams/103?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/TV3_logo.png|TV3
30
+LNT (ltc)|ltc::content/live-streams/104?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/LNT_logo.png|LNT
31
+TV6|ltc::content/live-streams/106?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/TV6_logo.png|TV6
32
+Kanāls 2|ltc::content/live-streams/608?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/Kanals2_logo.png|Kanāls 2
33
+3+|ltc::content/live-streams/107?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/3_logo.png|3+
34
+360TV|ltc::content/live-streams/1051?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/360TV_new.png|360TV
35
+STV Pirmā!|ltc::content/live-streams/1069?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/STV.png|STV Pirmā!
36
+TVRiga24|play24::tiesraide||TV live streams
37
+Re:TV|ltc::content/live-streams/924?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/RE_TV.png|Re:TV
38
+RU live|tvdom::tiesraides||RU live streams from TVDom
39
+BBC live (iPlayer)|iplayer::live||BBC live streams from iPlayer
40
+UK live (FilmOn) TV|filmon::group?id=5|https://static.filmon.com/assets/groups/5/big_logo.png|UK live streams from FilmOn
41
+US live (FilmOn)|ustvnow::tvlive||US live streams from FilmOn
42
+Canadian live (FilmOn)|filmon::group?id=44|https://static.filmon.com/assets/groups/44/big_logo.png|Canada live streams from FilmOn
43
+Sport stream|rtmp://184.172.124.216/live/test111||
44
+
45
+[my_archive]
46
+..return|back||Atgriezties atpakaļ
47
+LTV arhīvs LV|replay::visi/jaunakie/?source=ltv&lang=lv|http://replay.lsm.lv/apple-touch-icon.png|LTV1, LTV2 pārraižu arhīvs LV
48
+LTV arhīvs RU|replay::vse/novie/?source=ltv&lang=ru|http://replay.lsm.lv/apple-touch-icon.png|LTV1, LTV2 pārraižu arhīvs RU
49
+skaties.lv arhīvs|mtgplay::videos?country=lv&order=-airdate|http://skaties.lv/touch-icon-192x192.png|MTG (LNT, TV3, TV6 u.c.) pārraižu arhīvs
50
+Lattelecom.tv arhīvs - categories|ltc::archive/categories|http://www.lattelecom.tv/images/default-social-icon_free.png|Lattelecom.tv pārraižu arhīvs
51
+TVRiga24 arhīvs|play24::kategorija/raidijumi|http://play24.lv/images/play24-logo-black.png|TVRiga24.tv pārraižu arhīvs
52
+TVDom arhīvs - categories|tvdom::arhivs|https://tvdom.tv/front/assets/images/logo.png|TVDom(PBK, NTV, REN u.c.) pārraižu arhīvs RU
53
+BBC (iPlayer) arhīvs|iplayer::categories||BBC programmes by categories
54
+Category - News|euronews::content/getVertical?lang=en&byPage=40&page=1&vId=1|http://pbs.twimg.com/profile_images/732665354242150400/tZsCnjuh_400x400.jpg|Category - News
55
+Latest programs|euronews::content/getLatestPrograms?lang=en&byPage=40&page=1|http://pbs.twimg.com/profile_images/732665354242150400/tZsCnjuh_400x400.jpg|Latest programs
56
+
57
+[my_video]
58
+..return|back||Atgriezties atpakaļ
59
+Все фильмы|filmix::films|http://cs5324.vk.me/g33668783/a_903fcc63.jpg|Все фильмы
60
+Все сериалы|filmix::serialy|http://cs5324.vk.me/g33668783/a_903fcc63.jpg|Все сериалы
61
+
62
+[my_kids]
63
+..return|back|default|Atgriezties atpakaļ
64
+Bērnu TV|config::my_kids_tv||Bērnu TV kanāli
65
+Bērnu video|config::my_kids_video||Saglabātie bērnu video
66
+LTV bērnu TV arhīvs|replay::raidijumi/?lang=lv&type=video&theme=5||LTV bērnu TV arhīvs
67
+Skaties.lv bērnu TV arhīvs|mtgplay::formats?category=51&country=lv&order=title|http://mtgonline.lv/tv3play/categories/berni-new.jpg|Skaties.lv bērnu TV arhīvs
68
+Shortcut.lv video bērniem - latviski|ltc::videonoma?page=0&genre=3&sorts=title&cnt=40&clear=true&filter={"valoda":["lv"]}|https://www.lattelecom.tv/images/redesign/videonoma_dropdown_berniem.png|Shortuc.lv (Lattelecom) bērnu video latviski
69
+CBeebies video|iplayer::categories/cbeebies|http://www.userlogos.org/files/logos/inductiveload/BBC_iPlayer_logo.png|CBeebies videos from iPlayer
70
+CBBC video|iplayer::categories/cbbc|http://www.userlogos.org/files/logos/inductiveload/BBC_iPlayer_logo.png|CBBC videos from iPlayer
71
+TVDom bērnu video|tvdom::arhivs/bernu||TVDom bērnu video RU
72
+Filmix bērnu filmas|filmix::detskij|http://cs5324.vk.me/g33668783/a_903fcc63.jpg|Filmix bērnu filmas
73
+Filmix bērnu seriāli|filmix::detskij/s7|http://cs5324.vk.me/g33668783/a_903fcc63.jpg|Filmix bērnu seriāli
74
+SerialGURU multenes|serialguru::mult||SerialGURU multenes
75
+
76
+[my_kids_tv]
77
+..return|back|default|Atgriezties atpakaļ
78
+Kidzone|ltc::content/live-streams/951?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/kidzone2_new.png|Kidzone
79
+Nickelodeon|ltc::content/live-streams/302?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/Nickelodeon.png|Nickelodeon
80
+Jim Jam|ltc::content/live-streams/303?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/Jim_Jam.png|Jim Jam
81
+Nick Jr|ltc::content/live-streams/1095?include=quality|https://manstv.lattelecom.tv/images/01_Bildes/02_Kanalu_raidijumu_default/NickJR.png|Nick Jr
82
+CBeebies (iPlayer)|iplayer::live/cbeebies|http://www.lyngsat-logo.com/hires/bb/bbc_cbeebies_uk.png|CBeebies
83
+CBBC (iPlayer)|iplayer::live/cbbc|http://www.lyngsat-logo.com/hires/bb/bbc_cbbc.png|CBBC
84
+CBeebies (FilmOn)|filmon::channel?id=3191|http://static.filmon.com/assets/channels/3191/big_logo.png|CBeebies is dedicated to preschoolers. Packed full of their favourite characters, CBeebies offers 13 hours of programmes every day which encourage your child to play along and learn. It's also completely advert free and with a dedicated website and interactive service, at CBeebies it's "Playtime All the Time!"
85
+CBBC (FilmOn)|filmon::channel?id=29|http://static.filmon.com/assets/channels/29/big_logo.png|CBBC is a BBC Television channel aimed at 6 to 12 year olds.
86
+Om Nom (FilmOn)|filmon::channel?id=3824|http://static.filmon.com/assets/channels/3824/big_logo.png|The series chronicles Om Nom's adventures with a young boy named Evan, beginning  with the little monster's mysterious appearance on the boy's doorstep in Episode 1. The animation series goes on to reveal Om Nom's mischievous, yet endearing personality as he and Evan bond over day-to-day activities such as playing games, exploring house-hold items and celebrating holidays.
87
+
88
+[my_kids_video]
89
+..return|back|default|Atgriezties atpakaļ
90
+
91
+[my_radio]
92
+..return|back|default|Atgriezties atpakaļ
93
+LR1|replay::tiesraide/lr1/|http://replay.lsm.lv/resources/logo/lr1_logo.png|LR1 tiesraide (audio)
94
+LR2|replay::tiesraide/lr2/|http://replay.lsm.lv/resources/logo/lr2_logo.png|LR2 tiesraide (audio)
95
+LR3|replay::tiesraide/lr3/|http://replay.lsm.lv/resources/logo/lr3_logo.png|LR3 tiesraide (audio)
96
+LR4|replay::tiesraide/lr4/|http://replay.lsm.lv/resources/logo/lr4_logo.png|LR4 tiesraide (audio)
97
+LR5|replay::tiesraide/lr5/|http://replay.lsm.lv/resources/logo/lr5_logo.png|LR5 tiesraide (audio)
98
+LR6|replay::tiesraide/lr6/|http://replay.lsm.lv/resources/logo/lr6_logo.png|LR6 tiesraide (audio)
99
+
100
+[mtg]
101
+..return|back|default|Atgriezties atpakaļ
102
+Estonia (tv3play.ee)|mtgplay::home?country=ee||MTG Estonia media portal content
103
+Lithuania (play.tv3.lt/)|mtgplay::home?country=lt||MTG Lithuania media portal content
104
+Sweden (tvXplay.se)|mtgplay::home?country=se||MTG Sweden media portal content
105
+Denmark (tv3play.dk)|mtgplay::home?country=dk||MTG Denmark media portal content
106
+Norway (tv3play.no)|mtgplay::home?country=no||MTG Norway media portal content
107
+Bulgaria (play.novatv.bg/)|mtgplay::home?country=bg||MTG Bulgaria media portal content
108
+

+ 828
- 0
resources/lib/sources/swfinterp.py Parādīt failu

@@ -0,0 +1,828 @@
1
+# This code comes from youtube-dl: https://github.com/rg3/youtube-dl/blob/master/youtube_dl/swfinterp.py
2
+
3
+from __future__ import unicode_literals
4
+
5
+import collections
6
+import io
7
+import struct
8
+import zlib
9
+
10
+
11
+def _extract_tags(file_contents):
12
+    if file_contents[1:3] != b'WS':
13
+        print '[SWFInterpreter] Not an SWF file; header is %r' % file_contents[:3]
14
+    if file_contents[:1] == b'C':
15
+        content = zlib.decompress(file_contents[8:])
16
+    else:
17
+        raise NotImplementedError(
18
+            'Unsupported compression format %r' %
19
+            file_contents[:1])
20
+
21
+    # Determine number of bits in framesize rectangle
22
+    framesize_nbits = struct.unpack('!B', content[:1])[0] >> 3
23
+    framesize_len = (5 + 4 * framesize_nbits + 7) // 8
24
+
25
+    pos = framesize_len + 2 + 2
26
+    while pos < len(content):
27
+        header16 = struct.unpack('<H', content[pos:pos + 2])[0]
28
+        pos += 2
29
+        tag_code = header16 >> 6
30
+        tag_len = header16 & 0x3f
31
+        if tag_len == 0x3f:
32
+            tag_len = struct.unpack('<I', content[pos:pos + 4])[0]
33
+            pos += 4
34
+        assert pos + tag_len <= len(content), \
35
+            ('Tag %d ends at %d+%d - that\'s longer than the file (%d)'
36
+                % (tag_code, pos, tag_len, len(content)))
37
+        yield (tag_code, content[pos:pos + tag_len])
38
+        pos += tag_len
39
+
40
+
41
+class _AVMClass_Object(object):
42
+    def __init__(self, avm_class):
43
+        self.avm_class = avm_class
44
+
45
+    def __repr__(self):
46
+        return '%s#%x' % (self.avm_class.name, id(self))
47
+
48
+
49
+class _ScopeDict(dict):
50
+    def __init__(self, avm_class):
51
+        super(_ScopeDict, self).__init__()
52
+        self.avm_class = avm_class
53
+
54
+    def __repr__(self):
55
+        return '%s__Scope(%s)' % (
56
+            self.avm_class.name,
57
+            super(_ScopeDict, self).__repr__())
58
+
59
+
60
+class _AVMClass(object):
61
+    def __init__(self, name_idx, name, static_properties=None):
62
+        self.name_idx = name_idx
63
+        self.name = name
64
+        self.method_names = {}
65
+        self.method_idxs = {}
66
+        self.methods = {}
67
+        self.method_pyfunctions = {}
68
+        self.static_properties = static_properties if static_properties else {}
69
+
70
+        self.variables = _ScopeDict(self)
71
+        self.constants = {}
72
+
73
+    def make_object(self):
74
+        return _AVMClass_Object(self)
75
+
76
+    def __repr__(self):
77
+        return '_AVMClass(%s)' % (self.name)
78
+
79
+    def register_methods(self, methods):
80
+        self.method_names.update(methods.items())
81
+        self.method_idxs.update(dict(
82
+            (idx, name)
83
+            for name, idx in methods.items()))
84
+
85
+
86
+class _Multiname(object):
87
+    def __init__(self, kind):
88
+        self.kind = kind
89
+
90
+    def __repr__(self):
91
+        return '[MULTINAME kind: 0x%x]' % self.kind
92
+
93
+
94
+def _read_int(reader):
95
+    res = 0
96
+    shift = 0
97
+    for _ in range(5):
98
+        buf = reader.read(1)
99
+        assert len(buf) == 1
100
+        b = struct.unpack('<B', buf)[0]
101
+        res = res | ((b & 0x7f) << shift)
102
+        if b & 0x80 == 0:
103
+            break
104
+        shift += 7
105
+    return res
106
+
107
+
108
+def _u30(reader):
109
+    res = _read_int(reader)
110
+    assert res & 0xf0000000 == 0
111
+    return res
112
+_u32 = _read_int
113
+
114
+
115
+def _s32(reader):
116
+    v = _read_int(reader)
117
+    if v & 0x80000000 != 0:
118
+        v = - ((v ^ 0xffffffff) + 1)
119
+    return v
120
+
121
+
122
+def _s24(reader):
123
+    bs = reader.read(3)
124
+    assert len(bs) == 3
125
+    last_byte = b'\xff' if (ord(bs[2:3]) >= 0x80) else b'\x00'
126
+    return struct.unpack('<i', bs + last_byte)[0]
127
+
128
+
129
+def _read_string(reader):
130
+    slen = _u30(reader)
131
+    resb = reader.read(slen)
132
+    assert len(resb) == slen
133
+    return resb.decode('utf-8')
134
+
135
+
136
+def _read_bytes(count, reader):
137
+    assert count >= 0
138
+    resb = reader.read(count)
139
+    assert len(resb) == count
140
+    return resb
141
+
142
+
143
+def _read_byte(reader):
144
+    resb = _read_bytes(1, reader=reader)
145
+    res = struct.unpack('<B', resb)[0]
146
+    return res
147
+
148
+
149
+StringClass = _AVMClass('(no name idx)', 'String')
150
+ByteArrayClass = _AVMClass('(no name idx)', 'ByteArray')
151
+TimerClass = _AVMClass('(no name idx)', 'Timer')
152
+TimerEventClass = _AVMClass('(no name idx)', 'TimerEvent', {'TIMER': 'timer'})
153
+_builtin_classes = {
154
+    StringClass.name: StringClass,
155
+    ByteArrayClass.name: ByteArrayClass,
156
+    TimerClass.name: TimerClass,
157
+    TimerEventClass.name: TimerEventClass,
158
+}
159
+
160
+
161
+class _Undefined(object):
162
+    def __bool__(self):
163
+        return False
164
+    __nonzero__ = __bool__
165
+
166
+    def __hash__(self):
167
+        return 0
168
+
169
+    def __str__(self):
170
+        return 'undefined'
171
+    __repr__ = __str__
172
+
173
+undefined = _Undefined()
174
+
175
+
176
+class SWFInterpreter(object):
177
+    def __init__(self, file_contents):
178
+        self._patched_functions = {
179
+            (TimerClass, 'addEventListener'): lambda params: undefined,
180
+        }
181
+        code_tag = next(tag
182
+                        for tag_code, tag in _extract_tags(file_contents)
183
+                        if tag_code == 82)
184
+        p = code_tag.index(b'\0', 4) + 1
185
+        code_reader = io.BytesIO(code_tag[p:])
186
+
187
+        # Parse ABC (AVM2 ByteCode)
188
+
189
+        # Define a couple convenience methods
190
+        u30 = lambda *args: _u30(*args, reader=code_reader)
191
+        s32 = lambda *args: _s32(*args, reader=code_reader)
192
+        u32 = lambda *args: _u32(*args, reader=code_reader)
193
+        read_bytes = lambda *args: _read_bytes(*args, reader=code_reader)
194
+        read_byte = lambda *args: _read_byte(*args, reader=code_reader)
195
+
196
+        # minor_version + major_version
197
+        read_bytes(2 + 2)
198
+
199
+        # Constant pool
200
+        int_count = u30()
201
+        self.constant_ints = [0]
202
+        for _c in range(1, int_count):
203
+            self.constant_ints.append(s32())
204
+        self.constant_uints = [0]
205
+        uint_count = u30()
206
+        for _c in range(1, uint_count):
207
+            self.constant_uints.append(u32())
208
+        double_count = u30()
209
+        read_bytes(max(0, (double_count - 1)) * 8)
210
+        string_count = u30()
211
+        self.constant_strings = ['']
212
+        for _c in range(1, string_count):
213
+            s = _read_string(code_reader)
214
+            self.constant_strings.append(s)
215
+        namespace_count = u30()
216
+        for _c in range(1, namespace_count):
217
+            read_bytes(1)  # kind
218
+            u30()  # name
219
+        ns_set_count = u30()
220
+        for _c in range(1, ns_set_count):
221
+            count = u30()
222
+            for _c2 in range(count):
223
+                u30()
224
+        multiname_count = u30()
225
+        MULTINAME_SIZES = {
226
+            0x07: 2,  # QName
227
+            0x0d: 2,  # QNameA
228
+            0x0f: 1,  # RTQName
229
+            0x10: 1,  # RTQNameA
230
+            0x11: 0,  # RTQNameL
231
+            0x12: 0,  # RTQNameLA
232
+            0x09: 2,  # Multiname
233
+            0x0e: 2,  # MultinameA
234
+            0x1b: 1,  # MultinameL
235
+            0x1c: 1,  # MultinameLA
236
+        }
237
+        self.multinames = ['']
238
+        for _c in range(1, multiname_count):
239
+            kind = u30()
240
+            assert kind in MULTINAME_SIZES, 'Invalid multiname kind %r' % kind
241
+            if kind == 0x07:
242
+                u30()  # namespace_idx
243
+                name_idx = u30()
244
+                self.multinames.append(self.constant_strings[name_idx])
245
+            elif kind == 0x09:
246
+                name_idx = u30()
247
+                u30()
248
+                self.multinames.append(self.constant_strings[name_idx])
249
+            else:
250
+                self.multinames.append(_Multiname(kind))
251
+                for _c2 in range(MULTINAME_SIZES[kind]):
252
+                    u30()
253
+
254
+        # Methods
255
+        method_count = u30()
256
+        MethodInfo = collections.namedtuple(
257
+            'MethodInfo',
258
+            ['NEED_ARGUMENTS', 'NEED_REST'])
259
+        method_infos = []
260
+        for method_id in range(method_count):
261
+            param_count = u30()
262
+            u30()  # return type
263
+            for _ in range(param_count):
264
+                u30()  # param type
265
+            u30()  # name index (always 0 for youtube)
266
+            flags = read_byte()
267
+            if flags & 0x08 != 0:
268
+                # Options present
269
+                option_count = u30()
270
+                for c in range(option_count):
271
+                    u30()  # val
272
+                    read_bytes(1)  # kind
273
+            if flags & 0x80 != 0:
274
+                # Param names present
275
+                for _ in range(param_count):
276
+                    u30()  # param name
277
+            mi = MethodInfo(flags & 0x01 != 0, flags & 0x04 != 0)
278
+            method_infos.append(mi)
279
+
280
+        # Metadata
281
+        metadata_count = u30()
282
+        for _c in range(metadata_count):
283
+            u30()  # name
284
+            item_count = u30()
285
+            for _c2 in range(item_count):
286
+                u30()  # key
287
+                u30()  # value
288
+
289
+        def parse_traits_info():
290
+            trait_name_idx = u30()
291
+            kind_full = read_byte()
292
+            kind = kind_full & 0x0f
293
+            attrs = kind_full >> 4
294
+            methods = {}
295
+            constants = None
296
+            if kind == 0x00:  # Slot
297
+                u30()  # Slot id
298
+                u30()  # type_name_idx
299
+                vindex = u30()
300
+                if vindex != 0:
301
+                    read_byte()  # vkind
302
+            elif kind == 0x06:  # Const
303
+                u30()  # Slot id
304
+                u30()  # type_name_idx
305
+                vindex = u30()
306
+                vkind = 'any'
307
+                if vindex != 0:
308
+                    vkind = read_byte()
309
+                if vkind == 0x03:  # Constant_Int
310
+                    value = self.constant_ints[vindex]
311
+                elif vkind == 0x04:  # Constant_UInt
312
+                    value = self.constant_uints[vindex]
313
+                else:
314
+                    return {}, None  # Ignore silently for now
315
+                constants = {self.multinames[trait_name_idx]: value}
316
+            elif kind in (0x01, 0x02, 0x03):  # Method / Getter / Setter
317
+                u30()  # disp_id
318
+                method_idx = u30()
319
+                methods[self.multinames[trait_name_idx]] = method_idx
320
+            elif kind == 0x04:  # Class
321
+                u30()  # slot_id
322
+                u30()  # classi
323
+            elif kind == 0x05:  # Function
324
+                u30()  # slot_id
325
+                function_idx = u30()
326
+                methods[function_idx] = self.multinames[trait_name_idx]
327
+            else:
328
+                print '[SWFInterpreter] Unsupported trait kind %d' % kind
329
+                return None
330
+
331
+            if attrs & 0x4 != 0:  # Metadata present
332
+                metadata_count = u30()
333
+                for _c3 in range(metadata_count):
334
+                    u30()  # metadata index
335
+
336
+            return methods, constants
337
+
338
+        # Classes
339
+        class_count = u30()
340
+        classes = []
341
+        for class_id in range(class_count):
342
+            name_idx = u30()
343
+
344
+            cname = self.multinames[name_idx]
345
+            avm_class = _AVMClass(name_idx, cname)
346
+            classes.append(avm_class)
347
+
348
+            u30()  # super_name idx
349
+            flags = read_byte()
350
+            if flags & 0x08 != 0:  # Protected namespace is present
351
+                u30()  # protected_ns_idx
352
+            intrf_count = u30()
353
+            for _c2 in range(intrf_count):
354
+                u30()
355
+            u30()  # iinit
356
+            trait_count = u30()
357
+            for _c2 in range(trait_count):
358
+                trait_methods, trait_constants = parse_traits_info()
359
+                avm_class.register_methods(trait_methods)
360
+                if trait_constants:
361
+                    avm_class.constants.update(trait_constants)
362
+
363
+        assert len(classes) == class_count
364
+        self._classes_by_name = dict((c.name, c) for c in classes)
365
+
366
+        for avm_class in classes:
367
+            avm_class.cinit_idx = u30()
368
+            trait_count = u30()
369
+            for _c2 in range(trait_count):
370
+                trait_methods, trait_constants = parse_traits_info()
371
+                avm_class.register_methods(trait_methods)
372
+                if trait_constants:
373
+                    avm_class.constants.update(trait_constants)
374
+
375
+        # Scripts
376
+        script_count = u30()
377
+        for _c in range(script_count):
378
+            u30()  # init
379
+            trait_count = u30()
380
+            for _c2 in range(trait_count):
381
+                parse_traits_info()
382
+
383
+        # Method bodies
384
+        method_body_count = u30()
385
+        Method = collections.namedtuple('Method', ['code', 'local_count'])
386
+        self._all_methods = []
387
+        for _c in range(method_body_count):
388
+            method_idx = u30()
389
+            u30()  # max_stack
390
+            local_count = u30()
391
+            u30()  # init_scope_depth
392
+            u30()  # max_scope_depth
393
+            code_length = u30()
394
+            code = read_bytes(code_length)
395
+            m = Method(code, local_count)
396
+            self._all_methods.append(m)
397
+            for avm_class in classes:
398
+                if method_idx in avm_class.method_idxs:
399
+                    avm_class.methods[avm_class.method_idxs[method_idx]] = m
400
+            exception_count = u30()
401
+            for _c2 in range(exception_count):
402
+                u30()  # from
403
+                u30()  # to
404
+                u30()  # target
405
+                u30()  # exc_type
406
+                u30()  # var_name
407
+            trait_count = u30()
408
+            for _c2 in range(trait_count):
409
+                parse_traits_info()
410
+
411
+        assert p + code_reader.tell() == len(code_tag)
412
+
413
+    def patch_function(self, avm_class, func_name, f):
414
+        self._patched_functions[(avm_class, func_name)] = f
415
+
416
+    def extract_class(self, class_name, call_cinit=True):
417
+        try:
418
+            res = self._classes_by_name[class_name]
419
+        except KeyError:
420
+            print '[SWFInterpreter] Class %r not found' % class_name
421
+            return None
422
+
423
+        if call_cinit and hasattr(res, 'cinit_idx'):
424
+            res.register_methods({'$cinit': res.cinit_idx})
425
+            res.methods['$cinit'] = self._all_methods[res.cinit_idx]
426
+            cinit = self.extract_function(res, '$cinit')
427
+            cinit([])
428
+
429
+        return res
430
+
431
+    def extract_function(self, avm_class, func_name):
432
+        p = self._patched_functions.get((avm_class, func_name))
433
+        if p:
434
+            return p
435
+        if func_name in avm_class.method_pyfunctions:
436
+            return avm_class.method_pyfunctions[func_name]
437
+        if func_name in self._classes_by_name:
438
+            return self._classes_by_name[func_name].make_object()
439
+        if func_name not in avm_class.methods:
440
+            print '[SWFInterpreter] Cannot find function %s.%s' % (
441
+                avm_class.name, func_name)
442
+            return None
443
+        m = avm_class.methods[func_name]
444
+
445
+        def resfunc(args):
446
+            # Helper functions
447
+            coder = io.BytesIO(m.code)
448
+            s24 = lambda: _s24(coder)
449
+            u30 = lambda: _u30(coder)
450
+
451
+            registers = [avm_class.variables] + list(args) + [None] * m.local_count
452
+            stack = []
453
+            scopes = collections.deque([
454
+                self._classes_by_name, avm_class.constants, avm_class.variables])
455
+            while True:
456
+                opcode = _read_byte(coder)
457
+                if opcode == 9:  # label
458
+                    pass  # Spec says: "Do nothing."
459
+                elif opcode == 16:  # jump
460
+                    offset = s24()
461
+                    coder.seek(coder.tell() + offset)
462
+                elif opcode == 17:  # iftrue
463
+                    offset = s24()
464
+                    value = stack.pop()
465
+                    if value:
466
+                        coder.seek(coder.tell() + offset)
467
+                elif opcode == 18:  # iffalse
468
+                    offset = s24()
469
+                    value = stack.pop()
470
+                    if not value:
471
+                        coder.seek(coder.tell() + offset)
472
+                elif opcode == 19:  # ifeq
473
+                    offset = s24()
474
+                    value2 = stack.pop()
475
+                    value1 = stack.pop()
476
+                    if value2 == value1:
477
+                        coder.seek(coder.tell() + offset)
478
+                elif opcode == 20:  # ifne
479
+                    offset = s24()
480
+                    value2 = stack.pop()
481
+                    value1 = stack.pop()
482
+                    if value2 != value1:
483
+                        coder.seek(coder.tell() + offset)
484
+                elif opcode == 21:  # iflt
485
+                    offset = s24()
486
+                    value2 = stack.pop()
487
+                    value1 = stack.pop()
488
+                    if value1 < value2:
489
+                        coder.seek(coder.tell() + offset)
490
+                elif opcode == 32:  # pushnull
491
+                    stack.append(None)
492
+                elif opcode == 33:  # pushundefined
493
+                    stack.append(undefined)
494
+                elif opcode == 36:  # pushbyte
495
+                    v = _read_byte(coder)
496
+                    stack.append(v)
497
+                elif opcode == 37:  # pushshort
498
+                    v = u30()
499
+                    stack.append(v)
500
+                elif opcode == 38:  # pushtrue
501
+                    stack.append(True)
502
+                elif opcode == 39:  # pushfalse
503
+                    stack.append(False)
504
+                elif opcode == 40:  # pushnan
505
+                    stack.append(float('NaN'))
506
+                elif opcode == 42:  # dup
507
+                    value = stack[-1]
508
+                    stack.append(value)
509
+                elif opcode == 44:  # pushstring
510
+                    idx = u30()
511
+                    stack.append(self.constant_strings[idx])
512
+                elif opcode == 48:  # pushscope
513
+                    new_scope = stack.pop()
514
+                    scopes.append(new_scope)
515
+                elif opcode == 66:  # construct
516
+                    arg_count = u30()
517
+                    args = list(reversed(
518
+                        [stack.pop() for _ in range(arg_count)]))
519
+                    obj = stack.pop()
520
+                    res = obj.avm_class.make_object()
521
+                    stack.append(res)
522
+                elif opcode == 70:  # callproperty
523
+                    index = u30()
524
+                    mname = self.multinames[index]
525
+                    arg_count = u30()
526
+                    args = list(reversed(
527
+                        [stack.pop() for _ in range(arg_count)]))
528
+                    obj = stack.pop()
529
+
530
+                    if obj == StringClass:
531
+                        if mname == 'String':
532
+                            assert len(args) == 1
533
+                            assert isinstance(args[0], (
534
+                                int, unicode, _Undefined))
535
+                            if args[0] == undefined:
536
+                                res = 'undefined'
537
+                            else:
538
+                                res = unicode(args[0])
539
+                            stack.append(res)
540
+                            continue
541
+                        else:
542
+                            raise NotImplementedError(
543
+                                'Function String.%s is not yet implemented'
544
+                                % mname)
545
+                    elif isinstance(obj, _AVMClass_Object):
546
+                        func = self.extract_function(obj.avm_class, mname)
547
+                        res = func(args)
548
+                        stack.append(res)
549
+                        continue
550
+                    elif isinstance(obj, _AVMClass):
551
+                        func = self.extract_function(obj, mname)
552
+                        res = func(args)
553
+                        stack.append(res)
554
+                        continue
555
+                    elif isinstance(obj, _ScopeDict):
556
+                        if mname in obj.avm_class.method_names:
557
+                            func = self.extract_function(obj.avm_class, mname)
558
+                            res = func(args)
559
+                        else:
560
+                            res = obj[mname]
561
+                        stack.append(res)
562
+                        continue
563
+                    elif isinstance(obj, unicode):
564
+                        if mname == 'split':
565
+                            assert len(args) == 1
566
+                            assert isinstance(args[0], unicode)
567
+                            if args[0] == '':
568
+                                res = list(obj)
569
+                            else:
570
+                                res = obj.split(args[0])
571
+                            stack.append(res)
572
+                            continue
573
+                        elif mname == 'charCodeAt':
574
+                            assert len(args) <= 1
575
+                            idx = 0 if len(args) == 0 else args[0]
576
+                            assert isinstance(idx, int)
577
+                            res = ord(obj[idx])
578
+                            stack.append(res)
579
+                            continue
580
+                    elif isinstance(obj, list):
581
+                        if mname == 'slice':
582
+                            assert len(args) == 1
583
+                            assert isinstance(args[0], int)
584
+                            res = obj[args[0]:]
585
+                            stack.append(res)
586
+                            continue
587
+                        elif mname == 'join':
588
+                            assert len(args) == 1
589
+                            assert isinstance(args[0], unicode)
590
+                            res = args[0].join(obj)
591
+                            stack.append(res)
592
+                            continue
593
+                    raise NotImplementedError(
594
+                        'Unsupported property %r on %r'
595
+                        % (mname, obj))
596
+                elif opcode == 71:  # returnvoid
597
+                    res = undefined
598
+                    return res
599
+                elif opcode == 72:  # returnvalue
600
+                    res = stack.pop()
601
+                    return res
602
+                elif opcode == 73:  # constructsuper
603
+                    # Not yet implemented, just hope it works without it
604
+                    arg_count = u30()
605
+                    args = list(reversed(
606
+                        [stack.pop() for _ in range(arg_count)]))
607
+                    obj = stack.pop()
608
+                elif opcode == 74:  # constructproperty
609
+                    index = u30()
610
+                    arg_count = u30()
611
+                    args = list(reversed(
612
+                        [stack.pop() for _ in range(arg_count)]))
613
+                    obj = stack.pop()
614
+
615
+                    mname = self.multinames[index]
616
+                    assert isinstance(obj, _AVMClass)
617
+
618
+                    # We do not actually call the constructor for now;
619
+                    # we just pretend it does nothing
620
+                    stack.append(obj.make_object())
621
+                elif opcode == 79:  # callpropvoid
622
+                    index = u30()
623
+                    mname = self.multinames[index]
624
+                    arg_count = u30()
625
+                    args = list(reversed(
626
+                        [stack.pop() for _ in range(arg_count)]))
627
+                    obj = stack.pop()
628
+                    if isinstance(obj, _AVMClass_Object):
629
+                        func = self.extract_function(obj.avm_class, mname)
630
+                        res = func(args)
631
+                        assert res is undefined
632
+                        continue
633
+                    if isinstance(obj, _ScopeDict):
634
+                        assert mname in obj.avm_class.method_names
635
+                        func = self.extract_function(obj.avm_class, mname)
636
+                        res = func(args)
637
+                        assert res is undefined
638
+                        continue
639
+                    if mname == 'reverse':
640
+                        assert isinstance(obj, list)
641
+                        obj.reverse()
642
+                    else:
643
+                        raise NotImplementedError(
644
+                            'Unsupported (void) property %r on %r'
645
+                            % (mname, obj))
646
+                elif opcode == 86:  # newarray
647
+                    arg_count = u30()
648
+                    arr = []
649
+                    for i in range(arg_count):
650
+                        arr.append(stack.pop())
651
+                    arr = arr[::-1]
652
+                    stack.append(arr)
653
+                elif opcode == 93:  # findpropstrict
654
+                    index = u30()
655
+                    mname = self.multinames[index]
656
+                    for s in reversed(scopes):
657
+                        if mname in s:
658
+                            res = s
659
+                            break
660
+                    else:
661
+                        res = scopes[0]
662
+                    if mname not in res and mname in _builtin_classes:
663
+                        stack.append(_builtin_classes[mname])
664
+                    else:
665
+                        stack.append(res[mname])
666
+                elif opcode == 94:  # findproperty
667
+                    index = u30()
668
+                    mname = self.multinames[index]
669
+                    for s in reversed(scopes):
670
+                        if mname in s:
671
+                            res = s
672
+                            break
673
+                    else:
674
+                        res = avm_class.variables
675
+                    stack.append(res)
676
+                elif opcode == 96:  # getlex
677
+                    index = u30()
678
+                    mname = self.multinames[index]
679
+                    for s in reversed(scopes):
680
+                        if mname in s:
681
+                            scope = s
682
+                            break
683
+                    else:
684
+                        scope = avm_class.variables
685
+
686
+                    if mname in scope:
687
+                        res = scope[mname]
688
+                    elif mname in _builtin_classes:
689
+                        res = _builtin_classes[mname]
690
+                    else:
691
+                        # Assume unitialized
692
+                        # TODO warn here
693
+                        res = undefined
694
+                    stack.append(res)
695
+                elif opcode == 97:  # setproperty
696
+                    index = u30()
697
+                    value = stack.pop()
698
+                    idx = self.multinames[index]
699
+                    if isinstance(idx, _Multiname):
700
+                        idx = stack.pop()
701
+                    obj = stack.pop()
702
+                    obj[idx] = value
703
+                elif opcode == 98:  # getlocal
704
+                    index = u30()
705
+                    stack.append(registers[index])
706
+                elif opcode == 99:  # setlocal
707
+                    index = u30()
708
+                    value = stack.pop()
709
+                    registers[index] = value
710
+                elif opcode == 102:  # getproperty
711
+                    index = u30()
712
+                    pname = self.multinames[index]
713
+                    if pname == 'length':
714
+                        obj = stack.pop()
715
+                        assert isinstance(obj, (unicode, list))
716
+                        stack.append(len(obj))
717
+                    elif isinstance(pname, unicode):  # Member access
718
+                        obj = stack.pop()
719
+                        if isinstance(obj, _AVMClass):
720
+                            res = obj.static_properties[pname]
721
+                            stack.append(res)
722
+                            continue
723
+
724
+                        assert isinstance(obj, (dict, _ScopeDict)),\
725
+                            'Accessing member %r on %r' % (pname, obj)
726
+                        res = obj.get(pname, undefined)
727
+                        stack.append(res)
728
+                    else:  # Assume attribute access
729
+                        idx = stack.pop()
730
+                        assert isinstance(idx, int)
731
+                        obj = stack.pop()
732
+                        assert isinstance(obj, list)
733
+                        stack.append(obj[idx])
734
+                elif opcode == 104:  # initproperty
735
+                    index = u30()
736
+                    value = stack.pop()
737
+                    idx = self.multinames[index]
738
+                    if isinstance(idx, _Multiname):
739
+                        idx = stack.pop()
740
+                    obj = stack.pop()
741
+                    obj[idx] = value
742
+                elif opcode == 115:  # convert_
743
+                    value = stack.pop()
744
+                    intvalue = int(value)
745
+                    stack.append(intvalue)
746
+                elif opcode == 128:  # coerce
747
+                    u30()
748
+                elif opcode == 130:  # coerce_a
749
+                    value = stack.pop()
750
+                    # um, yes, it's any value
751
+                    stack.append(value)
752
+                elif opcode == 133:  # coerce_s
753
+                    assert isinstance(stack[-1], (type(None), unicode))
754
+                elif opcode == 147:  # decrement
755
+                    value = stack.pop()
756
+                    assert isinstance(value, int)
757
+                    stack.append(value - 1)
758
+                elif opcode == 149:  # typeof
759
+                    value = stack.pop()
760
+                    return {
761
+                        _Undefined: 'undefined',
762
+                        unicode: 'String',
763
+                        int: 'Number',
764
+                        float: 'Number',
765
+                    }[type(value)]
766
+                elif opcode == 160:  # add
767
+                    value2 = stack.pop()
768
+                    value1 = stack.pop()
769
+                    res = value1 + value2
770
+                    stack.append(res)
771
+                elif opcode == 161:  # subtract
772
+                    value2 = stack.pop()
773
+                    value1 = stack.pop()
774
+                    res = value1 - value2
775
+                    stack.append(res)
776
+                elif opcode == 162:  # multiply
777
+                    value2 = stack.pop()
778
+                    value1 = stack.pop()
779
+                    res = value1 * value2
780
+                    stack.append(res)
781
+                elif opcode == 164:  # modulo
782
+                    value2 = stack.pop()
783
+                    value1 = stack.pop()
784
+                    res = value1 % value2
785
+                    stack.append(res)
786
+                elif opcode == 168:  # bitand
787
+                    value2 = stack.pop()
788
+                    value1 = stack.pop()
789
+                    assert isinstance(value1, int)
790
+                    assert isinstance(value2, int)
791
+                    res = value1 & value2
792
+                    stack.append(res)
793
+                elif opcode == 171:  # equals
794
+                    value2 = stack.pop()
795
+                    value1 = stack.pop()
796
+                    result = value1 == value2
797
+                    stack.append(result)
798
+                elif opcode == 175:  # greaterequals
799
+                    value2 = stack.pop()
800
+                    value1 = stack.pop()
801
+                    result = value1 >= value2
802
+                    stack.append(result)
803
+                elif opcode == 192:  # increment_i
804
+                    value = stack.pop()
805
+                    assert isinstance(value, int)
806
+                    stack.append(value + 1)
807
+                elif opcode == 208:  # getlocal_0
808
+                    stack.append(registers[0])
809
+                elif opcode == 209:  # getlocal_1
810
+                    stack.append(registers[1])
811
+                elif opcode == 210:  # getlocal_2
812
+                    stack.append(registers[2])
813
+                elif opcode == 211:  # getlocal_3
814
+                    stack.append(registers[3])
815
+                elif opcode == 212:  # setlocal_0
816
+                    registers[0] = stack.pop()
817
+                elif opcode == 213:  # setlocal_1
818
+                    registers[1] = stack.pop()
819
+                elif opcode == 214:  # setlocal_2
820
+                    registers[2] = stack.pop()
821
+                elif opcode == 215:  # setlocal_3
822
+                    registers[3] = stack.pop()
823
+                else:
824
+                    raise NotImplementedError(
825
+                        'Unsupported opcode %d' % opcode)
826
+
827
+        avm_class.method_pyfunctions[func_name] = resfunc
828
+        return resfunc

+ 4
- 0
resources/lib/sources/tvdom.cfg Parādīt failu

@@ -0,0 +1,4 @@
1
+[tvdom]
2
+user = ivars777@gmail.com
3
+password = kaskade7
4
+

+ 277
- 0
resources/lib/sources/tvdom.py Parādīt failu

@@ -0,0 +1,277 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import urllib2, urllib
14
+import datetime, re, sys,os
15
+from collections import OrderedDict
16
+from SourceBase import SourceBase
17
+
18
+API_URL = 'http://replay.lsm.lv/'
19
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
20
+headers0 = headers2dict("""
21
+User-Agent: Mozilla/5.0 (Linux; U; Android 4.4.4; Nexus 5 Build/KTU84P) AppleWebkit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
22
+""")
23
+import HTMLParser
24
+h = HTMLParser.HTMLParser()
25
+
26
+class Source(SourceBase):
27
+
28
+    def __init__(self,country="lv"):
29
+        self.name = "tvdom"
30
+        self.title = "TVDom.tv"
31
+        self.img = "https://tvdom.tv/front/assets/images/logo.png"
32
+        self.desc = "TVDom.tv portāla satura skatīšanās"
33
+        self.headers = headers0
34
+
35
+        self.country=country
36
+        self.session = None
37
+        self.token = None
38
+
39
+        cur_directory = os.path.dirname(os.path.abspath(__file__))
40
+        self.config_file = os.path.join(cur_directory,self.name+".cfg")
41
+        self.options = OrderedDict([("user","lietotajs"),("password","parole")])
42
+        self.options_read()
43
+
44
+    def login(self,user="",password=""):
45
+        self.options_read()        
46
+        if not user: user=self.options["user"]
47
+        if not password: password = self.options["password"]
48
+        headers = headers2dict("""
49
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:49.0) Gecko/20100101 Firefox/49.0
50
+Accept: */*
51
+Accept-Language: en-US,en;q=0.5
52
+Accept-Encoding: gzip, deflate, br
53
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
54
+X-Requested-With: XMLHttpRequest
55
+Referer: https://tvdom.tv/
56
+        """)
57
+        url = "https://tvdom.tv/infinity/on_register_user"
58
+        params = "email=%s&password=%s&remember=false&auth_type=login"%(user,password)
59
+        import requests
60
+        r = requests.post(url, data=params, headers=headers)	
61
+        js = json.loads(r.content)
62
+        if 'success' in r.content:
63
+            self.token = js["access_token"] 
64
+            if 'PHPSESSID' in r.cookies:
65
+                self.session = r.cookies["PHPSESSID"]
66
+            return True
67
+        else:
68
+            raise Exception(js["error"])
69
+
70
+
71
+    def get_content(self, data):
72
+        print "[tvdom] get_content:", data
73
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
74
+        lang = qs["lang"] if "lang" in qs else self.country
75
+        content=[]
76
+        content.append(("..return", "back","","Return back"))
77
+
78
+        if clist=="home":
79
+            content.extend([
80
+                ("Live stream", "tvdom::tiesraides","","TV live streams"),
81
+                ("Archive - categories", "tvdom::arhivs","","Video archive by categories"),
82
+                ("Search", "tvdom::search/?srch-term={0}","","Search archive"),
83
+
84
+                #("Archive - all", "tvdom::arhivs_all","","Video archive all"),
85
+            ])
86
+            return content
87
+
88
+        ### Tiesraides kanalu saraksts ###
89
+        elif data=="tiesraides":
90
+            ch_name = {"49":"Дом Кино","50":"Карусель","51":"Время","52":"Музыка Первого","53":"Телекафе"}
91
+            url = "https://tvdom.tv/"
92
+            r = self._http_request(url)
93
+            #channels1 = re.findall(r'data-xprs_status="\d" data-href="/tiesraides/([^/]+)/[^"]+">.+?src="([^"]+)" alt="([^"]+)">', r, re.DOTALL)
94
+            channels2 = re.findall(r'<a class="channel-name">([^<]*)</a>\s+<div class="redirect-to-url" data-href="/tiesraides/([^/]+)/[^"]+">.+?<img style="width:100%;" src="([^"]+)".+?<h3>([^<]+)</h3>.+?<p class="unix">([^<]+)</p>', r, re.DOTALL)
95
+            channels = {}
96
+            for item in channels2:
97
+                title = item[0]
98
+                title =  h.unescape(title.decode("utf8")).encode("utf8")
99
+                img = "https://tvdom.tv"+item[2]
100
+                data2 = "tiesraides/%s/"%item[1]
101
+                desc = "%s\n%s\n%s"%(title,item[3],item[4])		    
102
+                channels[item[1]]={"title":title,"img":img,"desc":desc}
103
+                #content.append((title,self.name+"::"+data2,img,desc))
104
+
105
+            for r2 in re.findall(r'<div class="thumbnail-menu pull-left updater"(.+?)</div>\s+</div>', r, re.DOTALL):
106
+                ch = re.search('data-href="/tiesraides/([^/]+)/[^"]+"', r2, re.DOTALL).group(1)
107
+                data2 = "tiesraides/"+ch
108
+                m = re.search('src="(.+?)" alt="(.+?)">', r2, re.DOTALL)
109
+                title = m.group(2)
110
+                img = m.group(1)
111
+                desc = title
112
+                if ch in channels:
113
+                    img = channels[ch]["img"]
114
+                    desc = channels[ch]["desc"]
115
+                else:
116
+                    m = re.search('<img src="([^"]+)" alt="aaaaaa([^"]+)"><h3>.+<p class="unix">([^<]+)</p>', r2, re.DOTALL)
117
+                    if m:
118
+                        desc  = "%s\n%s\n%s"%(title,m.group(1),m.group(3))
119
+                        img = m.group(2)
120
+                content.append((title,self.name+"::"+data2,img,desc))
121
+            return content
122
+
123
+        elif clist == "tiesraides":
124
+            if not self.session:
125
+                self.login()
126
+            url = "https://tvdom.tv/" + data
127
+            headers = self.headers
128
+            headers["Cookie"] = "PHPSESSID=%s; neverending_story=1;"%self.session
129
+            r = self._http_request(url,headers=headers)
130
+            m = re.search("var streamConnectionUrl = '([^']+)'", r, re.DOTALL)
131
+            if m:
132
+                data2 = m.group(1)
133
+            else:
134
+                return ("No stream found %s"%data,"","","No stream found")
135
+            m = re.search('title: "([^"]+)"', r, re.DOTALL)
136
+            title = m.group(1) if m else data2
137
+            m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
138
+            desc = m.group(1) if m else title
139
+            m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
140
+            desc = m.group(1) if m else title 
141
+            m = re.search('var promo_image *= "([^"]+)', r, re.DOTALL)
142
+            img = m.group(1) if m else ""            
143
+            return (title,data2,img,desc)
144
+
145
+        ### Search ###
146
+        elif clist=="search":
147
+            url = "https://tvdom.tv/" + data
148
+            r = self._http_request(url)
149
+            for item in re.findall(r'<li data-xprs-search="\d+" data-href="([^"]+)".*?<img class="img-responsive" src="([^"]+)".*?<h3>([^<]+)</h3>.*?<h5>([^<]+)</h5>', r, re.DOTALL):
150
+                title = item[2] + " "+ item[3]
151
+                title =  h.unescape(title.decode("utf8")).encode("utf8")
152
+                img = "https://tvdom.tv" + item[1]
153
+                data2 = item[0][1:]
154
+                desc = title
155
+                content.append((title,self.name+"::"+data2,img,desc))
156
+            return content
157
+
158
+        ### Arhīva kategorijas ###
159
+        elif data=="arhivs":
160
+            url = "https://tvdom.tv/"+data
161
+            r = self._http_request(url)
162
+            for item in re.findall('pointer" href="/([^"]+)">([^<]+)</a>', r, re.DOTALL):
163
+                title = item[1]
164
+                title =  h.unescape(title.decode("utf8")).encode("utf8")
165
+                img = ""
166
+                data2 = item[0]
167
+                desc = title
168
+                content.append((title,self.name+"::"+data2,img,desc))
169
+            return content
170
+
171
+        ### Arhīva kategorijas programmas ###
172
+        elif clist=="arhivs":
173
+            url = "https://tvdom.tv/"+data
174
+            r = self._http_request(url)
175
+            for item in re.findall(r"""<li><div class="thumbnail pull-left" onclick="location\.href='([^']+)'" data-toggle="popover" title="([^"]+)" data-content="([^"]*)".+?<img class="img-responsive archive-image" src="([^"]+)""", r, re.DOTALL):
176
+            #for item in re.findall(r"""<li><div class="thumbnail pull-left" onclick="location\.href='([^']+)'" data-toggle="popover" title="([^"]+)" data-content="([^"]+)".+?<img class="img-responsive archive-image" src="([^"]+)""", r, re.DOTALL):
177
+                title = item[1].replace("&lt;br&gt;"," - ")
178
+                title =  h.unescape(title.decode("utf8")).encode("utf8")
179
+                img = "https://tvdom.tv"+item[3]
180
+                data2 = item[0][1:]
181
+                desc = item[2]
182
+                content.append((title,self.name+"::"+data2,img,desc))
183
+            return content
184
+
185
+        ### Arhīva programmas video saraksts ###
186
+        elif clist=="play_arhivs" and len(data.split("/"))==3 and not re.search("_\d+",plist[2]):
187
+            url = "https://tvdom.tv/"+data
188
+            r = self._http_request(url)
189
+            vid=re.search(r"id:(\d+), type: type", r, re.DOTALL).group(1)
190
+            data2 = data+"_"+vid
191
+            m = re.search('program_title        = "([^"]+)"', r, re.DOTALL)
192
+            title = m.group(1) if m else data2
193
+            m = re.search('<a class="episode">Pārraides laiks ēterā: <span>([^<]+)</span></a>', r, re.DOTALL)
194
+            datums = m.group(1) if m else ""
195
+            title = title + " " + datums
196
+            m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
197
+            desc = m.group(1) if m else title
198
+            m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
199
+            desc = m.group(1) if m else title 
200
+            m = re.search('var share_image *= "([^"]+)', r, re.DOTALL)
201
+            img = m.group(1) if m else ""            
202
+            content.append((title,self.name+"::"+data2,img,desc)) 
203
+            i = r.find('<span class="slider-top-title"')
204
+            if i>0: r = r[:i]
205
+            for item in re.findall('<div class="col-md-9 redirect-to-url same-event" data-href="/([^"]+)">.+?image" src="([^"]+)".+?<h3 class="same-title">([^<]+)</h3>.*?<h5 class="same-online">([^<]+)</h5>', r, re.DOTALL):
206
+                title = item[2] + " " + item[3]
207
+                title =  h.unescape(title.decode("utf8")).encode("utf8")
208
+                img = "https://tvdom.tv"+item[1]
209
+                data2 = item[0]
210
+                desc = title # TODO
211
+                content.append((title,self.name+"::"+data2,img,desc))
212
+            return content
213
+
214
+        ### Arhīva video
215
+        elif clist=="play_arhivs" and len(data.split("/"))==3 and re.search("_\d+",plist[2]):
216
+            url = "https://tvdom.tv/" + data
217
+            headers = self.headers
218
+            headers["Cookie"] = "PHPSESSID=%s; neverending_story=1;"%self.session
219
+            r = self._http_request(url,headers=headers)
220
+            m = re.search('var streamConnectionUrl  = "([^"]+)"', r, re.DOTALL)
221
+            if m:
222
+                data2 = m.group(1)
223
+            else:
224
+                return ("No stream found %s"%data,"","","No stream found")
225
+            m = re.search('program_title        = "([^"]+)"', r, re.DOTALL)
226
+            title = m.group(1) if m else data2
227
+            m = re.search('<a class="episode">Pārraides laiks ēterā: <span>([^<]+)</span></a>', r, re.DOTALL)
228
+            datums = m.group(1) if m else ""
229
+            title = title + " " + datums
230
+            m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
231
+            desc = m.group(1) if m else title
232
+            m = re.search('<div id="panel">([^<]+)<', r, re.DOTALL)
233
+            desc = m.group(1) if m else title 
234
+            m = re.search('var share_image *= "([^"]+)', r, re.DOTALL)
235
+            img = m.group(1) if m else ""            
236
+            return (title,data2,img,desc)
237
+
238
+
239
+    def is_video(self,data):
240
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
241
+        cmd = data.split("/")
242
+        if cmd[0] in ("tiesraides") and len(cmd)>1:
243
+            return True
244
+        elif cmd[0]=="play_arhivs" and len(cmd)==3 and re.search("_\d+",plist[2]):
245
+            return True
246
+        else:
247
+            return False
248
+
249
+    def call(self, data,headers=headers0,lang=""):
250
+        if not lang: lang = self.country
251
+        url = API_URL%lang + data
252
+        #print "[TVPlay Api] url: ",url
253
+        result = []
254
+        content = self._http_request(url)
255
+        return content
256
+
257
+if __name__ == "__main__":
258
+    country= "lv"
259
+    c = Source(country)
260
+    if len(sys.argv)>1:
261
+        data= sys.argv[1]
262
+    else:
263
+        data = "home"
264
+    content = c.get_content(data)
265
+    for item in content:
266
+        print item
267
+    #cat = api.get_categories(country)
268
+    #chan = api.get_channels("lv")
269
+    #prog = api.get_programs(channel=6400)
270
+    #prog = api.get_programs(category=55)
271
+    #seas = api.get_seasons(program=6453)
272
+    #str = api.get_streams(660243)
273
+    #res = api.get_videos(802)
274
+    #formats = api.getAllFormats()
275
+    #det = api.detailed("1516")
276
+    #vid = api.getVideos("13170")
277
+    pass

+ 4
- 0
resources/lib/sources/ustvnow.cfg Parādīt failu

@@ -0,0 +1,4 @@
1
+[ustvnow]
2
+user = ivars777@gmail.com
3
+password = kaskade7
4
+

+ 176
- 0
resources/lib/sources/ustvnow.py Parādīt failu

@@ -0,0 +1,176 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import urllib2, urllib
14
+import datetime, re, sys,os
15
+from collections import OrderedDict
16
+from SourceBase import SourceBase
17
+
18
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
19
+headers0 = headers2dict("""
20
+Host: m-api.ustvnow.com
21
+User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/47.0.2526.70 Mobile/13C71 Safari/601.1.46
22
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
23
+DNT: 1
24
+Connection: keep-alive
25
+""")
26
+import HTMLParser
27
+h = HTMLParser.HTMLParser()
28
+
29
+class Source(SourceBase):
30
+
31
+    def __init__(self,country="lv"):
32
+        self.name = "ustvnow"
33
+        self.title = "USTVNow"
34
+        self.img = "http://watch.ustvnow.com/assets/ustvnow/img/ustvnow_og_image.png"
35
+        self.desc = "USTVNow kanālu tiešraide"
36
+        self.headers = headers0
37
+
38
+        self.country=country
39
+        self.token = ""
40
+        cur_directory = os.path.dirname(os.path.abspath(__file__))
41
+        self.config_file = os.path.join(cur_directory,self.name+".cfg")
42
+        self.options = OrderedDict([("user","lietotajs"),("password","parole")])
43
+        self.options_read()
44
+
45
+    def login(self,user="",password=""):
46
+        if not user: user=self.options["user"]
47
+        if not password: password = self.options["password"]
48
+        self.options_read()        
49
+        headers = headers2dict("""
50
+        Host: m-api.ustvnow.com
51
+        Accept-Language: en-US,en;q=0.5
52
+        User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:46.0) Gecko/20100101 Firefox/46.0
53
+        Accept: text/html,application/xhtml+xml,application/xml
54
+        Connection: keep-alive
55
+        """)
56
+
57
+        url = "http://m-api.ustvnow.com/iphone/1/live/login?username=%s&password=%s&device=gtv&redir=0"%(user,password)
58
+        #url = "http://m-api.ustvnow.com/gtv/1/live/login?username=%s&password=%s&device=gtv&redir=0"%(user,password)
59
+        r = self._http_request(url,headers=headers)
60
+        if 'success' in r:
61
+            self.token = re.search('"token":"([^"]+)',r).group(1)
62
+            return True
63
+        else:
64
+            return False
65
+
66
+    def get_content(self, data):
67
+        print "[tvdom] get_content:", data
68
+        if "::" in data:
69
+            data = data.split("::")[1] 
70
+        path = data.split("?")[0]
71
+        clist = path.split("/")[0]
72
+        params = data[data.find("?"):] if "?" in data else ""
73
+        qs = dict(map(lambda x:x.split("="),re.findall("\w+=\w+",params)))
74
+        lang = qs["lang"] if "lang" in qs else self.country
75
+
76
+        content=[]
77
+        content.append(("..return", "back","","Return back"))
78
+
79
+        if clist=="home":
80
+            content.extend([
81
+                ("TV live streams", "ustvnow::tvlive","","TV live streams"),
82
+                ("Movies", "ustvnow::movies","","Movies (not implemented yet"),
83
+                ("Recordings", "ustvnow::recordings","","Recordings (not implemented yet"),
84
+            ])
85
+            return content
86
+
87
+        if clist=="movies":
88
+            return content
89
+
90
+        if clist=="recordings":
91
+            return content
92
+
93
+        ### Tiesraides kanalu saraksts ###
94
+        elif data=="tvlive":
95
+            if not self.token:
96
+                if not self.login():
97
+                    raise Exception("Can not login\nPlease check USTVNow username/password in\n/usr/lib/enigma2/python/Plugins/Extensions/sources/ustvnow.cfg file")
98
+            data = "live/channelguide?token=%s"%self.token
99
+            self.r = self.call(data)
100
+            if not self.r:
101
+                return content
102
+            for item in self.r["results"]:
103
+                if item["order"] == 1:    
104
+                    title = item["stream_code"]
105
+                    title =  h.unescape(title.decode("utf8")).encode("utf8")
106
+                    img = "http://m-api.ustvnow.com/"+item["prg_img"] #item["img"]
107
+                    data2 = "live/view?scode=%s&token=%s"%(item["scode"],self.token)
108
+                    desc = "%s\n%s (+%s')\n%s"%(item["title"],item["event_time"],int(item["actualremainingtime"])/60,item["description"])
109
+                    content.append((title,self.name+"::"+data2,img,desc))
110
+            return content
111
+
112
+        ### Tiesraides kanāls ###
113
+        elif path == "live/view":
114
+            url = "http://m-api.ustvnow.com/stream/1/%s"%data
115
+            r = self._http_request(url)
116
+            if not r:
117
+                return ("No stream found %s"%data,"","","No stream found")
118
+            r = json.loads(r)
119
+            if self.r:
120
+                ch = qs["scode"]
121
+                for item in self.r["results"]:
122
+                    if item["order"] == 1 and item["scode"] == ch:
123
+                        title = item["stream_code"]
124
+                        title = "%s - %s (%s)"%(item["stream_code"],item["title"],item["event_time"])
125
+                        img = "http://m-api.ustvnow.com/"+item["prg_img"]
126
+                        data2 = "live/view?scode=%s&token=%s"%(item["scode"],self.token)
127
+                        desc = "%s\n%s (+%s')\n%s"%(item["title"],item["event_time"],int(item["actualremainingtime"])/60,item["description"])
128
+            else:
129
+                title = data
130
+            data2 = r["stream"]
131
+            desc = title
132
+            img = ""          
133
+            return (title,data2,img,desc)               
134
+
135
+    def is_video(self,data):
136
+        if "::" in data:
137
+            data = data.split("::")[1]
138
+        if "live/view" in data:
139
+            return True
140
+        else:
141
+            return False
142
+
143
+    def call(self, data,headers=headers0,lang=""):
144
+        if not lang: lang = self.country
145
+        url = "http://m-api.ustvnow.com/gtv/1/"+data
146
+        content = self._http_request(url)
147
+        result = None
148
+        if content:
149
+            try:
150
+                result = json.loads(content)
151
+            except Exception, ex:
152
+                return None
153
+        return result
154
+
155
+
156
+if __name__ == "__main__":
157
+    country= "lv"
158
+    c = Source(country)
159
+    if len(sys.argv)>1:
160
+        data= sys.argv[1]
161
+    else:
162
+        data = "home"
163
+    content = c.get_content(data)
164
+    for item in content:
165
+        print item
166
+    #cat = api.get_categories(country)
167
+    #chan = api.get_channels("lv")
168
+    #prog = api.get_programs(channel=6400)
169
+    #prog = api.get_programs(category=55)
170
+    #seas = api.get_seasons(program=6453)
171
+    #str = api.get_streams(660243)
172
+    #res = api.get_videos(802)
173
+    #formats = api.getAllFormats()
174
+    #det = api.detailed("1516")
175
+    #vid = api.getVideos("13170")
176
+    pass

+ 5
- 0
resources/lib/sources/viaplay.cfg Parādīt failu

@@ -0,0 +1,5 @@
1
+[viaplay]
2
+user = ivars777@gmail.com
3
+password = kaskade7
4
+device = c3e3d2fb312d28f8f150772c9098c5eab40df72a-499b21d2-e6ec-4973-b57c-6db7cf43bdd0=36f25da2-3bb7-4a8e-9782-ba0cdc416973
5
+

+ 478
- 0
resources/lib/sources/viaplay.py Parādīt failu

@@ -0,0 +1,478 @@
1
+#!/usr/bin/env python
2
+# coding=utf8
3
+#
4
+# This file is part of PlayStream - enigma2 plugin to play video streams from various sources
5
+# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
6
+# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
7
+#
8
+try:
9
+    import json
10
+except:
11
+    import simplejson as json
12
+
13
+import requests, urlparse, urllib
14
+import datetime, time,re, sys,os
15
+from collections import OrderedDict
16
+from SourceBase import SourceBase
17
+try:
18
+    import util
19
+except:
20
+    parent = os.path.dirname(os.path.abspath(__file__))
21
+    parent = os.sep.join(parent.split(os.sep)[:-1])
22
+    sys.path.insert(0,parent)
23
+    import util
24
+
25
+headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
26
+
27
+class Source(SourceBase):
28
+
29
+    def __init__(self,language="en"):
30
+        self.name = "viaplay"
31
+        self.title = "viaplay.lv"
32
+        self.img = "https://yt3.ggpht.com/-noVdjbNR-V8/AAAAAAAAAAI/AAAAAAAAAAA/yZ9XNP5urLY/s900-c-k-no-mo-rj-c0xffffff/photo.jpg"
33
+        self.desc = "Viaplay.lv saturs"
34
+        self.url = "https://viaplay.lv/"
35
+        self.headers = headers2dict("""
36
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
37
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
38
+Connection: keep-alive
39
+Upgrade-Insecure-Requests: 1
40
+        """)
41
+        #self.language=language
42
+        cur_directory = os.path.dirname(os.path.abspath(__file__))
43
+        self.config_file = os.path.join(cur_directory,self.name+".cfg")
44
+        self.options = OrderedDict([("user","change_user"),("password","change_password"),("device","")])
45
+        self.options_read()
46
+        self.device = self.options["device"]
47
+        self.r = None # requests
48
+        self.play_session = None
49
+        self.s = None
50
+
51
+    def login(self,user="",password=""):
52
+        self.options_read()
53
+        if not user: user=self.options["user"]
54
+        if not password: password = self.options["password"]
55
+        self.s = requests.Session()
56
+
57
+        ### Dabu sesijas ID ===
58
+        headers = headers2dict("""
59
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
60
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
61
+Accept-Language: en-US,en;q=0.5
62
+Accept-Encoding: gzip, deflate, br
63
+Referer: https://viaplay.lv/
64
+Cookie: ott_cookies_confirmed=1;
65
+DNT: 1
66
+Connection: keep-alive
67
+Upgrade-Insecure-Requests: 1
68
+""")
69
+        r = requests.get(self.url,headers=headers)
70
+        if not "PLAY_SESSION" in r.cookies:
71
+            return False
72
+        self.play_session = r.cookies["PLAY_SESSION"]
73
+        self.csrfToken = re.search("csrfToken=(.+)",self.play_session).group(1)
74
+
75
+        ### Ielogojamies ###
76
+        headers = headers2dict("""
77
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
78
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
79
+Accept-Language: en-US,en;q=0.5
80
+Accept-Encoding: gzip, deflate, br
81
+Referer: https://viaplay.lv/
82
+Cookie: ott_cookies_confirmed=1; PLAY_SESSION=e618c42b377a65021298ff63309d5a907988ed1b-PSESSIONID=b010ea1b-fc5e-4a18-aa15-ebbe8b57b3f0&csrfToken=b4eb35263d9be16ef9f7b2f5d10a8ee99dfe75a8-1478051634814-63682b20f1e7e5579de6d056
83
+DNT: 1
84
+Connection: keep-alive
85
+Upgrade-Insecure-Requests: 1
86
+Content-Type: application/x-www-form-urlencoded
87
+""")
88
+        url = "https://viaplay.lv/tdi/login/nav/formular?csrfToken=%s"%self.csrfToken
89
+        params = "nav_redirectUri=https%3A%2F%2Fviaplay.lv%2F&nav_email={}&nav_password={}".format(urllib.quote(user),urllib.quote(password))
90
+        headers["Cookie"] = "ott_cookies_confirmed=1; PLAY_SESSION=%s;"%self.play_session
91
+        if self.device:
92
+            headers["Cookie"] += "ott_dids=%s"%self.device
93
+        #cookie = dict(PLAY_SESSION=self.play_session,_hjIncludedInSample=1, mobileAppPromo="shown")
94
+        r = requests.post(url,params,headers=headers,allow_redirects=False)
95
+        if not "Set-Cookie" in r.headers:
96
+            self.play_session = None
97
+            return False
98
+        self.ott = r.cookies["ott_web_sac"]
99
+
100
+        ### Dabu iekārtas ID ###
101
+        if not self.device:
102
+            headers = headers2dict("""
103
+User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36
104
+Accept: application/xml, text/xml, */*; q=0.01
105
+Accept-Language: en-US,en;q=0.5
106
+Accept-Encoding: gzip, deflate, br
107
+Content-Type: application/x-www-form-urlencoded; charset=UTF-8
108
+X-Requested-With: XMLHttpRequest
109
+Referer: https://viaplay.lv/movies/me-and-earl-and-the-dying-girl
110
+DNT: 1
111
+Connection: keep-alive    """)
112
+            url = "https://viaplay.lv/tdi/account/device/create?_infuse=1&csrfToken=%s"%self.csrfToken
113
+            params = "successRedirectUri=https%3A%2F%2Fviaplay.lv%2Fmovies%2F&slotId=&title=Enigma2"
114
+            headers["Cookie"] = "PLAY_SESSION=%s; ott_cookies_confirmed=1; ott_web_sac=%s;"%(self.play_session,self.ott)
115
+            #cookie = dict(PLAY_SESSION=self.play_session,_hjIncludedInSample=1, mobileAppPromo="shown")
116
+            r = requests.post(url,params,headers=headers,allow_redirects=False)
117
+            if not ("Set-Cookie" in r.headers and "ott_dids" in r.headers["Set-Cookie"]):
118
+                self.play_session = None
119
+                return False
120
+            self.device =  r.cookies["ott_dids"]
121
+            self.options["device"] = self.device
122
+            self.options_write(self.options)
123
+        return True
124
+
125
+    def logout(self):
126
+        return True
127
+
128
+    def is_logedin(self):
129
+        if self.play_session:
130
+            return True
131
+        else:
132
+            return False
133
+
134
+    def get_video_info(self,vid):
135
+        import demjson
136
+        ### Dabu strimus ###
137
+        headers = headers2dict("""
138
+Host: viaplay.lv
139
+User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/47.0.2526.70 Mobile/13C71 Safari/601.1.46
140
+Accept: application/xml, text/xml, */*; q=0.01
141
+Accept-Language: en-US,en;q=0.5
142
+Accept-Encoding: gzip, deflate, br
143
+X-Requested-With: XMLHttpRequest
144
+DNT: 1
145
+Connection: keep-alive
146
+Referer: https://viaplay.lv/
147
+""")
148
+        url = "https://viaplay.lv/prehravac/init?_infuse=1&productId=%s"%vid #t110623
149
+        headers["Cookie"] = "ott_cookies_confirmed=1; ott_dids=%s; PLAY_SESSION=%s"%(self.device,self.play_session)
150
+        r = requests.get(url,headers=headers,allow_redirects=False)
151
+        statuss = re.search("<status>(.+?)</status>", r.content).group(1)
152
+        if statuss.lower() <> "ok":
153
+            raise Exception(statuss)
154
+        #print r.content
155
+        m = re.search(r"<!\[CDATA\[\s+var TDIPlayerOptions = (.+?);[\n\t\s]+\]\]>\s+</script>", r.content, re.DOTALL)
156
+        if not m:
157
+            raise "Can not find stream info"
158
+        txt = m.group(1)
159
+        txt = re.sub("// .+$", "", txt, flags=re.MULTILINE)
160
+        #print txt
161
+        #for m in re.finditer("// .+$", txt, re.MULTILINE):
162
+        #    txt = txt[:m.start()] + txt[m.end():]
163
+        #print txt
164
+        js = demjson.decode(txt)
165
+        return js
166
+        #return txt
167
+
168
+
169
+    def get_content(self, data):
170
+        print "[%s] get_content:"%self.name, data
171
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
172
+        content=[]
173
+        content.append(("..return", "back","","Return back"))
174
+
175
+        if clist=="home":
176
+            content.extend([
177
+                ("Search", "viaplay::search-results-all?query={0}",self.img,"Meklēt"),
178
+                ("Filmas", "viaplay::movies",self.img,"Filmas"),
179
+                ("Seriāli", "viaplay::series",self.img,"Seriāli"),
180
+                ("Bērniem", "viaplay::kids",self.img,"Bērniem"),
181
+                ("Dokumentalās filmas", "viaplay::documentary",self.img,"Dokumentalās filmas"),
182
+                ("Sports", "viaplay::live",self.img,"Sports"),
183
+             ])
184
+            return content
185
+
186
+        ### Meklēt ###
187
+        elif clist=="search-results-all":
188
+            url = "https://viaplay.lv/"+data
189
+            r = self._http_request(url)
190
+            result = re.findall(r'<div id="product-(\w+)".+?<a href="([^"]+)">.+?<img data-srcset="([^ ]+).+?alt="([^"]+)">.+?<h3 class="is-size-h6">([^<]+)</h3>.*?<p>([^<]+).+?</p>.+?<p class="promo-notice">([^<]+)</p>.+?<p class="info">([^<]+)</p>', r, re.DOTALL)
191
+            for item in result:
192
+                vid = item[0]
193
+                data2 = item[1].replace("https://viaplay.lv/","")
194
+                img = item[2]
195
+                ep = item[3]
196
+                title= item[4]
197
+                seas = item[5].replace("\n","").replace("\t","")
198
+                desc = item[6]
199
+                desc2 = item[7]
200
+                if ep==title:
201
+                    title = "%s (%s)"%(title,seas)
202
+                else:
203
+                    title = "%s - %s%s"%(title,seas,ep)
204
+                desc = "%s\n%s\n%s"%(title,desc2,desc)
205
+                content.append((title,self.name+"::"+data2,img,desc))
206
+            return content
207
+
208
+        ### Sadalas ##
209
+        elif data in ["movies","series","kids","documentary"]:
210
+            r = self._http_request(self.url+data)
211
+            # https://viaplay.lv/tdi/movies/next?sections[]=MOVIES&genres[]=a3591&sort[]=latest&offset=0
212
+            # https://viaplay.lv/tdi/series/next?sections[]=SERIES&sort[]=latest&offset=0
213
+            # https://viaplay.lv/tdi/kids/next?sections[]=KIDS&cat[]=SERIES&cat[]=MOVIE&sort[]=latest&offset=18
214
+            # https://viaplay.lv/kids?sections[]=KIDS&cat[]=SERIES&sort[]=latest
215
+            sections =  {"movies":"MOVIES","series":"SERIES","kids":"KIDS","documentary":"DOCUMENTS"}
216
+            nosaukums = {"movies":"Flmas","series":"Seriāli","kids":"Bērnu","documentary":"Dokumentalās"}
217
+            #availability = {"new":"jaunākās","last":"pēdējā iespēja"}
218
+            sort = OrderedDict([("latest","jaunākais"),("title","pēc nosaukuma"),("popular","pēc popularitātes"),("year","pēc gada")])
219
+            for s in sort:
220
+                if data in ("movies","series"):
221
+                    title = "%s - %s"%(nosaukums[data],sort[s])
222
+                    data2 = "%s/next?sections[]=%s&sort[]=%s"%(data,sections[data],s)
223
+                    content.append((title,self.name+"::"+data2,self.img,title))
224
+                else:
225
+                    title = "%s filmas - %s"%(nosaukums[data],sort[s])
226
+                    data2 = "%s/next?sections[]=%s&cat[]=MOVIE&sort[]=%s"%(data,sections[data],s)
227
+                    content.append((title,self.name+"::"+data2,self.img,title))
228
+                    title = "%s seriāli - %s"%(nosaukums[data],sort[s])
229
+                    data2 = "%s/next?sections[]=%s&cat[]=SERIES&sort[]=%s"%(data,sections[data],s)
230
+                    content.append((title,self.name+"::"+data2,self.img,title))
231
+
232
+            # Pievienojam žanru sarakstu
233
+            result = re.findall(r'name="genres\[\]" value="([^"]+)">.+?class="">([^<]+)</label>', r, re.DOTALL)
234
+            for item in result:
235
+                s = "latest"
236
+                genre = item[1].replace("&amp;","&")
237
+                title = "%s: %s"%(nosaukums[data],genre)
238
+                data2 = "%s/next?sections[]=%s&genres[]=%s&sort[]=%s"%(data,sections[data],item[0],s)
239
+                content.append((title,self.name+"::"+data2,self.img,title))
240
+
241
+            return content
242
+
243
+        ### Filmu/seriālu/sēriju saraksts ###
244
+        elif clist in ("movies","series","kids","documentary") and plist[1] == "next":
245
+            url = "https://viaplay.lv/tdi/"+data
246
+            r = self._http_request(url)
247
+            if clist == "series" and "season" in qs:
248
+                result = re.findall(r'<div id="product-(\w+)".+?<a href="([^"]+)">.+?<img data-srcset="([^ ]+).+?alt="([^"]+)">.+?<h3 class="is-size-h6">([^<]+)</h3>.*?<p>([^<]+).+?</p>.+?<p class="promo-notice">([^<]+)</p>.+?<p class="info">([^<]+)</p>', r, re.DOTALL)
249
+                for item in result:
250
+                    vid = item[0]
251
+                    data2 = item[1].replace("https://viaplay.lv/","")
252
+                    img = item[2]
253
+                    ep = item[3]
254
+                    title= item[4]
255
+                    seas = item[5]
256
+                    desc = item[6]
257
+                    desc2 = item[7]
258
+                    title = "%s - %s%s"%(title,seas,ep)
259
+                    desc = "%s\n%s\n%s"%(title,desc2,desc)
260
+                    content.append((title,self.name+"::"+data2,img,desc))
261
+            else: # filmas
262
+                result = re.findall(r'<div id="product-(\w+)".+?<a href="([^"]+)">.+?<img data-srcset="([^ ]+).+?alt="([^"]+)">.+?<p>([^<]+)</p>.+?<p class="promo-notice">([^<]+).+?<p class="is-strong detail">(.+?)</p>.+?<p class="info">([^<]+)</p>', r, re.DOTALL)
263
+                for item in result:
264
+                    vid = item[0]
265
+                    data2 = item[1].replace("https://viaplay.lv/","")
266
+                    img = item[2]
267
+                    title = item[3]
268
+                    year = item[4]
269
+                    year  = year.replace("\n","").replace("\t","")
270
+                    title = title +"(%s)"%year
271
+                    desc= item[5]
272
+                    genre = re.findall(">([^<]+)<", item[6], re.DOTALL)
273
+                    genre = ("".join(genre)).replace("&amp;","&")
274
+                    desc2 = item[7]
275
+                    desc = "%s\n%s\n%s"%(genre,desc2,desc)
276
+                    content.append((title,self.name+"::"+data2, img,desc))
277
+            m = re.search(r"data\('href', 'https://viaplay\.lv/tdi/([^']+)'\)", r, re.DOTALL)
278
+            if m:
279
+                data2 = m.group(1)
280
+                content.append(("Next page",self.name+"::"+data2,img,"Next page"))
281
+            return content
282
+
283
+        ### Seriāls ###
284
+        elif clist == "series" and len(plist)==2:
285
+            url = "https://viaplay.lv/"+data
286
+            r = self._http_request(url)
287
+            result = re.findall(r'<li>.*?<a class="tdi" href="https://viaplay\.lv/([^"]+)" data-related-ancestor="\.js-tdi-items-filter-and-items">([^<]+)</a>.*?</li>', r, re.DOTALL)
288
+            for item in result:
289
+                title = item[1]
290
+                data2 = item[0]
291
+                data2 = data2.replace("series/","series/next/")
292
+                data2 = data2+"&sort[]=ord"
293
+                #series/littlest-pet-shop?season=t6821
294
+                #series/next/peppa-pig?season=t8430
295
+                # &sort[]=ord
296
+                if "availability=" in data2: continue
297
+                content.append((title,self.name+"::"+data2,self.img,title)) #TODO bilde
298
+            return content
299
+
300
+    def is_video(self,data):
301
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
302
+        if clist in ("movies","documentary","kids") and len(plist)>1 and plist[1]<>"next":
303
+            return True
304
+        elif clist == "series"  and len(plist)>1 and plist[1] == "episode":
305
+            return True
306
+        else:
307
+            return False
308
+
309
+    def get_streams(self, data):
310
+        print "[viaplay] get_streams:", data
311
+        if not self.is_video(data):
312
+            return []
313
+        source,data,path,plist,clist,params,qs = self.parse_data(data)
314
+        if not self.is_logedin():
315
+            self.login()
316
+        if not self.is_logedin():
317
+            raise Exception("Could not login to viaplay.lv, check username/password in options")
318
+
319
+        streams = []
320
+        url = "https://viaplay.lv/"+data
321
+        r = self._http_request(url)
322
+        if clist=="series":
323
+            m = re.search(r'<h1 class="is-bottom-sticked is-size-h2">(.+?)</h1>.*?<h2 class="is-size-h4">.*?<p class="is-size-h6 is-strong is-bottom-sticked">(.+?)<div class="toggler-content">\s+<p>(.+?)</p>', r, re.DOTALL)
324
+            if not m:
325
+                raise Exception("Problem getting video information")
326
+            title = m.group(1).replace("\n"," ").replace("\t","").strip()
327
+            title = re.sub("<[^>]+>","",title).strip()
328
+            desc2 = m.group(2).replace("\n"," ").replace("\t","").strip()
329
+            desc2 = re.sub("<[^>]+>","",desc2).strip()
330
+            desc = m.group(3)
331
+            desc = "%s\n%s"%(desc2,desc)
332
+            vid = re.search('data-productid="(\w+)"',r).group(1)
333
+        else:
334
+            m = re.search(r'<h1 class="is-strong is-bottom-sticked is-size-h2" jnp-id="(\w+)">([^<]+)</h1>.*?<h2 class="is-strong is-size-h4">([^<]+)</h2>.*?<p class="is-size-h6 is-strong is-bottom-sticked">(.+?)<div class="toggler-content">\s+<p>(.+?)</p>', r, re.DOTALL)
335
+            if not m:
336
+                raise Exception("Problem getting video information")
337
+            title = m.group(2).strip()
338
+            title2 = m.group(3).strip()
339
+            title = "%s | %s"%(title,title2)
340
+            desc = m.group(5).strip()
341
+            desc2 = m.group(4).strip()
342
+            desc2 = re.sub("<[^>]+>","",desc2)
343
+            desc2 = desc2.replace("\n"," ").replace("\t","")
344
+            desc = "%s\n%s"%(desc2,desc)
345
+            vid = m.group(1)
346
+
347
+        js = self.get_video_info(vid)
348
+        #for m in re.finditer(r"lang: '(?P<lang>\w+)',\s+src: '(?P<url>[^']+)',\s+type: '(?P<mime>[^']+)',\s+drm: \[(?P<drm>.+?)\]\s*\}", r, re.DOTALL):
349
+        if not js:
350
+            return []
351
+        tracks = js["tracks"]
352
+        #if not tracks["HLS"]:
353
+        #    raise Exception("Encrypted DASH playing not yet implemented")
354
+
355
+        captions = []
356
+        llist = ["fr","en","ru","lv"]
357
+        for st in js["plugins"]["settings"]["subtitles"]:
358
+            sub = {}
359
+            sub["url"] = st["src"]
360
+            sub["lang"] = st["srclang"]
361
+            sub["name"] = st["label"]
362
+            sub["type"] = "vtt"
363
+            sub["order"] = llist.index(sub["lang"])*10 if sub["lang"] in llist else 0
364
+            captions.append(sub)
365
+        captions = sorted(captions,key=lambda item: item["order"],reverse=True)
366
+
367
+        for s in tracks["HLS"] if tracks["HLS"]  else tracks["DASH"] :
368
+            stype = "DASH" if "dash" in s["type"] else "HLS"
369
+            if "drm" in s: ###
370
+                # TODO, encrypted stream
371
+                continue
372
+            url = s["src"]
373
+            #urlp = util.streamproxy_encode(s["src"])
374
+            stream = util.item()
375
+            stream["url"]=url
376
+            stream["resolver"] = "viaplay"
377
+            stream["lang"]=s["lang"]
378
+            stream["quality"]="variant"
379
+            stream["bitrate"]= "1000000"
380
+            stream["name"]= title
381
+            stream["desc"]=desc
382
+            stream["type"]=stype
383
+            stream["subs"] = captions
384
+            print url
385
+            if stype=="DASH": streams.append(stream)
386
+
387
+            if stype == "HLS": # izvelkam individuālos strimus
388
+                r = requests.get(url)
389
+                result = re.findall("#EXT-X-STREAM-INF:BANDWIDTH=(\d+),RESOLUTION=(\d+x\d+)\n(\w+.m3u8)", r.content)
390
+                if not result:
391
+                    continue
392
+                for s2 in result:
393
+                    ### TODO vajag lietot cookie ar tokenu no playlista requesta
394
+                    if "set-cookie" in r.headers:
395
+                        headers = {"Cookie":r.headers["set-cookie"]}
396
+                    else:
397
+                        headers={}
398
+                    #url2 = re.sub(r"(http.*://.+/)\w+.m3u8", r"\1"+s2[2], url)
399
+                    url2 = "/".join(url.split("/")[:-1])+"/"+s2[2]
400
+                    #r2 = requests.get(url2,headers=headers)
401
+                    #if "set-cookie" in r2.headers:
402
+                        #headers = {"Cookie":r2.headers["set-cookie"]}
403
+                    #else:
404
+                        #headers={}
405
+                    url2p=util.streamproxy_encode(url2,headers)
406
+                    stream = util.item()
407
+                    stream["url"]=url2p
408
+                    stream["lang"]=s["lang"]
409
+                    stream["quality"]="%s"%(s2[1])
410
+                    stream["name"]= title
411
+                    stream["desc"]=desc
412
+                    stream["bitrate"]=s2[0]
413
+                    stream["type"]="DASH" if "dash" in s["type"] else "HLS"
414
+                    streams.append(stream)
415
+
416
+        ### TODO - sakārtot sarakstu, lai pirmais ir labakais video
417
+        qlist = ["","512","640","758","1024","variant"]
418
+        llist = ["lt","et","fr","en","ru","lv"]
419
+        for s in streams:
420
+            lv = llist.index(s["lang"])*10000000 if s["lang"] in llist else 0
421
+            #qv=qlist.index(s["quality"]) if s["quality"] in qlist else 0
422
+            qv = int(s["bitrate"]) if s["bitrate"] else 0
423
+            s["order"] = lv+qv
424
+            #print s["lang"],s["quality"],s["bitrate"],s["order"]
425
+
426
+        streams = sorted(streams,key=lambda item: item["order"],reverse=True)
427
+        return streams
428
+
429
+    def call(self, data,params = None, headers=None):
430
+        if not headers: headers = self.headers
431
+        #if not lang: lang = self.country
432
+        url = "https://viaplay.lv/tdi/" + data
433
+        content = self._http_request(url, params, headers)
434
+        return content
435
+
436
+if __name__ == "__main__":
437
+    if len(sys.argv)>1:
438
+        data= sys.argv[1]
439
+    else:
440
+        data = "kids/child-and-karlson"
441
+    c = Source()
442
+    print "login: %s"%c.login()
443
+    if "/" in data:
444
+        streams = c.get_streams(data)
445
+        util.play_video(streams)
446
+    else:
447
+        vinfo = c.get_video_info(data)
448
+        if "HLS" in vinfo["tracks"] and vinfo["tracks"]["HLS"]:
449
+            url = vinfo["tracks"]["HLS"][0]["src"]
450
+            urlp = util.streamproxy_encode(url)
451
+            util.player(urlp)
452
+        else:
453
+            print "No HLS stream"
454
+    sys.exit()
455
+
456
+    r = requests.get("https://viaplay.lv/movies?sections[]=MOVIES")
457
+    result = re.findall(r'<div id="product-(\w+)".+?<a href="([^"]+)">.+?<img data-srcset="([^ ]+).+?alt="([^"]+)">.+?<p class="promo-notice">([^<]+)<', r.content, re.DOTALL)
458
+    for item in result:
459
+        vid = item[0]
460
+        url = item[1]
461
+        img = item[2]
462
+        title = item[3]
463
+        desc= item[4]
464
+        print "\n%s (%s):"%(title,vid)
465
+        vinfo = c.get_video_info(vid)
466
+        if "HLS" in vinfo["tracks"]:
467
+            for s in vinfo["tracks"]["HLS"]:
468
+                print "HLS %s: \n%s"%(s["lang"],s["src"])
469
+
470
+        if "DASH" in vinfo["tracks"]:
471
+            for s in vinfo["tracks"]["DASH"]:
472
+                print "DASH %s: \n%s"%(s["lang"],s["src"])
473
+        #except Exception,ex:
474
+            #print ex.message
475
+    #content = c.get_content(data)
476
+    #for item in content:
477
+    #    print item
478
+    pass

+ 603
- 0
resources/lib/util.py Parādīt failu

@@ -0,0 +1,603 @@
1
+# -*- coding: UTF-8 -*-
2
+# /*
3
+# *      Copyright (C) 2011 Libor Zoubek,ivars777
4
+# *
5
+# *
6
+# *  This Program is free software; you can redistribute it and/or modify
7
+# *  it under the terms of the GNU General Public License as published by
8
+# *  the Free Software Foundation; either version 2, or (at your option)
9
+# *  any later version.
10
+# *
11
+# *  This Program is distributed in the hope that it will be useful,
12
+# *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
+# *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
+# *  GNU General Public License for more details.
15
+# *
16
+# *  You should have received a copy of the GNU General Public License
17
+# *  along with this program; see the file COPYING.  If not, write to
18
+# *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
+# *  http://www.gnu.org/copyleft/gpl.html
20
+# *
21
+# */
22
+import os, sys, re
23
+import urllib, urllib2
24
+import datetime
25
+import traceback
26
+import cookielib
27
+import requests
28
+from htmlentitydefs import name2codepoint as n2cp
29
+import HTMLParser
30
+import StringIO
31
+
32
+#import threading
33
+#import Queue
34
+import pickle
35
+import string
36
+import simplejson as json
37
+#from demjson import demjson
38
+#import demjson
39
+import json
40
+#from bs4 import BeautifulSoup
41
+
42
+UA = 'Mozilla/6.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.5) Gecko/2008092417 Firefox/3.0.3'
43
+LOG = 2
44
+
45
+_cookie_jar = None
46
+CACHE_COOKIES = 'cookies'
47
+
48
+def system():
49
+    if "kodi" in sys.executable.lower():
50
+        return "kodi"
51
+    elif sys.platform == "win32":
52
+        return "windows"
53
+    elif sys.platform == "linux2":
54
+        return "enigma2"
55
+    else:
56
+        return "unknown"
57
+
58
+def play_video(streams):
59
+    if len(streams)>1:
60
+        for i,s in enumerate(streams):
61
+
62
+            print "%s: [%s,%s,%s] %s"%(i,s["quality"],s["lang"],s["type"],s["name"])
63
+        a = raw_input("Select stram to play: ")
64
+        try:
65
+            n = int(a)
66
+        except:
67
+            n = 0
68
+        if n>=len(streams):
69
+            stream = streams[-1]
70
+        else:
71
+            stream = streams[n]
72
+    else:
73
+        stream = streams[0]
74
+
75
+    stream = stream_change(stream)
76
+    title = stream["name"]
77
+    url = stream["url"]
78
+    suburl = ""
79
+    print url
80
+    if "subs" in stream and stream["subs"]:
81
+        suburl = stream["subs"][0]["url"]
82
+        print "\n**Download subtitles %s - %s"%(title,suburl)
83
+        subs = urllib2.urlopen(suburl).read()
84
+        if subs:
85
+            fname0 = re.sub("[/\n\r\t,]","_",title)
86
+            subext = ".srt"
87
+            subfile = os.path.join("",fname0+subext)
88
+            if ".xml" in suburl:
89
+                subs = ttaf2srt(subs)
90
+            with open(subfile,"w") as f:
91
+                f.write(subs)
92
+        else:
93
+            print "\n Error downloading subtitle %s"%suburl
94
+    return player(url,stream["name"],suburl,stream["headers"])
95
+
96
+def player(url,title="",suburl="",headers={}):
97
+    from subprocess import call
98
+    print "\n**Play stream %s\n%s"%(title,url.encode("utf8"))
99
+    cmd1 = [r"c:\Program Files\VideoLAN\VLC\vlc.exe",url,
100
+           "--meta-title",title.decode("utf8").encode(sys.getfilesystemencoding()),
101
+           "--http-user-agent","Enigma2"
102
+    ]
103
+    # gst-launch-1.0 -v souphttpsrc ssl-strict=false proxy=127.0.0.1:8888 extra-headers="Origin:adadadasd"  location="http://bitdash-a.akamaihd.net/content/sintel/sintel.mpd" ! decodebin! autovideosink
104
+    cmd2 = [
105
+        r"C:\gstreamer\1.0\x86_64\bin\gst-launch-1.0","-v",
106
+        "playbin", 'uri="%s"'%url,
107
+        #"souphttpsrc", "ssl-strict=false",
108
+        #"proxy=127.0.0.1:8888",
109
+        #'location="%s"'%url,
110
+        #'!decodebin!autovideosink'
111
+    ]
112
+    cmd = cmd1 if url.startswith("https") else cmd2
113
+    ret = call(cmd)
114
+    #if ret:
115
+        #a = raw_input("*** Error, continue")
116
+    return
117
+
118
+SPLIT_CHAR = "~"
119
+SPLIT_CODE = urllib.quote(SPLIT_CHAR)
120
+EQ_CODE = urllib.quote("=")
121
+COL_CODE = urllib.quote(":")
122
+SPACE_CODE = urllib.quote(" ")
123
+PROXY_URL = "http://localhost:88/"
124
+
125
+def stream_change(stream):
126
+    #return stream # TODO
127
+    if stream["surl"]:
128
+        if not re.search("https*://(hqq|goo.\gl)",stream["surl"]):
129
+            return stream
130
+        stream["url"] = streamproxy_encode(stream["url"],stream["headers"])
131
+        stream["headers"] = {}
132
+        return stream
133
+    else:
134
+        return stream
135
+
136
+def streamproxy_encode(url,headers=[]):
137
+    if not "?" in url:
138
+        url = url+"?"
139
+    url2 = url.replace(SPLIT_CHAR,SPLIT_CODE).replace(":",COL_CODE).replace(" ",SPACE_CODE)
140
+    url2 = PROXY_URL + url2
141
+    if headers:
142
+        headers2 = []
143
+        for h in headers:
144
+            headers2.append("%s=%s"%(h,headers[h].replace("=",EQ_CODE).replace(SPLIT_CHAR,SPLIT_CODE).replace(" ",SPACE_CODE)))
145
+        headers2 = SPLIT_CHAR.join(headers2)
146
+        url2 = url2+SPLIT_CHAR+headers2
147
+    return url2
148
+
149
+def streamproxy_decode(urlp):
150
+    import urlparse
151
+    path = urlp.replace(re.search("http://[^/]+",urlp).group(0),"")
152
+    p = path.split(SPLIT_CHAR)
153
+    url = urllib.unquote(p[0][1:])
154
+    #headers = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/47.0.2526.70 Mobile/13C71 Safari/601.1.46"}
155
+    headers={}
156
+    if len(p)>1:
157
+        for h in p[1:]:
158
+            #h = urllib.unquote()
159
+            headers[h.split("=")[0]]=urllib.unquote(h.split("=")[1])
160
+    return url,headers
161
+
162
+class Captions(object):
163
+    def __init__(self,uri):
164
+        self.uri = uri
165
+        self.subs = []
166
+        self.styles = {}
167
+        if uri.startswith("http"):
168
+            r = requests.get(uri)
169
+        if r.status_code == 200:
170
+            self.loads(r.content)
171
+
172
+    def loads(self,s):
173
+        if "WEBVTT" in s[:s.find("\n")]: # vtt captions
174
+            self.load_vtt(s)
175
+        elif "<?xml" in s[:s.find("\n")]:
176
+            self.load_ttaf(s)
177
+        else:
178
+            self.load_vtt(s) # TODO
179
+
180
+
181
+    def load_ttaf(self,s):
182
+        for r2 in re.findall("<style .+?/>", s):
183
+            st = {}
184
+            for a in re.findall(r'(\w+)="([^ "]+)"', r2):
185
+                st[a[0]] = a[1]
186
+                if a[0] == "id":
187
+                    sid = a[1]
188
+            self.styles[sid] = st
189
+        for r2 in re.findall("<p .+?</p>", s):
190
+            sub = {}
191
+            sub["begin"] = str2sec(re.search('begin="([^"]+)"', r2).group(1)) if re.search('begin="([^"]+)"', r2) else -1
192
+            sub["end"] = str2sec(re.search('end="([^"]+)"', r2).group(1)) if re.search('end="([^"]+)"', r2) else -1
193
+            sub["style"] = re.search('style="([^"]+)"', r2).group(1) if re.search('style="([^"]+)"', r2) else None
194
+            sub["text"] = re.search("<p[^>]+>(.+)</p>", r2).group(1).replace("\n","")
195
+            sub["text"] = re.sub("<br\s*?/>","\n",sub["text"])
196
+            sub["text"] = re.sub("<.+?>"," ",sub["text"])
197
+            self.subs.append(sub)
198
+        pass
199
+
200
+    def load_vtt(self,s):
201
+        f = StringIO.StringIO(s)
202
+        while True:
203
+            line = f.readline()
204
+            if not line:
205
+                break
206
+            m = re.search(r"([\d\.\,:]+)\s*-->\s*([\d\.\,\:]+)",line)
207
+            if m:
208
+                sub = {}
209
+                sub["begin"] = str2sec(m.group(1))
210
+                sub["end"] = str2sec(m.group(2))
211
+                sub["style"] = None
212
+                sub["text"] = []
213
+                line = f.readline()
214
+                while line.strip():
215
+                    txt = line.strip()
216
+                    if isinstance(txt,unicode):
217
+                        txt = txt.encode("utf8")
218
+                    sub["text"].append(txt)
219
+                    line = f.readline()
220
+                sub["text"] = "\n".join(sub["text"])
221
+                self.subs.append(sub)
222
+            else:
223
+                continue
224
+        pass
225
+
226
+    def get_srt(self):
227
+        out = ""
228
+        i = 0
229
+        for sub in self.subs:
230
+            i +=1
231
+            begin = sub["begin"]
232
+            begin = "%s,%03i"%(str(datetime.timedelta(seconds=begin/1000)),begin%1000)
233
+            end = sub["end"]
234
+            end = "%s,%03i"%(str(datetime.timedelta(seconds=end/1000)),end%1000)
235
+            txt2 = sub["text"]
236
+            out += "%s\n%s --> %s\n%s\n\n\n"%(i,begin,end,txt2)
237
+        return out
238
+
239
+def str2sec(r):
240
+    # Convert str time to miliseconds
241
+    r= r.replace(",",".")
242
+    m = re.search(r"(\d+\:)*(\d+)\:(\d+\.\d+)", r)
243
+    if m:
244
+        sec = int(m.group(1)[:-1])*60*60*1000 if m.group(1) else 0
245
+        sec += int(m.group(2))*60*1000 + int(float(m.group(3))*1000)
246
+        return sec
247
+    else:
248
+        return -1
249
+
250
+
251
+#c = Captions("http://195.13.216.2/mobile-vod/mp4:lb_barbecue_fr_lq.mp4/lb_barbecue_lv.vtt")
252
+#c = Captions("http://www.bbc.co.uk/iplayer/subtitles/ng/modav/bUnknown-0edd6227-0f38-411c-8d46-fa033c4c61c1_b05ql1s3_1479853893356.xml")
253
+#url = "http://195.13.216.2/mobile-vod/mp4:ac_now_you_see_me_2_en_lq.mp4/ac_now_you_see_me_2_lv.vtt"
254
+#c = Captions(url)
255
+
256
+#pass
257
+
258
+
259
+def ttaf2srt(s):
260
+    out = u""
261
+    i = 0
262
+    for p,txt in re.findall("<p ([^>]+)>(.+?)</p>", s, re.DOTALL):
263
+        i +=1
264
+        begin = re.search('begin="(.+?)"',p).group(1)
265
+        begin = begin.replace(".",",")
266
+        end = re.search('end="(.+?)"',p).group(1)
267
+        end = end.replace(".",",")
268
+        txt2 = re.sub("<br */>","\n",txt)
269
+        out += "%s\n%s --> %s\n%s\n\n"%(i,begin,end,txt2)
270
+    return out
271
+
272
+
273
+def item():
274
+    stream0 = {
275
+        'name': '',
276
+        'url': '',
277
+        'quality': '?',
278
+        'surl': '',
279
+        'subs': [],
280
+        'headers': {},
281
+        "desc":"",
282
+        "img":"",
283
+        "lang":"",
284
+        "type":"",
285
+        "resolver":"",
286
+        "order":0
287
+        }
288
+    return stream0
289
+
290
+class _StringCookieJar(cookielib.LWPCookieJar):
291
+
292
+    def __init__(self, string=None, filename=None, delayload=False, policy=None):
293
+        cookielib.LWPCookieJar.__init__(self, filename, delayload, policy)
294
+        if string and len(string) > 0:
295
+            self._cookies = pickle.loads(str(string))
296
+
297
+    def dump(self):
298
+        return pickle.dumps(self._cookies)
299
+
300
+
301
+def init_urllib(cache=None):
302
+    """
303
+    Initializes urllib cookie handler
304
+    """
305
+    global _cookie_jar
306
+    data = None
307
+    if cache is not None:
308
+        data = cache.get(CACHE_COOKIES)
309
+    _cookie_jar = _StringCookieJar(data)
310
+    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(_cookie_jar))
311
+    urllib2.install_opener(opener)
312
+
313
+
314
+def cache_cookies(cache):
315
+    """
316
+    Saves cookies to cache
317
+    """
318
+    global _cookie_jar
319
+    if _cookie_jar:
320
+        cache.set(CACHE_COOKIES, _cookie_jar.dump())
321
+
322
+
323
+def request0(url, headers={}):
324
+    debug('request: %s' % url)
325
+    req = urllib2.Request(url, headers=headers)
326
+    req.add_header('User-Agent', UA)
327
+    try:
328
+        response = urllib2.urlopen(req)
329
+        data = response.read()
330
+        response.close()
331
+    except urllib2.HTTPError, error:
332
+        data = error.read()
333
+
334
+    debug('len(data) %s' % len(data))
335
+    return data
336
+
337
+def request(url, headers={}):
338
+    debug('request: %s' % url)
339
+    #req = urllib2.Request(url, headers=headers)
340
+    #req.add_header('User-Agent', UA)
341
+    if 'User-Agent' not in headers:
342
+        headers['User-Agent']= UA
343
+    try:
344
+        r = requests.get(url, headers=headers)
345
+        data = r.content
346
+    except:
347
+        data = r.content
348
+
349
+    debug('len(data) %s' % len(data))
350
+    return data
351
+
352
+def post(url, data, headers={}):
353
+    postdata = urllib.urlencode(data)
354
+    #req = urllib2.Request(url, postdata, headers)
355
+    #req.add_header('User-Agent', UA)
356
+    import requests
357
+    if 'User-Agent' not in headers:
358
+        headers['User-Agent']= UA
359
+    try:
360
+        r = requests.post(url, data=postdata,headers=headers)
361
+        data = r.content
362
+    except urllib2.HTTPError, error:
363
+        data = r.content
364
+    return data
365
+
366
+def post0(url, data, headers={}):
367
+    postdata = urllib.urlencode(data)
368
+    req = urllib2.Request(url, postdata, headers)
369
+    req.add_header('User-Agent', UA)
370
+    try:
371
+        response = urllib2.urlopen(req)
372
+        data = response.read()
373
+        response.close()
374
+    except urllib2.HTTPError, error:
375
+        data = error.read()
376
+    return data
377
+
378
+
379
+def post_json(url, data, headers={}):
380
+    postdata = json.dumps(data)
381
+    headers['Content-Type'] = 'application/json'
382
+    req = urllib2.Request(url, postdata, headers)
383
+    req.add_header('User-Agent', UA)
384
+    response = urllib2.urlopen(req)
385
+    data = response.read()
386
+    response.close()
387
+    return data
388
+
389
+
390
+#def run_parallel_in_threads(target, args_list):
391
+    #result = Queue.Queue()
392
+    ## wrapper to collect return value in a Queue
393
+
394
+    #def task_wrapper(*args):
395
+        #result.put(target(*args))
396
+
397
+    #threads = [threading.Thread(target=task_wrapper, args=args) for args in args_list]
398
+    #for t in threads:
399
+        #t.start()
400
+    #for t in threads:
401
+        #t.join()
402
+    #return result
403
+
404
+
405
+def substr(data, start, end):
406
+    i1 = data.find(start)
407
+    i2 = data.find(end, i1)
408
+    return data[i1:i2]
409
+
410
+
411
+def save_to_file(url, file):
412
+    try:
413
+        return save_data_to_file(request(url), file)
414
+    except:
415
+        traceback.print_exc()
416
+
417
+
418
+def save_data_to_file(data, file):
419
+    try:
420
+        f = open(file, 'wb')
421
+        f.write(data)
422
+        f.close()
423
+        info('File %s saved' % file)
424
+        return True
425
+    except:
426
+        traceback.print_exc()
427
+
428
+
429
+def read_file(file):
430
+    if not os.path.exists(file):
431
+        return ''
432
+    f = open(file, 'r')
433
+    data = f.read()
434
+    f.close()
435
+    return data
436
+
437
+
438
+def _substitute_entity(match):
439
+    ent = match.group(3)
440
+    if match.group(1) == '#':
441
+        # decoding by number
442
+        if match.group(2) == '':
443
+            # number is in decimal
444
+            return unichr(int(ent))
445
+        elif match.group(2) == 'x':
446
+            # number is in hex
447
+            return unichr(int('0x' + ent, 16))
448
+    else:
449
+        # they were using a name
450
+        cp = n2cp.get(ent)
451
+        if cp:
452
+            return unichr(cp)
453
+        else:
454
+            return match.group()
455
+
456
+
457
+def decode_html(data):
458
+    if not type(data) == str:
459
+        return data
460
+    try:
461
+        if not type(data) == unicode:
462
+            data = unicode(data, 'utf-8', errors='ignore')
463
+        entity_re = re.compile(r'&(#?)(x?)(\w+);')
464
+        return entity_re.subn(_substitute_entity, data)[0]
465
+    except:
466
+        traceback.print_exc()
467
+        print[data]
468
+        return data
469
+
470
+def unescape(s0):
471
+    #s2 = re.sub("&#\w+;",HTMLParser.HTMLParser().unescape("\1"),s)
472
+    s0 = s0.replace("&amp;","&")
473
+    for s in re.findall("&#\w+;",s0):
474
+        s2 = HTMLParser.HTMLParser().unescape(s)
475
+        if isinstance(s0,str):
476
+            s2 = s2.encode("utf8")
477
+        s0 = s0.replace(s,s2)
478
+        pass
479
+    return s0
480
+
481
+def debug(text):
482
+    if LOG > 1:
483
+        print('[DEBUG] ' + str([text]))
484
+
485
+def info(text):
486
+    if LOG > 0:
487
+        print('[INFO] ' + str([text]))
488
+
489
+def error(text):
490
+    print('[ERROR] ' + str([text]))
491
+
492
+_diacritic_replace = {u'\u00f3': 'o',
493
+                      u'\u0213': '-',
494
+                      u'\u00e1': 'a',
495
+                      u'\u010d': 'c',
496
+                      u'\u010c': 'C',
497
+                      u'\u010f': 'd',
498
+                      u'\u010e': 'D',
499
+                      u'\u00e9': 'e',
500
+                      u'\u011b': 'e',
501
+                      u'\u00ed': 'i',
502
+                      u'\u0148': 'n',
503
+                      u'\u0159': 'r',
504
+                      u'\u0161': 's',
505
+                      u'\u0165': 't',
506
+                      u'\u016f': 'u',
507
+                      u'\u00fd': 'y',
508
+                      u'\u017e': 'z',
509
+                      u'\xed': 'i',
510
+                      u'\xe9': 'e',
511
+                      u'\xe1': 'a',
512
+                      }
513
+
514
+
515
+def replace_diacritic(string):
516
+    ret = []
517
+    for char in string:
518
+        if char in _diacritic_replace:
519
+            ret.append(_diacritic_replace[char])
520
+        else:
521
+            ret.append(char)
522
+    return ''.join(ret)
523
+
524
+
525
+def params(url=None):
526
+    if not url:
527
+        url = sys.argv[2]
528
+    param = {}
529
+    paramstring = url
530
+    if len(paramstring) >= 2:
531
+        params = url
532
+        cleanedparams = params.replace('?', '')
533
+        if (params[len(params) - 1] == '/'):
534
+            params = params[0:len(params) - 2]
535
+        pairsofparams = cleanedparams.split('&')
536
+        param = {}
537
+        for i in range(len(pairsofparams)):
538
+            splitparams = {}
539
+            splitparams = pairsofparams[i].split('=')
540
+            if (len(splitparams)) == 2:
541
+                param[splitparams[0]] = splitparams[1]
542
+    for p in param.keys():
543
+        param[p] = param[p].decode('hex')
544
+    return param
545
+
546
+
547
+def int_to_base(number, base):
548
+    digs = string.digits + string.letters
549
+    if number < 0:
550
+        sign = -1
551
+    elif number == 0:
552
+        return digs[0]
553
+    else:
554
+        sign = 1
555
+    number *= sign
556
+    digits = []
557
+    while number:
558
+        digits.append(digs[number % base])
559
+        number /= base
560
+    if sign < 0:
561
+        digits.append('-')
562
+    digits.reverse()
563
+    return ''.join(digits)
564
+
565
+
566
+def extract_jwplayer_setup(data):
567
+    """
568
+    Extracts jwplayer setup configuration and returns it as a dictionary.
569
+
570
+    :param data: A string to extract the setup from
571
+    :return: A dictionary containing the setup configuration
572
+    """
573
+    data = re.search(r'<script.+?}\(\'(.+)\',\d+,\d+,\'([\w\|]+)\'.*</script>', data, re.I | re.S)
574
+    if data:
575
+        replacements = data.group(2).split('|')
576
+        data = data.group(1)
577
+        for i in reversed(range(len(replacements))):
578
+            if len(replacements[i]) > 0:
579
+                data = re.sub(r'\b%s\b' % int_to_base(i, 36), replacements[i], data)
580
+        data = re.search(r'\.setup\(([^\)]+?)\);', data)
581
+        if data:
582
+            return json.loads(data.group(1).decode('string_escape'))
583
+        #return demjson.decode(data.group(1).decode('string_escape')) ### III
584
+    return None
585
+
586
+
587
+#def parse_html(url):
588
+#    return BeautifulSoup(request(url), 'html5lib', from_encoding='utf-8')
589
+
590
+if __name__ == "__main__":
591
+    s = 'B\xc4\x93thovena D\xc4\x81rgumu Taka (2014)/Beethoven&#x27;s Treasure [LV]'
592
+    #s = s.decode("utf8")
593
+    #s=unescape(s)
594
+    #url = "http://localhost:88/https://walterebert.com/playground/video/hls/ts/480x270.m3u8?token=xxxx~User-Agent=Enigma2~Cookie=xxxxx"
595
+    url = "http://hyt4d6.vkcache.com/secip/0/UMQ3q2gNjTlOPnEVm3iTiA/ODAuMjMyLjI0MC42/1479610800/hls-vod-s3/flv/api/files/videos/2015/09/11/144197748923a22.mp4.m3u8http://hyt4d6.vkcache.com/secip/0/Y-ZA1qRm8toplc0dN_L6_w/ODAuMjMyLjI0MC42/1479654000/hls-vod-s3/flv/api/files/videos/2015/09/11/144197748923a22.mp4.m3u8"
596
+    headers = {"User-Agent":"Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/47.0.2526.70 Mobile/13C71 Safari/601.1.46"}
597
+    urlp = streamproxy_encode(url,headers)
598
+    print urlp
599
+    player(urlp)
600
+
601
+    pass
602
+
603
+

+ 10
- 0
run.py Parādīt failu

@@ -0,0 +1,10 @@
1
+#!C:\Python27\python2.7.exe
2
+# EASY-INSTALL-ENTRY-SCRIPT: 'xbmcswift2==0.3.0','console_scripts','xbmcswift2'
3
+__requires__ = 'xbmcswift2==0.3.0'
4
+import sys
5
+from pkg_resources import load_entry_point
6
+#import xbmcswift2
7
+
8
+if __name__ == '__main__':
9
+    sys.exit(load_entry_point('xbmcswift2==0.3.0', 'console_scripts', 'xbmcswift2')())
10
+    #xbmcswift2.Plugin.run()