WebTelek Media Center Add-In

WebTelekSome of you might have noticed that there hasn’t been much going on with TunerFree for a few months. I can now reveal why that was. For the past 2 months I have been working with Russian internet television provider, WebTelek, on a Media Center interface. WebTelek specialize in providing television and radio programs over the internet for the Russian market, both at home and abroad with the ex-pat market. Today they have Live TV from almost 70 channels, 20 days complete coverage of Catchup TV for over 50 of those channels, and thousands of movies, with growing content all of the time.

WebTelek approached me with the request to create a top of the range Media Center interface for their internet television service. They already had a web interface and a Media Portal interface, but wanted to expand in to Media Center. One of their biggest concerns was that it look great so that they could confidently have a superior interface to their competitors. That was a challenge that I was happy to take on, especially with the prospect of developing new library components that I could use in TunerFree.

I won’t be publishing the full code for this project for obvious reasons, but wanted to share some of the key things I learnt from this project.

TV Guide

The first thing that WebTelek wanted was a program guide for their live TV. I wanted to produce a program guide that was as close as possible to the native TV Guide from media center.

Guide

Some people may not realize that the Media Center SDK doesn’t give you access to standard widgets like a program guide. In fact the only visible things you get are boxes, text and you can drop your own images on the page too. ?That means that everything had to built from those basic components, which as you can imagine isn’t trivial. Ideally I wanted both an x and y scrolling region to scroll down the channels and left and right through the times. Unfortunatly this wasn’t possible for two reasons – first of all media center seems to fall over when you put a scroller inside a scroller, and secondly, I need both time in step with the program boxes fixed at the top of the page, and channel naes in step with the program boxes fixed at the left of the page, and you can’t do both of those with a scroller. That meant that I needed to construct the guide scrolling vertically, but horizontally just displaying 2 hours at a time, refreshed every time you navigate right in the right hand box, or left in the left hand box.

Spinner

Displaying all of the guide boxes takes about 0.1 seconds to calculate, but about 1.5 seconds to display. To avoid an unpleasant user experience, I also had to find a way to display a wait spinner on the screen. Again, media center doesn’t give you access to the native spinner, so I had to build my own;

WebTelek2

The way I managed to achieve this was by surrounding the page with a “Fill” region with a “Center” region inside it, with an image inside that. I needed to animate the icon within media center, so I then added a rotation animation to the image to make it rotate like the native windows spinner, and hide/show it when I am doing processing.

<Panel Layout="Fill" Name="Default">
<Children>
<Panel Layout="Center" Name="spinner">
<Children>
<Graphic Content="image://styles:Spinner" MaintainAspectRatio="true">
<Animations>
<Animation Animation="animation://styles:spin2"/>
</Animations>
</Graphic>
</Children>
</Panel>

<Animation Loop="-1" Name="spin2" CenterPointPercent="0.5,0.5,0.5">
 <Keyframes>
 <RotateKeyframe RelativeTo="Current" Time="0" Value="0deg;0,0,1" Interpolation="Linear"/>
 <RotateKeyframe RelativeTo="Current" Time="0.33" Value="90deg;0,0,1" Interpolation="Linear"/>
 <RotateKeyframe RelativeTo="Current" Time=".66" Value="180deg;0,0,1" Interpolation="Linear"/>
 <RotateKeyframe RelativeTo="Current" Time="1" Value="270deg;0,0,1" Interpolation="Linear"/>
 <RotateKeyframe RelativeTo="Final" Time="1.33" Value="360deg;0,0,1" Interpolation="Linear"/>
 </Keyframes>
 </Animation>

The key to hiding and showing it is to do the work in a background thread so that the main thread is able to show the image and the animation, e.g.;

public GuideUI()
 {
   ShowSpinner = true;
   Microsoft.MediaCenter.UI.Application.DeferredInvokeOnWorkerThread(init, endInit, "");
 }

 public void init(object o1)
 {
   _theGuide.init();
 }

 public void endInit(object o1)
 {
   ShowSpinner = false;
 }

Archive TV

WebTelek4

The next thing in the system is a catchup screen. This contains a grid of channels, a horizontal scroller for dates, and a vertical scroller for the channels shown. I experimented with various different animations and styles for highlighting the current channel (one of which you will see in TunerFree V3), but in the end settled on a basic Scale animation. One of the important lessons in this though is when you hover over the item, use a Scale command with a scale animation, rather than a PlayAnimation command, because while Scale works on extenders, PlayAnimation does not, e.g.;

<Condition? Source="[Input.KeyFocus]" SourceValue="true">
 <Actions>
 <PlaySound Sound="sound://styles:FocusSound"/>
 <Set Target="[Background.Scale]" Value="1.3,1.3,1.3"/>
 </Actions>
 </Condition>

...

<Panel Name="Background" Layout="HorizontalFlow" Padding="5,5,5,5">
 <Animations>
 <Animation Animation="animation://styles:ScalePicture"/>
 </Animations>
 <Children>

...

<Animation Name="ScalePicture" CenterPointPercent=".5,.5,0" Type="Scale">
 <Keyframes>
 <ScaleKeyframe Time="0"? RelativeTo="Current"? Interpolation="SCurve"/>
 <ScaleKeyframe Time="0.5" />
 </Keyframes>
 </Animation>

Movies

WebTelek6

For the movies part of the add-in, I had quite a lot of metadata to play with, such as a high resolution image, and information about the move. I wanted to find a way to show that off as well as possible, and eventually settled on a cover flow style of layout, with rotated images to the left and right of the larger central image, and with reflections of the images below each one. The key to this was finding a way of identifying if the scroller item was to the left or to the right of the current item selected so that it can be rotated in the right direction. Key to this is passing the current index item from your repeater in to each movie item;

<me:Thumbnail Data="[RepeatedItem!a:Movie]"? Name="Thumbnails" MovieUI="[MovieUI]" RptdItemIndex="[RepeatedItemIndex]"/>

and then within the thumbnail both storing off the current selected item, and comparing that to the passed in index, e.g.

<Properties>
 <Index Name="RptdItemIndex" Index="$Required"/>
 <cor:Int32 Name="SelectedDifference"/>
</Properties>
 <Locals>
 <MathTransformer Name="SubtractIndex" SubtractInt="[RptdItemIndex.Value]"/>
 </Locals>

 <Rules>
 <Condition? Source="[Input.KeyFocus]" SourceValue="true">
 <Actions>
 <PlaySound Sound="sound://styles:FocusSound"/>
 <Set Target="[Background.Scale]" Value="1.3,1.3,1.3"/>
 <Set Target="[MovieUI.SelectedMovie]" Value="[RptdItemIndex.Value]"/>
 </Actions>
 </Condition>

 <Binding Target="[SelectedDifference]" Source="[MovieUI.SelectedMovie]" Transformer="[SubtractIndex]" />

 <Condition Source="[SelectedDifference]" ConditionOp="LessThan" SourceValue="0"
  Target="[Background.Rotation]" Value="75deg;0,1,0" />
 <Condition Source="[SelectedDifference]" ConditionOp="GreaterThan" SourceValue="0"
  Target="[Background.Rotation]" Value="-75deg;0,1,0" />
 <Condition Source="[SelectedDifference]" ConditionOp="Equals" SourceValue="0"
  Target="[Background.Rotation]" Value="0deg;0,1,0" />

and then as you scroll through the items, they neatly rotate in to the right place.

Clicking on a movie takes you to a full page of details, with the ability to play different chapters of the movie;

WebTelek7

Search

WebTelek8

Normally for a search page, I would just use a standard triple-tap text entry region. Unfortunately, since Russian text entry was a key requirement here, that wasn’t sufficient. I therefore had to adapt the keyboard from the “Z” project in the media center SDK to meet my needs. This involved changing it to have Russian characters as an option, to change the actions to behave properly for a search box on a page, and to shrink the UI so that it could fit side by side with the search results. Not trivial, but I would strongly recommend looking at that project as a starting place for building your own keyboard if you have special requirements.

The other thing you will see on this page is the highlighting round the selected item in the search results list. This was done by swapping in and out a selected and unselected panel depending on the focus, e.g.

<Condition Source="[Input.KeyFocus]" SourceValue="true">
 <Actions>
<!-- when focused, play a sound and show the Selected region -->
 <PlaySound Sound="sound://styles:FocusSound"/>
 <Set Target="[Selected.Visible]" Value="true"/>
 <Set Target="[Unselected.Visible]" Value="false"/>
 </Actions>
 </Condition>

 <Condition? Source="[Input.KeyFocus]" SourceValue="false">
 <Actions>
<!-- when unfocused, show the unselected region -->
 <Set Target="[Selected.Visible]" Value="false"/>
 <Set Target="[Unselected.Visible]" Value="true"/>
 </Actions>
 </Condition>

...

<Panel Layout="VerticalFlow">
 <Children>
<!-- shown when selected -->
   <Graphic Name="Selected" Content="image://styles:TextBorder" >
     <Children>

       <Panel Layout="HorizontalFlow">
         <Children>
           <Text Name="ProgramName2" Color="White" Font="Sergio UI,20,Bold" WordWrap="false" Margins="5,10,0,0"/>

         </Children>
       </Panel>
     </Children>
   </Graphic>
<!-- shown when not selected -->
   <Panel Name="Unselected" Layout="HorizontalFlow">
     <Children>
       <Text Name="ProgramName" Color="LightBlue" Font="Sergio UI,18" WordWrap="false" Margins="5,0,0,0"/>
     </Children>
   </Panel>
 </Children>
</Panel>

The key to getting it looking like the media center selection is to draw a nice rounded button with a circular shade in it. I use the open source GIMP package to draw all of my images, and something like this can be achieved quite easily with that.

Preferences

WebTelek9

Finally, the system had to run in multiple languages, and change which language it is running in based on user preference, not based on installed language (there are many US customers running with US English installations who want to have the WebTelek software running in Russian). Media Center gives no kind of native support for language switching like that, so I put the different language prompts in a static class;

public static class Language
 {
 public static String PlayPart, Loading, Actors, Length, mins, Producer, NoMovieDetails, Categories, Genres;

 public static void setLanguage(string language)
 {

 switch (language)
 {
 case "US":
 Loading = "Loading";
...

and then in the UI class for each page, exposed the prompt;

public string PreferencesText
 {
 get
 {
 return Language.Preferences;
 }
 }

This allows the text to be referenced in many places without constantly re-instantiating a new class, and also allows for the text to be changed on the fly without re-entering the application.

Summary

Hopefully I have managed to share some useful development tips, and if you are looking to get some Russian television within media center, hopefully I have enticed you enough to sign up with WebTelek.

Tags: ,

Leave a Reply