Page 1 of 1

Shoutcast Radio Player Example v1.0

Posted: Tue Feb 06, 2007 3:10 am
by Joakim Christiansen
Just made this while bored, I actually wanted to use it in a program but I couldn't since it's against Shoutcast's copyright laws.
And btw, it can't play the AAC+ streams.

Of course I can make it much nicer and also make it use FMOD to stream and such, but what is the point when it's a "illegal" program? :P

Code: Select all

; ------------------------------------------------
; Title:    Shoutcast Radio Player
; Version:  1.0
; PB Ver:   4.02
;
; Author:   Joakim L. Christiansen
; Homepage: http://www.myhome.no/jlc_software
;
; About:
; Little example on how to get shoutcast streams,
; but beware; it's against shoutcasts copyright laws.
; ------------------------------------------------

;- Enumeration
Enumeration ;Windows
  #Main
EndEnumeration
Enumeration ;Gadgets
  #Main_Genre
  #Main_Channels
  #Main_Find
  #Main_Player
  #Main_Pages
EndEnumeration
;_
;- Data
DataSection
  IID_IHTMLDocument2: ;{332C4425-26CB-11D0-B483-00C04FD90119}
    Data.l $332C4425
    Data.w $26CB, $11D0
    Data.b $B4, $83, $00, $C0, $4F, $D9, $01, $19
EndDataSection
;_
;- Structures
Structure Channel
  Name.s
  URL.s
  WebPage.s
  Listeners.s
  BitRate.l
  Type.s
  NowPlaying.s
EndStructure
;_
;- Variables
Global NewList Channel.Channel()
Define WindowEvent.l, SelectedChannel.l, i.l
;_
;- Procedures
Procedure.s DownloadToMemory(Url.s)
  Protected  hURL.l, Bytes.l, File.s, hInet.l
  Protected BufferLength.l = 2048, Buffer.s = Space(BufferLength)
  
  hInet = InternetOpen_("PB",1,0,0,0)
  hURL  = InternetOpenUrl_(hInet,Url,0,0,$80000000,0)
  
  If hURL
    While InternetReadFile_(hURL,@Buffer,BufferLength,@Bytes) And Bytes > 0
      File + PeekS(@Buffer,Bytes)
    Wend
  Else
    Debug "No such URL"
  EndIf
  
  InternetCloseHandle_(hURL)
  InternetCloseHandle_(hInet)
  
  ProcedureReturn File
EndProcedure
Procedure GetStreams(Genre.s,Page.l) ;page.l
  
  Protected Line.l
  Protected File.s, FileLength.l, FilePosition.l, FileString.s = ""
  File = DownloadToMemory("http://www.shoutcast.com/directory/index.phtml?sgenre="+Genre+"&startat="+Str(Page*20))
  If File
    FileLength = MemoryStringLength(@File) ;MemorySize(@File) StringByteLength(File)
    While FilePosition < FileLength
      Byte = PeekB(@File+FilePosition): FilePosition + 1
      If Byte = #LF
        ;- Scan
        If Line > 0
          Line + 1
        EndIf
        If Mid(FileString,52,6) = "a href" ;Get stream URL
          AddElement(Channel())
          Channel()\URL = "http://www.shoutcast.com"+StringField(FileString,6,#DQUOTE$)
          Line = 1
        EndIf
        Select Line
          Case 3 ;Get channel name and webpage
            Channel()\WebPage = StringField(FileString,20,#DQUOTE$)
            If StringField(FileString,8,">") = "CLUSTER </font"
              Channel()\Name = StringField(FileString,10,">")
            Else
              Channel()\Name = StringField(FileString,8,">")
            EndIf
            Channel()\Name = RemoveString(Channel()\Name,"</a")
          Case 5 ;Get now playing status ;if it's not found line++
            If CountString(FileString,"nbsp;") = 2
              Channel()\NowPlaying = StringField(FileString,8,">")
            ElseIf CountString(FileString,"nbsp;")
              Channel()\NowPlaying = StringField(FileString,6,">")
              If Channel()\NowPlaying = ""
                Line + 1
                Beep_(1000,2)
              EndIf
            Else
              Channel()\NowPlaying = StringField(FileString,4,">")
            EndIf
            Channel()\NowPlaying = LTrim(RemoveString(Channel()\NowPlaying,"</font"))
          Case 7 ;Get listners
            Channel()\Listeners = StringField(FileString,3,">")
            Channel()\Listeners = RemoveString(Channel()\Listeners,"</font")
          Case 9 ;Get bitrate
            Channel()\BitRate = Val(StringField(FileString,3,">"))
          Case 14 ;Get type
            Channel()\Type = StringField(FileString,3,">")
            Channel()\Type = LTrim(RemoveString(Channel()\Type,"</font"))
            With Channel()
            AddGadgetItem(#Main_Channels,-1,\Name+#LF$+\NowPlaying+#LF$+\Listeners+#LF$+Str(\BitRate)+#LF$+\Type)
            EndWith
        EndSelect
        ;_
        FileString = ""
      ElseIf Not Byte = #CR
        FileString + Chr(Byte)
      EndIf
    Wend
    FilePosition = 0
  EndIf
EndProcedure
Procedure.l WebGadget_Write(Gadget.l,Html.s)
  Protected Browser.IWebBrowser2 = GetWindowLong_(GadgetID(Gadget),#GWL_USERDATA)
  Protected Document.IHTMLDocument2
  Protected DocumentDispatch.IDispatch
  Protected Result.l, Busy.l, Unicode.s, bstr_string.l, *sfArray, *varParam.VARIANT
  
  If GetGadgetText(Gadget) = ""
    SetGadgetText(Gadget,"about:blank")
  EndIf
  
  Repeat
    While WindowEvent(): Wend
    Browser\get_Busy(@Busy)
    If Busy = #VARIANT_TRUE
      Delay(10)
    EndIf
  Until Busy = #VARIANT_FALSE
  
  If Browser
    If Browser\get_document(@DocumentDispatch) = #S_OK And DocumentDispatch
      If DocumentDispatch\QueryInterface(?IID_IHTMLDocument2,@Document) = #S_OK
        If Document
          Unicode = Space(Len(Html)*2+2)
          PokeS(@Unicode, Html, -1, #PB_Unicode)
          bstr_string = SysAllocString_(@Unicode)
          
          *sfArray = SafeArrayCreateVector_(#VT_VARIANT, 0, 1)
          If *sfArray
            If SafeArrayAccessData_(*sfArray, @*varParam) = #S_OK
              *varParam\vt = #VT_BSTR
              *varParam\bstrVal = bstr_string
              If SafeArrayUnaccessData_(*sfArray) = #S_OK
                Document\write(*sfArray)
                Result = #True ;Document written
              EndIf
            EndIf
            SafeArrayDestroy_(*sfArray)
          EndIf
          
          SysFreeString_(bstr_string)
        EndIf
        Document\close()
        Document\Release()
      EndIf
      DocumentDispatch\Release()
    EndIf
  EndIf
  
  ProcedureReturn Result
EndProcedure
Procedure PlayChannel(URL.s)
  Protected Html.s
  
  Html + "<object id='VIDEO' width='100%' height='100%'"
  Html + "style='position:absolute; left:0; top:0;'"
  Html + "classid='clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6'" ;normal
  Html + "type='application/x-oleobject'>"
  Html + "<param name='URL' value='"+URL+"'>"
  Html + "<param name='StretchToFit' value='true'>"
  Html + "<param name='UiMode' value='mini'>"
  Html + "<param name='EnableContextMenu' value='false'>"
  Html + "</object>"
  
  If Not WebGadget_Write(#Main_Player,Html)
    MessageRequester("Error!","Error changing webgadget content")
  EndIf
EndProcedure
Procedure.s GetStreamAddress(URL.s)
  ProcedureReturn StringField(StringField(DownloadToMemory(URL),3,Chr(10)),2,"=")
EndProcedure
;_
;- Open window
If OpenWindow(#Main,0,0,500,300,"Shoutcast Radio Player",#PB_Window_SystemMenu|#PB_Window_ScreenCentered|#PB_Window_SizeGadget) And CreateGadgetList(WindowID(0))
  WebGadget(#Main_Player,260,5,50,20,""): HideGadget(#Main_Player,#True)
  TextGadget(#PB_Any,260,8,80,20,"Pages to scan:")
  SpinGadget(#Main_Pages,340,5,30,20,1,4,#PB_Spin_Numeric)
   SetGadgetState(#Main_Pages,1): SetGadgetText(#Main_Pages,"1")
  ComboBoxGadget(#Main_Genre,5,5,200,160): ButtonGadget(#Main_Find,210,5,40,20,"Find")
   AddGadgetItem(#Main_Genre,-1,"TopTen")
   AddGadgetItem(#Main_Genre,-1,"Alternative")
   AddGadgetItem(#Main_Genre,-1,"Classical")
   AddGadgetItem(#Main_Genre,-1,"Comedy")
   AddGadgetItem(#Main_Genre,-1,"Country")
   AddGadgetItem(#Main_Genre,-1,"Dance")
   AddGadgetItem(#Main_Genre,-1,"Funk")
   AddGadgetItem(#Main_Genre,-1,"Jazz")
   AddGadgetItem(#Main_Genre,-1,"Metal")
   AddGadgetItem(#Main_Genre,-1,"Mixed")
   AddGadgetItem(#Main_Genre,-1,"Rock")
   AddGadgetItem(#Main_Genre,-1,"Talk")
   AddGadgetItem(#Main_Genre,-1,"Techno")
   AddGadgetItem(#Main_Genre,-1,"World")
   SetGadgetState(#Main_Genre,8)
  ListIconGadget(#Main_Channels,5,30,490,265,"Channel",150,#PB_ListIcon_FullRowSelect)
   AddGadgetColumn(#Main_Channels,1,"Now playing",140)
   AddGadgetColumn(#Main_Channels,2,"Listeners/Max",85)
   AddGadgetColumn(#Main_Channels,3,"BitRate",50)
   AddGadgetColumn(#Main_Channels,4,"Type",40)
Else
  MessageRequester("Error","Error opening window!",#MB_ICONERROR)
EndIf
;_

Repeat ;-Main loop
  WindowEvent = WaitWindowEvent()
  Select WindowEvent
    Case #PB_Event_CloseWindow
      Break
    Case #PB_Event_SizeWindow
      ResizeGadget(#Main_Channels,#PB_Ignore,#PB_Ignore,WindowWidth(#Main)-10,WindowHeight(#Main)-35)
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #Main_Find
          ClearList(Channel())
          ClearGadgetItemList(#Main_Channels)
          For i=0 To GetGadgetState(#Main_Pages)-1
            GetStreams(GetGadgetText(#Main_Genre),i)
          Next
        Case #Main_Channels 
          Select EventType()
            Case #PB_EventType_LeftDoubleClick
              If GetGadgetState(#Main_Channels) > -1
                SelectElement(Channel(),GetGadgetState(#Main_Channels))
                PlayChannel(GetStreamAddress(Channel()\URL))
                SetGadgetItemColor(#Main_Channels,SelectedChannel,#PB_Gadget_BackColor,-1)
                SelectedChannel = GetGadgetState(#Main_Channels)
                SetGadgetItemColor(#Main_Channels,SelectedChannel,#PB_Gadget_BackColor,#Green)
              EndIf
          EndSelect
      EndSelect
  EndSelect
ForEver

Re: Shoutcast Radio Player Example v1.0

Posted: Tue Feb 06, 2007 7:08 am
by Rescator
Joakim Christiansen wrote:Just made this while bored, I actually wanted to use it in a program but I couldn't since it's against Shoutcast's copyright laws.
And btw, it can't play the AAC+ streams.

Of course I can make it much nicer and also make it use FMOD to stream and such, but what is the point when it's a illegal program? :P
What do you mean by illegal? Interfacing with the Shoutcast directory "lists", streaming, music, codecs?

If you are talking about copyright laws and music royalties etc. Then that is the responsibility of the broadcaster not you.
For example. www.gridstream.org which I'm part of has been broadcasting since early 2002, and legally.

Now, when it comes to mp3 and aac licensing that is a different issue.
Using a mp3 codec for playback in non-commercial software should be no issue, same with aac.

Commercial software however might be a bigger issue, although your solution or using the mp3 codec (which your solution in a way does) available in the system gets around that as Microsoft already license the mp3 codec. When it comes to BASS and FMOD and so on those tend to already license those codecs.

Also, it is mostly the encoder part (creation of content) that the mp3 and aac licensors want money for.
Wikipedia should be a good starting point to find out more about the mp3 and aac licensing and whether it applies to you or not.

If you are planning to add shoutcast support to you internet TV program, and you use the mp3 codec (acm) installed (or mediaplayer/webplugin) on the system there should be no issues doing that licensewise as you are not distributing the codec itself, just using what is already available on the system. And for aac you could always point the users to where they can get a opensource aac codec (acm)

Nullsoft (Winamp makers) do not require any licensing to use the shoutcast protocol so that is not an issue either.
Personally I found BASS very handy for handling stream playback.
(ideally PureBasic would have had streaming/buffered playback so I could have used acm codecs etc but... maybe that is in PB 4.1 :P

Posted: Tue Feb 06, 2007 8:47 am
by Joakim Christiansen
I was just talking about what Nullsoft wrote in it's "terms of use / disclaimer / copyright complaints" thingy:

Code: Select all

By using this website, you agree that you will not store, reproduce, transmit, publicly display, publicly perform, distribute, publish, broadcast or otherwise make available the Directory or any portion of the Directory, whether electronically or in any other form, and whether for commercial purposes or any purpose other than your own personal use, unless approved in writing by Nullsoft.
And that sure scared me... :P
If you are planning to add shoutcast support to you internet TV program...
That was actually what I was thinking about (since many requested it), or just make a radio player program. But I'm having trouble finding a list of channels I can use with it.

But thank you for your whole "lesson" about this!

Posted: Tue Feb 06, 2007 9:01 am
by rsts
A really cool app.

Thanks

- off to see how much I can sell it for :D

The internet seems to bring the crooks out of the trashcans they live in.

Posted: Tue Feb 06, 2007 9:45 am
by GeoTrail
Nice app Joakim. Should add stop, pause, play, next and previous buttons to it ;)

Posted: Tue Feb 06, 2007 5:06 pm
by Joakim Christiansen
GeoTrail wrote:Nice app Joakim. Should add stop, pause, play, next and previous buttons to it ;)
Thanks, yeah guess I will do that then, and also make it minimize to the tray and such.

Posted: Tue Feb 06, 2007 5:53 pm
by Character
Cool. Thanks

Posted: Tue Feb 06, 2007 6:07 pm
by ricardo
Joakim Christiansen wrote:I was just talking about what Nullsoft wrote in it's "terms of use / disclaimer / copyright complaints" thingy:

Code: Select all

By using this website, you agree that you will not store, reproduce, transmit, publicly display, publicly perform, distribute, publish, broadcast or otherwise make available the Directory or any portion of the Directory, whether electronically or in any other form, and whether for commercial purposes or any purpose other than your own personal use, unless approved in writing by Nullsoft.
And that sure scared me... :P
This restriction is NOT to play shoutcast stations but to reproduce the list.

You can let that your users add by their own the stations... thats not against shoutcast licence.
i think that you can even give them the tool to add the stations as far as they do it one by one on their own PC.

Posted: Tue Feb 06, 2007 7:04 pm
by Rescator
Joakim Christiansen wrote:I was just talking about what Nullsoft wrote in it's "terms of use / disclaimer / copyright complaints" thingy:

Code: Select all

By using this website, you agree that you will not store, reproduce, transmit, publicly display, publicly perform, distribute, publish, broadcast or otherwise make available the Directory or any portion of the Directory, whether electronically or in any other form, and whether for commercial purposes or any purpose other than your own personal use, unless approved in writing by Nullsoft.
And that sure scared me... :P

But thank you for your whole "lesson" about this!
First of all it was not a lesson. (although I love sticking it to people :P
Just the facts as far as I know them.

As for the directory, email them and ask for permission.
Or ask on the Winamp shoutcast forums (unless it's already been answered there that is)

I'd also be surprised if there was not already some kind of "open directory" list out there with a xml or rss feed of sorts for syndication of channels.

Posted: Wed Feb 07, 2007 12:55 pm
by oryaaaaa
I am making new radio player "NetRadio Orya 3" now.
Let's make mutually excellent software.

Cheer :)

Playlist

Posted: Fri Feb 09, 2007 2:43 pm
by laborde
Nice program!
The playlist is correct when the program is first executed but it is not updated periodically.