Chrome extension: Can't make chrome.desktopCapture.chooseDesktopMedia capture window audio - google-chrome-extension

I'm trying to use the chrome.desktopCapture.chooseDesktopMedia API in order to capture audio from the extension window.
I'm sending the capture request from the popup.js page.
Manifest:
{
"background": {
"scripts": [ "background.js" ]
},
"browser_action": {
"default_icon": "style/icons/icon16.png",
"default_title": "__MSG_name__"
},
"default_locale": "en",
"description": "__MSG_description__",
"icons": {
"128": "style/icons/icon128.png"
},
"manifest_version": 2,
"name": "__MSG_extName__",
"permissions": ["activeTab","desktopCapture"],
"offline_enabled": true,
"short_name": "__MSG_short__",
"version": "1.0.9"
}
function:
chrome.desktopCapture.chooseDesktopMedia(["window"], function (streamId) {
var audioStream = navigator.mediaDevices.getUserMedia({
audio: true,
chromeMediaSource: 'desktop',
chromeMediaSourceId: streamId
});
audioStream.then(function (mediaStream) {...}
I have tried using different parameters, but whenever I omit: audio:true, I get :
Failed to execute 'getUserMedia' on 'MediaDevices': At least one of
audio and video must be requested(…).
The following code doesn't appear in the API, but I've read about it here and tried it, the previous error applies to it as well:
audio: {
mandatory: {
chromeMediaSource: 'desktop',
chromeMediaSourceId: streamId
}
}
When I do use audio:true, it records the mic, even though I get the source window selection dialog.
What am I doing wrong?

After experimenting with the code a bit, it seems to me like the only way to capture the system audio is through the video parameter. I wasn't able to capture a non-mic audio using the audio parameter. The screen recorder app is doing the same thing - system audio is recorded through the video.

Related

Enable Chrome extension action button only on one host

I've been trying to migrate one of my Chrome extensions to manifest v3, and I'm having trouble with the page_action. In manifest v3, the page_action and browser_action are merged into action, which is all good, but it's not clear to me how I can get the behavior I had previously with the new APIs.
A bit of background; the extension in question is only supposed to run on one host (let's say https://example.com). As such, I want to grey out the icon on pages with a different host. It has a popup with some settings but the main functionality is inserted via a content script (this works).
The old extension using manifest v2 used
{
"manifest_version": 2,
"name": "...",
"description": "...",
"version": "...",
"permissions": ["declarativeContent", "storage", "https://example.com/", "tabs"],
"page_action": {
"default_icon": { ... },
"default_popup": "popup.html"
},
"background": {
"scripts": ["background.js"],
"persistent": false
},
"icons": { ... },
"content_scripts": [{
"js": ["content.js"],
"matches": ["https://example.com/*", "https://www.example.com/*"]
}]
}
and in background.js I used
chrome.runtime.onInstalled.addListener(function(){
const pageUrl = {hostEquals: 'www.example.com'};
const {
onPageChanged,
PageStateMatcher,
ShowPageAction
} = chrome.declarativeContent;
onPageChanged.removeRules(undefined, function(){
onPageChanged.addRules([{
conditions: [new PageStateMatcher({pageUrl})],
actions: [new ShowPageAction()]
}]);
});
});
this works fine and the icon gets greyed out except on https://example.com. When migrating, the manifest looks like
{
"manifest_version": 3,
"name": ...,
"description": ...,
"version": ...,
"permissions": ["storage", "tabs", "declarativeContent", "activeTab"],
"background": {"service_worker": "service-worker.js"},
"action": {
"default_icon": { ... },
"default_popup": "popup/index.html"
},
"icons": { ... },
"content_scripts": [{
"matches": ["*://*.example.com/*"],
"js": ["content/detect-theme.js"]
}]
}
I cannot seem to get this to work properly. I've tried adding host_permissions, removing the declarativeContent-related code (as it doesn't seem to affect the icon whatsoever) but the extension stays available on all hosts. I know I can use the chrome.action.enable and chrome.action.disable methods to simulate this behavior but it seems overkill for such a simple use-case.
Actually, the action being available even on other pages is not breaking by any means, but I would like to make it more clear to my users that the extension only does things on https://example.com and nowhere else. Perhaps this is not even the right approach; if it isn't, I accept that as an answer as well.
TLDR; how do I only enable the (page-)action on a specific host with manifest v3?
Had the same issue myself, and I just solved it!
I fixed it by disabling the extension in the handler before adding the activation rule. I've removed the actual handler for brevity.
chrome.runtime.onInstalled.addListener(() => {
chrome.action.disable(); // The important line!
// actual handler...
});
I would guess that ShowPageAction doesn't disable the extension by default anymore.

Script doesn't fully execute in Chrome Extension

Hopefully this is something simple. I'm testing a simple Chrome Extension script and it appears it'll execute part of the script, but won't complete it. For example, if I add an alert() to the beginning of a script, it will execute the alert. But if I place it after anything calling the chrome DOM object, it won't execute. Here's an example:
Will execute alert
alert("Test");
chrome.webRequest.onCompleted.addListener(function (request) { });
Will not execute alert
chrome.webRequest.onCompleted.addListener(function (request) { });
alert("Test");
Am I missing something?
Here is my manifest:
{
"background": {
"persistent": true,
"scripts": [
"scripts/libs/jquery.1.11.2.min.js",
"scripts/background.js"
]
},
"browser_action": {
"default_icon": "resources/icon.19.png"
},
"icons": {
"48": "resources/icon.48.png"
},
"manifest_version": 2,
"name": "Test",
"permissions": [
"<all_urls>",
"webNavigation",
"webRequest",
"webRequestBlocking"
],
"version": "1.0"
}
You are missing debugging it yourself.
Go to chrome://extensions/ and load the Dev Tools for your background page. You will see an uncaught exception that stops execution.
For webRequest events, you must include a filter argument to the addListener function.

Simple Chrome Content Script Not Running

I wrote a short content script, which stops a particular site from creating new windows for link clicks.
This is my first Chrome extension, and I've scored this website and the internet for a reason why it won't run, but I can't find any. I'm probably making a fundamental amateur mistake somewhere.
Manifest.json:
{
"manifest_version": 2,
"name": "DHS Links",
"description": "Stops the school's site from constantly opening new windows.",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"content_scripts":[
{
"matches": ["*://www.darienps.org/dhs/*"],
"js": ["jquery.js", "makeNormalLinks.js"],
"run_at": "document_end"
}
]
}
I tested the Javascript file by itself on a local version of the site, so I'm pretty sure it's fine, but just in case:
makeNormalLinks.js:
$(document).ready(function() {
$("a").each(function(){
$(this).removeAttr("onclick");
});
});
A copy of jQuery is in the same directory and doesn't seem to have any issues.
Here's the onclick code for many links on the website:
onclick="window.open(this.href,'targetWindow','toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable=yes,')
Thank you for looking this over!
Edit:
I tried two of the injection methods from Rob W's response to another question linked to in the comments by Teepeemm.
Here's the new code for Method 1:
Manifest.json:
{
"manifest_version": 2,
"name": "DHS Links",
"description": "Stops the school's site from constantly opening new windows.",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"content_scripts":[
{
"matches": ["*://www.darienps.org/dhs/*"],
"js": ["jquery.js", "scriptLauncher.js"]
}
],
"web_accessible_resources": ["makeNormalLinks.js"]
}
scriptLauncher.js:
var s = document.createElement('script');
// TODO: add "script.js" to web_accessible_resources in manifest.json
s.src = chrome.extension.getURL('makeNormalLinks.js');
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
Method 2a:
(Uses old Manifest.js)
makeNormalLinks.js:
var actualCode = ['$(document).ready(function(){',
'$("a").each(function(){',
'$(this).removeAttr("onclick");',
'});',
'});'].join('\n');
var script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
Unfortunately, neither method seems to work. I'm extremely grateful to those who commented and think we're getting close to an answer.
Solution:
Manifest.json:
{
"manifest_version": 2,
"name": "DHS Links",
"description": "Stops the school's site from constantly opening new windows.",
"version": "1.0",
"browser_action": {
"default_icon": "icon.png"
},
"content_scripts":[
{
"matches": ["*://www.darienps.org/dhs/*"],
"js": ["makeNormalLinks.js"]
}
]
}
makeNormalLinks.js:
document.addEventListener("click", function(e) {
e.stopPropagation();
}, true);
Thanks you, Scott and all who commented!
Using the onclick attribute has many weird side effects. A more up to date approach would be to add a listener to the document that filters unwanted events. Like:
document.addEventListener("click", function(e) {
e.stopPropagation();
}, true);
The true argument is important (see event capture). This will block all click event listeners from firing, but the default click action will still be triggered.
I was having a similiar issue getting the content script to fire in Google Mail. I stumbled upon a page that recommended using the "hashchange" event.
// Event listener
window.addEventListener("hashchange", function () {
alert("hashchanged");
}, false);

chrome extension background page sock.js Socket connection lost on OSX sleep

My current client is a radio station.
They use sockets to push data.
Some examples
song play (contains song info, thumb, playlists, artist info and
more)
program start (program info, dj's and more)
The extention I built has a socket listening script built in.
https://chrome.google.com/webstore/detail/q-music-nl/mhobnnhfmhcnomoehjomodcjmcjhfaea
The socket listening is done via "SockJS client, version 0.3.4, http://sockjs.org, MIT License".
This is built in the back.html like so:
MANIFEST
{
"manifest_version": 2,
"name": "NAME",
"description": "DESC",
"version": "3.1",
"icons": {
"128": "logo_128.png"
},
"permissions": [
"notifications"
],
"browser_action": {
"name": "Click to start",
"default_icon" : "Q.png",
"default_popup": "popup.html"
},
"background": {
"page": "back.html"
},
"options_page": "options.html"
}
BACK.HTML
<script src="back.js">
</script>
BACK.JS
function init() {
(function(){
var a = document.createElement('script');
a.type = 'text/javascript';
a.async = true;
a.src = 'sock.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(a, s);
})();
}
window.onload = init;
This works perfect!
The problem is after resuming my MAC (Software OS X 10.8.4 (12E55)) from sleep the connection seems to be lost.
No loggings in back html console, no other indications, just no communication over the wire anymore.
The pushes are there however.
What am I doing wrong?
*edit you may email me for the full source code of the extension.

How to open my Chrome Extension in new Tab?

Hi I have found other similiar questions on stackoverflow but none of them solved the purpose.
I want my chrome extension/app to be opened in a full tab like how POSTMAN extension is opened.
My manifest.json
{
"name": "Sample App",
"manifest_version": 2,
"version": "0.0.1",
"app": {
"background": {
"scripts": ["main.js"]
}
},
"icons": { "128": "icon.png" },
"permissions" : ["tabs" ]
}
My main.js (alias for background.js)
chrome.app.runtime.onLaunched.addListener(function() {
chrome.tabs.create({'url': chrome.extension.getURL('index.html')}, function(tab) {
alert("Hi");
});
});
index.html is the file i want to load on opening the new tab.
My first time responding here on stackoverflow, please be gentle...
I discovered that it's much easier to add "launch" : { "local_path" : "index.html" } within the manifest.json file. See my sample manifest file below.
{
"manifest_version" : 2,
"name": "Hello World!",
"description": "My first Chrome App.",
"version": "0.1",
"app": {
"launch" : {
"local_path" : "index.html"
}
},
"icons": { "16": "icon.png" }
}
Keep in mind that this example is very basic, it has been stripped of some unnecessary information such as a background script but it should accomplish what you want.
http://developer.chrome.com/apps/first_app.html
chrome.app.runtime.onLaunched is only for Chrome apps, not extensions. The code for your background page will automatically run when the Chrome browser starts, so you can start directly with chrome.tabs.create(...).
Also, you need to include index.html and any resource included in your extension that the page will use in a web_accesible_resources section in your manifest.

Resources