--[[ DISCLAIMER: SCRIPT IS PROVIDED AS IS USE AT YOUR OWN RISK! Save this script as "hockey.lua" Place this script in: - Windows (all users): %ProgramFiles%\VideoLAN\VLC\lua\sd\ - Windows (current user): %APPDATA%\VLC\lua\sd\ - Linux (all users): /usr/share/vlc/lua/sd/ - Linux (current user): ~/.local/share/vlc/lua/sd/ - Mac OS X (all users): VLC.app/Contents/MacOS/share/lua/sd/ --]] require "simplexml" MILITARY_TIME=true SHOW_LOCAL_TIME=true API_USERNAME="rhockeyvlc" USER_AGENT="PS4 libhttp/1.62 (PlayStation 4)" --Alternative User-Agents: -- USER_AGENT="Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0; Xbox; Xbox One)" -- USER_AGENT="iTunes-AppleTV/4.1" function descriptor() return { title="/r/hockey" } end local function get_date_parts(date_str) _,_,y,m,d,h,M,s=string.find(date_str, "(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)") return {year=tonumber(y),month=tonumber(m),day=tonumber(d),hour=tonumber(h),min=tonumber(M),sec=tonumber(s)} end local function get_et_date() local et_time_xml = simplexml.parse_url("http://api.geonames.org/timezone?lat=40.67&lng=-73.94&username=" .. API_USERNAME) local et_date = nil for _, child in ipairs( et_time_xml.children ) do if (child.name == "timezone") then for _, subchild in ipairs( child.children ) do if (subchild.name == "time") then et_date = subchild.children[1] .. ":00" end end end end return et_date end local function get_et_diff() if not SHOW_LOCAL_TIME then return nil end local status, et_date = pcall(get_et_date) if (status == false or et_date == nil) then vlc.msg.warn("Couldn't get ET time, showing default times: " .. et_date) return nil end local local_time = os.time() local et_time = os.time(get_date_parts(et_date)) local diff_seconds = os.difftime(local_time, et_time) -- Round to closest 5mins local excess = diff_seconds % 300 if (excess < 150) then diff_seconds = diff_seconds - excess else diff_seconds = diff_seconds + (300 - excess) end return diff_seconds end local function convert_to_local(date, diff) local time, local_time, local_date if diff == nil then diff = 0 end time = os.time(get_date_parts(date)) local_time = time + diff; local_date = os.date(time_display_format, local_time) -- Strip leading zero from 12 hour format if not MILITARY_TIME then local_date = local_date:gsub("^0", "") end return local_date end local function set_time_display_format(diff) if MILITARY_TIME then time_display_format = "%H:%M" else time_display_format = "%I:%M %p" end if (diff == nil) then time_display_format = time_display_format .. " ET" end end local function convert_game_time_string_to_date(game_time) _,_,m,d,y,h,M,s=string.find(game_time, "(%d+)/(%d+)/(%d+) (%d+):(%d+):(%d+)") return string.format("%d-%d-%d %d:%d:%d", y, m, d, h, M, 0) end local function get_feed_date() -- Calculate date for -10:00 local timestamp = os.time() -- ! gives GMT time local format = "!%Y%m%d" -- Offset causes date to only switch over at 10am GMT -- which is 5am ET local tzoffset = -36000 return os.date(format, timestamp + tzoffset) end function main() local et_diff = get_et_diff() set_time_display_format(et_diff) local games = simplexml.parse_url("http://feeds.cdnak.neulion.com/fs/nhl/mobile/feeds/data/"..get_feed_date()..".xml") local test_games = {} if #(games.children) == 0 then vlc.sd.add_node({path="", title="No games today."}) return end for _, game in ipairs( games.children ) do if(game.name == "game") then simplexml.add_name_maps( game ) local game_date, home_team, away_team, title = getInfoForGame(game, et_diff) if string.find(home_team,"^T%d+$") or string.find (away_team,"^T%d+$") then table.insert(test_games, game) else add_node_for_game(game, home_team, away_team, title) end end end if #(test_games) > 0 then local test_node = vlc.sd.add_node( { path = "", title = "Test Streams" } ) for _, game in ipairs(test_games) do local game_date, home_team, away_team, title = getInfoForGame(game, et_diff) add_node_for_game(game, home_team, away_team, title) end end end function getInfoForGame(game, et_diff) local game_date = convert_game_time_string_to_date(""..game.children_map["eastern-start-time"][1].children[1]) local local_game_date = convert_to_local(game_date, et_diff) local home_team = full_name(""..game.children_map['home-team'][1].children_map["team-abbreviation"][1].children[1]) local away_team = full_name(""..game.children_map['away-team'][1].children_map["team-abbreviation"][1].children[1]) local title = local_game_date .. " - " .. away_team .. " @ " .. home_team return local_game_date, home_team, away_team, title end function add_node_for_game_team_type(parentNode, node, prefix) local quality = {400, 800, 1200, 1600, 3000, 4500} if (node ~= nil) then for _, q in ipairs(quality) do local url = string.gsub(node, "ipad", q) parentNode:add_subitem({ path = url, title = prefix .. ' - ' .. q .. ' kbps ', options = { "http-user-agent=" .. USER_AGENT } }) end end end function add_node_for_game_team(parentNode, node) if (node.children_map["live"] ~= nil) then add_node_for_game_team_type(parentNode, node.children_map["live"][1].children[1], "Live") end if (node.children_map["vod-condensed"] ~= nil) then add_node_for_game_team_type(parentNode, node.children_map["vod-condensed"][1].children[1], "Condensed VOD") end if (node.children_map["vod-continuous"] ~= nil) then local url = string.gsub(node.children_map["vod-condensed"][1].children[1], "condensed", "continuous") add_node_for_game_team_type(parentNode, url, "Continuous Feed") end end local function add_missing_feed_node(parent_node, game) local game_state = game.children_map["game-state"][1].children[1] if game_state ~= nil and string.find(game_state, "FINAL") ~= nil then parent_node:add_subnode({title = "Game has finished. No replay or highlights available yet."}) else parent_node:add_subnode({title = "No stream available yet."}) end end function add_node_for_game(game, home_team, away_team, title) local parentNode = vlc.sd.add_node( { path = "", title = title } ) local home_feed_node = parentNode:add_subnode({ title = home_team }) local away_feed_node = parentNode:add_subnode({ title = away_team }) local streams = game.children_map["streams"] if (streams ~= nil) then local ipad = streams[1].children_map["ipad"][1] local home = ipad.children_map["home"] local away = ipad.children_map["away"] if (home ~= nil) then add_node_for_game_team(home_feed_node, home[1]) else add_missing_feed_node(home_feed_node, game) end if (away ~= nil) then add_node_for_game_team(away_feed_node, away[1]) else add_missing_feed_node(away_feed_node, game) end else add_missing_feed_node(home_feed_node, game) add_missing_feed_node(away_feed_node, game) end end function full_name(abr) local all_names = { BOS = "Boston Bruins", BUF = "Buffalo Sabres", CGY = "Calgary Flames", CHI = "Chicago Blackhawks", DET = "Detroit Red Wings", EDM = "Edmonton Oilers", CAR = "Carolina Hurricanes", LAK = "Los Angeles Kings", MTL = "Montreal Canadiens", DAL = "Dallas Stars", NJD = "New Jersey Devils", NYI = "New York Islanders", NYR = "New York Rangers", PHI = "Philadelphia Flyers", PIT = "Pittsburgh Penguins", COL = "Colorado Avalanche", STL = "St. Louis Blues", TOR = "Toronto Maple Leafs", VAN = "Vancouver Canucks", WSH = "Washington Capitals", PHX = "Phoenix Coyotes", SJS = "San Jose Sharks", OTT = "Ottawa Senators", TBL = "Tampa Bay Lightning", ANA = "Anaheim Ducks", FLA = "Florida Panthers", CBJ = "Columbus Blue Jackets", MIN = "Minnesota Wild", NSH = "Nashville Predators", WPG = "Winnipeg Jets" } local name = all_names[abr] if name == nil then name = abr end return(name) end