#!/usr/bin/env python
# coding=utf8
# This file is part of PlayStream - enigma2 plughhhhin to play video streams from various sources
# Copyright (c) 2016 ivars777 (ivars777@gmail.com)
# Distributed under the GNU GPL v3. For full terms see http://www.gnu.org/licenses/gpl-3.0.en.html
# Used fragments of code from enigma2-plugin-tv3play by Taapat (https://github.com/Taapat/enigma2-plugin-tv3play)
#

__version__ = "0.7o"
__id__ = "playstream"
__title__ = "PlayStream"
__author__ = "ivars777@gmail.com"
__desc__ = "Play online video streams from various sources"

import os,time,sys,os,os.path
import datetime,re, traceback
import urllib2

from Plugins.Plugin import PluginDescriptor
from enigma import ePicLoad, eServiceReference, eTimer, getDesktop
from Screens.Screen import Screen
from Screens.InfoBarGenerics import InfoBarShowHide
from Screens.InfoBar import MoviePlayer
from Screens.MessageBox import MessageBox
from Screens.LocationBox import LocationBox
from Screens.ChoiceBox import ChoiceBox
from Screens.VirtualKeyBoard import VirtualKeyBoard
from Screens.Console import Console
from Screens.Standby import TryQuitMainloop
#from Screens.InputBox import InputBox
from Components.AVSwitch import AVSwitch
from Components.ActionMap import ActionMap, HelpableActionMap
from Components.Label import Label
from Components.ScrollLabel import ScrollLabel
from Components.Input import Input
from Components.MenuList import MenuList
from Components.Pixmap import Pixmap
from Components.Sources.List import List
from Components.Sources.StaticText import StaticText
from Components.Button import Button
from Components.Task import job_manager
from Components.config import config, ConfigSubsection, ConfigText, ConfigInteger, ConfigLocations, ConfigDirectory, ConfigSet, ConfigYesNo, ConfigSelection, getConfigListEntry, ConfigSelectionNumber, ConfigNumber
from Components.config import config, ConfigSubsection, ConfigYesNo, getConfigListEntry, ConfigSelection, ConfigNumber, ConfigDirectory,ConfigText, ConfigSubDict
from Components.ConfigList import ConfigListScreen
#from Screens.LocationBox import LocationBox
from Tools import Notifications
from Tools.BoundFunction import boundFunction
from Tools.Directories import resolveFilename, SCOPE_PLUGINS
from Tools.LoadPixmap import LoadPixmap
from skin import loadSkin
from twisted.web.client import downloadPage,defer,reactor
try:
    # available since twisted 14.0
    from twisted.internet._sslverify import ClientTLSOptions
except ImportError:
    ClientTLSOptions = None
from twisted.internet.ssl import ClientContextFactory

from plugin_locale import _
from content import ContentSources
from content import util
from VideoDownload import DownloadJob, HLSDownloadJob,VideoDownloadList
from content.Downloader import get_header, get_ext
#import enigma2_api

e2 = None
cur_directory = os.path.dirname(os.path.realpath(__file__))
loadSkin(os.path.join(cur_directory, "skin.xml"))

#####################################################################################################################
config.plugins.playstream = ConfigSubsection()
config.plugins.playstream.locations = ConfigLocations(default=["/media/hdd/movie/"])
config.plugins.playstream.download_dir = ConfigDirectory(default="/media/hdd/movie/")
config.plugins.playstream.tmp_dir = ConfigDirectory(default="/tmp/playstream/")
config.plugins.playstream.streamproxy_start = ConfigYesNo(default = True)
config.plugins.playstream.overwrite_download = ConfigYesNo(default = False)
#config.plugins.playstream.size = ConfigSelection({"400x240":"400x240","220x132":"220x132","100x60":"100x60"}, default="220x132")
config.plugins.playstream.clear_tmp = ConfigYesNo(default = True)
config.plugins.playstream.check_update = ConfigYesNo(default = True)


class CustomContextFactory(ClientContextFactory):
    def __init__(self, hostname = None):
        self.hostname = hostname
    def getContext(self):
        ctx = self._contextFactory(self.method)
        if self.hostname and ClientTLSOptions:
            ClientTLSOptions(self.hostname, ctx)
        return ctx

#####################################################################################################################
class MainScreen(Screen):
    def __init__(self, session):
        Screen.__init__(self, session)
        self.skinName = ["PSMain"]
        self.session = session
        self.e2 = None
        self["key_red"] = Button(_("Exit"))
        self["key_green"] = Button(_("Select"))
        self["key_yellow"] = Button(_("Options"))
        self["key_blue"] = Button(_("Config"))
        self["key_menu"] = Button("Menu")
        self["key_exit"] = Button("Back")

        self["actions"] = ActionMap(["OkCancelActions", "ColorActions","MenuActions", "NumberActions",
                                     "WizardActions","ButtonSetupActions"], {
            #"cancel": self.Cancel,
            "ok": self.ok,
            "green": self.ok,
            "red": self.cancel,
            "yellow": self.options_screen,
            "blue": self.config_screen,
            "menu": self.item_menu,
            "cancel": self.back,
            "info": self.show_info,
            "pageup": self.page_up,
            "channelup":self.page_up,
            "pagedown": self.page_down,
            "channeldown":self.page_down,
       })
        self["list"] = List([])
        self["list"].onSelectionChanged.append(self.selection_changed)
        self["pic"] = Pixmap()
        self["cur"] = ScrollLabel()
        self["title"] = Label()
        self.downloading = 0
        self.active_downloads = 0
        if not os.path.exists(config.plugins.playstream.tmp_dir.value):
            os.mkdir(config.plugins.playstream.tmp_dir.value)
        self.onLayoutFinish.append(self.layout_finished)

    def layout_finished(self):
        self.defimage = LoadPixmap(os.path.join(cur_directory,"PlayStream.png"))
        #self.defimage = None
        #sc = AVSwitch().getFramebufferScale()
        #self.defimage0 = ePicLoad()
        #self.defimage0.PictureData.get().append(boundFunction(self.FinishDecodeDef, os.path.join(cur_directory,"PlayStream.png")))
        #self.defimage0.setPara((self["pic"].instance.size().width(),self["pic"].instance.size().height(),sc[0], sc[1], False, 0, "#00000000"))
        #self.defimage0.startDecode("default")

        self.active_downloads = 0
        self.images = {}
        self.images_url = {}
        self.picloads = {}
        self.history = []

        reload(ContentSources)
        self.sources = ContentSources.ContentSources(os.path.join(cur_directory, "content", "sources"))
        self.config = self.sources.plugins["config"]
        self.cur_menu = ("Home","config::home","","Sākums") #
        self.content = self.sources.get_content(self.cur_menu[1])
        #print self.content
        self["list"].setList(self.content)
        self["cur"].setText(self.content[0][3])
        self.setTitle2(self.cur_menu[0] + " (" + self.cur_menu[1].split("::")[0]+")")
        self.show_picture(self.content[0][2])
        reactor.callLater(1,self.check_update)

    def check_update(self):
        #print "Check PlayStream for update"
        if config.plugins.playstream.check_update:
            self.cver = util.check_version("enigma2-plugin-extensions-playstream")
            if self.cver and self.cver>__version__:
                txt = "New version of plugin  available for update - %s\nCurrent version - %s\nDo you want to upgrade?"%(self.cver,__version__)
                mbox = self.session.openWithCallback(self.update, MessageBox, txt, MessageBox.TYPE_YESNO)
                mbox.setTitle("Upgrade plugin?")

    def update(self,answer):
        if answer:
            plugin_update(self.session)

    def page_down(self):
        self["cur"].pageDown()

    def page_up(self):
        self["cur"].pageUp()

    def selection_changed(self):
        current = self["list"].getCurrent()
        print "[PlayStream] SelectionChanged: current=",current
        if not current: return
        self["cur"].setText(current[3]) if current[3] else self["cur"].setText("")
        if current[2]:
            self.show_picture(current[2])
        else:
            self.show_default_picture()

    def setTitle2(self,title):
        #print self.keys()
        self["title"].setText(title)

    def show_default_picture(self):
        if self.defimage:
            self["pic"].instance.setPixmap(self.defimage)

    def show_picture(self, image_url):
        if image_url == "default":
            self.show_default_picture()
            return
        elif self.images.has_key(image_url):
            if self.images[image_url] in (-1,-2):
                return
            elif self.images[image_url] == -3:
                self.show_default_picture()
                return
            else:
                self["pic"].instance.setPixmap(self.images[image_url])
        else:
            if image_url.startswith("http"):
                fname = image_url.replace(":","-").replace("/","_")
                image_path = os.path.join(config.plugins.playstream.tmp_dir.value, fname)
                self.download_image(image_path, image_url)
            else: # local file
                image_path = os.path.join(cur_directory, "picons", image_url)
                self.start_decode(image_path,image_url)

    def start_decode(self,image_path,image_url):
        self.images[image_url] = -2
        self.images_url[image_path] = image_url
        sc = AVSwitch().getFramebufferScale()
        if  not self.picloads.has_key(image_path):
            self.picloads[image_path] = ePicLoad()
            try:
                self.picloads[image_path].PictureData.get().append(boundFunction(self.decode_finished, image_path))
            except:
                self.picloads[image_path].PictureData.connect(boundFunction(self.decode_finished, image_path))
            self.picloads[image_path].setPara((self["pic"].instance.size().width(),
                                          self["pic"].instance.size().height(),
                                          sc[0], sc[1], True, 0, "#00000000"))
            print image_path,image_url
            self.picloads[image_path].startDecode(image_path)

    def decode_finished(self, image_path, picInfo = None):
        image_url = self.images_url[image_path]
        del self.images_url[image_path] #III
        self.images[image_url] = self.picloads[image_path].getData()
        self["pic"].instance.setPixmap(self.images[image_url])
        del self.picloads[image_path]
        if len(self.images)>30:
            del self.images[self.images.keys()[0]]
            # self.images.pop()

    #def FinishDecodeDef(self, image_path,picInfo = None):
    #    self.defimage = self.defimage0.getData()
    #    del self.defimage0
    #    self["pic"].instance.setPixmap(self.defimage)

    def download_image(self,image_path,image_url):
        #print "Image download started",self.downloading,image_path,image_url
        self.downloading += 1
        self.images[image_url] = -1
        downloadPage(image_url, image_path, CustomContextFactory(image_url.split("/")[2])).addCallback(boundFunction(self.download_image_finished, image_path, image_url)).addErrback(boundFunction(self.download_image_failed, image_path, image_url))

    def download_image_finished(self, image_path, image_url, result):
        self.downloading -= 1
        #print "[ Play] Image downloaded finished ",self.downloading,image_path, image_url,result
        self.start_decode(image_path,image_url)

    def download_image_failed(self, image_path, image_url, result):
        self.downloading -= 1
        print "[TV Play] Image downloaded failed ",self.downloading,image_path, image_url,result
        self.images[image_url] = -3


    def ok(self):
        current = self["list"].getCurrent()
        self.current = current
        index = self["list"].getIndex()
        self.index = index
        print "[PlayStream] - menu selected ", current
        data = current[1].split("::")[1] if "::" in current[1] else current[1]
        if not data:
            return

        elif self.sources.is_video(current[1]):
            if ContentSources.stream_type(current[1]):
                stream = util.item()
                stream["url"] = current[1]
                stream["name"] = current[0]
                streams = [stream]
            else:
                try:
                    streams = self.sources.get_streams(current[1])
                except Exception,e:
                    print str(e)
                    traceback.print_exc()
                    self.session. open(MessageBox, "Error - %s"%str(e) , MessageBox.TYPE_INFO)
                    return
            if streams:
                #print streams
                for s in streams:
                    if not s["name"]: s["name"] = current[0]
                    if not s["img"]: s["img"] = current[2]
                    if not s["desc"]: s["desc"] = current[3]
                try:
                    self.session.open(PSPlayer, streams)
                except Exception as e:
                    traceback.print_exc()
                    self.msg("Error launching player - " + str(e))
                    return
            else:
                self.msg("No stream found - %s"%(self.current[1]))
                return

        elif current[1] == "back":
            cur_menu_old = self.cur_menu
            self.cur_menu = self.history.pop()
            new_content = self.sources.get_content(self.cur_menu[1])
            try:
                index = zip(*new_content)[1].index(cur_menu_old[1])
            except:
                index = 0
            self.setTitle2(self.cur_menu[0]+ " (" + self.cur_menu[1].split("::")[0]+")")
            self.show_content(new_content,index)

        else:
            print "selected=",current
            if "{0}" in current[1]:
                self.session.openWithCallback(self.cb_input,VirtualKeyBoard, title="Enter value", text="")
                #a = raw_input("Enter value:")
                #a = "big bang"
                #current = (current[0],current[1].format(a),current[2],current[3])
                #self.get_content(current)
            else:
                self.get_content(current)


    def show_info(self):
        self.current = self["list"].getCurrent()
        data = self.current[1]
        source = data.split("::")[0]
        if self.sources.is_video(data) and "get_info" in dir(self.sources.plugins[source]):
            #self.sources.plugins
            try:
                nfo = self.sources.get_info(self.current[1])
            except Exception, e:
                print str(e)
                traceback.print_exc()
                self.session.open(MessageBox, "Error - %s" % str(e), MessageBox.TYPE_INFO)
                return
        else:
            nfo = {"movie": {"title": self.current[0], "thumb": self.current[2], "plot": self.current[3]}}
        self.session.open(StreamInfo, nfo)

    def cb_input(self,value):
        if not value:
            return
        current = self.current
        current = (current[0],current[1].format(value),current[2],current[3])
        self.get_content(current)

    def get_content(self,current):
            self.history.append(self.cur_menu)
            self.cur_menu = current
            try:
                new_content = self.sources.get_content(self.cur_menu[1])
            except Exception,e:
                self.cur_menu = self.history.pop()
                traceback.print_exc()
                self.session. open(MessageBox, "Error - %s"%str(e) , MessageBox.TYPE_INFO)
                return
            self.setTitle2(self.cur_menu[0] + " (" + self.cur_menu[1].split("::")[0]+")")
            self.show_content(new_content)

    def back(self):
        if self.history:
            self["list"].setIndex(0)
            self.ok()
        else:
            self.cancel()

    def show_content(self,content,index=0):
        self["list"].setList(content)
        self["list"].setIndex(index)
        self.selection_changed()

    def cancel(self):
        print "Exiting PlayStream"
        if config.plugins.playstream.clear_tmp.value and os.path.exists(config.plugins.playstream.tmp_dir.value):
            for name in os.listdir(config.plugins.playstream.tmp_dir.value):
                #print "remove "+os.path.join(config.plugins.playstream.tmp_dir.value, name)
                os.remove(os.path.join(config.plugins.playstream.tmp_dir.value, name))
            #os.rmdir(config.plugins.playstream.tmp_dir.value)
        self.close()


    def item_menu(self):
        print "\n[PlayStream] options\n"
        self.current = self["list"].getCurrent()
        self.index = self["list"].getIndex()
        #self.session. open(MessageBox, "Item options - %s"%current[0] , MessageBox.TYPE_INFO)
        #args=[current,self.cur_menu]
        #self.session.open(ItemMenuScreen,current,index,self)
        lst = [
            ("Aditional information","info","Display additional information about item"),
            ("Add to bouquet","bouquet","Add current item to Enigma2 bouquet"),
            ("Add to favorites","favorites","Add current item to PlayStrem favorites"),
            ("Show active downloads","download_list","Show active downloads list"),
            ("Set download folder","download_folder","Set download folder")
        ]
        if self.sources.is_video(self.current[1]):
            lst.extend([
            ("Download video to default folder","download","Download video to default folder"),
            ("Download video, ask folder","download2","Download video, ask download folder"),
            ("Download video to subfolder, ask parent folder","download3","Download video to subfolder, ask download folder"),

            ])
        else:
            lst.extend([
            ("Download list to default folder","download","Download videos in list (if any)"),
            ("Download list, ask folder","download2","Download videos in list (if any), ask download folder"),
            ])
        if "config::" in self.cur_menu[1]:
            lst.extend([
            ("Rename item","rename","Rename list item"),
            ("Move item","move","Move list item"),
            ("Delete item","delete","Delete list item"),
            ("Add submenu","add_list","Add submenu before selected item"),
            ])
        title = self.current[0]
        self.session.openWithCallback(self.cb_item_menu, ChoiceBox, title = title, list = lst) #TODO

    def cb_item_menu(self,answer):
        #print "item_menu_selected",answer
        if not answer:
            return
        self.answer = answer[1]

        if answer[1] == "info":
            #self.show_nfo()
            #self.session.open(MessageBox, "Not yet implemented!", MessageBox.TYPE_INFO)
            self.show_info()

        elif answer[1] == "bouquet":
            #if not e2:
                #e2 = enigma2_api.DBServices()
            #print "load_buuquets - ",e2._load_bouquets()
            self.session.open(MessageBox, "Not yet implemented!", MessageBox.TYPE_INFO)

        elif answer[1] == "favorites":
            lists = self.config.get_lists()
            lists2 = [(self.config.get_title(l),l) for l in lists]
            print lists2
            self.session.openWithCallback(self.cb_favorites, ChoiceBox, title="Selected menu item will be added",list = lists2)

        elif answer[1] in ("download2","download3"):  # ask download folder before
            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)

        elif answer[1] == 'download':
            self.download_prepare(config.plugins.playstream.download_dir.value)

        elif answer[1] == 'download_list':
            self.download_list()

        elif answer[1] == 'download_folder':
            #downloadDir = "/media/hdd/movie" #config.plugins.playstream.downloadDir.value TODO
            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)

        elif answer[1] == "delete":
            lst = self.cur_menu[1].replace("config::","")
            #print lst
            self.config.del_item(lst,self.index)
            self.config.write_streams()
            txt = "'%s' deleted from favourite stream list '%s'"%(self.current[0],lst)
            self.session.open(MessageBox, txt, MessageBox.TYPE_INFO,timeout=5)

        elif answer[1] == "rename":
            #name2 = "Renamed"
            self.session.openWithCallback(self.cb_rename,VirtualKeyBoard, title="Enter new item name", text=self.current[0])

        elif answer[1] == "add_list":
            self.session.open(MessageBox, "Not yet implemented!", MessageBox.TYPE_INFO,timeout=5)
            pass #TODO
        return

    def download_prepare(self, download_dir=""):
        current = self.current
        if not download_dir:
            return
            #download_dir = config.plugins.playstream.download_dir.value
        title = re.sub("\[.+?\]","", util.make_fname(current[0])).strip()
        download_dir2 = os.path.join(download_dir, title)
        if not self.sources.is_video(current[1]):
            #self.msg("Can not download listst (yet) - %s"%(current[1]))
            n = 0
            for current2 in self.sources.get_content(current[1]):
                if self.sources.is_video(current2[1]):
                    n += 1
                    self.download_video(current2,download_dir2)
            if n>0:
                self.msg("%s videos download started to %s"%(n,download_dir2))
            else:
                self.msg("No videos to download")
        else:
            if self.answer == "download":
                download_dir2 = download_dir
            if self.download_video(current,download_dir2):
                self.msg("Video download started to %s"%download_dir2)

    def cb_download_dir(self, downloadDir, select=None):
        if not downloadDir:
            return
        print "Folder selected - %s"%downloadDir
        config.plugins.playstream.download_dir.setValue(downloadDir)
        config.plugins.playstream.download_dir.save()
        config.plugins.playstream.locations.save()
        config.save()

    def download_list(self):
        self.session.open(VideoDownloadList)

    def download_video(self,current, download_dir=""):
        if ContentSources.stream_type(current[1]):
            stream = util.item()
            stream["url"] = current[1]
            stream["name"] = current[0]
            streams = [stream]
        else:
            try:
                streams = self.sources.get_streams(current[1])
            except Exception,e:
                print "Error - %s"%str(e)
                traceback.print_exc()
                self.session. open(MessageBox, "Error - %s"%str(e) , MessageBox.TYPE_INFO)
                return
        if not streams:
            self.msg("No stream found to download - %s"%(self.current[1]))
            return
        for s in streams:
            if not s["name"]: s["name"] = current[0]
            if not s["img"]: s["img"] = current[2]
            if not s["desc"]: s["desc"] = current[3]

        if len(streams)>1:
            stream = streams[0] # TODO iespeja izvelēties strīmu, ja to ir vairāki
        else:
            stream = streams[0]
        stream = util.stream_change(stream)
        return self.download_stream(stream, download_dir)

    def download_stream(self,stream,download_dir=""):
        print "download stream",stream
        #self.msg("Start downloading..")
        self.stream = stream
        url = stream["url"]
        headers = stream["headers"] if "headers" in stream else {}
        stream_type = ContentSources.stream_type(url) #self.sources.stream_type(stream["url"])
        if not stream_type: #
            print "Not supported stream type found to download - %s"%(self.current[1])
            self.msg("Not supported stream type found to download - %s"%(self.current[1]))
            return

        title = self.stream["name"].strip()
        downloadDir = config.plugins.playstream.download_dir.value if not download_dir else download_dir
        if not os.path.exists(downloadDir):
            try:
                os.mkdir(downloadDir)
            except Exception as e:
                traceback.print_exc()
                print 'Error creating download directory "%s"!\nPlease specify in the settings existing directory\n%s'%(downloadDir,str(e))
                self.msg('Error creating download directory "%s"!\nPlease specify in the settings existing directory\n%s'%(downloadDir,str(e)))
                return
        fname0 = util.make_fname(title)
        #print "Trying to download - ", current
        if self.stream["img"]:
            try:
                thumb = urllib2.urlopen(stream["img"]).read()
            except:
                thumb = ""
            if thumb:
                imgext = ".jpg"
                m = re.search("(\.\w{3})$",stream["img"])
                if m:
                    imgext = m.group(1)
                imgfile = os.path.join(downloadDir,fname0+imgext)
                with open(imgfile,"wb") as f:
                    f.write(thumb)
        if self.stream["subs"]:
            suburl = self.stream["subs"][0]["url"]
            print "\n**Download subtitles %s - %s"%(title,suburl)
            subs = urllib2.urlopen(suburl).read()
            if subs:
                #fname0 = re.sub("[/\n\r\t,:]"," ",title)
                subext = ".srt"
                subfile = os.path.join(downloadDir,fname0+subext)
                if ".xml" in suburl:
                    subs = util.ttaf2srt(subs)
                with open(subfile,"w") as f:
                    f.write(subs)
            else:
                print "\n Error downloading subtitle %s"%suburl
        if "nfo" in self.stream and self.stream["nfo"]:
            nfofile = subfile = os.path.join(downloadDir,fname0+".nfo")
            with open(nfofile,"w") as f:
                nfo_txt = util.nfo2xml(self.stream["nfo"])
                f.write(nfo_txt)
        try:
            h = get_header(url,headers)
        except:
            h = None
        if not h:
            self.session.open(MessageBox, "Can non get headers - %s" % url)
            return False

        mtype = h.get("content-type")
        if not mtype:
            mtype = "videp/mp4" # TODO default mtype if not content-type in header?

        fext,stream_type = get_ext(mtype)
        fname = fname0 + fext
        outputfile = os.path.join(downloadDir, fname)
        overwrite = config.plugins.playstream.overwrite_download.value
        if not overwrite and os.path.exists(outputfile):
            self.msg( _('Sorry, this file already exists:\n%s') % outputfile)
            return False
            #os.remove(outputfile)

        if stream_type in ("http","https", "hls"):
            print "\n**Download %s - %s"%(title,url)
            #reload(DownloadJob)
            try:
                job_manager.AddJob(DownloadJob(url, outputfile, title[:20], self.video_download_stop, headers, stream_type))
            except Exception as e:
                print str(e)
                traceback.print_exc()
                self.session.open(MessageBox, "Error - %s" % str(e), MessageBox.TYPE_INFO)
                return  False

            self.active_downloads += 1
            #self.msg(_('Video download started!'))
            return True

        elif stream_type == "hls":
            #self.msg("HLS stream download not yet implemented!")
            print "\n**Download %s - %s"%(title,url)
            #reload(HLSDownloadJob)
            print "HLSDownload", url,outputfile
            job_manager.AddJob(HLSDownloadJob(url, outputfile, title[:20], self.video_download_stop))
            self.active_downloads += 1
            #self.msg(_('Video download started!'))
            return True

        elif stream_type == "rstp":
            self.msg("RSTP stream download not yet implemented!")
            return False
        else:
            self.msg("Unkown stream type - %s!"%stream_type)
            return False


    def cb_rename(self,value):
        if not value:
            return
        lst = self.cur_menu[1].replace("config::","")
        pos = self.index
        print value
        item2 = list(self.current)
        item2[0]=value
        item2 = tuple(item2)
        self.config.replace_item(lst,item2,pos)
        self.config.write_streams()
        txt = "'%s' renamed to '%s'"%(self.current[0],value)
        self.session.open(MessageBox, txt, MessageBox.TYPE_INFO,timeout=5)

    def cb_favorites(self,answer):
        print "cb_favorites",answer,self.current
        if not answer:
            return
        value = answer[1]
        self.config.add_item(value,self.current)
        self.config.write_streams()
        txt = "'%s' added to favourite stream list '%s'"%(self.current[0],value)
        self.session.open(MessageBox, txt, MessageBox.TYPE_INFO,timeout=3)
        #self.session.openWithCallback(self.callMyMsg, MessageBox, _("Do you want to exit the plugin?"), MessageBox.TYPE_INFO)

    def config_screen(self):
        self.session.open(ConfigScreen,self)

    def options_screen(self):
        source = self.cur_menu[1].split("::")[0]
        options = self.sources.options_read(source)
        print source
        if not options:
            self.session. open(MessageBox, "No options available for source %s (%s)"%(self.cur_menu[0],source) , MessageBox.TYPE_INFO)
        else:
            self.session.open(OptionsScreen,self)

    def video_download_stop(self,title):
        self.active_downloads -= 1
        self.msg2(title)
        print "video_download_stop ", title

    def msg2(self,msg,timeout=10,mtype = None):
        mtype=mtype if mtype else MessageBox.TYPE_INFO
        Notifications.AddPopup(text = msg, type=mtype, timeout=timeout)

    def msg(self,msg,timeout=10):
        self.session.open(MessageBox, msg, MessageBox.TYPE_INFO, timeout)

def make_service(stream):
    url = stream["url"]
    headers = []
    if stream.has_key("headers"):
        for h in stream["headers"]:
            headers.append("%s=%s"%(h,stream["headers"][h]))
    if headers:
        headers ="&".join(headers)
        url = url+"#"+headers
        print "stream_url with headers=",headers
    url = url.encode("utf8")
    if "|" in url:
        url = url.replace("|","#")
    service_type = 4097
    if re.search("\.ts$",url.split("?")[0],re.IGNORECASE):
        service_type = 1
    if "resolver" in stream and stream["resolver"] in ("hqq","viaplay","filmas"):
        url = util.streamproxy_encode(stream["url"], stream["headers"])
        #if os.path.exists("/usr/bin/exteplayer3"): # problem playing hqq streams with gstreamer, use exteplayer3
            #service_type = 5002
    print "service_type=",service_type
    print "stream_url=",url
    service = eServiceReference(service_type, 0, url)
    service.setName( stream["name"])
    return service

def plugin_update(session):
    feed_file = "/etc/opkg/ivars777-feed.conf"
    if not os.path.exists(feed_file):
        with open(feed_file, "w") as f:
            f.write("src/gz ivars777 http://feed.blue.lv")
    cmdlist = [
        "opkg update",
        "opkg install enigma2-plugin-extensions-playstream",
        "echo Restart Enigma after upgrade!"
    ]
    # os.chmod(cmd, 493)
    session.open(Console, "Update PlayStream plugin", cmdlist)

#####################################################################################################################
class PSSubs(Screen):

    def __init__(self, session):
        desktopWidth = getDesktop(0).size().width()
        desktopHeight = getDesktop(0).size().height()
        offset = 20
        screenWidth = desktopWidth - (2 * offset)
        widgetWidth = screenWidth / 2 - 5
        self.skin = """
            <screen position="%d,%d" size="%d,140" zPosition="2" backgroundColor="transparent" flags="wfNoBorder">
                <widget name="subtitle" position="0,0" size="%d,140" valign="center" halign="center" font="Regular;36" transparent="1" foregroundColor="white" shadowColor="#40101010" shadowOffset="2,2" />
             </screen>""" % (offset, desktopHeight-offset-140, screenWidth, screenWidth)
        self['subtitle'] = Label()
        Screen.__init__(self, session)


#####################################################################################################################
class PSPlayer(MoviePlayer):
    def __init__(self, session, streams):
        print "PSPlayer init: ",streams
        self.session = session
        self.streams = streams
        self.cur_stream = self.streams[0] # TODO
        self.selected = 0
        self.resume_pos = 0
        service = make_service(self.cur_stream)

        MoviePlayer.__init__(self, session, service)
        self.skinName = "MoviePlayer"
        self["actions"] = ActionMap(["MediaPlayerActions","MediaPlayerSeekActions","MoviePlayerActions","InfobarSeekActions","MovieSelectionActions","ColorActions"], {
            "stop":self.leavePlayer,
            "leavePlayer":self.leavePlayer,

            "audio":self.select_stream,
            "AudioSelection":self.select_stream,
            "green":self.select_stream,

            "subtitles":self.select_captions,
            "text":self.select_captions,
            "yellow_key":self.select_captions,
            "yellow":self.select_captions,
            "pauseServiceYellow":self.select_captions,
            "pause":self.select_captions,

            "showEventInfo":self.service_info,
            "info":self.service_info
        })
        self.stimer = eTimer()
        if "callback" in dir(self.stimer):
            self.stimer.callback.append(self.update_subtitles)
        elif "timeout" in dir(self.stimer):
            self.stimer_conn = self.stimer.timeout.connect(self.update_subtitles)
        else:
            self.stimer = None
        self.stimer_step = 500
        if self.cur_stream["subs"]:
            self.subs = self.cur_stream["subs"]
            self.cur_subs = 0 # TODO - no konfigurācijas
            self.svisible = True # TODO - no konfigurācijas
            self.sind = 0
            self.get_subs_current()
        else:
            self.subs = []
            self.cur_subs = 0
            self.svisible = False
        self.subtitle_window = self.session.instantiateDialog (PSSubs)
        self.onLayoutFinish.append(self.start_subtitles_timer)

    def start_subtitles_timer0(self):
        if self.stimer:
            self.subtitle_window.show()
            print "start_subtitles_timer"
            self.stimer.start(self.stimer_step)

    def start_subtitles_timer(self):
        self.stimer.start(self.stimer_step)


    def get_sub_pts(self,pts):
        sc = self.get_sub_ind(self.sind) # current subbtitle
        while True:
            if not sc:
                return "Error - no subs find" # TODO
            if pts > sc["end"]:
                self.sind += 1
                sc = self.get_sub_ind(self.sind)
                continue
            else:
                if pts <sc["begin"]:
                    return " "
                else:
                    txt = sc["text"] if sc["text"] else " "
                    return txt

    def get_sub_ind(self,ind):
        subs_object = self.get_subs_current() # current subs object
        if subs_object:
            return subs_object.subs[ind] if ind<len(subs_object.subs) else None
        else:
            return None

    def get_subs_current(self):
        "Return current sub_object"
        if not "subs" in self.subs[self.cur_subs]:
            print "===== Captions to download", self.subs[self.cur_subs]["url"]
            subs_object = util.Captions(self.subs[self.cur_subs]["url"])
            print len(subs_object.subs), "items"
            self.subs[self.cur_subs]["subs"] = subs_object
            if not subs_object:
                return None
            else:
                return subs_object
        else:
            return self.subs[self.cur_subs]["subs"]

    def update_subtitles(self):
        if not self.shown and self.svisible:
            seek = self.getSeek()
            pos = seek.getPlayPosition()
            pts = pos[1]/90
            txt0 = "%d:%02d (%i)" % (pts/60/1000, (pts/1000)%60, pts)
            #print "Update_subtitles", txt0
            if not self.subtitle_window.shown:
                self.subtitle_window.show()
            if not self.subs:
                return
            txt = self.get_sub_pts(pts)
            #print "Show subtitle",txt
            #txt = txt0+": "+ txt
            self.subtitle_window["subtitle"].setText(txt)
        elif self.shown and self.svisible:
            if self.subtitle_window.shown:
                self.subtitle_window.hide()
        elif not self.svisible:
            if self.subtitle_window.shown:
                self.subtitle_window.hide()

        # 	struct SubtitleTrack
        #	int type;
        #	int pid;
        #	int page_number;
        #	int magazine_number;
        #	std::string language_code;
        #selectedSubtitle = ???
        #self.enableSubtitle(selectedSubtitle)

    def play_service(self,service):
        self.movieSelected(service)

    #def doShow(self):
        #self.svisible = False
        #InfoBarShowHide.doShow(self)

    #def doHide(self):
        #self.svisible = True
        #InfoBarShowHide.doHide(self)

    def service_info(self):
        print "########[MoviePlayer] service_info"
        text = "%s\n%s %s\n%s"%(self.cur_stream["name"],self.cur_stream["lang"],self.cur_stream["quality"],self.cur_stream["desc"])
        text = text.encode("utf8")
        #print text
        #mtype = MessageBox.TYPE_INFO
        #Notifications.AddPopup(text = text, type=mtype, timeout = 10)
        print "StreamInfo", self.cur_stream
        nfo = self.cur_stream["nfo"] if "nfo" in self.cur_stream else {"movie":{"title":self.current[0],"thumb":self.current[1],"plot":self.current[3]}}
        self.session.open(StreamInfo, nfo)

    def select_stream(self):
        print "########[MoviePlayer] select_stream"
        lst = []
        title = "Select stream"
        for i,s in enumerate(self.streams):
            lst.append(("[%s,%s] %s"%(s["lang"],s["quality"],s["name"]),i))
        self.session.openWithCallback(self.cb_select_stream, ChoiceBox, title = title, list = lst,selection = self.selected)

    def cb_select_stream(self,answer):
        #print "item_menu_selected",answer
        if not answer:
            return
        self.selected = answer[1]
        service = make_service(self.streams[self.selected])
        self.resume_pos = self.getSeek().getPlayPosition()[1]
        self.play_service(service)

    def serviceStarted(self):
        print "serviceStarted"
        if not self.resume_pos:
            self.resume_pos = 0
            print "doSeek",self.resume_pos
            #self.doSeek(self.resume_pos)


    def select_captions(self):
        print "########[MoviePlayer] select_caption"
        lst = []
        title = "Select subtitles"
        for i,s in enumerate(self.subs):
            lst.append((("%s - %s"%(s["lang"],s["name"])).encode("utf8"),i))
        if self.svisible:
            selection = self.cur_subs
        else:
            selection = len(lst)
        lst.append(("No captions",-1))
        self.session.openWithCallback(self.cb_select_captions, ChoiceBox, title = title, list = lst,selection = selection)

    def cb_select_captions(self,answer):
        #print "item_menu_selected",answer
        if not answer:
            return
        if answer[1] == -1:
            self.svisible = False
        else:
            self.cur_subs = answer[1]
            self.svisible = True

    def leavePlayer(self):
        self.close()
        #self.session.openWithCallback(self.leavePlayerConfirmed, MessageBox, _("Stop playing?"))

    def leavePlayerConfirmed(self, answer):
        if answer:
            self.close()

    def doEofInternal(self, playing):
        self.close()

    #def getPluginList(self):
            #from Components.PluginComponent import plugins
            #list = []
            #for p in plugins.getPlugins(where = PluginDescriptor.WHERE_EXTENSIONSMENU):
                    #if p.name != _("TV Play"):
                        #list.append(((boundFunction(self.getPluginName, p.name),
                            #boundFunction(self.runPlugin, p), lambda: True), None))
            #return list

    #def showMovies(self):
            #pass


#####################################################################################################################
class ConfigScreen(ConfigListScreen,Screen):

    def __init__(self, session, args = 0):
        self.session = session
        #self.setup_title = "Options"
        Screen.__init__(self, session)
        self.skinName = ["PSConfig"]
        self.list = [
            getConfigListEntry(_("Download folder"), config.plugins.playstream.download_dir),
            getConfigListEntry(_("Overwrite download video"), config.plugins.playstream.overwrite_download),
            getConfigListEntry(_("TMP folder"), config.plugins.playstream.tmp_dir),
            getConfigListEntry(_("Clear tmp folder on exit"), config.plugins.playstream.clear_tmp),
            getConfigListEntry(_("Start playstreamproxy"), config.plugins.playstream.streamproxy_start),
            getConfigListEntry(_("Check new plugin version in feed"), config.plugins.playstream.check_update)
        ]
        ConfigListScreen.__init__(self, self.list, session = self.session)
        self["title"] = Label()
        self["key_red"] = Button(_("Cancel"))
        self["key_green"] = Button(_("Save"))
        self["key_yellow"] = Button("Update")
        self["key_blue"] = Button("Downloads")
        self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
                                         {
                                             "red": self.cancel,
                                             "green": self.save,
                                             "yellow": self.update_plugin,
                                             "blue": self.downloads,
                                             "save": self.save,
                                             "cancel": self.cancel,
                                             "ok": self.ok,
                                             }, -2)
        self["title"].setText("Version %s, ivars777@gmail.com"%__version__)

    def getCurrentEntry(self):
        return self["config"].getCurrent()[0]

    def getCurrentValue(self):
        return str(self["config"].getCurrent()[1].getText())

    def ok(self):
        if self["config"].getCurrent()[1] == config.plugins.playstream.download_dir:
            folder = config.plugins.playstream.download_dir.value
            #self.session.openWithCallback(self.cb_download_dir, LocationBox,"Select Folder")
            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)
        elif self["config"].getCurrent()[1] == config.plugins.playstream.tmp_dir:
            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)
        else:
            self.save()

    def cb_download_dir(self, folder, select=None):
        if not folder:
            return
        print "Folder selected - %s"%folder
        config.plugins.playstream.download_dir.setValue(folder)
        config.plugins.playstream.download_dir.save()
        config.plugins.playstream.locations.save()
        config.save()

    def select_tmp_dir(self, folder, select=None):
        if not folder:
            return
        print "Folder selected - %s"%folder
        config.plugins.playstream.tmp_dir.setValue(folder)
        config.plugins.playstream.tmp_dir.save()
        config.plugins.playstream.locations.save()
        config.save()

    def save(self):
        print "saving"
        self.saveAll()
        self.close(True,self.session)

    def cancel(self):
        #print "cancel"
        self.close(False,self.session)

    def downloads(self):
        self.session.open(VideoDownloadList)

    def update_plugin(self):
        #print "Check PlayStream for update"
        self.cver = util.check_version("enigma2-plugin-extensions-playstream")
        if self.cver and self.cver>__version__:
            txt = "New version of plugin  available for update - %s\nCurrent version - %s\nDo you want to upgrade?"%(self.cver,__version__)
        else:
            txt = "No new version of plugin  available for update - %s\nCurrent version - %s\nDo you want to upgrade?"%(self.cver,__version__)
        mbox = self.session.openWithCallback(self.update, MessageBox, txt, MessageBox.TYPE_YESNO)
        mbox.setTitle("Upgrade plugin?")

    def update(self,answer):
        if answer:
            plugin_update(self.session)

    def restart_dialog(self):
        self.session.openWithCallback(self.restart, MessageBox, _("Restart Enigma2?"),MessageBox.TYPE_YESNO)

    def restart(self, answer):
        if answer:
            self.session.open(TryQuitMainloop, retvalue=3)
        else:
            return

#####################################################################################################################
class OptionsScreen(ConfigListScreen,Screen):

    def __init__(self, session,*args):
        self.session = session
        Screen.__init__(self, session)
        self.skinName = ["PSOptions"]
        self.main = args[0]
        self.setTitle("Source options")
        self.source = self.main.cur_menu[1].split("::")[0]
        self.cfg = ConfigSubDict() #config.plugins.playstream
        self.list = []
        self.options = self.main.sources.options_read(self.source)
        if not self.options:
            #self.session. open(MessageBox, "No options available for source %s (%s)"%(self.main.cur_menu[0],self.source) , MessageBox.TYPE_INFO)
            self.close(False,self.session)
        for k in self.options:
            self.cfg[k]=ConfigText(default=self.options[k],fixed_size=False)
            self.list.append(getConfigListEntry(k, self.cfg[k]))
        ConfigListScreen.__init__(self, self.list, session = self.session)
        self["title"] = Label()
        self["key_red"] = Button(_("Cancel"))
        self["key_green"] = Button("Save")
        self["key_yellow"] = Button("")
        self["key_blue"] = Button("")
        self["setupActions"] = ActionMap(["SetupActions", "ColorActions"],
                                         {
                                             "red": self.cancel,
                                             "green": self.save,
                                             "save": self.save,
                                             "cancel": self.cancel,
                                             "ok": self.ok,
                                             }, -2)
        self["title"].setText(self.main.sources.plugins[self.source].title)

    def getCurrentEntry(self):
        return self["config"].getCurrent()[0]

    def getCurrentValue(self):
        return str(self["config"].getCurrent()[1].getText())

    def ok(self):
        self.save()
        #if self["config"].getCurrent()[1] == config.plugins.getpicons.folder:
            #folder  = config.plugins.getpicons.folder.value
            #self.session.openWithCallback(self.change_dir, LocationBox,"Select Folder")
        #else:


    #def change_dir(self, folder, select=None):
        #if folder:
            ##print "change_dir to %s"%folder
            #config.plugins.getpicons.folder.value = folder

    def save(self):
        print "saving"
        #self.saveAll()
        for k in self.options.keys():
            self.options[k]=self.cfg[k].value
            print "%s=%s"%(k,self.cfg[k].value)
        self.main.sources.options_write(self.source,self.options)
        self.close(True,self.session)

    def cancel(self):
        print "cancel"
        self.close(False,self.session)

#####################################################################################################################
class StreamInfo(Screen):

    def __init__(self, session, nfo):
        if not nfo:
            return
        Screen.__init__(self, session)
        self.skinName = ["PSStreamInfo"]
        self.session = session
        self["key_red"] = Button(_("Exit"))
        self["actions"] = ActionMap(["OkCancelActions", "ColorActions","ButtonSetupActions"], {
            "ok": self.cancel,
            "red": self.cancel,
            "cancel": self.cancel,
            "pageup": self.page_up,
            "channelup":self.page_up,
            "pagedown": self.page_down,
            "channeldown":self.page_down,
        })
        self["pic"] = Pixmap()
        self["info"] = ScrollLabel()
        self["title"] = Label()
        self.nfo = nfo
        self.onLayoutFinish.append(self.layout_finished)

    def cancel(self):
        #print "cancel"
        self.close(False,self.session)

    def layout_finished(self):
        nfo = self.nfo
        print "StreamInfo nfo", nfo
        if not "title" in nfo:
            nfo_type, nfo = next(nfo.iteritems())
        title = util.nfo2title(nfo)
        desc = util.nfo2desc(nfo)
        self["title"].setText(title)
        self["info"].setText(desc)
        image_url = nfo["thumb"]
        if image_url and image_url.startswith("http"):
            fname = image_url.replace(":", "-").replace("/", "_")
            image_path = os.path.join(config.plugins.playstream.tmp_dir.value, fname)
            if not os.path.exists(image_path):
                downloadPage(image_url, image_path, CustomContextFactory(image_url.split("/")[2])).addCallback(boundFunction(self.download_finished, image_path,image_url)).addErrback(boundFunction(self.download_failed, image_path,image_url))
            else:
                self.download_finished(image_path, image_url)
        elif image_url:
            image_path = os.path.join(cur_directory, image_url)
            self.download_finished(image_path,"")

    def download_finished(self, image_path,image_url):
        sc = AVSwitch().getFramebufferScale()
        self.picloads = ePicLoad()
        try:
            self.picloads.PictureData.get().append(boundFunction(self.finish_decode, image_path))
        except:
            self.picloads.PictureData.connect(boundFunction(self.finish_decode, image_path))
        # 0=Width 1=Height 2=Aspect 3=use_cache 4=resize_type 5=Background(#AARRGGBB)
        self.picloads.setPara((self["pic"].instance.size().width(), self["pic"].instance.size().height(),
                               sc[0], sc[1], True, 0, "#00000000"))
        print image_path,image_url
        self.picloads.startDecode(image_path.encode("utf8"))

    def download_failed(self, image_path,image_url):
        print "[PlayStream] Image downloaded failed ",image_url

    def finish_decode(self, image_path,picInfo = None):
        ptr = self.picloads.getData()
        self["pic"].instance.setPixmap(ptr)

    def page_down(self):
        self["info"].pageDown()

    def page_up(self):
        self["info"].pageUp()

