Chrome-Extension : restart automatically extension through code - google-chrome-extension

I'm using Chrome Extension to scrape web sites and once in a while the Chrome Extension crashes. To reload the crashed extension, I have created another extension that reloads the crashed extension every X minutes.
It all worked fine until recently. The extension that I was using to restart the scraper did not restart the extension anymore while I haven't changed anything to it.
Here is a sample for the alarm:
chrome.alarms.get(alarmName, function(Alarm)
{
if (typeof Alarm === 'undefined')
{
console.log('is not defined');
chrome.alarms.create(alarmName,
{
periodInMinutes: 1
});
}
else
{
console.log('is defined');
}
});
and then the code to restart the extension:
chrome.alarms.onAlarm.addListener(async function( alarm )
{
var child = null;
chrome.management.getAll(function (info) {
for (var i=0; i < info.length; i++) {
if (info[i].name == 'MyScraper') {
child = info[i];
console.log(child);
chrome.management.setEnabled(child.id, true, function ()
{
console.log('Enabled '+Date.now());
});
break;
}
}
});
});
The code finds the extension correctly and display the child object, the content of this object is ok but once I try to reload it with setEnabled, the console outputs "Enable + time" but the scraping extension is not restarted. I don't get any error message.
The extension is running on a Raspberry Pi 4 with Chromium, it used to run on Windows before but I don't see why the code would not work anymore.
Any idea?
Thanks!

As I couldn't find a way to solve this through a Chrome Extension, I have installed xdotool and created a script that clicks on the reload button every 10 minutes. It's not super clean but at least it solves my issue.
Thanks

Related

How to debug chrome extension at such part of code?

The code below is the JavaScript file works with popup.html from a small project.
I use it for chrome extension development learning.
The first part of this code piece is getting two variable from chrome storage, let's call it part1.
The second part is a button-click event function,Let's call it part2.
The button is on popup page and called "spend".
In part2, I can set a breakpoint2 on chrome debugger DevTools,when I click the button on popup page, it will stop at breakpoint2.
But when I place a Breakpoint1 at part1,the code will not stop at that line, even I add one more line "debugger;", the program will not stop there.
So my problem is how to make the debugger stop at places like breakpoint1?
The source code for the extension:https://drive.google.com/file/d/1odxJy9pGnovzox2yXH-6MDO03_T7QIDE/view?usp=sharing
//popup.js
$(function(){
chrome.storage.sync.get(['total','limit'],function(budget){
//Breakpoint1
$('#total').text(budget.total);
$('#limit').text(budget.limit);
});
$('#spendAmount').click(function(){
//Breakpoint2
chrome.storage.sync.get(['total', 'limit'],function(budget){
var newTotal = 0;
if (budget.total){
newTotal += parseInt(budget.total);
}
var amount = $('#amount').val();
if (amount){
newTotal += parseInt(amount);
}
chrome.storage.sync.set({'total': newTotal}, function(){
bla();
bla();
}
});
$('#total').text(newTotal);
$('#amount').val('');
});
});
});
Any assistance is highly appreciated,Thanks in advance.

Detect end of a track's playback with Spotify Web API / Playback SDK

Working with Spotify Web API and Web Playback SDK, does anybody know a good way to detect when a track's playback has finished, i.e. the song is over?
I know about some event named player_state_changed in Web Playback SDK, but the data provided in the event doesn't seem to be very helpful to me.
In my web app, the next song to be played is determined pretty spontaneously. It would be nice, if I could determine it only, when the current track has reached its end. Hence, there is no playlist. Instead, the app plays single tracks in series and should determine the next song, when the current one has ended.
Meanwhile I try it with this code here:
var bCallingNextSong = false;
player.addListener('player_state_changed', state => {
if (state != null &&
state.position == 0 &&
state.duration == 0 &&
state.paused == true) {
if (!bCallingNextSong) {
playNextSong();
}
}
});
function playNextSong() {
$.ajax({
url:"playback.php", //the page containing php script
type: "post", //request type,
dataType: 'json',
data: {action: "next", device: deviceId},
success: function(result) {
bCallingNextSong = false;
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
bCallingNextSong = false;
}
});
}
and in playback.php:
switch ($action) {
case "next":
//some blackbox magic here to determine next song, do logging etc.
//but for now just play the same song over and over
$api->play($deviceId, ['uris' => "spotify:track:0eGsygTp906u18L0Oimnem"],]);
echo json_encode(array("answer"=>"played next"));
break;
// more code
}
However, this will often (but not always) throw an InvalidStateError (I haven't found out where exactly yet nor why). Stack says dequeueUpdates / tryUpdate / _processUpdate / _appendUpdate. Yet, I'm a beginner and I've gotta learn how to cope with Firefox Debugger first.. :)
My last answer got broken so I will now add new solution which work for now.
this.player.addListener('player_state_changed', (state) => {
console.log(state);
if (
this.state
&& state.track_window.previous_tracks.find(x => x.id === state.track_window.current_track.id)
&& !this.state.paused
&& state.paused
) {
console.log('Track ended');
this.setTrackEnd(true);
}
this.state = state;
});
So what is different from last solution? I check that current_track is in previous track list. But there was problem now with position check because it seems that current track appears to previous track list before track is completely end. But that wasn't problem in my app because there is always small delays with commands.
EDIT: This is not working anymore for some reason. Check my other answer which will work now. https://stackoverflow.com/a/51114848/8081009
Here is my solution. It works most of the time. Actually I didn't get it broken in any scenarios I can imagine. So hold last state and check that is it gone to paused state. Hopefully Spotify will ease our work with track ended event. It would be great if they does. This is still better than polling their /me/player/currently-playing endpoint for every 1 second or so.
this.player.addListener(
'player_state_changed',
state =>
{
console.log(state);
if(this.state && !this.state.paused && state.paused && state.position === 0) {
console.log('Track ended');
this.setTrackEnd(true);
}
this.state = state;
}
);
I had this same problem, this is how I solved it.
When a song finish playing it gets added to the state.track_window.previous_tracks list
state.track_window.previous_tracks gets populated only if there is a next track and it starts playing
But every time you call the api to play a new track, it clears the state.track_window.previous_tracks & state.track_window.next_tracks list.
If there is a next track, I want to stop and choose my own next track and then call the api
var alreadyPlayed = state.track_window.previous_tracks
if(alreadyPlayed.length > 0) {
player.pause()
}
if there is no next track the player will be paused when the song finish
if(state.paused && state.position === 0) {
//song ended
ChooseNextSong()
}
the state callback gets fired many times but I want to call ChooseNextSong()
only once, so I increment startCheck every time it fires
if(state.paused && state.position === 0) {
//song ended
startCheck++
if(startCheck === 1) {
ChooseNextSong()
}
}
check if song started
if(state.position === 0 && alreadyPlayed.length === 0 && !state.paused)
{
//song started
startCheck = 0
}
You should use the player_state_changed event and look at which track is playing to see if the track has changed. You can find the current track in playerStateObject.track_window.current_track.
A possible implementation could look like this:
let currentTrack = '';
player.on('player_state_changed', state => {
if( state.track_window.current_track.id != currentTrack ) {
// The track changed!
currentTrack = state.track_window.current_track.id;
}
});

Firefox doesn't wait for a page load Webdriverio

I am trying to run my test using Selenium and just encountered the problem. I have my test written for the Chrome browser. Now I have been trying to run the same tests in the Firefox browser, but they failed.
I've started to investigate the problem and found out that Firefox doesn't wait until page is fully loaded. Chrome works perfectly.
I am running Selenium in docker containers.
Here is my script
storeSearch(info) {
let that = this;
return new Promise(function (resolve, reject) {
browserClient.init()
.url("http://somewhere.com")
.selectByVisibleText("#store","Tech")
// Redirect to a new page
.setValue("input[name='search']", info.searchCriteria)
.selectByValue(".featured", 'MacBook')
.click("button[name='info']")
.element('.popup')
.then(function (element) {
if (element.state === 'success') {
}
});
});
}
It doesn't try even to select a store type from the select .selectByVisibleText("#store","Tech") and just throws an exception.
"An element could not be located on the page using the given search
parameters (\"input[name='search']\").",
I have tried to add timeouts but it doesn't work as well and gives me an error.
browserClient.init()
.url("http://somewhere.com")
.timeouts('pageLoad', 100000)
.selectByVisibleText("#store","Tech")
The following error is thrown.
"Unknown wait type: pageLoad\nBuild info: version: '3.4.0', revision:
'unknown', time: 'unknown'\nSystem info: host: 'ef7581676ebb', ip:
'172.17.0.3', os.name: 'Linux', os.arch: 'amd64', os.version:
'4.9.27-moby', java.version: '1.8.0_121'\nDriver info: driver.version:
unknown
I have been trying to solve this problem for two days, but no luck so far.
Could someone help, maybe you have some ideas what can cause the problem ?
Thanks.
UPDATE
.url("http://somewhere.com")
.pause(2000)
.selectByVisibleText("#store","Tech")
If I put some pause statements it works, but this is really bad and not what I expect from this framework. Chrome works perfectly. It waits until loading bar is fully loaded and only then performs actions.
The problem is in geckodriver I guess, I have tested it the same flow in Python, Java and the behavior is exactly the same.
I am experiencing the exact behavior you detailed above, all-green/passing test cases in Chrome, but on Firefox, a different story.
First off, never use timeouts, or pause in your test cases unless you are debugging. In which case, chaining a .debug() previously to your failing step/command will actually do more good.
I wrapped all my WDIO commands in waitUntill() and afterwards, I saw green in Firefox as well. See your code bellow:
storeSearch(info) {
let that = this;
return new Promise(function (resolve, reject) {
browserClient.init()
.url("http://somewhere.com")
.waitUntil(function() {
return browser
.isExisting("#store");
}, yourTimeout, "Your custom error msg for this step")
.selectByVisibleText("#store","Tech")
// Redirect to a new page
.waitUntil(function() {
return browser
.setValue("input[name='search']", info.searchCriteria);
}, yourTimeout, "Your custom error msg for this step")
.waitUntil(function() {
return browser
.selectByValue(".featured", 'MacBook');
}, yourTimeout, "Your custom error msg for this step")
.waitUntil(function() {
return browser
.click("button[name='info']");
}, yourTimeout, "Your custom error msg for this step")
.waitUntil(function() {
return browser
.isExisting(".popup");
}, yourTimeout, "Your custom error msg for this step")
.element('.popup')
.then(function (element) {
assert.equal(element.state,'success');
});
});
}
It's not pretty, but it did the job for me. Hopefully for you as well.
Enhancement: If you plan on actually building & maintaining a strong automation harness using WDIO, then you should consider creating custom commands that package the waiting & make your test cases more readable. See bellow an example for .click():
commands.js:
module.exports = (function() {
browser.addCommand('cwClick', function(element) {
return browser
.waitUntil(function() {
return browser.isExisting(element);
}, timeout, "Oups! An error occured.\nReason: element(" + element + ") does not exist")
.waitUntil(function() {
return browser.isVisible(element);
}, timeout, "Oups! An error occured.\nReason: element(" + element + ") is not visible")
.waitUntil(function() {
return browser.click(element);
}, timeout, "Oups! An error occured.\nReason: element(" + element + ") could not be clicked")
});
})();
All that's left to do, is import your module via require() in your test case file: var commands = require('./<pathToCommandsFile>/commands.js');
You can use code in javascript which will be waiting for state of website.
In C# looks like this:
public void WaitForPage(IWebDriver driver, int timeout = 30)
{
IWait<IWebDriver> wait = new WebDriverWait(driver, TimeSpan.FromSeconds(timeout));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
}
I've run into quite a few issues like this with Selenium in Python and C#, unfortunately both in the Chrome and Firefox webdrivers. The problem seems to be that the code gets ahead of itself and tries to reference elements before they even exist/are visible on the page. The solution I found in Python at least was to use the Wait functions like this: http://selenium-python.readthedocs.io/waits.html
If there isn't an equivalent in node, you might have to code a custom method to check the source every so often for the presence of the element in x intervals over time.

Chrome extension delay condition

I have created a chrome extension which does something after its button is clicked.
However I dont want it be abused so I need the its code to be executed after some time.
How can I surround this code with a timeout in order to achieve this?
Thank you for reading me!
chrome.tabs.getSelected(null,function(tab) {
var Mp=tab.url.substring(0,23);
if(Mp=='https://www.example.com')
{
onWindowLoad();
chrome.extension.onMessage.addListener(function(request, sender) {
if (request.action == "getSource")
{
...Working here
}
});
}
else
{
message.innerHTML='<span style="color: #f00">This is not a valid page</span>';
}
});
function onWindowLoad()
{
var message = document.querySelector('#message');
chrome.tabs.executeScript(null, {file: "getPagesSource.js"});
}
I had to make a compromise so just after the getSelected I added the following line:
chrome.browserAction.disable(tab.Id);
It disables the action button thus it cant be clicked while the script sends the data to the server, as with this extension I grab the tab url in order to store it in my database.
After the ajax response and adding the following
if(xhr.readyState==4)
{
message.innerHTML=xhr.responseText;
chrome.browserAction.enable(tab.Id); /////<---THAT LINE
}
the button gets ready again to be clicked.
I couldnt find the way to add a specific delay in seconds, this way seems stupid but its working, as the response's delay from my server is enough for switching the 2 states of the action button.
With this, however another problem came up, which Ill write in different question.

How to detect when action popup gets closed?

I want to trigger some code when page action or browser action popup gets closed. I tried listening to onunload and onbeforeunload events on <body> or window but they never fire.
It's a bug, but a chromium developer posted a workaround.
http://crbug.com/31262#c13
As looks like there is no straight forward solution, this is what I ended up doing if anyone interested.
Periodically ping background page from the popup, and if background page is not received ping within some time period, it triggers required action. Works like a time bomb :)
In background page:
var timeoutId = 0;
function popupPing() {
if(timeoutId != 0) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(function() {
popupClosed();
timeoutId = 0;
}, 1000);
}
function popupClosed() {
//...
}
In popup:
ping();
function ping() {
chrome.extension.getBackgroundPage().popupPing();
setTimeout(ping, 500);
}
(note that popup pings 2 times faster than "trigger" time in background page)

Resources