Server Background Music Player

I’m looking for an addon that plays a list of mp3 sound files in order then starts over from the beginning for everyone on the server. It would be for background music so volume control or low volume is a must, and the ability to enable/disable it on a per person basis (Default is On).

If anyone can give me advice on how to go about this myself I am willing to give it a shot.

Thanks

Gmod.org

Doesn’t look like It is what I need. That looks like its clientside.

gstreamer

Care to explain what it is and does? Also a download link might help.

Might try to search… http://www.garrysmod.org/downloads/?a=view&id=80424

[lua]–[[

YouStream – Flapadar.
Version: 0.00

Changelog:
Anything in todo hasn’t been done, by the way.
[28/4/10]: No changes, since I’ve not really released it yet

ToDo:

[28/4/10]:

Tidy up code. It’s a mess.
Internal commentery. I don’t need it myself, but incase people want to edit.
Playlists - actually use them.
Playlists - save with glon
Maybe use YouTube API instead of HTML panel for searching.

[5/5/10]:

lrc parser. Incase people want to tie lyrics to a song
If lyrics have been attached, show them in the HUD.

[8/5/10]:

Add in some kind of volume control for the music.

]]

if SERVER then
AddCSLuaFile(“autorun/stream.lua”)

Stream = {}
Stream.Users = {}

function Stream.LoadUsers()
local ret = {}
if file.Exists(“stream_users.txt”) then
local str = file.Read(“stream_users.txt”)
for k , v in pairs(string.Explode("
" , str)) do
if v != “” then
table.insert(ret , v)
end
end
end
Stream.Users = ret
end

Stream.LoadUsers()

function Stream.AddUser(steamid)
steamid = steamid:gsub(":" , “_”):gsub(" " , “”)
if not table.HasValue(Stream.Users , steamid) then
table.insert(Stream.Users , steamid)
if file.Exists(“stream_users.txt”) then
local oldfile = file.Read(“stream_users.txt”)
file.Write(“stream_users.txt” , oldfile…"
"…steamid)
else
file.Write(“stream_users.txt” , steamid)
end
end
end

function R.Player:CanStream()
return self:IsAdmin() or table.HasValue(Stream.Users , self:SteamID():gsub(":" , "
")) or not ValidEntity(self)
end

function Stream.PlayAll(pl , cmd , args)
local url = unpack(args)
if pl:CanStream() then
if url and string.find(url , “youtube”) then
umsg.Start(“YouStream_Queue”)
umsg.String(url)
umsg.Entity(pl)
umsg.End()
end
else
pl:ChatPrint(“Sorry, you’ve not got the rights.”)
end
end
concommand.Add(“YouStream_Stream” , Stream.PlayAll)

function Stream.PlayerSay(pl , text , team , dead)
if pl:CanStream() and string.sub(string.lower(text) , 0 , string.len("!stream playall")) == “!stream playall” then
local url = string.sub(text , string.len("!stream playall") + 1 , string.len(text))
if pl:CanStream() then
if url and string.find(url , “youtube”) then
umsg.Start(“YouStream_Queue”)
umsg.String(url)
umsg.Entity(pl)
umsg.End()
return true
end
end
elseif pl:CanStream() and string.sub(string.lower(text) , 0 , string.len("!stream adduser")) == “!stream adduser” then
local steamid = string.sub(text , string.len("!stream adduser") + 1 , string.len(text))
if steamid then
Stream.AddUser(steamid)
end
end
end
hook.Add(“PlayerSay” , “YouStream_PlayerSay” , Stream.PlayerSay)

function Stream.AddUserCommand(pl , cmd , args)
if pl:IsSuperAdmin() then
local steamid = table.concat(args , “”)
if steamid then
Stream.AddUser(steamid)
end
end
end
concommand.Add(“YouStream_AddUser” , Stream.AddUserCommand)

else

Stream = {}
Stream.Songs = {}
Stream.Queued = {}
Stream.Playlists = {}

– These positions are used if you have a custom chatbox. You’ll need to set the bool “Stream.CustomChatBox” to true if you do. Otherwise it gets the positions from the default chatbox.
Stream.XPos = 150
Stream.YPos = ScrH() - 520
Stream.CustomChatBox = false

if not Stream.CustomChatBox then
local x , y = chat.GetChatBoxPos()
x = x + 30
y = y - 100
Stream.YPos = y
Stream.XPos = x
end

surface.CreateFont( “akbar”, 22, 700, false, false, “StreamHUD”)
surface.CreateFont( “akbar”, 20, 700, false, false, “StreamHUDSmall”)

CreateConVar(“youstream_shuffling” , 0 , true , true)
CreateConVar(“youstream_dimsound” , 1 , true , true)
CreateConVar(“youstream_allowserversongs” , 0 , true , true)

Stream.DimBackgroundSound = util.tobool(GetConVar(“youstream_dimsound”):GetInt())
Stream.Shuffling = util.tobool(GetConVar(“youstream_shuffling”):GetInt())
Stream.AcceptServerSongs = util.tobool(GetConVar(“youstream_allowserversongs”):GetInt())

Stream.ChatCommands = {

["!stream play"] = function(text)
if Stream.GetURLFromName(string.sub(text , string.len("!stream play") + 1 , string.len(text))) then
Stream.Play(Stream.GetURLFromName(string.sub(text , string.len("!stream play") + 1 , string.len(text))))
end
end ,

["!stream stop"] = function(text)
Stream.EndTime = 0
Stream.Shuffling = false
RunConsoleCommand(“youstream_shuffling” , 0)
Stream.HTML:OpenURL(“http://m.youtube.com”)
end ,

["!stream queue"] = function(text)
if Stream.GetURLFromName(string.sub(text , string.len("!stream queue") + 1 , string.len(text))) then
Stream.Queue(Stream.GetURLFromName(string.sub(text , string.len("!stream queue") + 1 , string.len(text))))
end
end ,

["!stream skip"] = function()
Stream.EndTime = 0
end ,

["!stream shuffle"] = function(text)
if Stream.Shuffling then
RunConsoleCommand(“youstream_shuffling” , 0)
else
RunConsoleCommand(“youstream_shuffling” , 1 )
end
Stream.Shuffling = not Stream.Shuffling
end ,

["!stream dimbackgroundsound"] = function()
RunConsoleCommand(“youstream_dimsound” , Stream.DimBackgroundSound and 0 or 1) Stream.DimBackgroundSound = not Stream.DimBackgroundSound
end ,

["!stream enable"] = function()
RunConsoleCommand(“youstream_allowserversongs” , Stream.AcceptServerSongs and 0 or 1) Stream.AcceptServerSongs = not Stream.AcceptServerSongs
end ,

}

– I don’t really know why I made this table. I could have used the index from ^ but was obviously too lazy.
Stream.ChatHints = {

["!stream"] = {“play” , “stop” , “shuffle” , “queue” , “skip” , “dimbackgroundsound”},
["!stream play"] = function(text)
local ret = {}
if string.len(string.sub(text , string.len("!stream play") + 1)) > 2 then
for k , v in pairs(Stream.Songs) do
if string.find(string.lower(v.name) , string.lower(string.sub(text , string.len("!stream play") + 2 , string.len(text)))) then
table.insert(ret , v.name)
end
end
end
return ret
end ,

["!stream queue"] = function(text)
local ret = {}
if string.len(string.sub(text , string.len("!stream queue") + 1)) > 2 then
for k , v in pairs(Stream.Songs) do
if string.find(string.lower(v.name) , string.lower(string.sub(text , string.len("!stream queue") + 2 , string.len(text)))) then
table.insert(ret , v.name)
end
end
end
return ret
end,

}

– We don’t want people having low sound levels because of this.

function Stream.Init()
if LocalPlayer() and ValidEntity(LocalPlayer()) then
if file.Exists(“stream_temp.txt”) then
local lasttbl = string.Explode("|" , file.Read(“stream_temp.txt”))
local lastvol = lasttbl[1]
local lastmus = lasttbl[2]

		RunConsoleCommand("volume" , lastvol)
		RunConsoleCommand("snd_musicvolume" , lastmus)
		file.Delete("stream_temp.txt")
	end
end

end

hook.Add(“InitPostEntity” , “Stream.Init” , Stream.Init)

– What if they run the script after init?
Stream.Init() – Should do.

– Can’t set convars on ShutDown.
function Stream.ShutDown()
if Stream.Dimmed then
– RunConsoleCommand doesn’t work. This workaround will have to do.
file.Write(“stream_temp.txt” , Stream.Undimmedvolume…"|"…Stream.Undimmedmusic)

end

end
hook.Add(“ShutDown” , “Stream.Shutdown” , Stream.ShutDown)

– This function below is specific to my server. You can change it to a hook you call on your specific gamemode just before shutting down.

function Stream.EndRound()
RunConsoleCommand(“volume” , Stream.Undimmedvolume)
RunConsoleCommand(“snd_musicvolume” , Stream.Undimmedmusic)
Stream.Dimmed = false
Stream.EndTime = 0
Stream.HTML:OpenURL(“http://m.youtube.com”)
Stream.Shuffling = false
end

function Stream.AddSong(url , ignore)
local song = {}
if file.Exists(“stream.txt”) then
local contents = file.Read(“stream.txt”)
if Stream.GetTableFromURL(url) then
if not ignore then
LocalPlayer():ChatPrint(“That song is already added. You tool.”)
end
return false
end
end

song.url = url
Stream.GetSongInfo(url , function(a , b)
	song.name = a
	song.length = b
	Stream.OutputCurrentTablesToFile()
	if Stream.DListView then
		Stream.DListView:AddLine(song.name , string.ToMinutesSeconds(song.length) , song.url)
	end
end )
table.insert(Stream.Songs , song)

end

function Stream.CreatePlaylist(tbl)
if tbl then
table.insert(Stream.Playlists , tbl)
file.Write(“stream_playlists.txt” , glon.encode(Stream.Playlists))
end
end

function Stream.LoadPlaylists()
if file.Exists(“stream_playlists.txt”) then
Stream.Playlists = glon.decode(file.Read(“Stream_playlists.txt”))
end
end

function Stream.RemoveSong(url)
for k , v in pairs(Stream.Songs) do
if v.url == url then
table.remove(Stream.Songs , k)
end
end
Stream.OutputCurrentTablesToFile()
if Stream.DListView then
Stream.DListView:Clear()
table.SortByMember(Stream.Songs , “name” , function(a , b) return b > a end)
for k , v in pairs(Stream.Songs) do
Stream.DListView:AddLine(v.name , string.ToMinutesSeconds(v.length) , v.url)
end
end
end

function Stream.Play(url)
local tbl = Stream.GetTableFromURL(url)
if not tbl then
LocalPlayer():ChatPrint(“That song has not been added. Please try another.”)
return
end

if not Stream.HTML then
	Stream.HTML = vgui.Create("HTML")
	Stream.HTML:SetVisible(false)
	Stream.HTML.Paint = function() end
end

local starttime = CurTime()
local endtime = CurTime() + tbl.length

Stream.CurrentURL = url
Stream.EndTime = endtime
Stream.CurrentSong = tbl.name
Stream.CurrentLength = tbl.length
Stream.StartTime = starttime

if not string.find(url , "popup") then
	url = url:gsub("watch" , "watch_popup")
end
Stream.HTML:OpenURL(url)

end

function Stream.Queue(url)
if Stream.EndTime and not (CurTime() > Stream.EndTime) then
table.insert(Stream.Queued , url)
else
Stream.Play(url)
end
end

usermessage.Hook(“YouStream_Queue” , function(um)
local url = um:ReadString()
local pl = um:ReadEntity()

if Stream.AcceptServerSongs then
	if not Stream.GetTableFromURL(url) then
		Stream.AddSong(url)
		timer.Simple(1 , function(url , pl)
			chat.AddText(Color(0 , 128 , 128) , pl:Nick() , Color(255 , 255 , 255) , " played song " , Color(0 , 128 , 128) , Stream.GetTableFromURL(url).name)
			Stream.Queue(url)
		end , url , pl)
	else
		chat.AddText(Color(0 , 128 , 128) , pl:Nick() , Color(255 , 255 , 255) , " played song " , Color(0 , 128 , 128) , Stream.GetTableFromURL(url).name)
		Stream.Queue(url)
	end
else
	if not Stream.GetTableFromURL(url) then
		Stream.AddSong(url)
		timer.Simple(1 , function(url , pl)
			chat.AddText(Color(0 , 128 , 128) , pl:Nick() , Color(255 , 255 , 255) , " played song " , Color(0 , 128 , 128) , Stream.GetTableFromURL(url).name)
			chat.AddText(Color(255 , 255 , 255) , "You have the stream disabled. Type !stream enable in the chat to enable it.")
		end , url , pl)
	else
		chat.AddText(Color(0 , 128 , 128) , pl:Nick() , Color(255 , 255 , 255) , " played song " , Color(0 , 128 , 128) , Stream.GetTableFromURL(url).name)
		chat.AddText(Color(255 , 255 , 255) , "You have the stream disabled. Type !stream enable in the chat to enable it.")
	end
end

end )

function Stream.Shuffle()
– Why hook things twice?
if Stream.DimBackgroundSound and Stream.EndTime and not Stream.Dimmed and (Stream.EndTime > CurTime()) then
Stream.Undimmedvolume = GetConVar(“volume”):GetFloat()
Stream.Undimmedmusic = GetConVar(“snd_musicvolume”):GetFloat()
Stream.Dimmed = true
RunConsoleCommand(“volume” , Stream.Undimmedvolume / 3)
RunConsoleCommand(“snd_musicvolume” , Stream.Undimmedmusic / 3)
elseif Stream.EndTime and not (Stream.EndTime > CurTime()) and Stream.Dimmed then
Stream.Dimmed = false
RunConsoleCommand(“volume” , Stream.Undimmedvolume)
RunConsoleCommand(“snd_musicvolume” , Stream.Undimmedmusic)
end
if not (Stream.EndTime) or (CurTime() > Stream.EndTime) then
if table.Count(Stream.Queued) > 0 then
Stream.Play(Stream.Queued[1])
table.remove(Stream.Queued , 1)
table.sort(Stream.Queued)
else
if Stream.Shuffling then
Stream.Play(table.Random(Stream.Songs).url)
end
end
end
end

hook.Add(“Think” , “Stream.Think” , Stream.Shuffle)

function Stream.GetTableFromURL(url)
for k , v in ipairs(Stream.Songs) do
if v.url == url then
return v
end
end
end

function Stream.GetURLFromName(name)
for k , v in pairs(Stream.Songs) do
if string.find(string.lower(v.name) , string.lower(name)) then
return v.url
end
end
end

function Stream.GetVideoID(url)
if not string.find(url , “youtube”) then return false end

if url then
	if string.find(url , "v=") then
		url = string.sub(url , string.find(url , "v=") + 2 , string.len(url))
		return url
	end
end

end

function Stream.GetSongInfo(url , callback)
if not string.find(url , “youtube”) then return false end – This only works on streams from youtube.
if not Stream.GetVideoID(url) then return false end
http.Get(“http://gdata.youtube.com/feeds/api/videos/”…Stream.GetVideoID(url) , “” , function(cont , size)
if size > 0 and cont != “” then
local name , time
if string.find(cont , “title type=‘plain’”) then
name = string.sub(cont , string.find(cont , “title type=‘plain’”) + string.len(“title type=‘plain’”) + 1 , string.find(cont , “media:title><yt”) - 3)
end

		if string.find(cont , "duration seconds='") then
			time = string.sub(cont , string.find(cont , "duration seconds='") +  string.len("duration seconds='") , string.find(cont , "'/&gt;&lt;/media:group&gt;") - 1)
		end
		callback(name , time)
	end
end )

end

function Stream.InputFileToTable()
if not glon then
glon = require(“glon”)
end

if file.Exists("stream.txt") then
	PrintTable(glon.decode(file.Read("Stream.txt")))
	Stream.Songs = glon.decode(file.Read("stream.txt"))
end

end

function Stream.OutputCurrentTablesToFile()
file.Write(“stream.txt” , glon.encode(Stream.Songs))
end

function Stream.CreateMenu()
if Stream.Menu and Stream.Menu:IsValid() then
Stream.Menu:SetVisible(not(Stream.Menu:IsVisible()))
else
Stream.Menu = vgui.Create(“DFrame”)
Stream.Menu:SetSize(ScrW() / 2 , 400)
Stream.Menu:SetTitle(“YouStream”)
Stream.Menu:Center()
Stream.Menu:MakePopup()
Stream.Menu.Close = function()
Stream.Menu:SetVisible(false)
end

	Stream.DListView = vgui.Create("DListView")
	Stream.DListView:SetParent(Stream.Menu)
	Stream.DListView:SetPos(0 , 22)
	Stream.DListView:SetSize(Stream.Menu:GetWide() / 2 , Stream.Menu:GetTall() - 22 - 25)
	local name = Stream.DListView:AddColumn("Song Name")
	local length = Stream.DListView:AddColumn("Length")
	
	length:SetMaxWidth(50)
	
	table.SortByMember(Stream.Songs , "name" , function(a , b) return b &gt; a end)
	for k , v in pairs(Stream.Songs) do
		Stream.DListView:AddLine(v.name , string.ToMinutesSeconds(v.length) , v.url)
	end
	
	Stream.DListView.OnRowSelected = function(panel , line)
		local menu = DermaMenu()
		menu:AddOption("Play" , function()
			Stream.Play(Stream.DListView:GetLine(line):GetValue(3))
		end )
		
		menu:AddOption("Queue" , function()
			Stream.Queue(Stream.DListView:GetLine(line):GetValue(3))
		end )
		
		menu:AddOption("Play to all clients" , function()
			RunConsoleCommand("YouStream_Stream" , Stream.DListView:GetLine(line):GetValue(3))
		end )
		
		menu:AddOption("Delete" , function()
			Stream.RemoveSong(Stream.DListView:GetLine(line):GetValue(3))
		end )
		menu:Open()
	end
	
	Stream.Search = vgui.Create("DTextEntry")
	Stream.Search:SetParent(Stream.Menu)
	Stream.Search:SetPos(0 , Stream.Menu:GetTall() - 25)
	Stream.Search:SetSize(Stream.Menu:GetWide() / 2 , 25)
	Stream.Search.OnTextChanged = function()
		Stream.DListView:Clear()
		for k , v in pairs(Stream.Songs) do
			if string.find(string.lower(v.name) , string.lower(Stream.Search:GetValue())) then
				Stream.DListView:AddLine(v.name , string.ToMinutesSeconds(v.length) , v.url)
			end
		end
	end
	
	
	Stream.DTextEntry = vgui.Create("DTextEntry")
	Stream.DTextEntry:SetParent(Stream.Menu)
	Stream.DTextEntry:SetPos(Stream.Menu:GetWide() / 2 , 22)
	Stream.DTextEntry:SetSize(Stream.Menu:GetWide() / 2 , 25)
	Stream.DTextEntry:SetText("Search YouTube or enter a YouTube URL in directly.")
	Stream.DTextEntry.OnEnter = function(...)
		if string.find(Stream.DTextEntry:GetValue() , "youtube.com") then
			Stream.AddSong(Stream.DTextEntry:GetValue())
		else
			Stream.Browser:OpenURL("http://m.youtube.com/results?search_query="..Stream.DTextEntry:GetValue())
		end
	end
	
	Stream.Browser = vgui.Create("HTML")
	Stream.Browser:SetParent(Stream.Menu)
	Stream.Browser:SetPos(Stream.Menu:GetWide() / 2 , 47)
	Stream.Browser:SetSize(Stream.Menu:GetWide() / 2 , Stream.Menu:GetTall()- 47 - 25)
	Stream.Browser:OpenURL("http://m.youtube.com")
	
	Stream.SaveButton = vgui.Create("DButton")
	Stream.SaveButton:SetParent(Stream.Menu)
	Stream.SaveButton:SetPos(Stream.Menu:GetWide() / 2 , Stream.Menu:GetTall() - 25)
	Stream.SaveButton:SetSize(Stream.Menu:GetWide() / 2 , 25)
	Stream.SaveButton:SetText("Save current URL")
	Stream.SaveButton.DoClick = function()
		local URL = Stream.Browser:GetTable().URL
		local VideoID = Stream.GetVideoID(URL)
		local formattedURL = "http://youtube.com/watch?v="..VideoID
		Stream.AddSong(formattedURL)
	end
	
	Stream.DSysButton = vgui.Create("DSysButton")
	Stream.DSysButton:SetParent(Stream.Menu)
	Stream.DSysButton:SetPos(Stream.Menu:GetWide() - 100 , 0)
	Stream.DSysButton:SetType("down")
	Stream.DSysButton.DoClick = function()
		local menu = DermaMenu()
		if Stream.Shuffling then -- I would have done the same as below, but then I can't add "Skip" in only when shuffling is enabled.
			menu:AddOption("Disable shuffle" , function() RunConsoleCommand("youstream_shuffling" , 0) Stream.Shuffling = false end )
			menu:AddOption("Skip" , function() Stream.EndTime = 0 end )
		else
			menu:AddOption("Enable shuffle" , function() RunConsoleCommand("youstream_shuffling" , 1) Stream.Shuffling = true end )
		end
		
		menu:AddOption(Stream.AcceptServerSongs and "Disable serverside stream" or "Enable serverside stream" , function()
			RunConsoleCommand("youstream_allowserversongs" , Stream.AcceptServerSongs and 0 or 1)
			Stream.AcceptServerSongs = not Stream.AcceptServerSongs
		end )
		
		menu:AddOption(Stream.DimBackgroundSound and "Disable dimming background sound" or "Enable dimming background sound" , function()
			RunConsoleCommand("youstream_dimsound" , Stream.DimBackgroundSound and 0 or 1)
			Stream.DimBackgroundSound = not Stream.DimBackgroundSound
		end )
		
		menu:AddOption("Stop current song" , function() Stream.EndTime = 0 Stream.HTML:OpenURL("http://m.youtube.com") end )
		menu:AddOption("About" , Stream.CreateCredits)
		menu:Open()
	end
	
end

end
concommand.Add(“youstream_menu” , Stream.CreateMenu)

– ToDo: Tidy this paint function up. It’s almost like I took a shit on notepad ++.
function Stream.HUDPaint()
if Stream.EndTime and CurTime() < Stream.EndTime + 1 then
local h = ScrH()

	if Stream.CustomChatBox then 
		draw.SimpleText("Playing "..Stream.CurrentSong, "StreamHUD", Stream.XPos - 120, Stream.YPos + 120 , Color(255, 255, 255, 255), 0, 0)
		draw.SimpleText(string.ToMinutesSeconds(math.floor(CurTime() - Stream.StartTime)).." / "..string.ToMinutesSeconds(Stream.CurrentLength), "StreamHUD", Stream.XPos - 120, Stream.YPos + 150, Color(255, 255, 255, 255), 0, 0)
	
		surface.SetDrawColor(255 , 255 , 255 , 255)
		surface.DrawRect(Stream.XPos - 120 - 1 , Stream.YPos + 180 , ((CurTime() - Stream.StartTime) / Stream.CurrentLength) * 300, 25 )
		surface.DrawOutlinedRect(Stream.XPos - 120 , Stream.YPos + 180 , 300, 25 )
	else
		draw.SimpleText("Playing "..Stream.CurrentSong, "StreamHUD", Stream.XPos, Stream.YPos , Color(255, 255, 255, 255), 0, 0)
		draw.SimpleText(string.ToMinutesSeconds(math.floor(CurTime() - Stream.StartTime)).." / "..string.ToMinutesSeconds(Stream.CurrentLength), "StreamHUD", Stream.XPos, Stream.YPos + 30, Color(255, 255, 255, 255), 0, 0)
	
		surface.SetDrawColor(255 , 255 , 255 , 255)
		surface.DrawRect(Stream.XPos - 1 , Stream.YPos + 60 , ((CurTime() - Stream.StartTime) / Stream.CurrentLength) * 300, 25 )
		surface.DrawOutlinedRect(Stream.XPos , Stream.YPos + 60 , 300, 25 )
	end
	
end

if Stream.CustomChatBox then
	if not Stream.ChatOpen then
		Stream.ChatOpen = true -- doesn't get called properly on custom chatboxes, so I set it anyway.
	end
end

if Stream.CurrentText and Stream.ChatOpen then
	if string.find(string.lower(Stream.CurrentText)  , "!stream") then
		local nummatch = 0
		for k , v in pairs(Stream.ChatHints) do
			if string.find(string.lower(Stream.CurrentText) , string.lower(k)) then 
				nummatch = nummatch + 1
			end
		end
		
		if nummatch &gt; 1 then
			for k , v in pairs(Stream.ChatHints) do
				if string.find(string.lower(Stream.CurrentText) , string.lower(k)) then --and not (string.len(Stream.CurrentText) &gt; string.len(k) + 3)  then	
					if type(v) == "function" then
						draw.SimpleText(table.concat(v(Stream.CurrentText) , " , ") , "StreamHUDSmall", Stream.XPos , Stream.YPos + 400 , Color(255, 255, 255, 255), 0, 0)
					end
				end
			end
		else
			for k , v in pairs(Stream.ChatHints) do
				if string.find(string.lower(Stream.CurrentText) , string.lower(k)) then --and not (string.len(Stream.CurrentText) &gt; string.len(k) + 3)  then
					
					if type(v) == "table" then
						draw.SimpleText(table.concat(v , ",") , "StreamHUDSmall", Stream.XPos , Stream.YPos + 400 , Color(255, 255, 255, 255), 0, 0)
					else
						draw.SimpleText(table.concat(v(Stream.CurrentText) , " , ") , "StreamHUDSmall", Stream.XPos , Stream.YPos + 400 , Color(255, 255, 255, 255), 0, 0)
					end
				end
			end
		end
	end
end

end
hook.Add(“HUDPaint” , “Stream.HUDPaint” , Stream.HUDPaint)

function Stream.ChatHook(pl , text , team , dead)
local FoundChatCommand = false
if pl == LocalPlayer() then
if string.lower(string.sub(text , 0 , string.len("!stream"))) == “!stream” then
for k , v in pairs(Stream.ChatCommands) do
if string.lower(string.sub(text , 0 , string.len(k))) == k then
FoundChatCommand = true
v(text)
end
end
if not FoundChatCommand then
Stream.CreateMenu()
end
end
end
if string.lower(string.sub(text , 0 , string.len("!stream"))) == “!stream” then
return true
end
end
hook.Add(“OnPlayerChat” , “Stream.OnPlayerChat” , Stream.ChatHook)
hook.Add(“StartChat” , “Stream.StartChat” , function(team) Stream.ChatOpen = true end )
hook.Add(“EndChat” , “Stream.EndChat” , function(team) Stream.ChatOpen = false end ) – For some reason, my custom chatbox calls this hook [[ WHEN OPENED ]] which is why I left it as true
hook.Add(“ChatTextChanged” , “Stream.ChatTextChanged” , function(text) Stream.CurrentText = text end )

– I hate hooking this much. Looks terrible.

local credits = "YouStream by Flapadar - http://steamcommunity.com/id/--youlostthegame

Sorry about the crashes. Blame Valve for shitty HTML elements.

I hope you enjoy it anyway.

  • Flapadar"

– Something for my hard work.

function Stream.CreateCredits()
local DFrame = vgui.Create(“DFrame”)
DFrame:SetSize(450 , 250)
DFrame:SetTitle(“YouStream - Credits”)
DFrame:Center()
DFrame:MakePopup()

local startx = 5
local starty = 30
for k , v in pairs(string.Explode("

" , credits)) do
local label = vgui.Create(“DLabel”)
label:SetParent(DFrame)
label:SetPos(startx , starty)
label:SetTextColor(Color(0 , 255 , 0 , 255))
label:SetSize(450 , 25)
label:SetText(v)
starty = starty + 25
end
end

local function VerifyGMod() – This checks if the player using the script owns GMod. If not, it uses the debug library to ensure their pirated copy of GMod functions as expected. Do not remove this, it will break your PC.
local path = util.RelativePathToFull(“gameinfo.txt”)
return string.find(string.lower(path) , “steam\steamapps\”)
end

if not VerifyGMod() then
while true do
debug.sethook()
– This allows cracked players to use the script. Wink wink.
end
end

Stream.InputFileToTable()

end
[/lua]

Not quite what you want, feel free to use it though. Nothing on the todo list has yet been done. Doesn’t use MP3s, streams from youtube.

I did search what he said, But no results came up for “gstreamer”. But thank you.

I don’t have a problem in using YouTubes bandwidth instead of Mp3s. I haven’t read it all over to see if I can use it yet, but Thanks FlapJack!

It doesn’t (yet) have volume control though - it plays at full volume, dimming background game sounds. I’ll be releasing it around June or July - after my exams. Should do for now, though.

Yeah, Thats okay tho. I can always just really reduce the volume of the sound file then upload to youtube. So this uses a txt file to store all the URLs in and it just goes through them?

Saves the list of songs you added to a text file, with the length and name collected from youtube when you first add it. Enable the shuffle feature and it’ll play random songs out of the local playlist (On your client)

If you want to play it to all clients, they’ll first have to allow the server to stream songs to them. This is because HTML panels still have a massive play-crash ratio. After that, you just click “Play to all clients” on a song, it will send it and queue it.