# -*- coding: utf-8 -*- """ Plexus (c) 2015 enen92 The code present on this file had as initial input the X-Sopcast plugin code by Cristi-Atlanta """ import xbmc, xbmcgui, xbmcplugin, urllib2, os, sys, subprocess, xbmcvfs, socket, re, requests, shutil from thread import start_new_thread from plexusutils.pluginxbmc import * from plexusutils.utilities import handle_wait from history import add_to_history """ Sopcast Dependent variables are listed below""" LISTA_SOP = 'http://www.sopcast.com/chlist.xml' SPSC_BINARY = "sp-sc-auth" LOCAL_PORT = settings.getSetting('local_port') VIDEO_PORT = settings.getSetting('video_port') BUFER_SIZE = int(settings.getSetting('buffer_size')) if (settings.getSetting('auto_ip') == 'true'): LOCAL_IP = xbmc.getIPAddress() else: LOCAL_IP = settings.getSetting('localhost') VIDEO_STREAM = "http://" + LOCAL_IP + ":" + str(VIDEO_PORT) + "/" """ Addon functions related to sopcast Main functions: sopstreams(name,iconimage,sop) -> This function processes the id/sop url received as argument and does the magic for windows. If the OS is not windows, it sends the processed url to sopstreams_function sopstreams_builtin(name,iconimage,sop) -> This function processes the url received from sopstreams and does the magic for all *nix based OS's. Classes: SopWindowsPlayer -> Inheritance of XBMC Player class used only for Windows streamplayer -> Inheritance of XBMC Player class used for Linux/osx/Android Sopcast Utils: sop_sleep(time , spsc_pid) -> sopcast_binary pid sleep function. For all supported OS's except Windows. handle_wait_socket(time_to_wait,title,text,segunda='') -> Timer to check if sopcast local server has started (attempt to connect on sopcast local server port). This function is Windows only. break_sopcast() -> intentionally break the sopcast player in windows to avoid double sound created by the running sopcastp2p service osx_sopcast_downloader() -> Sopcast downloader thread to avoid curl bugs in OSX """ """ Sopcast Main functions""" def sopstreams(name, iconimage, sop): if not iconimage: iconimage = os.path.join(addonpath, 'resources', 'art', 'sopcast_logo.jpg') if "sop://" not in sop: sop = "sop://broker.sopcast.com:3912/" + sop else: pass print("Starting Player Sop URL: " + str(sop)) labelname = name if settings.getSetting('addon_history') == "true": try: add_to_history(labelname, str(sop), 2, iconimage) except: pass if not xbmc.getCondVisibility('system.platform.windows'): if xbmc.getCondVisibility('System.Platform.Android'): if settings.getSetting('external-sopcast') == "1": xbmc.executebuiltin( 'XBMC.StartAndroidActivity("org.sopcast.android","android.intent.action.VIEW","",' + sop + ')') else: sopstreams_builtin(name, iconimage, sop) else: sopstreams_builtin(name, iconimage, sop) else: cmd = ['sc', 'sdshow', 'sopcastp2p'] import subprocess proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) config = True for line in proc.stdout: if " 1060:" in line.rstrip(): config = False print("Sopcast configuration is not done!") if config == False: mensagemok(translate(30000), translate(30027), translate(30028), translate(30029)) else: import _winreg aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) # Dirty hack to break sopcast h264 codec so double sound can be avoided try: aKey = _winreg.OpenKey(aReg, r'SOFTWARE\SopCast\Player\InstallPath', 0, _winreg.KEY_READ) name, value, type = _winreg.EnumValue(aKey, 0) codec_file = os.path.join(os.path.join(value.replace("SopCast.exe", "")), 'codec', 'sop.ocx') _winreg.CloseKey(aKey) if xbmcvfs.exists(codec_file): xbmcvfs.rename(codec_file, os.path.join( os.path.join(value.replace("SopCast.exe", "")), 'codec', 'sop.ocx.old')) except: pass aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) aKey = _winreg.OpenKey(aReg, r'SYSTEM\CurrentControlSet\Services\sopcastp2p\Parameters', 3, _winreg.KEY_WRITE) _winreg.SetValueEx(aKey, "AppParameters", 0, _winreg.REG_SZ, sop) _winreg.CloseKey(aKey) cmd = ['sc', 'start', 'sopcastp2p'] import subprocess proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) servicecreator = False for line in proc.stdout: print("result line: " + line.rstrip()) res = handle_wait_socket(int(settings.getSetting('socket_time')), translate(30000), translate(30030)) if res == True: print("Server created - waiting x seconds for confirmation") try: sock.close() except: pass sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) handle_wait(int(settings.getSetting('stream_time')), translate(30000), translate(30031), segunda='') try: result = sock.connect(('127.0.0.1', 8902)) connected = True except: connected = False if connected == True: playlist = xbmc.PlayList(1) playlist.clear() listitem = xbmcgui.ListItem(labelname, iconImage=iconimage, thumbnailImage=iconimage) listitem.setLabel(labelname) listitem.setInfo("Video", {"Title": labelname}) listitem.setProperty('mimetype', 'video/x-msvideo') listitem.setProperty('IsPlayable', 'true') windows_sop_url = "http://127.0.0.1:8902/tv.asf" listitem.setPath(path=windows_sop_url) playlist.add(windows_sop_url, listitem) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem) player = SopWindowsPlayer() if int(sys.argv[1]) < 0: player.play(playlist) while player._playbackLock: xbmc.sleep(5000) else: xbmc.executebuiltin("Notification(%s,%s,%i,%s)" % ( translate(30000), translate(30032), 1, os.path.join(addonpath, "icon.png"))) else: xbmc.executebuiltin("Notification(%s,%s,%i,%s)" % ( translate(30000), translate(30032), 1, os.path.join(addonpath, "icon.png"))) print("Player reached the end") cmd = ['sc', 'stop', 'sopcastp2p'] import subprocess proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) servicecreator = False for line in proc.stdout: print("result line" + line.rstrip()) # dirty hack to break sopcast.exe player codec - renaming the file later import _winreg aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) try: aKey = _winreg.OpenKey(aReg, r'SOFTWARE\SopCast\Player\InstallPath', 0, _winreg.KEY_READ) name, value, type = _winreg.EnumValue(aKey, 0) codec_file = os.path.join(os.path.join(value.replace("SopCast.exe", "")), 'codec', 'sop.ocx.old') _winreg.CloseKey(aKey) if xbmcvfs.exists(codec_file): xbmcvfs.rename(codec_file, os.path.join( os.path.join(value.replace("SopCast.exe", "")), 'codec', 'sop.ocx')) except: pass def sopstreams_builtin(name, iconimage, sop): try: global spsc if xbmc.getCondVisibility('System.Platform.Linux') and not xbmc.getCondVisibility('System.Platform.Android'): if os.uname()[4] == "armv6l" or os.uname()[4] == "armv7l" or settings.getSetting( 'openelecx86_64') == "true": if settings.getSetting('jynxbox_arm7') == "true": cmd = [os.path.join(pastaperfil, 'sopcast', 'ld-linux.so.3'), '--library-path', os.path.join(pastaperfil, 'sopcast', 'libqemu'), os.path.join(pastaperfil, 'sopcast', 'qemu-i386'), os.path.join(pastaperfil, 'sopcast', 'lib/ld-linux.so.2'), "--library-path", os.path.join(pastaperfil, 'sopcast', "lib"), os.path.join(pastaperfil, 'sopcast', 'sp-sc-auth'), sop, str(LOCAL_PORT), str(VIDEO_PORT)] else: cmd = [os.path.join(pastaperfil, 'sopcast', 'qemu-i386'), os.path.join(pastaperfil, 'sopcast', 'lib/ld-linux.so.2'), "--library-path", os.path.join(pastaperfil, 'sopcast', "lib"), os.path.join(pastaperfil, 'sopcast', 'sp-sc-auth'), sop, str(LOCAL_PORT), str(VIDEO_PORT)] elif settings.getSetting('openeleci386') == "true": cmd = [os.path.join(pastaperfil, 'sopcast', 'lib/ld-linux.so.2'), "--library-path", os.path.join(pastaperfil, 'sopcast', "lib"), os.path.join(pastaperfil, 'sopcast', 'sp-sc-auth'), sop, str(LOCAL_PORT), str(VIDEO_PORT)] else: cmd = [os.path.join(pastaperfil, 'sopcast', 'ld-linux.so.2'), '--library-path', os.path.join(pastaperfil, 'sopcast', 'lib'), os.path.join(pastaperfil, 'sopcast', SPSC_BINARY), sop, str(LOCAL_PORT), str(VIDEO_PORT)] elif xbmc.getCondVisibility('System.Platform.OSX'): cmd = [os.path.join(pastaperfil, 'sopcast', 'sp-sc-auth'), str(sop), str(LOCAL_PORT), str(VIDEO_PORT)] elif xbmc.getCondVisibility('System.Platform.Android'): cmd = [str(settings.getSetting('android_sopclient')), str(sop), str(LOCAL_PORT), str(VIDEO_PORT)] print(cmd) # Check if another instance of the sopcast executable might still be running on the same port. Attempt to connect to server and video ports giving the user the choice before creating a new subprocess try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((LOCAL_IP, int(LOCAL_PORT))) sock.close() sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((LOCAL_IP, int(VIDEO_PORT))) sock.close() existing_instance = True except: existing_instance = False if existing_instance == True: option = xbmcgui.Dialog().yesno(translate(30000), translate(30033), translate(30034)) if not option: if xbmc.getCondVisibility('System.Platform.Android') == "true": xbmc_user = os.getlogin() procshut = subprocess.Popen(['ps', '|', 'grep', 'sopclient'], shell=False, stdout=subprocess.PIPE) for line in procshut.stdout: match = re.findall(r'\S+', line.rstrip()) if match: if 'sopclient' in match[-1] and len(match) > 2: if xbmc_user == match[0]: os.system("kill -9 " + match[1]) xbmc.sleep(200) else: os.system("su -c kill -9 " + match[1]) xbmc.sleep(200) elif xbmc.getCondVisibility('System.Platform.Linux'): os.system("kill -9 $(ps aux | grep '[s]p-sc-auth' | awk '{print $1}')") # openelec os.system("kill -9 $(ps aux | grep '[s]p-sc-auth' | awk '{print $2}')") elif xbmc.getCondVisibility('System.Platform.OSX'): os.system("kill -9 $(ps aux | grep '[s]p-sc-auth')") else: pass else: pass # opening the subprocess if settings.getSetting('debug_mode') == "false": spsc = subprocess.Popen(cmd, shell=False, bufsize=BUFER_SIZE, stdin=None, stdout=None, stderr=None) else: spsc = subprocess.Popen(cmd, shell=False, bufsize=BUFER_SIZE, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE) listitem = xbmcgui.ListItem(name, iconImage=iconimage, thumbnailImage=iconimage) listitem.setLabel(name) listitem.setInfo('video', {'Title': name}) url = "http://" + LOCAL_IP + ":" + str(VIDEO_PORT) + "/" xbmc.sleep(int(settings.getSetting('wait_time'))) res = False # counter=50 counter = int(int(settings.getSetting("loading_time")) * 2 + 10) ret = mensagemprogresso.create(translate(30000), "SopCast", translate(30035) % (str(20))) mensagemprogresso.update(0) warning = 0 while counter > 0 and spsc.pid: if mensagemprogresso.iscanceled(): mensagemprogress.close() break xbmc.sleep(400) counter -= 1 mensagemprogresso.update(int((1 - (counter / 50.0)) * 100), "SopCast", translate(30035) % str( int(int(settings.getSetting("loading_time")) * (1 - ((1 - (counter / 50.0))))))) try: urllib2.urlopen(url) counter = 0 res = sop_sleep(200, spsc.pid) break except: if warning == 0: print("Other instance of sopcast is still running") warning += 1 else: pass if res: mensagemprogresso.update(100) if not xbmc.getCondVisibility('System.Platform.OSX'): listitem.setPath(path=url) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem) player = streamplayer(spsc_pid=spsc.pid, listitem=listitem) if int(sys.argv[1]) < 0: player.play(url, listitem) while player._playbackLock: xbmc.sleep(500) else: xbmc.sleep(200) video_file = os.path.join(pastaperfil, 'sopcast.avi') start_new_thread(osx_sopcast_downloader, ()) handle_wait(int(settings.getSetting('stream_time_osx')), translate(30000), translate(30031), segunda='') listitem.setPath(path=video_file) xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem) player = streamplayer(spsc_pid=spsc.pid, listitem=listitem) player.play(video_file, listitem) while player._playbackLock: xbmc.sleep(500) else: xbmc.sleep(200) xbmc.executebuiltin("Notification(%s,%s,%i,%s)" % ( translate(30000), translate(30032), 1, os.path.join(addonpath, "icon.png"))) except: pass if settings.getSetting('debug_mode') == "true": try: stdout, stderr = spsc.communicate() print(stdout, stderr) except: pass try: os.kill(spsc.pid, 9) except: pass xbmc.sleep(100) try: os.system("killall -9 " + SPSC_BINARY) except: pass xbmc.sleep(100) try: spsc.kill() except: pass xbmc.sleep(100) try: spsc.wait() except: pass xbmc.sleep(100) try: os.kill(spsc.pid, 9) except: pass mensagemprogresso.close() print("Player ended at last") """ Sopcast Player classes """ class SopWindowsPlayer(xbmc.Player): def __init__(self): self._playbackLock = True if settings.getSetting('force_dvplayer') == 'true': xbmc.Player(xbmc.PLAYER_CORE_DVDPLAYER) print("Player created") def onPlayBackStarted(self): print("Player has started") def onPlayBackStopped(self): print("Player stoped") self._playbackLock = False import subprocess cmd = ['sc', 'stop', 'sopcastp2p'] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) for line in proc.stdout: print(line.rstrip()) def onPlayBackEnded(self): self.onPlayBackStopped() print("Player ended") class streamplayer(xbmc.Player): def __init__(self, *args, **kwargs): self.spsc_pid = kwargs.get('spsc_pid') self.listitem = kwargs.get('listitem') self._playbackLock = True def onPlayBackStarted(self): mensagemprogresso.close() if xbmc.Player().getPlayingFile() != "http://" + LOCAL_IP + ":" + str( VIDEO_PORT) + "/" and 'sopcast' not in xbmc.Player(xbmc.PLAYER_CORE_AUTO).getPlayingFile(): try: os.kill(self.spsc_pid, 9) except: pass else: pass def onPlayBackEnded(self): url = "http://" + LOCAL_IP + ":" + str(VIDEO_PORT) + "/" xbmc.sleep(300) if os.path.exists("/proc/" + str(self.spsc_pid)) and xbmc.getCondVisibility( "Window.IsActive(epg.xml)") and settings.getSetting('safe_stop') == "true": if not xbmc.Player().isPlaying(): player = streamplayer(spsc_pid=self.spsc_pid, listitem=self.listitem) player.play(url, self.listitem) try: xbmcvfs.delete(os.path.join(pastaperfil, 'sopcast.avi')) except: pass def onPlayBackStopped(self): self._playbackLock = False url = "http://" + LOCAL_IP + ":" + str(VIDEO_PORT) + "/" xbmc.sleep(300) if os.path.exists("/proc/" + str(self.spsc_pid)) and xbmc.getCondVisibility( "Window.IsActive(epg.xml)") and settings.getSetting('safe_stop') == "true": if not xbmc.Player().isPlaying(): player = streamplayer(spsc_pid=self.spsc_pid, listitem=self.listitem) player.play(url, self.listitem) else: try: os.kill(self.spsc_pid, 9) except: pass try: xbmcvfs.delete(os.path.join(pastaperfil, 'sopcast.avi')) except: pass """ Sopcast Utils""" def handle_wait_socket(time_to_wait, title, text, segunda=''): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) connected = False ret = mensagemprogresso.create(' ' + title) secs = 0 percent = 0 increment = int(100 / time_to_wait) cancelled = False while secs < time_to_wait: try: result = sock.connect(('127.0.0.1', 8902)) connected = True print("Connected to port 8902, server is working") break sock.close() except: print("Stil trying to connect") secs = secs + 1 percent = increment * secs secs_left = str((time_to_wait - secs)) if segunda == '': remaining_display = translate(30036) + " " + str(percent) + " %" else: remaining_display = segunda mensagemprogresso.update(percent, text, remaining_display) xbmc.sleep(1000) if (mensagemprogresso.iscanceled()): cancelled = True break if cancelled == True: return False elif connected == True: mensagemprogresso.close() return True else: mensagemprogresso.close() return False def sop_sleep(time, spsc_pid): counter = 0 increment = 200 path = "/proc/%s" % str(spsc_pid) try: while counter < time and spsc_pid > 0 and not xbmc.abortRequested: counter += increment xbmc.sleep(increment) except: return True if counter < time: return False else: return True # dirty hack to break sopcast.exe player codec to avoid double sound def break_sopcast(): if xbmc.getCondVisibility('system.platform.windows'): import _winreg aReg = _winreg.ConnectRegistry(None, _winreg.HKEY_LOCAL_MACHINE) try: aKey = _winreg.OpenKey(aReg, r'SOFTWARE\SopCast\Player\InstallPath', 0, _winreg.KEY_READ) name, value, type = _winreg.EnumValue(aKey, 0) codec_file = os.path.join(os.path.join(value.replace("SopCast.exe", "")), 'codec', 'sop.ocx.old') _winreg.CloseKey(aKey) if xbmcvfs.exists(codec_file): xbmcvfs.rename(codec_file, os.path.join(os.path.join(value.replace("SopCast.exe", "")), 'codec', 'sop.ocx')) except: pass def osx_sopcast_downloader(): print VIDEO_STREAM print "started osx downloader thread" response = requests.get(VIDEO_STREAM, stream=True) print response.headers video_file = os.path.join(pastaperfil, 'sopcast.avi') with open(video_file, 'wb') as out_file: shutil.copyfileobj(response.raw, out_file) print "ended thread"