From c5641df3258dbe6081295411caa3e325d7e1f3b6 Mon Sep 17 00:00:00 2001 From: Justin Loutsenhizer Date: Tue, 12 Nov 2013 15:10:28 -0500 Subject: [PATCH] -Added start of framework for additional chromecast repositories to be supported -Made setUserAgent compatibility optional (needed for youtube to work but we just disable it if it's unavailable) -This makes CR Cast Compatible with Chrome 31 and greater (stable channel) -note: no change for chromebooks --- extension/js/ChromecastApp.js | 7 ++ extension/js/app.js | 153 ++++++++++++++++++++++++++++------ extension/js/appview.js | 2 +- extension/js/management.js | 11 ++- extension/manifest.json | 4 +- 5 files changed, 146 insertions(+), 31 deletions(-) diff --git a/extension/js/ChromecastApp.js b/extension/js/ChromecastApp.js index 0327044..ed1dd77 100644 --- a/extension/js/ChromecastApp.js +++ b/extension/js/ChromecastApp.js @@ -1,4 +1,7 @@ define(["WebRequestResponder","WebSocket"],function(Responder,WebSocket){ + + var canSupportYoutube = document.createElement("webview").setUserAgentOverride != null; + var ChromecastApp = function(name,url,options){ if (typeof name == "object"){ options = name; @@ -34,6 +37,10 @@ define(["WebRequestResponder","WebSocket"],function(Responder,WebSocket){ console.error("Can't support external apps! Didn't load " + this.app_name); return; } + if (this.app_name == "YouTube" && !canSupportYoutube){ + console.error("API needed for YouTube to work is missing! Didn't load " + this.app_name); + return; + } if (ChromecastApp.apps[this.app_name] != null){ console.error("Already have app by name " + this.app_name); return; diff --git a/extension/js/app.js b/extension/js/app.js index c76251d..40d02f6 100644 --- a/extension/js/app.js +++ b/extension/js/app.js @@ -2,6 +2,8 @@ chrome.app.runtime.onLaunched.addListener(function(){ chrome.app.window.create("management.html",{state:"normal",minWidth:640,minHeight:480,id:"CrCastManagement"}); }); +chrome.storage.local.remove("officialDeviceConfig"); + require(["SSDPServer","WebServer","WebRequestResponder","ChromecastApp"],function(SSDPServer,WebServer,Responder,ChromecastApp){ App = { httpServer: null, @@ -60,29 +62,12 @@ require(["SSDPServer","WebServer","WebRequestResponder","ChromecastApp"],functio App.httpServer.addResponder(ChromecastApp.appConnectionResponder); App.httpServer.addResponder(ChromecastApp.appRemoteResponder); - chrome.storage.local.get("officialDeviceConfig",function(s){ - if (s.officialDeviceConfig != null){ - ChromecastApp.loadConfiguration(JSON.parse(s.officialDeviceConfig.substring(4))); - } - $.ajax("https://clients3.google.com/cast/chromecast/device/config",{ - dataType:"text", - success:function(data){ - App.serviceState = "running"; - App.updateConfigRequest = null; - chrome.storage.local.set({"officialDeviceConfig":data}); - ChromecastApp.loadConfiguration(JSON.parse(data.substring(4))); - if (App.useIdleScreen && !bootStart) - ChromecastApp.launchApp(ChromecastApp.idleAppname); - }, - error:function(){ - App.serviceState = "running"; - if (App.useIdleScreen && !bootStart) - ChromecastApp.launchApp(ChromecastApp.idleAppname); - App.updateConfigRequest = null; - } - }); - + App.getCombinedRepositoryData(function(data){ + ChromecastApp.loadConfiguration(data); + App.serviceState = "running"; + if (App.useIdleScreen && !bootStart) + ChromecastApp.launchApp(ChromecastApp.idleAppname); }); }); }, @@ -103,10 +88,11 @@ require(["SSDPServer","WebServer","WebRequestResponder","ChromecastApp"],functio useIdleScreen: App.useIdleScreen, runOnStart: App.runOnStart }}); + chrome.storage.local.set({"repositories":App.repositories}); }, loadSettings: function(){ - chrome.storage.local.get("settings",function(s){ + chrome.storage.local.get(["settings","repositories"],function(s){ if (s.settings != null){ App.setFriendlyName(s.settings.name); App.useIdleScreen = s.settings.useIdleScreen; @@ -119,20 +105,129 @@ require(["SSDPServer","WebServer","WebRequestResponder","ChromecastApp"],functio App.setFriendlyName("CR Cast"); App.persistSettings(); } + if (s.repositories != null){ + App.repositories = s.repositories; + } + else{ + App.repositories = []; + App.repositories.push(makeRepositoryListing("Google Official Repository","https://clients3.google.com/cast/chromecast/device/config",true)); + App.persistSettings(); + } }); + }, + getCombinedRepositoryData: function(callback){ + var result = makeEmptyRepository(); + + function getRepository(i){ + if (App.repositories[i].active){ + getRepositoryData(App.repositories[i].url,function(newData){ + result = mergeRepositoryDatas(result,newData); + continueIteration(i+1); + }) + } + else{ + continueIteration(i+1); + } + } + function continueIteration(i){ + if (App.repositories.length > i) + getRepository(i); + else + callback(result); + } + continueIteration(0); } }; + function makeRepositoryListing(name,url,active){ + return { + name: name, + url: url, + active: active + }; + } + + function makeEmptyRepository(){ + return { + configuration:{}, + applications: [] + } + } + + function mergeRepositoryDatas(data1,data2){ + var result = makeEmptyRepository(); + if (data2.configuration != null && data2.configuration.idle_screen_app != null) + result.configuration.idle_screen_app = data2.configuration.idle_screen_app; + else if (data1.configuration.idle_screen_app != null) + result.configuration.idle_screen_app = data1.configuration.idle_screen_app; + for (var i = 0, li = data2.applications.length; i < li; i++){ + var app = data2.applications[i]; + var appCopy = {}; + for (var member in app){ + appCopy[member] = app[member]; + } + result.applications.push(appCopy); + } + for (var i = 0, li = data1.applications.length; i < li; i++){ + var app = data2.applications[i]; + for (var j = 0, lj = data2.applications.length; j < lj; j++){ + if (data2.applications[j].app_name == app.app_name) + break; + } + if (j == data2.applications.length){ + var appCopy = {}; + for (var member in app){ + appCopy[member] = app[member]; + } + result.applications.push(appCopy); + } + } + return result; + } + + function getRepositoryData(url,callback){ + var hash = Sha1.hash(url,true); + $.ajax(url,{ + dataType: "text", + success: function(data){ + var object = {}; + object[hash] = data; + chrome.storage.local.set(object); + callback(parseRepositoryData(data)); + }, + error: function(data){ + chrome.storage.local.get(hash,function(s){ + if (s[hash] == null){ + callback(parseRepositoryData("")); + } + else{ + callback(parseRepositoryData(s[hash])); + } + }); + } + }) + } + + function parseRepositoryData(data){ + try{ + return JSON.parse(data.substring(data.indexOf("{"),data.lastIndexOf("}") + 1)); + } + catch (error){ + return {applicatoins:[]}; + } + + } + App.setFriendlyName('CR Cast'); App.loadSettings(); window.addEventListener("message", function(messageEvent){ - var message = JSON.parse(messageEvent.data); + var message = messageEvent.data; switch (message.type){ case "GET_STATE": - messageEvent.source.postMessage(JSON.stringify({ + messageEvent.source.postMessage({ type: "APP_STATE", app_state: { serviceState: App.serviceState, @@ -141,7 +236,13 @@ require(["SSDPServer","WebServer","WebRequestResponder","ChromecastApp"],functio useIdleScreen: App.useIdleScreen, runOnStart: App.runOnStart } - }),"*"); + },"*"); + break; + case "GET_REPOSITORY_LIST": + messageEvent.source.postMessage({ + type: "REPOSITORY_LIST", + repositories: App.repositories + },"*"); break; case "START_SERVICE": App.startService(false); diff --git a/extension/js/appview.js b/extension/js/appview.js index f17f05b..3dbca62 100644 --- a/extension/js/appview.js +++ b/extension/js/appview.js @@ -11,7 +11,7 @@ } webview = $("#appview")[0] - if (params.user_agent != null) + if (params.user_agent != null && webview.setUserAgentOverride) webview.setUserAgentOverride(params.user_agent); webview.addEventListener('loadstop', function(e) { if (params.css_inject != null) diff --git a/extension/js/management.js b/extension/js/management.js index 67415b5..0e7d029 100644 --- a/extension/js/management.js +++ b/extension/js/management.js @@ -73,7 +73,7 @@ $(document).ready(function(){ }) window.addEventListener("message", function(messageEvent){ - var message = JSON.parse(messageEvent.data); + var message = messageEvent.data; switch (message.type){ case "APP_STATE": app_state = message.app_state; @@ -119,6 +119,9 @@ $(document).ready(function(){ runOnStart[0].checked = app_state.runOnStart; } break; + case "REPOSITORY_LIST": + console.log(message.repositories); + break; } }); @@ -126,14 +129,18 @@ $(document).ready(function(){ chrome.runtime.getBackgroundPage(function(backgroundWindow){ sendMessage = function(message){ - backgroundWindow.postMessage(JSON.stringify(message),"*"); + backgroundWindow.postMessage(message,"*"); } var getStateMessage = { type: "GET_STATE" }; + var getRepositoriesMessage = { + type: "GET_REPOSITORY_LIST" + }; sendMessage(getStateMessage); $.doTimeout(50,function(){//setup state polling sendMessage(getStateMessage); + sendMessage(getRepositoriesMessage); return true; }) diff --git a/extension/manifest.json b/extension/manifest.json index e86a400..237f05a 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -1,6 +1,6 @@ { "name": "CR Cast", - "version": "0.6.7", + "version": "0.6.8", "manifest_version": 2, "description": "Turn your chrome browser into a chromecast receiver!!", "offline_enabled": false, @@ -25,5 +25,5 @@ "256": "img/icon/256.png", "128": "img/icon/128.png" }, - "minimum_chrome_version":"32" + "minimum_chrome_version":"31" } \ No newline at end of file