I'm trying to launch the cast api from a chrome extension that i'm writing. When I run this same code in a regular old HTML file on my webserver, it works perfectly. It doesn't work when I use this code in the popup of my extension. The requestSession call doesn't work at all in that case and nothing seems to happen after it's called.
I believe the expected behaviour is that the google cast extension will show the device list popup. Here is my javascript and html. Most of it is copied right out of CastHelloVideo-chrome.
HTML:
<html>
<head>
<title>Popup</title>
<style>
body {
min-width:5px;
overflow-x:hidden;
}
</style>
<script type="text/javascript" src="https://www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>
</head>
<body>
<button type="button" id="castButton">Cast!</button>
</body>
<script type="text/javascript" src="popup.js"></script>
</html>
Javascript:
//Constants
var applicationID = "<App ID>";
var session;
var currentMediaSession;
///////////////////////////////////////////////////////////////////
//Chromecast API
///////////////////////////////////////////////////////////////////
if (!chrome.cast || !chrome.cast.isAvailable) {
setTimeout(initializeCastApi, 1000);
}
function loadMedia() {
if (!session) {
console.log("no session");
return;
}
var mediaInfo = new chrome.cast.media.MediaInfo('http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4');
mediaInfo.contentType = 'video/mp4';
var request = new chrome.cast.media.LoadRequest(mediaInfo);
request.autoplay = false;
request.currentTime = 0;
session.loadMedia(request,
onMediaDiscovered.bind(this, 'loadMedia'),
onMediaError);
}
/**
* callback on success for loading media
* #param {Object} e A non-null media object
*/
function onMediaDiscovered(how, mediaSession) {
console.log("new media session ID:" + mediaSession.mediaSessionId);
currentMediaSession = mediaSession;
}
/**
* callback on media loading error
* #param {Object} e A non-null media object
*/
function onMediaError(e) {
console.log("media error");
}
//////////////////////////////////////////////////////////////////
//UI
//////////////////////////////////////////////////////////////////
var castbutton = document.getElementById("castButton");
castButton.onclick=function(){
window.close();
chrome.cast.requestSession(onRequestSessionSuccess, onLaunchError);
// loadMedia();
};
//////////////////////////////////////////////////////////////////
//Helper Functions
//////////////////////////////////////////////////////////////////
function initializeCastApi() {
var sessionRequest = new chrome.cast.SessionRequest(applicationID);
var apiConfig = new chrome.cast.ApiConfig(sessionRequest,
sessionListener,
receiverListener);
chrome.cast.initialize(apiConfig, onInitSuccess, onError);
}
function sessionListener(e) {
console.log('New session ID: ' + e.sessionId);
session = e;
}
function receiverListener(e) {
console.log(e);
}
function onInitSuccess() {
console.log("init success");
}
function onError() {
console.log("error");
}
function onSuccess(message) {
console.log(message);
}
function onRequestSessionSuccess(e) {
session = e;
console.log("session created");
}
function onLaunchError(e) {
console.log(e.description);
}
I think this may be caused because I'm trying to run this out of the popup of my extension. Maybe chrome doesn't allow multiple plugins to show their (the device list is google cast's popup) popup window's at the same time? I've tried closing the popup before executing the requestSession call, but it still doesn't work. Anyone have any ideas?
Invoking requestionSession API call within a Chrome extension is not supported. That's why you cannot get a list of devices.
In any case this method call only works from a regular web page and it triggers the extension to show a pop-up of Cast devices. That's the only current way it's supposed to work.
Related
When loading the page I get a alert box with unidentified in, when remove this bit code it goes. I need this as it makes the menu work.
Going in a bit blind on this so wasn't sure what it doesn't like, I suppose I should be asking what does this actually mean?
<script type="text/javascript">
var loadEvents = new Array();
function addInitFunction(func) { loadEvents.push( { 'func':func, 'seq':-1 } ); }
function addLoadEvent(func, seq) { loadEvents.push( { 'func':func, 'seq':seq } ); }
var linkver="-65";
var IP="";
var proto="https:";
var def_proto="http:";
</script>
Narrowed it down to this line
function addInitFunction(func) { loadEvents.push( { 'func':func, 'seq':-1 }); }
I've also found what I think is the function with the issue
<script type="text/javascript">
// Move responsive divs
function homeRespChange(from, too, source) {
respMoveContent('respHeaderLogin', { 'default':'respMove_HeaderLogin_default', 'phone':'respMove_HeaderLogin_phone' });
}
function homeInit() {
responsiveKick();
}
addInitFunction('homeInit');
addInitFunction('menuFixup');
addInitFunction('setWallp');
addInitFunction('tidyFunc');
addInitFunction('moveBasket');
addInitFunction('loginMenu');
function mess() {
alertX('EUCookieMessage_Holder');
}
//addLoadEvent(mess);
</script>
This script works just fine in Tampermonkey on both Chrome and Firefox, but doesn't work in Greasemonkey on Firefox. When I say it doesn't work I mean the button does not show up on the page. I'm using Chrome 61.0.3163.79 and Firefox 52.3.0.
The firefox console shows this warning but I'm not sure if it's relevant:
unreachable code after return statement[Learn More] jquery-1.3.2.min.js
Here's the code. Using greasemonkey on Firefox, I see "create button" in the console, but not "button has been created", which makes me think something is going wrong with the button creation. Any help greatly appreciated!
// ==UserScript==
// #name MyScript
// #namespace MyNS
// #description Adds a button to insert text into 2 text boxes
// #version 0.1
// #include *Removed for confidentiality*
// #compatible Greasemonkey
// ==/UserScript==
var descriptionText = "myDescription";
var testingText = "myTesting";
// Check if jQuery's loaded
function GM_wait() {
if (typeof unsafeWindow.jQuery == 'undefined') { window.setTimeout(GM_wait,100); }
else { $ = unsafeWindow.jQuery; init(); }
}
// All your GM code must be inside this function
function init() {
var description = $('#description');
var testingDone = $('#testing_done');
function insertText(template, editor) {
if (template) {
if (!editor._editing) {
editor.startEdit();
}
editor._field.queue(function() {
var oldVal = editor._field.val();
editor._field.val(template + (oldVal ? "\n" : "") + oldVal);
editor._field.keyup();
editor._field.dequeue();
});
}
}
function createButton(editor) {
console.log("create button:");
editor._insertTextButton = $('<input/>')
.attr('type', 'button')
.attr('value', 'Insert CR Template')
.css('margin-left', '1em')
.click(function() {
insertText(testingText, testingDoneEditor);
insertText(descriptionText, descriptionEditor);
});
console.log("button has been created");
editor._insertTextButton.insertAfter(editor._editIcon);
}
descriptionEditor = description.data('inlineEditor');
testingDoneEditor = testingDone.data('inlineEditor');
createButton(descriptionEditor);
}
GM_wait();
For some reason I can't switch to nested frames in selenium-webdriver using node.js. I have tried setting timeouts to let the page load or timeouts to give the driver time to switch to another frame, nothing worked. This question is most likely a continuation of this. I am getting a NoSuchFrameError.
HTML - full url here
<!DOCTYPE html>
<html>
<head>
<title>HTML Target Frames</title>
</head>
<frameset rows="16%,84%">
<frame src="./framesHtml/top.htm" name="top_page" >
<frameset cols="50%,50%">
<frame src="./framesHtml/menu.htm" name="menu_page" >
<frame src="./framesHtml/main.html" name="main_page" >
</frameset>
</frameset>
</html>
Function switching to main_page
var webdriver = require('selenium-webdriver');
var chrome = require('selenium-webdriver/chrome');
var chromePath = require('selenium-chromedriver').path;
var FrameHandler = require('../../JS-Selenium-Toolkit/src/FrameHandler');
var expect = require('chai').expect;
describe('FrameHandler', function () {
it('Should pass if the set frame is main_page', function (done) {
this.timeout(15000);
var service = new chrome.ServiceBuilder(chromePath).build();
chrome.setDefaultService(service);
var chromeDriver = new webdriver.Builder()
.withCapabilities(webdriver.Capabilities.chrome())
.build();
var frameHandler = new FrameHandler(chromeDriver);
//check current frame name
frameHandler.getCurrentFrameName(function (name) {
console.log(name + ' current frame inside second function');
});
chromeDriver.get('http://orasi.github.io/Selenium-Java-Core/sites/unitTests/orasi/utils/frameHandler.html').then(function () {
frameHandler.switchToFrame('top_page').then(function () {
frameHandler.switchToFrame('main_page').then(function () {
frameHandler.getCurrentFrameName(function (name) {
console.log(name + ' this frame was switched to ');
expect(name).to.equal('main_page');
done();
});
});
});
});
});
});
FrameHandler Object
var webdriver = require('selenium-webdriver');
var FrameHandler = function (driver) {
this.switchToFrame = function (name)
{
if (typeof name !== 'string' || name === '' || !name)
{
console.log('error');
}
else
{
console.log(this.getCurrentFrameName(function (name) {
console.log(name + ' this is the current frame before switch');
}));
console.log(name + ' switch to this frame');
return driver.switchTo().frame(name);
}
};
this.getCurrentFrameName = function (callback)
{
driver.executeScript('return self.name').then(function (name)
{
return callback(name);
});
};
};
module.exports = FrameHandler;
I haven't verified myself with your example, but the consensus is that you cannot switch directly to a nested <frame> from the top-level, you need to switch into a parent <frame> first.
In other words, into 'top_page', then into 'main_page'.
See the top answers to:
Unable to click with Selenium in nested frames
How to navigate a subframe inside a frameset using Selenium WebDriver?
After further testing and switching drivers I found that the chrome driver doesn't support nested framesets. I tried going from top_page to menu_page and also tried just going directly to the menu_page, neither worked. I tried all types of solutions and was unable to get anything to work until I switched from the chrome driver to ie or firefox. I also tried removing the nested frameset in the html file and then running the chrome driver, the test case passed. So this is in fact an issue with nested framesets and the chrome driver. I really need to get a fix for this as this can affect automation using the chrome driver.
everyone
I am working on some sort of image view application using node-webkit. I made a function to read dir inside the given location and search for the image files(*.jpg and *.png). Code I used is as follows:
app.js
var fs = require("fs");
var gui = require('nw.gui');
var win = gui.Window.get();
var directory;
var db = require('diskdb');
var path = require('path')
db = db.connect("lib/collections", ['temp']);
function chooseFile(name) {
var chooser = $(name);
scr = 0;
chooser.change(function(evt) {
directory = $(this).val();
var asdf;
console.clear();
readDir(directory);
$(this).val('').hide();
});
}
function readDir(directory){
c = 0;
console.log("reading "+directory);
if(fs.statSync(directory).isDirectory() == true){
fs.readdir(directory,function(err,files){
if (err){
console.log(err);
return;
}
var ext;
files.forEach(function(file){
console.log("Got what: "+file);
var fulls = directory+"\\"+file;
if(file.indexOf(".") != 0){
if(path.extname(fulls) == ""){
console.log("Got a directory: "+file);
if(fs.statSync(fulls).isDirectory() == true){
readDir(fulls);
}
}
else{
console.log("Got a file: "+file);
if(checkExtension(file, 'jpg,png')){
scr++;
c = saveTemp(fulls,scr,file);
}
}
}
});
if(c == 1){
loadgun();
}
});
}
}
function loadgun(){
if(db.temp.count()!=0){
for(i=1;i<=db.temp.count();i++){
var asd = db.temp.findOne({'id':i});
var theTempScript = $("#tmpl-imgholder").html();
var theTemp = Handlebars.compile(theTempScript);
$("#ContentWrapper").append(theTemp({"fulls":asd.file, "id":asd.id, "title":asd.title}));
}
}
}
saveTemp = function(file,id, title) {
var savedUser = db.temp.save({
file:file,
id:id,
title:title
});
return 1;
};
function checkExtension(str, ext) {
extArray = ext.split(',');
for(i=0; i < extArray.length; i++) {
if(str.toLowerCase().split('.').pop() == extArray[i]) {
return true;
}
}
return false;
};
$(document).ready(function(){
if(db.temp.count() != 0){
loadgun();
}
else{
$('#blah').css('display','block');
chooseFile('#blah');
}
});
index.html
<html>
.
.
.
<body>
<input type="file" nwdirectory id="blah" style="display:none"/>
<script src="js/jquery.min.js"></script>
<script src="js/app.js"></script>
<script src="js/handlebars.js"></script>
<script id="tmpl-imgholder" type="x-handlebars-template">
<div class="image-container grid__item" data-id="{{id}}" data-src="{{fulls}}">
<div class="cover" style="background:url({{fulls}})" title="{{title}}"></div>
<div class="info">
<div class="title">{{title}}</div>
</div>
<div class="clear"></div>
</div>
</script>
</body>
</html>
Here i tried to load data using loadgun function. Its hangs the node webkit window. If I could know when the readDir function terminates then i could do load the required datas.
If there is another way please do say.
Thanks in advance.
the problem with readDir is that is asynchronous function , that is why you have to provide a callback. you can however use fs.readdirSync(path) which is synchronous , and then the code flows synchronously. a psoducode may look like this :
function readDirAsynch(dir){
var files = fs.readdirSync(dir);
for (var i in files){
if (files[i] isDir){
readDirAsynch(files[i]);
} else if (myCondition){
//do somehting
}
}
}
needless to say , you know that the function is done when the next line after the function call is being executed
Quick answer:
You can use the synchrohous method fs.readdirSync(path) and everything should work just fine for you. You don't need to keep reading. https://nodejs.org/api/fs.html#fs_fs_readdirsync_path
My personal suggestion:
Since node is single threaded I would recommend you to keep using the asynchronous version but adding a callback to your method.
This means that your "readDir" method is going to be asynchronous too. You only need to add a callback parameter to your method. E.g.
readDir(dir, fnCallback) {
...
fs.readdir(directory, function(err,files){
... doing cool stuff ...
fnCallback();
});
}
If you want to read more about writing asynchronous code maybe this guide can help you.
http://callbackhell.com/
Also if you want to go further in the wonderful asynchronous world you can take a look to 'Promises' https://www.npmjs.com/package/node-promise, 'Future' https://www.npmjs.com/package/async-future, 'Async' https://www.npmjs.com/package/async and have more fun than you have ever imagined before.
I have written an extension for google chrome and I have a bug I need a help solving.
what I do is using either a text selection or an input of text search for photos on flickr and then create a results tab.
The extension works most of the times. but sometimes it creates a blank tab with no results and when I repeat the same search it then shows results. I figured that it's something to do with the html files messaging maybe something to do with them communicating. I have to say that I always receive the results from flickr so that the request/responce with flickr works ok. Sometimes the error happens when I play with other tabs or do something on other tabs while waiting for results. can you please help me figure out where's the fault?
the background file:
function searchSelection(info,tab){
var updated;
if(info.selectionText==null){
var value = prompt("Search Flickr", "Type in the value to search");
updated=makeNewString(value);
}
else{
updated=makeNewString(info.selectionText);
}
var resultHtml;
var xhReq = new XMLHttpRequest();
xhReq.open(
"GET",
"http://api.flickr.com/services/rest/?method=flickr.photos.search&text="+updated+
"&api_key=a0a60c4e0ed00af8d70800b0987cae70&content_type=7&sort=relevance&per_page=500",
true);
xhReq.onreadystatechange = function () {
if (xhReq.readyState == 4) {
if (xhReq.status == 200) {
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='auto';"});
var photos = xhReq.responseXML.getElementsByTagName("photo");
if(photos.length==0){
alert("No results found for this selection");
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='auto';"});
return;
}
var myJSPhotos=[];
for(var i=0; i<photos.length; i++){
var data={"id":photos[i].getAttribute("id"),"owner":photos[i].getAttribute("owner"),
"secret":photos[i].getAttribute("secret"),"server":photos[i].getAttribute("server"),
"farm":photos[i].getAttribute("farm"),"title":photos[i].getAttribute("title")};
myJSPhotos[i]=data;
}
chrome.tabs.create({"url":"results.html"},function(thistab){
var port= chrome.tabs.connect(thistab.id);
port.postMessage({photos:myJSPhotos});
});
}
};
};
xhReq.send(null);
chrome.tabs.executeScript(tab.id, {code:"document.body.style.cursor='wait';"});
}
var context="selection";
var id = chrome.contextMenus.create({"title": "search Flickr", "contexts":[context,'page'],"onclick":searchSelection});
results html: has only a reference to the js file res.js
res.js :
chrome.extension.onConnect.addListener(function(port) {
port.onMessage.addListener(function(msg) {
//*****//
var photos=msg.photos;
createPage(photos);
});
});
I have to mention that when the tab is empty if I put alert on the //*****// part it won't
fire.
but when I print out the photos.length at the tab create call back function part it prints out the correct result.
Try to set "run_at":"document_start" option for your res.js in the manifest.
I think callback from chrome.tabs.create is fired right away without waiting for page scripts to be loaded, so you might try something like this instead:
//global vars
var createdTabId = null;
var myJSPhotos = null;
xhReq.onreadystatechange = function () {
//assign myJSPhotos to a global var
chrome.tabs.create({"url":"results.html"},function(thistab){
createdTabId = thistab.id;
});
}
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "complete" && tab.id == createdTabId) {
createdTabId = null;
//now page is loaded and content scripts injected
var port = chrome.tabs.connect(tab.id);
port.postMessage({photos:myJSPhotos});
}
});