How to: Make a Screen Saver that Plays Movie Trailers? (Easter Egg Included in ...
I decided to build a screensaver that plays movie trailers. The purpose was to learn about how screensavers worked and build a random movie trailer screensaver. The code pulls the trailers from the trailer API at http://api.traileraddict.com. I chose trailer addict because the XML for retrieving movie trailers was simple. In addition, I have an Easter egg in my original code which I am leaving out of this article to help make it brief and easily manageable. However, the executable does include an Easter egg, so feel free to try it out.
Making/Coding Screen Saver Form
For this article, I have named the screensaver form:
frmScreenSaver. The following properties are important to set and need to be set for
WindowsState- Maximized (after you finishing debugging the screensaver)
False(can set to
In addition, the Shockwave Flash component needs to be added to
frmScreenSaver (can be added to the toolbox via COM component tab in Choose Toolbox Items Dialog) and resized to fit onto the whole form.
frmScreenSaver is shown in Dialog 1 below with the Shockwave Flash Object added.
Dialog 1 - frmScreenSaver with ShockWave Flash Object
In Figure 1, the screensaver form code below first loads the option information from an XML file (will show code for saving/loading XML file later below). Next, it proceeds to adding a timer interval of 500 ms to the timer on the form so that the first trailer will load fast. The
formsize variable below was used to make the trailer automatically size to
fullscreen after debugging of the application was finished. Then, the timer is started and the loaded options are checked for the timer interval. If no interval is selected, the default is 60 secs (60000 ms). Third, a random movie trailer is pulled from a collection of 6 from the category set in the options form and the trailer is supposed to start playing automatically (I was having trouble playing the trailer automatically with trailer addicts API). Finally, the key press events are added to allow an escape key to be pressed to escape the screensaver (oddly, mouse capture events do not work with the flash ActiveX control or I might have used them improperly).
Figure 1 - frmScreenSaver code
Public Class frmScreenSaver Private FirstTrailer As Boolean Private Sub frmScreenSaver_Load(sender As Object, e As EventArgs) Handles Me.Load myoptions.LoadOptions() 'have the first trailers timer be low so it will start playing quicker TrailerRotateTimer.Interval = 500 TrailerRotateTimer.Stop() Dim formsize As Size formsize.Height = Me.Size.Height formsize.Width = Me.Size.Width Video.Size = formsize Video.AllowFullScreen = True Video.Visible = True TrailerRotateTimer.Start() End Sub Private Sub TrailerRotateTimer_Tick(sender As Object, e As EventArgs) _ Handles TrailerRotateTimer.Tick If FirstTrailer = False Then Select Case myoptions.TrailerPlayTime Case Is = 60 TrailerRotateTimer.Interval = 60000 FirstTrailer = True Case Is = 90 TrailerRotateTimer.Interval = 90000 FirstTrailer = True Case Is = 120 TrailerRotateTimer.Interval = 120000 FirstTrailer = True Case Else TrailerRotateTimer.Interval = 60000 FirstTrailer = True End Select End If Dim randnum As New Random() Dim firstvideo As String = myoptions.TrailerUrlCollection.Item(randnum.Next(0, 5)) ' Video.Movie = firstvideo Video.Stop() Video.LoadMovie(0, firstvideo) If Video.IsPlaying = False Then ' Video.Playing = True Video.Play() Video.Playing = True Video.Loop = False End If End Sub Private Sub frmScreenSaver_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress If e.KeyChar <> "" Then Application.Exit() End If End Sub Private Sub Video_PreviewKeyDown(sender As Object, e As PreviewKeyDownEventArgs) _ Handles Video.PreviewKeyDown If e.KeyCode = Keys.Escape Then Application.Exit() End If End Sub End Class
frmOptions was easy to code and only had five controls: two
cboPlayTime, and a
BtnSave. Dialog 2 provides a preview of what
frmOptions looks like.
Dialog 2 - frmOptions
Figure 2 shows how the load code loads the options and selects the option already set previously in the XML file. In addition, it shows the code for the
BtnSave click event which calls
RetrieveVideos which retrieves 6 videos from the API service, retrieves the pause time in-between screensavers, and saves the information to an XML file.
Figure 2 - frmOptions code
Public Class frmOptions Private Sub frmOptions_Load(sender As Object, e As EventArgs) Handles MyBase.Load myoptions.LoadOptions() If myoptions.VideoGenreSelection <> "" Then cboGenre.SelectedIndex = cboGenre.Items.IndexOf(myoptions.VideoGenreSelection) Else cboGenre.SelectedIndex = 0 End If End Sub Private Sub BtnSave_Click(sender As Object, e As EventArgs) Handles BtnSave.Click myoptions.IsTransparent = False If cboGenre.SelectedIndex > -1 Then myoptions.TrailerUrlCollection = ProgramServices.RetrieveVideos_ (cboGenre.Items.Item(cboGenre.SelectedIndex)) myoptions.VideoGenreSelection = cboGenre.Items.Item(cboGenre.SelectedIndex) If IsNumeric(cboPlayTime.Text) Then myoptions.TrailerPlayTime = CInt(cboPlayTime.Text) End If myoptions.SaveOptions() Me.Close() Else MsgBox("need to have a genre selected!") End If End Sub End Class
Retrieving Videos from TrailerAddict
Now, we actually show how the videos are retrieved from Trailer Addicts movie trailer service. I created a class called
ProgramServices and a Shared Function called
RetrieveVideos to retrieve the trailers from trailer addict. This line:
Dim url As String = "http://api.traileraddict.com/?actor=" + genre.ToLower + "&count=6"
retrieves the XML that contains the 6 different trailer urls. To try out different options, go to http://www.traileraddict.com and play with it (look for the gears icon that has a tool-tip with API in it to see the url you can use to get your result). I used actor because it allows me to separate out the trailers by genre. The rest of the code in Figure 3 retrieves the trailer id of each trailer which I add to a variable called
templst and return to be saved in the XML options file. Note: This section of code with the address automatically returns the SWF player for each trailer: http://v.traileraddict.com/emd/
Figure 3 - ProgramServices class
Imports System.Net Imports System.Text Imports System.IO Public Class ProgramServices Public Shared Function RetrieveVideos(genre As String) As List(Of String) Dim templst As New List(Of String) 'retrieve top 4 videos and add them to the list Dim url As String = "http://api.traileraddict.com/?actor=" + _ genre.ToLower + "&count=6" Dim req As HttpWebRequest = WebRequest.Create(url) Dim resp As HttpWebResponse = req.GetResponse() Dim enc As Encoding = System.Text.Encoding.GetEncoding(1252) Dim loResponseStream As StreamReader = New StreamReader(resp.GetResponseStream(), enc) Dim Response As String = loResponseStream.ReadToEnd() Dim xmlfile As XDocument = XDocument.Parse(Response) Dim videos As IEnumerable(Of XElement) = From t In xmlfile.Descendants("trailers") Select t For Each video As XElement In videos For Each trailer As XElement In video.Elements("trailer") templst.Add("http://v.traileraddict.com/emd/"+_ trailer.Element("trailer_id").Value+"?id=" + _ trailer.Element("trailer_id").Value) Next Next loResponseStream.Close() resp.Close() Return templst End Function End Class
Saving/Opening from/to Options XML file
Saving to the options XML file is easy. I reference some code from this article for saving to the XML file but changed some code to make it applicable for my scenario: http://www.devasp.net/net/articles/display/566.html. Figure 4 shows the whole code for saving to the XML file. I would go into explaining the whole thing but looking at it, most of it is self explanatory. However, to help people better understand the code, there are some important things to mention:
My settings file is named settings.opt and will be created/loaded from wherever the screensaver is placed,
m_VideoTrailerUrl is the list of movie trailer urls that are retrieved from trailer addicts API (in
string format), and
m_GSelection is the genre selection (defaults to Sci-fi), and
m_TrailerPlayTime is the time each trailer has to play (defaults to 60 seconds).
Figure 4 - Options Class code
Option Strict On Imports System.Xml.Serialization Imports System.Xml Imports System.IO <serializable> Public Class Options Private m_VideoTrailerUrl As List(Of String) Private m_IsTransparent As Boolean = True Private m_GSelection As String = "Sci-fi" Private m_TrailerPlayTime As Integer = 60 ' Set the OptionsPath to the current location with a fixed file name. Private OptionsPath As String = Application.StartupPath & "\settings.opt" ' This property returns whether the screen saver should use transparency ' when drawing the shapes to the screen. Public Property IsTransparent() As Boolean Get Return m_IsTransparent End Get Set(ByVal Value As Boolean) m_IsTransparent = Value End Set End Property ' This property returns what genre video to retrieve from the trailer service. Public Property VideoGenreSelection() As String Get Return m_GSelection End Get Set(value As String) m_GSelection = value End Set End Property Public Property TrailerPlayTime As Integer Get Return m_TrailerPlayTime End Get Set(value As Integer) m_TrailerPlayTime = value End Set End Property ' This property returns what speed the screen saver should use ' when drawing to the screen. Public Property TrailerUrlCollection As List(Of String) Get Return m_VideoTrailerUrl End Get Set(ByVal Value As List(Of String)) m_VideoTrailerUrl = Value End Set End Property ' --- Class Methods --- ' This function returns 'true' if the options file exists, 'false' otherwise. Public Function IsOptionFileExisting() As Boolean Dim myIO As New System.IO.FileInfo(OptionsPath) Return myIO.Exists() End Function ' This function loads the user defined options. First, it checks to see ' if an options file exists. If it does, the options are loaded from it. ' If the file doesn't exist, one is created with the defaults. Public Sub LoadOptions() Dim myOptions As New Options ' An Options object to use ' Check to see if an Option file exists, if so, load it! Else ' create one. If myOptions.IsOptionFileExisting() Then ' Load the options ' Create an XmlSerializer to use for retrieving options values Dim mySerializer As New XmlSerializer(GetType(Options)) ' Create a StreamReader to point to the options file Dim myTextReader As New StreamReader(OptionsPath) ' Create an XmlTextReader to actually read the options. Dim myXmlReader As New Xml.XmlTextReader(myTextReader) ' First verify that the file can be deserialized into an Option ' object format. If mySerializer.CanDeserialize(myXmlReader) Then ' Deserialize the object myOptions = CType(mySerializer.Deserialize(myXmlReader), Options) Else ' Save a new Options file myOptions.SaveOptions() End If ' Close the IO objects we've used. myXmlReader.Close() myTextReader.Close() ' Set the properties for this Options object to those retrieved ' from the file (or else use the defaults from the temporary ' Options object, if the file could not be deserialized). Me.m_GSelection = myOptions.m_GSelection Me.m_IsTransparent = myOptions.IsTransparent Me.m_VideoTrailerUrl = myOptions.m_VideoTrailerUrl End If End Sub ' This function saves the user defined options to disk. Public Sub SaveOptions() ' Create a stream writer to overwrite any files currently there, so that ' the fresh options can be saved. Dim myWriter As New System.IO.StreamWriter(OptionsPath) ' Create an XML Serializer to serialize the object Dim myXmlSerializer As New XmlSerializer(Me.GetType()) ' Serialize the current Options object (Me) to disk. myXmlSerializer.Serialize(myWriter, Me) ' Close the writer. myWriter.Close() End Sub End Class