Ivars преди 7 години
родител
ревизия
ee3876f54b
променени са 19 файла, в които са добавени 761 реда и са изтрити 559 реда
  1. 12
    5
      ContentSources.py
  2. 98
    59
      PlayStream.py
  3. 535
    437
      PlayStream.wpr
  4. 5
    1
      changelog.md
  5. 1
    1
      imake.bat
  6. 68
    35
      playstreamproxy.py
  7. 3
    1
      plugin.py
  8. 1
    5
      resolver.py
  9. 3
    1
      resolvers/hdgo.py
  10. Двоични данни
      resolvers/hdgo.pyc
  11. 2
    0
      resolvers/hqqresolver.py
  12. Двоични данни
      resolvers/hqqresolver.pyc
  13. 3
    1
      resolvers/kapnob.py
  14. Двоични данни
      resolvers/kapnob.pyc
  15. 3
    1
      resolvers/kodik.py
  16. Двоични данни
      resolvers/kodik.pyc
  17. 8
    6
      resolvers/openload3.py
  18. Двоични данни
      resolvers/openload3.pyc
  19. 19
    6
      util.py

+ 12
- 5
ContentSources.py Целия файл

7
 #
7
 #
8
 
8
 
9
 import sys,os,re
9
 import sys,os,re
10
-import glob
10
+import glob, traceback
11
 sys.path.insert(0,os.path.dirname(os.path.abspath(__file__)))
11
 sys.path.insert(0,os.path.dirname(os.path.abspath(__file__)))
12
 from  sources.SourceBase import stream_type
12
 from  sources.SourceBase import stream_type
13
 import util
13
 import util
105
                 for k in s:
105
                 for k in s:
106
                     if isinstance(s[k],unicode):
106
                     if isinstance(s[k],unicode):
107
                         s[k] = s[k].encode("utf8")
107
                         s[k] = s[k].encode("utf8")
108
+                if not "resolver" in s:
109
+                    s["resolver"] = stream
110
+                if not "surl" in s or not s["surl"]:
111
+                    s["surl"] = data
112
+                if not "nfo" in s:
113
+                    s["nfo"]={"tvshow":{"title":s["title"],"thumb":s["img"],"plot":s["desc"]}}
108
             return streams
114
             return streams
109
         else:
115
         else:
110
             return []
116
             return []
155
     while True:
161
     while True:
156
         print
162
         print
157
         for i,item in enumerate(content):
163
         for i,item in enumerate(content):
158
-            s = "%i: %s - %s %s %s "%(i+1,item[0],item[1],item[2],item[3])
164
+            s = "%i: %s - %s %s %s "%(i,item[0],item[1],item[2],item[3])
159
             print s #.encode(sys.stdout.encoding,"replace")
165
             print s #.encode(sys.stdout.encoding,"replace")
160
 
166
 
161
         while True:
167
         while True:
170
             except:
176
             except:
171
                 print "Not number!"
177
                 print "Not number!"
172
         if exit_loop: break
178
         if exit_loop: break
173
-        cur2 = content[n-1]
179
+        cur2 = content[n]
174
 
180
 
175
         data0 = cur2[1].split("::")[1] if "::" in cur2[1] else cur2[1]
181
         data0 = cur2[1].split("::")[1] if "::" in cur2[1] else cur2[1]
176
         if not data0:
182
         if not data0:
188
                 try:
194
                 try:
189
                     streams = sources.get_streams(cur2[1])
195
                     streams = sources.get_streams(cur2[1])
190
                 except Exception as e:
196
                 except Exception as e:
191
-                    print str(e)
197
+                    print unicode(e)
198
+                    traceback.print_exc()
192
                     streams = []
199
                     streams = []
193
             if streams:
200
             if streams:
194
                 util.play_video(streams)
201
                 util.play_video(streams)
208
         try:
215
         try:
209
             content = sources.get_content(cur[1])
216
             content = sources.get_content(cur[1])
210
         except Exception as e:
217
         except Exception as e:
211
-            print str(e)
218
+            print unicode(e)
212
             raw_input("Continue?")
219
             raw_input("Continue?")
213
 
220
 
214
 
221
 

+ 98
- 59
PlayStream.py Целия файл

1
 #!/usr/bin/env python
1
 #!/usr/bin/env python
2
 # coding=utf8
2
 # coding=utf8
3
 #
3
 #
4
-#
5
 # This file is part of PlayStream - enigma2 plugin to play video streams from various sources
4
 # This file is part of PlayStream - enigma2 plugin to play video streams from various sources
6
 # Copyright (c) 2016 ivars777 (ivars777@gmail.com)
5
 # Copyright (c) 2016 ivars777 (ivars777@gmail.com)
7
 # Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
6
 # Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
12
 import datetime,re
11
 import datetime,re
13
 import urllib2
12
 import urllib2
14
 
13
 
14
+from Plugins.Plugin import PluginDescriptor
15
 from enigma import ePicLoad, eServiceReference, eTimer, getDesktop
15
 from enigma import ePicLoad, eServiceReference, eTimer, getDesktop
16
-from Components.ActionMap import ActionMap, HelpableActionMap
16
+from Screens.Screen import Screen
17
 from Screens.InfoBarGenerics import InfoBarShowHide
17
 from Screens.InfoBarGenerics import InfoBarShowHide
18
+from Screens.InfoBar import MoviePlayer
19
+from Screens.MessageBox import MessageBox
20
+from Screens.LocationBox import LocationBox
21
+from Screens.ChoiceBox import ChoiceBox
22
+from Screens.VirtualKeyBoard import VirtualKeyBoard
23
+#from Screens.InputBox import InputBox
18
 from Components.AVSwitch import AVSwitch
24
 from Components.AVSwitch import AVSwitch
25
+from Components.ActionMap import ActionMap, HelpableActionMap
19
 from Components.Label import Label
26
 from Components.Label import Label
27
+from Components.Input import Input
20
 from Components.MenuList import MenuList
28
 from Components.MenuList import MenuList
21
 from Components.Pixmap import Pixmap
29
 from Components.Pixmap import Pixmap
22
 from Components.Sources.List import List
30
 from Components.Sources.List import List
23
 from Components.Sources.StaticText import StaticText
31
 from Components.Sources.StaticText import StaticText
24
 from Components.Button import Button
32
 from Components.Button import Button
25
-from Plugins.Plugin import PluginDescriptor
26
-from Screens.InfoBar import MoviePlayer
27
-from Screens.MessageBox import MessageBox
33
+from Components.Task import job_manager
34
+from Components.config import config, ConfigSubsection, ConfigText, ConfigInteger, ConfigLocations, ConfigDirectory, ConfigSet, ConfigYesNo, ConfigSelection, getConfigListEntry, ConfigSelectionNumber, ConfigNumber
35
+from Components.ConfigList import ConfigListScreen
28
 from Tools import Notifications
36
 from Tools import Notifications
29
-from Screens.LocationBox import LocationBox
30
-#from Screens.InputBox import InputBox
31
-from Screens.ChoiceBox import ChoiceBox
32
-from Screens.VirtualKeyBoard import VirtualKeyBoard
33
-from Components.Input import Input
34
-from Screens.Screen import Screen
35
 from Tools.BoundFunction import boundFunction
37
 from Tools.BoundFunction import boundFunction
36
 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
38
 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
37
 from Tools.LoadPixmap import LoadPixmap
39
 from Tools.LoadPixmap import LoadPixmap
38
 from twisted.web.client import downloadPage,defer,reactor
40
 from twisted.web.client import downloadPage,defer,reactor
39
-from Components.Task import job_manager
40
-from Components.config import config, ConfigSubsection, ConfigText, ConfigInteger, ConfigLocations, ConfigDirectory, ConfigSet, ConfigYesNo, ConfigSelection, getConfigListEntry, ConfigSelectionNumber
41
-
42
 
41
 
43
 import ContentSources
42
 import ContentSources
44
 import util
43
 import util
45
 from VideoDownload import downloadJob, HLSDownloadJob,VideoDownloadList
44
 from VideoDownload import downloadJob, HLSDownloadJob,VideoDownloadList
46
 #import enigma2_api
45
 #import enigma2_api
47
-e2 = None
48
 
46
 
47
+e2 = None
49
 ##########################################################################
48
 ##########################################################################
50
-from Components.config import config, ConfigSubsection, ConfigYesNo, getConfigListEntry, \
51
-     ConfigSelection, ConfigNumber, ConfigDirectory,ConfigText
52
-from Components.ConfigList import ConfigListScreen
53
-from Screens.LocationBox import LocationBox
54
-
55
 config.plugins.playstream = ConfigSubsection()
49
 config.plugins.playstream = ConfigSubsection()
56
 config.plugins.playstream.locations = ConfigLocations(default=["/media/hdd/movie/"])
50
 config.plugins.playstream.locations = ConfigLocations(default=["/media/hdd/movie/"])
57
 config.plugins.playstream.download_dir = ConfigDirectory(default="/media/hdd/movie/")
51
 config.plugins.playstream.download_dir = ConfigDirectory(default="/media/hdd/movie/")
58
 config.plugins.playstream.tmp_dir = ConfigDirectory(default="/tmp/playstream/")
52
 config.plugins.playstream.tmp_dir = ConfigDirectory(default="/tmp/playstream/")
59
 config.plugins.playstream.streamproxy_start = ConfigYesNo(default = True)
53
 config.plugins.playstream.streamproxy_start = ConfigYesNo(default = True)
54
+config.plugins.playstream.overwrite_download = ConfigYesNo(default = False)
60
 #config.plugins.playstream.size = ConfigSelection({"400x240":"400x240","220x132":"220x132","100x60":"100x60"}, default="220x132")
55
 #config.plugins.playstream.size = ConfigSelection({"400x240":"400x240","220x132":"220x132","100x60":"100x60"}, default="220x132")
61
 config.plugins.playstream.clear_tmp = ConfigYesNo(default = True)
56
 config.plugins.playstream.clear_tmp = ConfigYesNo(default = True)
62
 
57
 
83
         cfg = config.plugins.playstream
78
         cfg = config.plugins.playstream
84
         self.list = [
79
         self.list = [
85
             getConfigListEntry(_("Download folder"), cfg.download_dir),
80
             getConfigListEntry(_("Download folder"), cfg.download_dir),
81
+            getConfigListEntry(_("Overwrite download video"), cfg.overwrite_download),
86
             getConfigListEntry(_("TMP folder"), cfg.tmp_dir),
82
             getConfigListEntry(_("TMP folder"), cfg.tmp_dir),
87
             getConfigListEntry(_("Clear tmp folder on exit"), cfg.clear_tmp),
83
             getConfigListEntry(_("Clear tmp folder on exit"), cfg.clear_tmp),
88
             getConfigListEntry(_("Start playstreamproxy"), cfg.streamproxy_start),
84
             getConfigListEntry(_("Start playstreamproxy"), cfg.streamproxy_start),
85
+
89
         ]
86
         ]
90
         ConfigListScreen.__init__(self, self.list, session = self.session)
87
         ConfigListScreen.__init__(self, self.list, session = self.session)
91
         self["key_red"] = Button(_("Cancel"))
88
         self["key_red"] = Button(_("Cancel"))
110
     def ok(self):
107
     def ok(self):
111
         if self["config"].getCurrent()[1] == config.plugins.playstream.download_dir:
108
         if self["config"].getCurrent()[1] == config.plugins.playstream.download_dir:
112
             folder = config.plugins.playstream.download_dir.value
109
             folder = config.plugins.playstream.download_dir.value
113
-            #self.session.openWithCallback(self.select_download_dir, LocationBox,"Select Folder")
114
-            self.session.openWithCallback(self.select_download_dir, LocationBox,"Select download folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
110
+            #self.session.openWithCallback(self.cb_download_dir, LocationBox,"Select Folder")
111
+            self.session.openWithCallback(self.cb_download_dir, LocationBox,"Select download folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
115
         elif self["config"].getCurrent()[1] == config.plugins.playstream.tmp_dir:
112
         elif self["config"].getCurrent()[1] == config.plugins.playstream.tmp_dir:
116
             self.session.openWithCallback(self.select_tmp_dir, LocationBox,"Select tmp folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
113
             self.session.openWithCallback(self.select_tmp_dir, LocationBox,"Select tmp folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
117
         else:
114
         else:
118
             self.save()
115
             self.save()
119
 
116
 
120
-    def select_download_dir(self, folder, select=None):
117
+    def cb_download_dir(self, folder, select=None):
121
         if not folder:
118
         if not folder:
122
             return
119
             return
123
         print "Folder selected - %s"%folder
120
         print "Folder selected - %s"%folder
160
     service_type = 4097
157
     service_type = 4097
161
     if re.search("\.ts$",url.split("?")[0],re.IGNORECASE):
158
     if re.search("\.ts$",url.split("?")[0],re.IGNORECASE):
162
         service_type = 1
159
         service_type = 1
163
-    if "resolver" in stream and stream["resolver"] in ("hqq","viaplay"):
160
+    if "resolver" in stream and stream["resolver"] in ("hqq","viaplay","filmas"):
164
         url = util.streamproxy_encode(stream["url"], stream["headers"])
161
         url = util.streamproxy_encode(stream["url"], stream["headers"])
165
-        if os.path.exists("/usr/bin/exteplayer3"): # problem playing hqq streams with gstreamer, use exteplayer3
166
-            service_type = 5002
162
+        #if os.path.exists("/usr/bin/exteplayer3"): # problem playing hqq streams with gstreamer, use exteplayer3
163
+            #service_type = 5002
167
     print "service_type=",service_type
164
     print "service_type=",service_type
168
     print "stream_url=",url
165
     print "stream_url=",url
169
     service = eServiceReference(service_type, 0, url)
166
     service = eServiceReference(service_type, 0, url)
632
                 try:
629
                 try:
633
                     self.session.open(PSPlayer, streams)
630
                     self.session.open(PSPlayer, streams)
634
                 except Exception as e:
631
                 except Exception as e:
635
-                    self.msg2("Error launching player - " + str(e))
632
+                    self.msg("Error launching player - " + str(e))
636
                     return
633
                     return
637
             else:
634
             else:
638
                 self.msg("No stream found - %s"%(self.current[1]))
635
                 self.msg("No stream found - %s"%(self.current[1]))
715
         ]
712
         ]
716
         if self.sources.is_video(self.current[1]):
713
         if self.sources.is_video(self.current[1]):
717
             lst.extend([
714
             lst.extend([
718
-            ("Download video","download","Download video in background"),
715
+            ("Download video to default folder","download","Download video to default folder"),
716
+            ("Download video, ask folder","download2","Download video, ask download folder"),
717
+            ("Download video to subfolder, ask parent folder","download3","Download video to subfolder, ask download folder"),
718
+
719
             ])
719
             ])
720
         else:
720
         else:
721
             lst.extend([
721
             lst.extend([
722
-            ("Download videos in folder","download","Download videos in folder (if any)"),
722
+            ("Download list to default folder","download","Download videos in list (if any)"),
723
+            ("Download list, ask folder","download2","Download videos in list (if any), ask download folder"),
723
             ])
724
             ])
724
         if "config::" in self.cur_menu[1]:
725
         if "config::" in self.cur_menu[1]:
725
             lst.extend([
726
             lst.extend([
735
         #print "item_menu_selected",answer
736
         #print "item_menu_selected",answer
736
         if not answer:
737
         if not answer:
737
             return
738
             return
739
+        self.answer = answer[1]
738
 
740
 
739
         if answer[1] == "info":
741
         if answer[1] == "info":
740
             self.session.open(MessageBox, "Not yet implemented!", MessageBox.TYPE_INFO)
742
             self.session.open(MessageBox, "Not yet implemented!", MessageBox.TYPE_INFO)
748
 
750
 
749
         elif answer[1] == "favorites":
751
         elif answer[1] == "favorites":
750
             lists = self.config.get_lists()
752
             lists = self.config.get_lists()
751
-            lists2 = [(l,l) for l in lists]
753
+            lists2 = [(self.config.get_title(l),l) for l in lists]
754
+            print lists2
752
             self.session.openWithCallback(self.cb_favorites, ChoiceBox, title="Selected menu item will be added",list = lists2)
755
             self.session.openWithCallback(self.cb_favorites, ChoiceBox, title="Selected menu item will be added",list = lists2)
753
 
756
 
754
-        elif answer[1] == 'download':
755
-            current = self.current
756
-            if not self.sources.is_video(current[1]):
757
-                #self.msg("Can not download listst (yet) - %s"%(current[1]))
758
-                n = 0
759
-                for current2 in self.sources.get_content(current[1]):
760
-                    if self.sources.is_video(current2[1]):
761
-                        n += 1
762
-                        self.download_video(current2)
763
-                if n>0:
764
-                    self.msg("%s videos download started"%n)
765
-                else:
766
-                    self.msg("No videos to download")
767
-            else:
768
-                if self.download_video(current):
769
-                    self.msg("Video download started")
757
+        elif answer[1] in ("download2","download3"):  # ask download folder before
758
+            self.session.openWithCallback(self.download_prepare, LocationBox,"Select download folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
770
 
759
 
760
+        elif answer[1] == 'download':
761
+            self.download_prepare(config.plugins.playstream.download_dir.value)
771
 
762
 
772
         elif answer[1] == 'download_list':
763
         elif answer[1] == 'download_list':
773
             self.download_list()
764
             self.download_list()
774
 
765
 
775
         elif answer[1] == 'download_folder':
766
         elif answer[1] == 'download_folder':
776
             #downloadDir = "/media/hdd/movie" #config.plugins.playstream.downloadDir.value TODO
767
             #downloadDir = "/media/hdd/movie" #config.plugins.playstream.downloadDir.value TODO
777
-            self.session.openWithCallback(self.select_download_dir, LocationBox,"Select download folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
768
+            self.session.openWithCallback(self.cb_download_dir, LocationBox,"Select download folder","",config.plugins.playstream.download_dir.value,config.plugins.playstream.locations,False,"Select folder",None,True,True)
778
 
769
 
779
         elif answer[1] == "delete":
770
         elif answer[1] == "delete":
780
             lst = self.cur_menu[1].replace("config::","")
771
             lst = self.cur_menu[1].replace("config::","")
793
             pass #TODO
784
             pass #TODO
794
         return
785
         return
795
 
786
 
796
-    def select_download_dir(self, downloadDir, select=None):
787
+    def download_prepare(self, download_dir=""):
788
+        current = self.current
789
+        if not download_dir:
790
+            return
791
+            #download_dir = config.plugins.playstream.download_dir.value
792
+        title = re.sub("\[.+?\]","", util.make_fname(current[0])).strip()
793
+        download_dir2 = os.path.join(download_dir, title)
794
+        if not self.sources.is_video(current[1]):
795
+            #self.msg("Can not download listst (yet) - %s"%(current[1]))
796
+            n = 0
797
+            for current2 in self.sources.get_content(current[1]):
798
+                if self.sources.is_video(current2[1]):
799
+                    n += 1
800
+                    self.download_video(current2,download_dir2)
801
+            if n>0:
802
+                self.msg("%s videos download started to %s"%(n,download_dir2))
803
+            else:
804
+                self.msg("No videos to download")
805
+        else:
806
+            if self.answer == "download":
807
+                download_dir2 = download_dir
808
+            if self.download_video(current,download_dir2):
809
+                self.msg("Video download started to %s"%download_dir2)
810
+
811
+    def cb_download_dir(self, downloadDir, select=None):
797
         if not downloadDir:
812
         if not downloadDir:
798
             return
813
             return
799
         print "Folder selected - %s"%downloadDir
814
         print "Folder selected - %s"%downloadDir
805
     def download_list(self):
820
     def download_list(self):
806
         self.session.open(VideoDownloadList)
821
         self.session.open(VideoDownloadList)
807
 
822
 
808
-    def download_video(self,current):
823
+    def download_video(self,current, download_dir=""):
809
         if self.sources.stream_type(current[1]):
824
         if self.sources.stream_type(current[1]):
810
             stream = util.item()
825
             stream = util.item()
811
             stream["url"] = current[1]
826
             stream["url"] = current[1]
831
         else:
846
         else:
832
             stream = streams[0]
847
             stream = streams[0]
833
         stream = util.stream_change(stream)
848
         stream = util.stream_change(stream)
834
-        return self.download_stream(stream)
849
+        return self.download_stream(stream, download_dir)
835
 
850
 
836
-    def download_stream(self,stream):
851
+    def download_stream(self,stream,download_dir=""):
837
         print "download stream",stream
852
         print "download stream",stream
838
         #self.msg("Start downloading..")
853
         #self.msg("Start downloading..")
839
         self.stream = stream
854
         self.stream = stream
846
         title = self.stream["name"].strip()
861
         title = self.stream["name"].strip()
847
         url = self.stream["url"]
862
         url = self.stream["url"]
848
         stream_type = self.stream["type"] #self.sources.stream_type(stream["url"])
863
         stream_type = self.stream["type"] #self.sources.stream_type(stream["url"])
849
-        downloadDir = config.plugins.playstream.download_dir.value
864
+        downloadDir = config.plugins.playstream.download_dir.value if not download_dir else download_dir
850
         if not os.path.exists(downloadDir):
865
         if not os.path.exists(downloadDir):
851
-            print 'Sorry, download directory "%s" not exist!\nPlease specify in the settings existing directory'%downloadDir
852
-            self.msg0(_('Sorry, download directory "%s" not exist!\nPlease specify in the settings existing directory'%downloadDir))
853
-            return
854
-        fname0 = re.sub("[/\n\r\t,:]"," ",title)
855
-        fname0 = re.sub("['""]","",fname0)
866
+            try:
867
+                os.mkdir(downloadDir)
868
+            except Exception as e:
869
+                print 'Error creating download directory "%s"!\nPlease specify in the settings existing directory\n%s'%(downloadDir,str(e))
870
+                self.msg('Error creating download directory "%s"!\nPlease specify in the settings existing directory\n%s'%(downloadDir,str(e)))
871
+                return
872
+        fname0 = util.make_fname(title)
856
         fname = fname0 +".mp4"
873
         fname = fname0 +".mp4"
857
         outputfile = os.path.join(downloadDir, fname)
874
         outputfile = os.path.join(downloadDir, fname)
858
         #print "Trying to download - ", current
875
         #print "Trying to download - ", current
876
+        if self.stream["img"]:
877
+            try:
878
+                thumb = urllib2.urlopen(stream["img"]).read()
879
+            except:
880
+                thumb = ""
881
+            if thumb:
882
+                imgext = ".jpg"
883
+                m = re.search("(\.\w{3})$",stream["img"])
884
+                if m:
885
+                    imgext = m.group(1)
886
+                imgfile = os.path.join(downloadDir,fname0+imgext)
887
+                with open(imgfile,"wb") as f:
888
+                    f.write(thumb)
859
         if self.stream["subs"]:
889
         if self.stream["subs"]:
860
             suburl = self.stream["subs"][0]["url"]
890
             suburl = self.stream["subs"][0]["url"]
861
             print "\n**Download subtitles %s - %s"%(title,suburl)
891
             print "\n**Download subtitles %s - %s"%(title,suburl)
870
                     f.write(subs)
900
                     f.write(subs)
871
             else:
901
             else:
872
                 print "\n Error downloading subtitle %s"%suburl
902
                 print "\n Error downloading subtitle %s"%suburl
873
-
874
-        if os.path.exists(outputfile):
903
+        if "nfo" in self.stream and self.stream["nfo"]:
904
+            nfofile = subfile = os.path.join(downloadDir,fname0+".nfo")
905
+            with open(nfofile,"w") as f:
906
+                nfo_type,nfo = next(self.stream["nfo"].iteritems())
907
+                f.write("<%s>\n"%nfo_type.encode("utf8"))
908
+                for k,v in nfo.iteritems():
909
+                    if isinstance(v,unicode): v = v.encode("utf8")
910
+                    f.write("    <%s>%s</%s>\n"%(k.encode("utf8"), v, k.encode("utf8")))
911
+                f.write("</%s>\n"%nfo_type.encode("utf8"))
912
+        overwrite = config.plugins.playstream.overwrite_download.value
913
+        if not overwrite and os.path.exists(outputfile):
875
             self.msg( _('Sorry, this file already exists:\n%s') % outputfile)
914
             self.msg( _('Sorry, this file already exists:\n%s') % outputfile)
876
             return False
915
             return False
877
             #os.remove(outputfile)
916
             #os.remove(outputfile)

+ 535
- 437
PlayStream.wpr
Файловите разлики са ограничени, защото са твърде много
Целия файл


+ 5
- 1
changelog.md Целия файл

1
-**0.6a** (12.02.2016):
1
+**0.6b** (05.03.2017)
2
+- uzlabota lejupielāde (foldera paprasišana, lejupielāde apakšfolderi u.c.)
3
+- .nfo un .jpg failu veidošana pie lejupielādes (jēdzigs .nfo pagaidam tikai iPlayer)
4
+
5
+**0.6a** (12.02.2017):
2
 - kombinētā versija ar Kodi, salabots, lai iet kopā (funkcionali nekas jauns)
6
 - kombinētā versija ar Kodi, salabots, lai iet kopā (funkcionali nekas jauns)
3
 
7
 
4
 **0.5y** (11.02.2016):
8
 **0.5y** (11.02.2016):

+ 1
- 1
imake.bat Целия файл

2
 :=== Parameters ===
2
 :=== Parameters ===
3
 
3
 
4
 if ()==(%1%) (
4
 if ()==(%1%) (
5
-    set ver=0.6a
5
+    set ver=0.6b
6
 	rem echo Please provide version
6
 	rem echo Please provide version
7
 	rem pause
7
 	rem pause
8
 	rem GOTO:EOF
8
 	rem GOTO:EOF

+ 68
- 35
playstreamproxy.py Целия файл

8
 import time
8
 import time
9
 import atexit
9
 import atexit
10
 import re
10
 import re
11
+import binascii
11
 
12
 
12
 from signal import SIGTERM
13
 from signal import SIGTERM
13
 
14
 
22
 
23
 
23
 HOST_NAME = ""
24
 HOST_NAME = ""
24
 PORT_NUMBER = 88
25
 PORT_NUMBER = 88
25
-DEBUG = True
26
+DEBUG = False
26
 
27
 
27
 headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
28
 headers2dict = lambda  h: dict([l.strip().split(": ") for l in h.strip().splitlines()])
28
 sessions = {}
29
 sessions = {}
41
         SPLIT_CODE = "%7E"
42
         SPLIT_CODE = "%7E"
42
         EQ_CODE = "%3D"
43
         EQ_CODE = "%3D"
43
         COL_CODE = "%3A"
44
         COL_CODE = "%3A"
44
-
45
+        self.log_message("get_url: \n%s", self.path)
45
         p = self.path.split("~")
46
         p = self.path.split("~")
46
         url = urllib.unquote(p[0][1:])
47
         url = urllib.unquote(p[0][1:])
47
         url = url.replace(COL_CODE, ":")
48
         url = url.replace(COL_CODE, ":")
68
 
69
 
69
     def fetch_url2(self, wfile, url, headers):
70
     def fetch_url2(self, wfile, url, headers):
70
         if DEBUG: print "\n***********************************************************"
71
         if DEBUG: print "\n***********************************************************"
71
-        self.log_message("fetch_url: %s", url)
72
+        self.log_message("fetch_url: \n%s", url)
72
         #self.log_message("headers: %s", headers)
73
         #self.log_message("headers: %s", headers)
73
 
74
 
74
         base_url = "/".join(url.split("/")[0:-1])
75
         base_url = "/".join(url.split("/")[0:-1])
75
         if base_url not in sessions:
76
         if base_url not in sessions:
76
-            sessions[base_url] = requests.Session()
77
+            sessions[base_url]={}
78
+            sessions[base_url]["session"] = requests.Session()
79
+            sessions[base_url]["key"] = binascii.a2b_hex(headers["key"]) if "key" in headers and headers["key"] else None
77
             #cj = cookielib.CookieJar()
80
             #cj = cookielib.CookieJar()
78
             #sessions[base_url] = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
81
             #sessions[base_url] = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
79
         else:
82
         else:
80
-            pass
81
-        ses = sessions[base_url]
83
+            if "key" in headers and headers["key"]: sessions[base_url]["key"] = binascii.a2b_hex(headers["key"])
84
+        ses = sessions[base_url]["session"]
85
+        key = sessions[base_url]["key"]
86
+
82
         if DEBUG: print "**Request headers: "
87
         if DEBUG: print "**Request headers: "
83
         ses.headers.update(headers)
88
         ses.headers.update(headers)
84
         #ses.addheaders=[]
89
         #ses.addheaders=[]
93
         for h in r.headers:
98
         for h in r.headers:
94
             if DEBUG: print h,"=",r.headers[h]
99
             if DEBUG: print h,"=",r.headers[h]
95
         self.send_response(code)
100
         self.send_response(code)
101
+
102
+        print code
103
+        if code <> 200:
104
+            self.fetch_offline(wfile)
105
+            return
106
+
96
         if DEBUG: print "**Return headers:"
107
         if DEBUG: print "**Return headers:"
108
+        headers2 = {}
97
         for h in r.headers:
109
         for h in r.headers:
98
-            if h.lower() in ("user-agent","server"):continue
99
-            if h.lower()=="connection":
100
-                if DEBUG: print h," skipped"
110
+            if h.lower() in ("user-agent","server","transfer-encoding","content-encoding","connection"):
111
+                if DEBUG: print h," - skipped"
101
                 continue
112
                 continue
102
-            self.send_header(h, r.headers[h])
103
-            if DEBUG:print h,"=",r.headers[h]
104
-        self.end_headers()
113
+            else:
114
+                headers2[h] = r.headers[h]
115
+                if DEBUG:print h,"=",r.headers[h]
116
+
117
+        # Content-Type: application/vnd.apple.mpegurl
118
+        if r.headers["Content-Type"] == "application/vnd.apple.mpegurl" and key:
119
+            content = r.content
120
+            content = r.content.replace(base_url+"/","")
121
+            content = re.sub("#EXT-X-KEY:METHOD=AES-128.+\n", "", content, 0, re.IGNORECASE | re.MULTILINE)
122
+            headers2["Content-Length"] = "%s"%len(content)
123
+            self.send_headers(headers2)
124
+            wfile.write(content)
125
+
126
+        # Content-Type: video/MP2T
127
+        elif r.headers["Content-Type"] == "video/MP2T" and key:
128
+            content = r.content
129
+            from Crypto.Cipher import AES
130
+            iv = content[:16]
131
+            d = AES.new(key, AES.MODE_CBC, iv)
132
+            content = d.decrypt(content[16:])
133
+            headers2["Content-Length"] = "%s"%len(content)
134
+            self.send_headers(headers2)
135
+            wfile.write(content)
105
 
136
 
106
-        CHUNK_SIZE = 4 * 1024
107
-        if code == 200:
108
-            #while True:
109
-                #chunk = r.read(CHUNK_SIZE)
110
-                #if not chunk:
111
-                    #break
112
-                #wfile.write(chunk)
113
-            #pass
114
-            #wfile.close()
115
-            for chunk in r.iter_content(1024):
116
-                try:
117
-                    #print "#",
118
-                    wfile.write(chunk)
119
-                except Exception as e:
120
-                    print "Exception: ", str(e)
121
-                    return
122
-            if DEBUG: print "  = file downloaded = "
123
-            time.sleep(2)
124
-            #self.wfile.close()
137
+        else:
138
+            self.send_headers(headers2)
139
+            CHUNK_SIZE = 4 * 1024
140
+            if code == 200:
141
+                #while True:
142
+                    #chunk = r.read(CHUNK_SIZE)
143
+                    #if not chunk:
144
+                        #break
145
+                    #wfile.write(chunk)
146
+                #pass
147
+                #wfile.close()
148
+                for chunk in r.iter_content(1024):
149
+                    try:
150
+                        #print "#",
151
+                        wfile.write(chunk)
152
+                    except Exception as e:
153
+                        print "Exception: ", str(e)
154
+                        return
155
+                if DEBUG: print "  = file downloaded = "
156
+                time.sleep(1)
157
+        self.wfile.close()
125
 
158
 
159
+    def send_headers(self,headers):
160
+        for h in headers:
161
+            self.send_header(h, headers[h])
162
+        self.end_headers()
126
 
163
 
127
-        else:
128
-            print code
129
-            self.fetch_offline(wfile)
130
-            pass
131
 
164
 
132
 class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
165
 class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
133
     """Handle requests in a separate thread."""
166
     """Handle requests in a separate thread."""

+ 3
- 1
plugin.py Целия файл

1
 from Plugins.Plugin import PluginDescriptor
1
 from Plugins.Plugin import PluginDescriptor
2
 import PlayStream
2
 import PlayStream
3
 from . import _
3
 from . import _
4
+import traceback
4
 
5
 
5
 def main(session, **kwargs):
6
 def main(session, **kwargs):
6
     try:
7
     try:
8
         session.open(PlayStream.MainScreen)
9
         session.open(PlayStream.MainScreen)
9
     except Exception as e:
10
     except Exception as e:
10
         print "Error loading PlayStream - "+ e.message
11
         print "Error loading PlayStream - "+ e.message
12
+        traceback.print_exc()
11
 
13
 
12
 def menu(menuid, **kwargs):
14
 def menu(menuid, **kwargs):
13
     if menuid == "mainmenu":
15
     if menuid == "mainmenu":
17
 def Plugins(**kwargs):
19
 def Plugins(**kwargs):
18
     return [
20
     return [
19
         PluginDescriptor(name = "Play Stream",description = _("Play online streams from various sources"),where = [PluginDescriptor.WHERE_PLUGINMENU,PluginDescriptor.WHERE_EXTENSIONSMENU], icon = "plugin.png", fnc = main),
21
         PluginDescriptor(name = "Play Stream",description = _("Play online streams from various sources"),where = [PluginDescriptor.WHERE_PLUGINMENU,PluginDescriptor.WHERE_EXTENSIONSMENU], icon = "plugin.png", fnc = main),
20
-        PluginDescriptor(name="TV Play", description=_("Play online streams from various sources"), where = [PluginDescriptor.WHERE_MENU], fnc=menu)
22
+        PluginDescriptor(name="Play Stream", description=_("Play online streams from various sources"), where = [PluginDescriptor.WHERE_MENU], fnc=menu)
21
     ]
23
     ]

+ 1
- 5
resolver.py Целия файл

56
 def resolve(url):
56
 def resolve(url):
57
     """
57
     """
58
         resolves given url by asking all resolvers
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
59
         returns Array of resolved objects in positive usecase
63
     """
60
     """
64
     url = util.decode_html(url)
61
     url = util.decode_html(url)
65
     util.info('Resolving ' + url)
62
     util.info('Resolving ' + url)
66
     resolver = _get_resolver(url)
63
     resolver = _get_resolver(url)
67
-    value = None
68
     if resolver is None:
64
     if resolver is None:
69
         return []
65
         return []
70
     util.info('Using resolver \'%s\'' % str(resolver.__name__));
66
     util.info('Using resolver \'%s\'' % str(resolver.__name__));
87
                 if "=" in h:
83
                 if "=" in h:
88
                     i["headers"][h.split("=")[0]] = h.split("=")[1]
84
                     i["headers"][h.split("=")[0]] = h.split("=")[1]
89
 
85
 
90
-    return sorted(value, key=lambda i: i['quality'], reverse=True)
86
+    return sorted(value, key=lambda i: i['quality'], reverse=True) # TODO sorted by order?
91
 
87
 
92
 
88
 
93
 def _get_resolver(url):
89
 def _get_resolver(url):

+ 3
- 1
resolvers/hdgo.py Целия файл

30
     import util
30
     import util
31
 import urllib2
31
 import urllib2
32
 import requests
32
 import requests
33
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
34
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
33
 #from aadecode import AADecoder
35
 #from aadecode import AADecoder
34
 
36
 
35
 if __name__ <> "__main__":
37
 if __name__ <> "__main__":
90
     util.play_video(streams)
92
     util.play_video(streams)
91
 
93
 
92
 
94
 
93
-    #print streams[0]["url"]    
95
+    #print streams[0]["url"]
94
     #call([r"gst-launch-1.0.exe",'uri="%s""'%streams[0]["url"]])
96
     #call([r"gst-launch-1.0.exe",'uri="%s""'%streams[0]["url"]])
95
     pass
97
     pass

Двоични данни
resolvers/hdgo.pyc Целия файл


+ 2
- 0
resolvers/hqqresolver.py Целия файл

24
     sys.path.insert(0, os.sep.join(pp.split(os.sep)[:-1]))
24
     sys.path.insert(0, os.sep.join(pp.split(os.sep)[:-1]))
25
     import util
25
     import util
26
 import requests
26
 import requests
27
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
28
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
27
 
29
 
28
 __author__ = 'ivars777'
30
 __author__ = 'ivars777'
29
 if __name__ <> "__main__":
31
 if __name__ <> "__main__":

Двоични данни
resolvers/hqqresolver.pyc Целия файл


+ 3
- 1
resolvers/kapnob.py Целия файл

29
     sys.path.insert(0,os.sep.join(pp.split(os.sep)[:-1]))
29
     sys.path.insert(0,os.sep.join(pp.split(os.sep)[:-1]))
30
     import util
30
     import util
31
 import requests
31
 import requests
32
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
33
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
32
 
34
 
33
 __author__ = 'ivars777'
35
 __author__ = 'ivars777'
34
 if __name__ <> "__main__":
36
 if __name__ <> "__main__":
89
         sys.exit()
91
         sys.exit()
90
     for s in streams:
92
     for s in streams:
91
         print s
93
         print s
92
-    print streams[0]["url"]    
94
+    print streams[0]["url"]
93
     util.play_video(streams)
95
     util.play_video(streams)
94
     pass
96
     pass

Двоични данни
resolvers/kapnob.pyc Целия файл


+ 3
- 1
resolvers/kodik.py Целия файл

29
     sys.path.insert(0,os.sep.join(pp.split(os.sep)[:-1]))
29
     sys.path.insert(0,os.sep.join(pp.split(os.sep)[:-1]))
30
     import util
30
     import util
31
 import requests
31
 import requests
32
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
33
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
32
 
34
 
33
 __author__ = 'ivars777'
35
 __author__ = 'ivars777'
34
 if __name__ <> "__main__":
36
 if __name__ <> "__main__":
90
         sys.exit()
92
         sys.exit()
91
     for s in streams:
93
     for s in streams:
92
         print s
94
         print s
93
-    print streams[0]["url"]    
95
+    print streams[0]["url"]
94
     util.play_video(streams)
96
     util.play_video(streams)
95
     pass
97
     pass

Двоични данни
resolvers/kodik.pyc Целия файл


+ 8
- 6
resolvers/openload3.py Целия файл

30
     import util
30
     import util
31
 import urllib2
31
 import urllib2
32
 import requests
32
 import requests
33
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
34
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
33
 #from aadecode import AADecoder
35
 #from aadecode import AADecoder
34
 
36
 
35
 __author__ = 'Jose Riha/Lubomir Kucera'
37
 __author__ = 'Jose Riha/Lubomir Kucera'
49
         'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
51
         'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.3',
50
         'Accept-Encoding': 'none',
52
         'Accept-Encoding': 'none',
51
         'Accept-Language': 'en-US,en;q=0.8',
53
         'Accept-Language': 'en-US,en;q=0.8',
52
-        'Referer': url}  # 'Connection': 'keep-alive'    
54
+        'Referer': url}  # 'Connection': 'keep-alive'
53
 
55
 
54
     stream = util.item()
56
     stream = util.item()
55
     m = re.search('https*://openload\.\w+/embed/([^/]+)', url)
57
     m = re.search('https*://openload\.\w+/embed/([^/]+)', url)
68
     stream["url"] = res["url"]
70
     stream["url"] = res["url"]
69
     stream["name"]= res["url"]
71
     stream["name"]= res["url"]
70
     ### Retrieve subtitles ####
72
     ### Retrieve subtitles ####
71
-    html = requests.get(url, headers=HTTP_HEADER).content 
73
+    html = requests.get(url, headers=HTTP_HEADER).content
72
     m = re.search('<track kind="captions" src="([^"]+)" srclang="([^"]+)" label="([^"]+)"', html)
74
     m = re.search('<track kind="captions" src="([^"]+)" srclang="([^"]+)" label="([^"]+)"', html)
73
     if m:
75
     if m:
74
         stream["subs"] = m.group(1)
76
         stream["subs"] = m.group(1)
75
-        stream["lang"] = m.group(2)   
77
+        stream["lang"] = m.group(2)
76
 
78
 
77
     return [stream]
79
     return [stream]
78
 
80
 
90
     #url = "https://kinostok.tv/embed/731f3437e3c53104dd56d04039a0b15a"
92
     #url = "https://kinostok.tv/embed/731f3437e3c53104dd56d04039a0b15a"
91
     #url = "http://vk.com/video_ext.php?oid=246066565&id=169244575&hash=d430ab0e76c9f7a1&hd=3"
93
     #url = "http://vk.com/video_ext.php?oid=246066565&id=169244575&hash=d430ab0e76c9f7a1&hd=3"
92
     #url ="https://openload.co/embed/rPMXJYPTkw4/"
94
     #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/bE7WfZ-vz_A/"
96
+    #url = "https://openload.co/embed/bE7WfZ/"
95
     #url = "https://openload.co/embed/OuskaKyC2GU/"
97
     #url = "https://openload.co/embed/OuskaKyC2GU/"
96
     url = "http://hqq.tv/player/embed_player.php?vid=235238210241210222228241233208212245&autoplay=no"
98
     url = "http://hqq.tv/player/embed_player.php?vid=235238210241210222228241233208212245&autoplay=no"
97
     url = "https://openload.co/embed/rmNcP-0QopE/"
99
     url = "https://openload.co/embed/rmNcP-0QopE/"
104
     for s in streams:
106
     for s in streams:
105
         print s
107
         print s
106
 
108
 
107
-    print streams[0]["url"]    
109
+    print streams[0]["url"]
108
     call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",streams[0]["url"]])
110
     call([r"c:\Program Files\VideoLAN\VLC\vlc.exe",streams[0]["url"]])
109
     pass
111
     pass

Двоични данни
resolvers/openload3.pyc Целия файл


+ 19
- 6
util.py Целия файл

25
 import traceback
25
 import traceback
26
 import cookielib
26
 import cookielib
27
 import requests
27
 import requests
28
+from requests.packages.urllib3.exceptions import InsecureRequestWarning
29
+requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
28
 from htmlentitydefs import name2codepoint as n2cp
30
 from htmlentitydefs import name2codepoint as n2cp
29
 import HTMLParser
31
 import HTMLParser
30
 import StringIO
32
 import StringIO
109
         #'location="%s"'%url,
111
         #'location="%s"'%url,
110
         #'!decodebin!autovideosink'
112
         #'!decodebin!autovideosink'
111
     ]
113
     ]
114
+    cmd3 = ["ffplay.exe",url]
112
     cmd = cmd1 if url.startswith("https") else cmd2
115
     cmd = cmd1 if url.startswith("https") else cmd2
113
-    ret = call(cmd)
116
+    ret = call(cmd3)
114
     #if ret:
117
     #if ret:
115
         #a = raw_input("*** Error, continue")
118
         #a = raw_input("*** Error, continue")
116
     return
119
     return
117
 
120
 
121
+
118
 SPLIT_CHAR = "~"
122
 SPLIT_CHAR = "~"
119
 SPLIT_CODE = urllib.quote(SPLIT_CHAR)
123
 SPLIT_CODE = urllib.quote(SPLIT_CHAR)
120
 EQ_CODE = urllib.quote("=")
124
 EQ_CODE = urllib.quote("=")
122
 SPACE_CODE = urllib.quote(" ")
126
 SPACE_CODE = urllib.quote(" ")
123
 PROXY_URL = "http://localhost:88/"
127
 PROXY_URL = "http://localhost:88/"
124
 
128
 
129
+
130
+def make_fname(title):
131
+    "Make file name from title"
132
+    title = title.strip()
133
+    fname0 = re.sub("[/\n\r\t,:]"," ",title)
134
+    fname0 = re.sub("['""]","",fname0)
135
+    return fname0
136
+
125
 def stream_change(stream):
137
 def stream_change(stream):
126
     #return stream # TODO
138
     #return stream # TODO
127
-    if stream["surl"]:
128
-        if not re.search("https*://(hqq|goo.\gl)",stream["surl"]):
129
-            return stream
139
+    if "resolver" in stream and stream["resolver"] in ("viaplay","hqq","filmas") or \
140
+        "surl" in stream and re.search("https*://(hqq|goo.\gl)",stream["surl"]):
130
         stream["url"] = streamproxy_encode(stream["url"],stream["headers"])
141
         stream["url"] = streamproxy_encode(stream["url"],stream["headers"])
131
         stream["headers"] = {}
142
         stream["headers"] = {}
132
         return stream
143
         return stream
271
 
282
 
272
 
283
 
273
 def item():
284
 def item():
285
+    """Default item content"""
274
     stream0 = {
286
     stream0 = {
275
-        'name': '',
287
+        'name': '', #
276
         'url': '',
288
         'url': '',
277
         'quality': '?',
289
         'quality': '?',
278
         'surl': '',
290
         'surl': '',
283
         "lang":"",
295
         "lang":"",
284
         "type":"",
296
         "type":"",
285
         "resolver":"",
297
         "resolver":"",
286
-        "order":0
298
+        "order":0,
299
+        "live":False
287
         }
300
         }
288
     return stream0
301
     return stream0
289
 
302