Enigma2 Streamer

Share your advanced PureBasic knowledge/code with the community.
User avatar
HeX0R
Addict
Addict
Posts: 980
Joined: Mon Sep 20, 2004 7:12 am
Location: Hell

Enigma2 Streamer

Post by HeX0R »

I played a little bit with the webif API of enigma2 boxes (in my case it is a gigabyte blue).
Of course you can also just stream directly from the web interface, I had just fun playing with it.

Maybe it is of any use for some of you.

Code: Select all

CompilerIf #PB_Compiler_Thread = 0
	CompilerError "Please enable Thread Save Option"
CompilerEndIf

EnableExplicit

InitNetwork()

Structure _EPGINFO_
	Title.s
	InfoSmall.s
	InfoExtended.s
	Started.i
	Duration.i
EndStructure

Structure _Channels_
	Name.s
	Stream.s
	EPG._EPGINFO_
EndStructure

Structure _Bouquets_
	Name.s
	InternalName.s
	List Chan._CHANNELS_()
EndStructure

Global NewList Bouquets._Bouquets_()
Global VideoPlayer.s, ThreadID.i

Procedure.s GetAppDataFolder()
	Protected Location.s = Space(#MAX_PATH)

	CompilerIf #PB_Compiler_OS = #PB_OS_Windows
	Protected *itemid.ITEMIDLIST

	If SHGetSpecialFolderLocation_ (0, #CSIDL_APPDATA, @*itemid) = #NOERROR
		If SHGetPathFromIDList_(*itemid, @Location)
			CoTaskMemFree_(*itemid)
			If Right(Location, 1) <> "\"
				Location + "\"
			EndIf
		EndIf
	EndIf
	CompilerElse
	;-Mac OS ?
	;I guess this is o.k., or where does MAC OS save the normal appdata?
	Location = GetHomeDirectory()
	CompilerEndIf

	ProcedureReturn Trim(Location)
EndProcedure

Procedure GetInfo(*CurrentNode)
	Protected *ChildNode, Name.s, CurrRef.s, Info.s, InfoExtended.s, Title.s, Started.i, Duration.i, CurrTime.i, AddHours
	
	If XMLNodeType(*CurrentNode) = #PB_XML_Normal
			
		If LCase(GetXMLNodeName(*CurrentNode)) = "e2event"
			Info         = ""
			InfoExtended = ""
			CurrRef      = ""
			*ChildNode   = ChildXMLNode(*CurrentNode)
			
			While *ChildNode <> 0
				Select LCase(GetXMLNodeName(*ChildNode))
					Case "e2eventservicereference"
						CurrRef = GetXMLNodeText(*ChildNode)
					Case "e2eventdescription"
						Info = GetXMLNodeText(*ChildNode)
					Case "e2eventtitle"
						Title = GetXMLNodeText(*ChildNode)
					Case "e2eventdescriptionextended"
						InfoExtended = GetXMLNodeText(*ChildNode)
					Case "e2eventstart"
						Started = Val(GetXMLNodeText(*ChildNode))
					Case "e2eventduration"
						Duration = Val(GetXMLNodeText(*ChildNode))
					Case "e2eventcurrenttime"
						CurrTime = Val(GetXMLNodeText(*ChildNode))
				EndSelect
				*ChildNode = NextXMLNode(*ChildNode)
			Wend 
			
			ForEach Bouquets()\Chan()
				If Bouquets()\Chan()\Stream = CurrRef
					AddHours = Hour(Date()) - Hour(CurrTime)
					Bouquets()\Chan()\EPG\Title        = Title
					Bouquets()\Chan()\EPG\InfoSmall    = Info
					Bouquets()\Chan()\EPG\InfoExtended = InfoExtended
					Bouquets()\Chan()\EPG\Started      = Started + AddHours * 3600
					Bouquets()\Chan()\EPG\Duration     = Duration
					Break
				EndIf
			Next
					
		EndIf
	EndIf
	
EndProcedure

Procedure ThreadGetInfo(Dummy.i)
	Protected URL$, *Buffer, XML.i, *MainNode, *NextNode
	
	ForEach Bouquets()
		URL$    = "http://" + GetGadgetText(DialogGadget(0, "ip_address")) + "/web/epgnow?bRef=" + Bouquets()\InternalName
		URL$    = URLEncoder(URL$)
		*Buffer = ReceiveHTTPMemory(URL$)
		If *Buffer
			XML = CatchXML(#PB_Any, *Buffer, MemorySize(*Buffer))
			If XMLStatus(XML) = #PB_XML_Success
				*MainNode = MainXMLNode(XML)
				*NextNode = ChildXMLNode(*MainNode)
				While *NextNode <> 0
					GetInfo(*NextNode)
					*NextNode = NextXMLNode(*NextNode)
				Wend
			EndIf
			FreeXML(XML)
		EndIf
		FreeMemory(*Buffer)
	Next
	
EndProcedure

Procedure.s GetVLC()
	Protected Result.s, PATH.s, hKey, lpcbData, *lpData, lpType
	
	PATH = "SOFTWARE\VideoLAN\VLC"
	
	If RegOpenKeyEx_(#HKEY_LOCAL_MACHINE, PATH, 0, #KEY_READ, @hKey) = #ERROR_SUCCESS
		If RegQueryValueEx_(hKey, "", 0, 0, 0, @lpcbData) = #ERROR_SUCCESS
			*lpData = AllocateMemory(lpcbData)
			If *lpData
				If RegQueryValueEx_(hKey, "", 0, @lpType, *lpData, @lpcbData) = #ERROR_SUCCESS
					Result = PeekS(*lpData)
				EndIf
				FreeMemory(*lpData)
			EndIf
		EndIf
		RegCloseKey_(hKey)
	EndIf
	
	ProcedureReturn Result
EndProcedure

Procedure GetBouquets(*CurrentNode)
	Protected *ChildNode
	
	If XMLNodeType(*CurrentNode) = #PB_XML_Normal
		
		If LCase(GetXMLNodeName(*CurrentNode)) = "e2servicereference"
			AddElement(Bouquets())
			Bouquets()\InternalName = GetXMLNodeText(*CurrentNode)
		ElseIf LCase(GetXMLNodeName(*CurrentNode)) = "e2servicename"
			Bouquets()\Name = GetXMLNodeText(*CurrentNode)
		EndIf   
		
		*ChildNode = ChildXMLNode(*CurrentNode)
		
		While *ChildNode <> 0
			GetBouquets(*ChildNode)
			*ChildNode = NextXMLNode(*ChildNode)
		Wend        
		
	EndIf
	
EndProcedure

Procedure GetChannels(*CurrentNode)
	Protected *ChildNode, a$
	
	If XMLNodeType(*CurrentNode) = #PB_XML_Normal
		
		If LCase(GetXMLNodeName(*CurrentNode)) = "e2servicereference"
			AddElement(Bouquets()\Chan())
			Bouquets()\Chan()\Stream = GetXMLNodeText(*CurrentNode)
		ElseIf LCase(GetXMLNodeName(*CurrentNode)) = "e2servicename"
			a$ = GetXMLNodeText(*CurrentNode)
			If a$ = "<n/a>"
				DeleteElement(Bouquets()\Chan())
			Else
				Bouquets()\Chan()\Name = a$
			EndIf
		EndIf   
		
		*ChildNode = ChildXMLNode(*CurrentNode)
		
		While *ChildNode <> 0
			GetChannels(*ChildNode)
			*ChildNode = NextXMLNode(*ChildNode)
		Wend        
		
	EndIf
	
EndProcedure


Procedure LoadBouquets()
	Protected URL$, *Buffer, i
	Protected *MainNode
	
	ClearList(Bouquets())
	URL$    = "http://" + GetGadgetText(DialogGadget(0, "ip_address")) + "/web/getservices"
	URL$    = URLEncoder(URL$)
	*Buffer = ReceiveHTTPMemory(URL$)
	If *Buffer
		If CatchXML(0, *Buffer, MemorySize(*Buffer))
			If XMLStatus(0) = #PB_XML_Success
				*MainNode = MainXMLNode(0)
				GetBouquets(*MainNode)
			EndIf
			FreeXML(0)
		EndIf
		FreeMemory(*Buffer)
	EndIf
	ForEach Bouquets()
		URL$    = "http://" + GetGadgetText(DialogGadget(0, "ip_address")) + "/web/getservices?sRef=" + Bouquets()\InternalName
		URL$    = URLEncoder(URL$)
		*Buffer = ReceiveHTTPMemory(URL$)
		If *Buffer
			If CatchXML(0, *Buffer, MemorySize(*Buffer))
				If XMLStatus(0) = #PB_XML_Success
					*MainNode = MainXMLNode(0)
					GetChannels(*MainNode)
				EndIf
				FreeXML(0)
			EndIf
			FreeMemory(*Buffer)
		EndIf
	Next
	
	ClearGadgetItems(DialogGadget(0, "tree_channels"))
	;now fill Tree
	i = 0
	ForEach Bouquets()
		AddGadgetItem(DialogGadget(0, "tree_channels"), -1, Bouquets()\Name, 0, 0)
		i + 1
		ForEach Bouquets()\Chan()
			AddGadgetItem(DialogGadget(0, "tree_channels"), -1, Bouquets()\Chan()\Name, 0, 1)
			SetGadgetItemData(DialogGadget(0, "tree_channels"), i, @Bouquets()\Chan())
			i + 1
		Next
	Next
	
	ThreadID = CreateThread(@ThreadGetInfo(), 0)
	
EndProcedure

Runtime Procedure GadgetEvent_Load()
	LoadBouquets()
EndProcedure

Runtime Procedure GadgetEvent_BrowseVideoPlayer()
	Protected File.s
	
	File = OpenFileRequester("Select VideoPlayer", VideoPlayer, "Executable (*.exe)|*.exe|All files (*.*)|*.*", 0)
	If File
		SetGadgetText(DialogGadget(0, "string_videoplayer"), File)
		VideoPlayer = File
	EndIf

EndProcedure


Runtime Procedure GadgetEvent_TreeChannels()
	Protected i, *C._Channels_
	
	i = GetGadgetState(DialogGadget(0, "tree_channels"))
	If i > -1
		*C = GetGadgetItemData(DialogGadget(0, "tree_channels"), i)
		If *C
			Select EventType()
				Case #PB_EventType_LeftDoubleClick
					RunProgram(VideoPlayer, "http://" + GetGadgetText(DialogGadget(0, "ip_address")) + ":8001/" + *C\Stream, "")
				Case #PB_EventType_LeftClick
					ForEach Bouquets()
						ForEach Bouquets()\Chan()
							If @Bouquets()\Chan() = *C
								SetGadgetItemText(DialogGadget(0, "webview_info"), #PB_Web_HtmlCode, "<html><title></title><body><b>Title: " + Bouquets()\Chan()\EPG\Title + "</b><br><br>Info:<br>" + 
								                                                   Bouquets()\Chan()\EPG\InfoSmall + "<br><br>Extended:<br>" + Bouquets()\Chan()\EPG\InfoExtended + 
								                                                   "<br><br>Started: " + FormatDate("%hh:%ii", Bouquets()\Chan()\EPG\Started) + 
								                                                   "<br>Ends: " + FormatDate("%hh:%ii", Bouquets()\Chan()\EPG\Started + Bouquets()\Chan()\EPG\Duration) + "<br></body></html>")
							EndIf
						Next
					Next
			EndSelect
		EndIf
	EndIf
	
EndProcedure

Procedure main()
	Protected IP, Path.s, DialogsXML
	
	OpenPreferences(GetAppDataFolder() + "hextools/enigmastream/app.prefs")
	VideoPlayer = ReadPreferenceString("VideoPlayer", GetVLC())
	IP          = ReadPreferenceInteger("BoxIP", MakeIPAddress(127, 0, 0, 1))
	ClosePreferences()
	
	DialogsXML = CatchXML(#PB_Any, ?MyDialog, ?MyDialogEnd - ?MyDialog)
	If DialogsXML And CreateDialog(0) And OpenXMLDialog(0, DialogsXML, "mainwindow")
		RefreshDialog(0)
		
		SetGadgetText(DialogGadget(0, "string_videoplayer"), VideoPlayer)
		SetGadgetState(DialogGadget(0, "ip_address"), IP)
	
		Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
	
		Path = GetAppDataFolder() + "hextools/"
		If FileSize(Path) <> -2
			CreateDirectory(Path)
		EndIf
		Path + "enigmastream/"
		If FileSize(Path) <> -2
			CreateDirectory(Path)
		EndIf
		If CreatePreferences(Path + "app.prefs")
			WritePreferenceString("VideoPlayer", GetGadgetText(DialogGadget(0, "string_videoplayer")))
			WritePreferenceInteger("BoxIP", GetGadgetState(DialogGadget(0, "ip_address")))
			ClosePreferences()
		EndIf
	
		If IsThread(ThreadID)
			WaitThread(ThreadID)
		EndIf
	EndIf
	
	
EndProcedure

main()

End

DataSection
	MyDialog:
	Data.s "	<window name='mainwindow' flags='#PB_Window_SystemMenu|#PB_Window_MaximizeGadget|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered|#PB_Window_SizeGadget' text='Enigma2 LAN Streamer' width='400' minwidth='auto' minheight='auto'>" +
	       "		<vbox>" +
	       "			<frame text='Enigma2 Box'>" +
	       "				<hbox>" +
	       "					<text text='IP:'/>" +
	       "					<ipaddress name='ip_address'/>" +
	       "					<button text='Load Channels' onevent='GadgetEvent_Load()'/>" +
	       "				</hbox>" +
	       "			</frame>" +
	       "			<frame text='Select Video Player'>" +
	       "				<hbox>" +
	       "					<string name='string_videoplayer' width='250'/>" +
	       "					<button text='...' onevent='GadgetEvent_BrowseVideoPlayer()'/>" +
	       "				</hbox>" +
	       "			</frame>" +
	       "			<frame text='Bouquets/Channels'>" +
	       "				<tree name='tree_channels' height='250' onevent='GadgetEvent_TreeChannels()'/>" +
	       "			</frame>" +
	       "			<frame text='Info'>" +
	       "				<web name='webview_info' height='150'/>" +
	       "			</frame>" +
	       "		</vbox>" +
	       "	</window>" +
	       "</dialogs>"
	MyDialogEnd:
EndDataSection