I’ve changed the USTVnow script from my previous post. I needed it to work without XBMC running or even installed.

The script below will login into USTVnow, grab the stream info for each channel you have access to and then write out .strm files to a directory of your choosing. To use it just change email, password, and stream_dir to your own credentials.

I have the script set to run via CRON every thirty minutes. Then I have the scripts stream_dir setup as a source in XBMC so I can play the stream files.

The script is pure Python and should run on anything that will run Python. No need to have XBMC working.

Download: ustvnow.py

7/14/15: I’ve updated the script to work with USTVNOW’s website changes.

    ustvnow XBMC Plugin
    Copyright (C) 2011 t0mm0

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

20131227 - Modified by Dean Vaughan - http://deanvaughan.org to work from command line and output stream files to a directory
20140610 - Modified by Dean Vaughan - http://deanvaughan.org to work without XBMC running or installed

email = 'youemail'
password = 'yourpassword'
stream_dir = 'Streams'

stream_type = 'rtmp'
quality = '1'

import cookielib
import os
import re
import urllib, urllib2
import sys

class Ustvnow:
    __BASE_URL = 'http://lv2.ustvnow.com'
    def __init__(self, user, password):
        self.user = user
        self.password = password

    def get_channels(self, quality=1, stream_type='rtmp'):
        html = self._get_html('iphone_ajax', {'tab': 'iphone_playingnow',
                                              'token': self.token})
        channels = []
        for channel in re.finditer('class="panel".+?title="(.+?)".+?src="' +
                                   '(.+?)".+?class="nowplaying_item">(.+?)' +
                                   '<\/td>.+?class="nowplaying_itemdesc".+?' +
                                   html, re.DOTALL):
            name, icon, title, plot, url = channel.groups()

            #tmp work around till ustvnow stablizes changes
            name = name.replace('\n','').replace('\t','').replace('\r','').replace('<fieldset> ','').replace('<div class=','').replace('>','').replace('"','').replace(' ','')
            if not name:
                name = ((icon.rsplit('/',1)[1]).replace('.png','')).upper()
                name = name.replace('WLYH','CW').replace('WHTM','ABC').replace('WPMT','FOX').replace('WPSU','PBS').replace('WHP','CBS').replace('WGAL','NBC').replace('WHVLLD','MY9')

                if not url.startswith('http'):
                    now = {'title': title, 'plot': plot.strip()}
                    url = '%s%s%d' % (stream_type, url[4:-1], quality + 1)

                   # if self.premium == False:
                   #     if name not in ['CW','ABC','FOX','PBS','CBS','NBS','MY9']:
                   #         raise

                    print name
                    channels.append({'name': name, 'url': url,
                                   'icon': icon, 'now': now})
        return channels

    def _build_url(self, path, queries={}):
        if queries:
            query = build_query(queries)
            return '%s/%s?%s' % (self.__BASE_URL, path, query)
            return '%s/%s' % (self.__BASE_URL, path)

    def _fetch(self, url, form_data=False):
        if form_data:
            req = urllib2.Request(url, form_data)
            req = url
            response = urllib2.urlopen(url)
            return response
        except urllib2.URLError, e:
            return False

    def _get_html(self, path, queries={}):
        html = False
        url = self._build_url(path, queries)

        response = self._fetch(url)
        if response:
            html = response.read()
            html = False

        return html

    def _login(self):
        self.token = None
        self.cj = cookielib.CookieJar()
        opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cj))

        url = self._build_url('iphone_login', {'username': self.user,
                                               'password': self.password})
        response = self._fetch(url)
        #response = opener.open(url)

        for cookie in self.cj:
            if cookie.name == 'token':
                self.token = cookie.value

def build_query(queries):
    return '&amp;'.join([k+'='+urllib.quote(str(v)) for (k,v) in queries.items()])

ustv = Ustvnow(email, password)
channels = ustv.get_channels(int(quality), stream_type)

    old_streams = os.listdir(stream_dir)
    for old_stream in old_streams:
        if 'USTV-' in old_stream:
          os.remove(stream_dir + '/' + old_stream)

for c in channels:
    title = c['now']['title']
    title = re.sub('[^\w\-_\. ]', '', title)
    title = title.replace(' amp ', ' and ')
    f = open(stream_dir + '/USTV-' + c['name'] + ': ' + title + '.strm', 'w')

I was asked to give a run down of the XBMC computer I am currently using. It was assembled from parts and is running openELEC.

HTPC XBMC Computer

The case looks good.

My XBMC PC is capable of:

  • Playing 1080i video with no stutter or buffering. (Both local files and files from a Windows file server)
  • Playing 1080i streams of local cable TV channels.
  • Recoding those streams DVR style.
  • Playing 720p streams of premium cable TV channels via USTVNOW. (The 720p limit is from USTVNOW, not the computer)
  • Using my surround sound system for 5.1 sound.
  • Playing older video games from Super Nintendo, NES, Game Boy, Genesis, ect.
  • Throwing some colors on the wall with a Light Pack.

Parts List:

Total Cost: $638.26

Not cheap. You get what you pay for.

Some notes on the hardware:

My previous HTPC was an ASROCK Ion 330. It was prone to overheating. A lot of this was due to the small case size. The CPU fan lay under a spinning hard drive with a 1/4 inch gap. The fan blew hot air onto a hard drive producing its own heat. This was then blown out of the case by a 25mm fan. Because of the cramped quarters I didn’t have any other options for larger fans or moving parts. While the PC never got hot enough to shutdown it did get hot enough to make me worry about.

The case on this XBMC PC is roomy. The fan from the CPU isn’t constricted. It has a 65mm case fan with room for a second. I’m using an SSD drive as they produce little to no heat. The SSD has the added benefit of being silent. The PC as a whole is quiet enough that you cannot hear it without putting your ear near the case. Even under a load it doesn’t get hot enough to spin the fans up. Idle temperature is around 40C, loaded is around 55C.

The CPU has an integrated GPU. It comes with a heat sink and fan in the box. The CPU is overkill for playing videos. I went big with the CPU because someday I plan on emulating N64 and Playstation games. Possibly even Game Cube.

The HDHomeRun is for watching cable TV. If that’s not applicable to you, then no need to buy one.

The lighting arrangement can be had in a DIY kit for $50.


Putting it all together gets you this:

My camera is unable to capture the lighting effect. Here is a video from the vendor showing how it looks.
ADAlight demo from adafruit industries on Vimeo.



Getting the Free Cable addon to work under OpenELEC takes a little bit of command line work. You’ll need to install some Python modules and create some directories on your OpenELEC computer.

Here’s what you need to do to get Free Cable working:

Install the Blue Cop Repository

From that repository, install Free Cable.

Open the configuration for Free Cable and then save it as is.

SSH to your OpenELEC computer. Run the following on the command line:

wget http://www.crummy.com/software/BeautifulSoup/bs4/download/4.3/beautifulsoup4-4.3.2.tar.gz
cd beautifulsoup4-4.3.2/
python setup.py install --prefix=/storage/usr
cp -R /storage/usr/lib/python2.7/site-packages/bs4/ /storage/usr/lib/python2.7/site-packages/beautifulsoup

wget http://deron.meranda.us/python/demjson/dist/demjson-1.6.tar.gz
tar zxvf demjson-1.6.tar.gz
cd demjson-1.6
python setup.py install --prefix=/storage/usr

mkdir /storage/.xbmc/addons/script.module.free.cable.database/
mkdir /storage/.xbmc/addons/script.module.free.cable.database/lib

touch /storage/.config/autostart.sh
chmod 755 /storage/.config/autostart.sh

Once that’s done edit /storage/.config/autostart.sh and add

export PYTHONPATH=$PYTHONPATH:/storage/usr/lib/python2.7/site-packages/

If you already have ‘#!/bin/sh’ in the file, don’t add is again.

Reboot. Free Cable should now work.

I was having trouble keeping hdhomerun_recorder always running under openELEC. Sometimes it wouldn’t start at boot, or sometimes it would randomly stop running, causing my shows not to be recorded. Below is a short Python script I came up with. It runs under CRON every five minutes. If hdhomerun_recorder isn’t running, it starts it. I have not had a problem since.

import os

find = 'hdhomerun_recorder'
start = '/storage/etc/hdhomerun_recorder/start.sh &'

f = os.popen('ps ax | grep -v grep | grep "' + find + '"')
out = f.read()
if not find in out:
  print 'Running: ' + start

What you see here is the act of a desperate man who got sick of trying to make XBMC’s PVR support work. I tried for several days to get tvheadend to work with my HDHomeRun. In the end I gave up and went my way. What you see may be a mess to setup but it works very well for me.

When all setup XBMC will have a directory full or playlist files representing your channels/streams. The playlist files will be named after the channel they represent along with the current and next show that is going to play.

Here is a video to show what I mean:

Quick note on my setup; I have an HDHomeRun receiving QAM channels from Cox cable. These channels come in as by product of the Internet service I receive. Via Cox and the HDHomeRun I receive local network stations. I also have an USTVNOW account for basic cable channels. Why do I use USTVNOW instead of getting basic cable from Cox? USTVNOW is about $10 a month cheaper and receives more channels.

Installation is a crazy mess. I didn’t expect to release this but I figured at the least the USTVNOW streams will be useful to someone.

I did all of this under openElec. XBMCbuntu works. Other Linux based installs should work. Windows will probably work if you install Python and something similar to CRON.


For USTV: Just make sure you have the USTVNOW plugin working. XBMC HUB Article About It

For HD Home Run: Make sure its connected to your network and can view some channels. Have hdhomerun_config working. (Part of libhdhomerun: Download It


  • Download this repo. (Direct link to zip)
  • Unzip it and copy everything into /storage/dean. If you’re the picky sort this is where you begin to change pathnames. For narcissistic reasons I’m going to assume you’ve put everything in /storage/dean.
  • Make a directory: /storage/Streams. This is where all your stream files will go. Add that directory as video source in XBMC.


  • We’re going to add a script to the USTVNOW addon to download a list of channels and turn them into stream files (.strm). We’re going to place this in CRON so it updates itself.
  • Edit /storage/dean/ustvnow_stream_grabber.py and change the email and password variables to your USTVNOW credentials.
  • Move /storage/dean/ustvnow_stream_grabber.py to the directory your USTVNOW addon resides in. For me its /storage/.xbmc/addons/ustvnow/
  • Make sure it works by running /storage/dean/ustvnow.sh. After that you should see a bunch of stream files in /storage/Streams. Each file should represent one of your USTVNOW channels.
  • Add a cron job so that /storage/dean/ustvnow.sh is ran every thirty minutes. Example in /storage/dean/crontab.

Go to your stream video source in XBMC. You should be able to play each file in there.

HDHomeRun Streams

  • We’re going to build stream (.strm) files for each channel your HDHomeRun receives.
  • On a Windows box open up HDHomeRun Setup and look at the tab that shows all of your channels, Digital Cable for me.
  • Write down the channel numbers and what channel they represent. (FOX, ABC, ect)

  • Two options now. Build the stream files by hand or use HDHomeRun Stream Builder to do it for you.
  • If you’re doing it by hand and pretending we’re working on the file for CBS in Fort Smith, AR:
  • Create a file named KFSMDT.strm
  • Open the file up and add this: hdhomerun://103D1F0E-0/tuner0?channel=auto:92&program=1
  • Notice a few things you’ll need to change.
  • 103D1F0E-0 is the ID of my tuner. You’ll need to change it to your tuner’s ID.
  • tuner0 is the first tuner on my HDHomeRun. The second tuner is tuner1. I watch TV on tuner0. I record TV on tuner1.
  • channel=auto:92&program=1 represents CH92 – 1 from HDHomeRun Setup. Change the 92 and the 1 as appropriate for your channels.
  • Save the file and put it in /storage/dean/Streams-default
  • Repeat this for every channel your HDHomeRun receives.
  • HDHomeRun Stream Builder will automate all of this for you, but it is a PITA to setup. (As if all the above hasn’t been)
  • If you don’t care about having the currently playing show in the file name, copy the all the .strm file you made into /storage/Streams and call it done. Just like the USTVNOW streams they should play as if they were any other video file.

Getting the currently playing show to be in the HDHomeRun stream’s file name

  • Theory behind this is that we’re going to use mc2xml to download TV scheduling information, parse it, and rename our stream files using the info.
  • Get mc2xml working for your zip code. There is a copy in /storage/dean/mc2xml-local
  • For me the command line is ./mc2xml -c us -g 72714 -d 72 -f (72714 is my zip code)
  • Have cron run /storage/dean/update_xmltv.sh once a day. Example in /storage/dean/crontab
  • Have cron run /storage/dean/update_streams.sh every thirty minutes. Example in /storage/dean/crontab
  • Now your stream files in /storage/Streams should be all renamed with the current show playing.