I'm writing a Tampermonkey script that I want to use to redirect from youtube.com/* to a YouTube channel address.
window.addEventListener ("load", LocalMain, false);
function LocalMain () {
location.replace("https://www.youtube.com/channel/*");
}
When the script is running it redirects to the channel URL but then keeps running and continuously redirects.
The standard, much more efficient, and much faster performing way to do this kind of redirect is to tune the script's metadata to not even run on the redirected-to page.
Also, use // #run-at document-start for even better response.
So your script would become something like:
// ==UserScript==
// #name YouTube, Redirect to my channel
// #match https://www.youtube.com/*
// #exclude https://www.youtube.com/channel/*
// #run-at document-start
// ==/UserScript==
location.replace("https://www.youtube.com/channel/UC8VkNBOwvsTlFjoSnNSMmxw");
Also, for such "broad spectrum" redirect scripts, consider using location.assign() so that you or your user can recover the original URL in the history in case of an overzealous redirect.
You could check to see if the location contains 'channel', then return before you change the location.
window.addEventListener ("load", LocalMain, false);
function LocalMain () {
if(location.href.indexOf('channel') === -1) return;
location.replace("https://www.youtube.com/channel/*");
}
You need to check if the current pathname includes channel before reassigning a new href
function LocalMain () {
if(!location.pathname.includes('/channel/')) {
location.replace("https://www.youtube.com/channel/*");
}
}
Also note you don't need to window load event to complete to do this
Is tampermonkey configured to run the script only when not on your channel URL?
If not... then your script might ironically be doing exactly what you want: running once each page load. And the script loads a new page.
You can fix this within the script, like this:
window.addEventListener ('load', localMain, false);
function localMain () {
if (location.href.startsWith('https://www.youtube.com/channel/')) {
return; // exit
}
location.replace('https://www.youtube.com/channel/*');
}
I have a userscript that refreshes the page every second, but sometimes the website it's trying to refresh runs into the status 503 error, and that stops the script from running anymore. That means that script will no longer try refresh the page every second. How do I keep the script running after the page runs into the status 503 error? The error looks like this in the console:
Failed to load resource: the server responded with a status of 503 (Service Unavailable)
// ==UserScript==
// #name script
// #namespace name
// #description example
// #match *^https://example.com/$*
// #version 1
// #require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// #grant GM_xmlhttpRequest
// #run-at document-end
// ==/UserScript==
//*****************************************START OF SET_TIMEOUT
var timeOne = 1000;
var theTime = timeOne;
var timeout = setTimeout("location.reload(true);", theTime);
function resetTimeout() {
clearTimeout(timeout);
timeout = setTimeout("location.reload(true);", theTime);
} //end of function resetTimeout()
//*****************************************END OF SET_TIMEOUT
The user-script run at page load, they won't run if page does not load at all for any status code other than 200. You can use <iframe> as #Hemanth suggested but you have to break the infinite loop as the <iframe> will also load the user-script and so on. To break it just check if the user-script is loaded on the top window.
if (window == window.top) {
// Remove everything from the page
// Add an iframe with current page URL as it's source
// Add an event to reload the iframe few seconds after it is loaded
}
Complete Code:
(function ($) {
'use strict';
var interval = 5000;
if (window == window.top) {
var body = $('body').empty();
var myframe = $('<iframe>')
.attr({ src: location.href })
.css({ height: '95vh', width: '100%' })
.appendTo(body)
.on('load', function () {
setTimeout(function () {
myframe.attr({ src: location.href });
}, interval);
});
}
})(jQuery);
Simple solution I could think of is to move the actual webpage that need to be refreshed every second to another frame or some HTML container and using your user script you could refresh or reload that container with the HTML page you want to refresh.
Unless you are making a http request to load webpage from your script it may not be possible to handle the http errors (I might be wrong!). Your user script should be at a superset level where it will have control or scope even after any 503 or any similar HTTP errors.
You could use Page state change events to ensure or to check to refresh the page in the frame/container has loaded or not to avoid reloading the webpage before it loads. Unless if you want to reload irrespective of webpage successfully loaded or not.
Hope this helps..
The problem is that location.reload attempts to completely replace the page with a reloaded version, but if the browser fails to connect to the server, the page will not be loaded, and any userscripts for that page will fail to run, because there's no page for them to run on.
A workaround would be to use a Javascript network request to fetch the text of the new page, and then replace the existing content with the new content with Javascript - if the response is a 503 error (or some other error), you can simply ignore it and try again. This ensures that you'll always stay on the same (loaded) page, so the userscript will continue running indefinitely, even if the responses sometimes fail.
Here's an example of a userscript that updates StackOverflow's homepage every 10 seconds with new HTML. You can use DOMParser to transform response text into a document that can be navigated with querySelector, among other things:
// ==UserScript==
// #name Update SO
// #namespace CertainPerformance
// #version 1
// #match https://stackoverflow.com/
// #grant none
// ==/UserScript==
const container = document.querySelector('.container');
function getNewData() {
console.log('getting new data');
fetch('https://stackoverflow.com',
{
// The following is needed to include your existing cookies with the request, which may be needed:
credentials: "same-origin"
})
.then((resp) => {
// If there are errors, such as a 503 error, proceed directly to the `finally` to try again:
if (!resp.ok) return;
return resp.text();
})
.then((text) => {
const doc = new DOMParser().parseFromString(text, 'text/html');
container.innerHTML = doc.querySelector('.container').innerHTML;
})
.finally(() => {
// Whether there was an error or not, try to refresh again in a few seconds:
setTimeout(getNewData, 10000);
});
}
setTimeout(getNewData, 10000);
I have an angularjs application running on tomcat, and behind a loadbalancer
If the app is requested via the loadbalancer with https, the balancer still requests the application internally via http, of course.
Problem: I'd like to hide one tab that shows mixed content in this case (because I have to embed external pdf links which do not support https, thus I'd like to hide them).
I cannot use $location.protocol() because the app is behind the loadbalancer and always only gets http.
Question: is there a chance I could detect if the browser is actually showing mixed content?
You can't detect it in the simple way. You can try to listen load event on iframe and set timeout, and when timeout triggered, block iframe because iframe didn't loaded like this (jsfiddle example):
checkMixedContent(urlToCheck, function(urlToCheck) {
// For example, change location
alert('ok');
// load iframe
}, function() {
alert('Error: resource timed out');
// hide iframe / show message
}, checkDelay);
function checkMixedContent(urlToCheck, successCallback, errorCallback, checkDelay, dontCheckOnError) {
checkDelay = checkDelay || 10000;
// 1. Create invisible iframe and append it to body
var iframeHelper = document.createElement("iframe");
iframeHelper.src = urlToCheck;
iframeHelper.height = 0;
iframeHelper.width = 0;
iframeHelper.style.visibility = 'hidden';
document.body.appendChild(iframeHelper);
// 2. Set time out and while content on iframeHelper.src should be definitely loaded
var checkTimeout = window.setTimeout(function() {
errorCallback(urlToCheck);
}, checkDelay);
var onLoad = function() {
window.clearTimeout(checkTimeout); // if OK - not show error => clearTimeout
iframeHelper.removeEventListener('load', onLoad);
iframeHelper.removeEventListener('error', onError);
document.body.removeChild(iframeHelper);
successCallback(urlToCheck);
};
var onError = function() {
window.clearTimeout(checkTimeout); // if OK - not show error => clearTimeout
iframeHelper.removeEventListener('load', onLoad);
iframeHelper.removeEventListener('error', onError);
document.body.removeChild(iframeHelper);
errorCallback(urlToCheck);
};
// 3. If everything is fine - "load" should be triggered
iframeHelper.addEventListener('load', onLoad);
// Turn "true" in case of "X-Frame-Options: SAMEORIGIN"
if (!dontCheckOnError) {
iframeHelper.addEventListener('error', onError);
}
}
For some reason my ISP is blocking the following URL:
http://assets.tumblr.com/javascript/prototype_and_effects.js
Chrome console states:
Failed to load resource: the server responded with a status of 403 (URLBlocked)
The result is I can't use Tumblr properly because many functions depend on this script. I have already contacted my ISP and asked them to stop blocking this URL, but meanwhile I would like to do something about it.
How can I load this resource externally? It could be a bookmarklet solution, userscript/Greasemonkey or any other thing you can think of.
A 403 status means that the server (assets.tumblr.com) blocked the request, not your ISP. The most common reasons a server does this are (a) because you've not logged in with sufficient access, and/or (b) The server didn't receive the referrer header and/or cookies it wanted, and/or (c) the request came from an IP address that the server has blacklisted. Using a proxy server can trigger any or all of these for some sites.
This means that if you, or your proxy server, are being blocked from that file, then the standard methods of injecting remote javascript, that a userscript would use, will also be blocked.
To get around this Greasemonkey can backfill the javascript file from a local copy. To do this:
Create the file, Insure Tumbler has prototype.user.js, as shown below. Place it in a directory that is not in a temp folder on your machine.
Download the prototype_and_effects.js file you referenced and place it in the same folder. You may have to use a different (or no proxy), or a different browser profile, or whatever. (It downloads just fine, for me, just by right-clicking the immediately-preceding link.)
Install the script with Greasemonkey. (Firefox: File -> Open (CtrlO) will work.)
The script tests for the Prototype and Effect libraries and loads them locally if one is missing. There may be more required to get Tumblr working again but, if so, that is beyond the scope of this question.
Works in Firefox+Greasemonkey. Should work in Chrome+Tampermonkey (not tested), Will not work where #resource is not supported, such as straight Chrome.
// ==UserScript==
// #name _Backfill Prototype and Effect libraries on Tumblr pages
// #match http://tumblr.com/*
// #match http://www.tumblr.com/*
// #match https://tumblr.com/*
// #match https://www.tumblr.com/*
// #resource PandE_src prototype_and_effects.js
// #grant GM_getResourceText
// ==/UserScript==
//-- Does this page load prototype_and_effects.js?
var protoScriptNode = document.querySelector ("script[src*='prototype_and_effects']");
if (protoScriptNode) {
//console.log ("Page uses prototype_and_effects.js.");
//-- Are Prototype and Effects loaded?
var P = unsafeWindow.Prototype;
var E = unsafeWindow.Effect;
if (P && P.Version && E && E.BlindDown) {
//console.log ("Everything's loaded, no action needed.");
}
else {
//console.log ("Loading prototype_and_effects.js");
var PandE_src = GM_getResourceText ("PandE_src");
var scriptNode = document.createElement ('script');
scriptNode.type = "text/javascript";
scriptNode.textContent = PandE_src;
var targ = document.getElementsByTagName ('head')[0];
targ.appendChild (scriptNode);
}
}
else {
//-- No action needed
//console.log ("Page doesn't use prototype_and_effects.js.");
}
I am trying to monitor a website (www.bidcactus.com). While on the website I open up Firebug, go to the net tab, and click the XHR tab.
I want to take the responses of the requests and save it to a mySql database (I have a local one running on my computer(XAMPP).
I have been told to do a variety of things mainly using jQuery or JavaScript but I'm not experienced either so I was wondering if anyone can help me out here.
Someone suggested me this link
Using Greasemonkey and jQuery to intercept JSON/AJAX data from a page, and process it
Its using Greasemonkey as well which I don't know much about either...
Thanks in advance for any help
Example/more detail:
While monitoring the requests sent(via firebug) I see below
http://www.bidcactus.com/CactusWeb/ItemUpdates?rnd=1310684278585
The response of this link is the following:
{"s":"uk5c","a":[{"w":"MATADORA","t":944,"p":5,"a":413173,"x":10},
{"w":"1000BidsAintEnough","t":6,"p":863,"a":413198,"x":0},
{"w":"YourBidzWillBeWastedHere","t":4725,"p":21,"a":413200,"x":8},
{"w":"iwillpay2much","t":344,"p":9,"a":413201,"x":9},
{"w":"apcyclops84","t":884,"p":3,"a":413213,"x":14},
{"w":"goin_postal","t":165,"p":5,"a":413215,"x":12},
{"w":"487951","t":825,"p":10,"a":413218,"x":6},
{"w":"mishmash","t":3225,"p":3,"a":413222,"x":7},
{"w":"CrazyKatLady2","t":6464,"p":1,"a":413224,"x":2},
{"w":"BOSS1","t":224,"p":102,"a":413230,"x":4},
{"w":"serbian48","t":62,"p":2,"a":413232,"x":11},
{"w":"Tuffenough","t":1785,"p":1,"a":413234,"x":1},
{"w":"apcyclops84","t":1970,"p":1,"a":413240,"x":13},
{"w":"Tuffenough","t":3524,"p":1,"a":413244,"x":5},
{"w":"Cdm17517","t":1424,"p":1,"a":413252,"x":3}],"tau":"0"}
I understand what this information and I think I could format it myself however the website randomly creates new requests.
Example http://www.bidcactus.com/CactusWeb/ItemUpdates?rnd=XXXXXXXXXXXX
and I'm not sure how it creates them.
So I'm needing to get the response for all the requests that are for item updates and send the information to a mysql database.
OK, here's working code, somewhat tuned for that site (front page, no account, only).
Instructions for use:
Install the GM script. Note that it is Firefox only, for now.
Observe it running in Firebug's console, and tune the filter section (clearly marked), to target the data you are interested in. (Maybe the whole a array?)
Note that it can take several seconds after "Script Start" is printed, for the ajax intercepts to start.
Setup your web application and server to receive the data. The script posts JSON, so PHP, for example, would grab the data, like so:
$jsonData = json_decode ($HTTP_RAW_POST_DATA);
Point the script to your server.
VoilĂ . She is done.
/******************************************************************************
*******************************************************************************
** This script intercepts ajaxed data from the target web pages.
** There are 4 main phases:
** 1) Intercept XMLHttpRequest's made by the target page.
** 2) Filter the data to the items of interest.
** 3) Transfer the data from the page-scope to the GM scope.
** NOTE: This makes it technically possibly for the target page's
** webmaster to hack into GM's slightly elevated scope and
** exploit any XSS or zero-day vulnerabilities, etc. The risk
** is probably zero as long as you don't start any feuds.
** 4) Use GM_xmlhttpRequest () to send the data to our server.
*******************************************************************************
*******************************************************************************
*/
// ==UserScript==
// #name _Record ajax, JSON data.
// #namespace stackoverflow.com/users/331508/
// #description Intercepts Ajax data, filters it and then sends it to our server.
// #include http://www.bidcactus.com/*
// ==/UserScript==
DEBUG = true;
if (DEBUG) console.log ('***** Script Start *****');
/******************************************************************************
*******************************************************************************
** PHASE 1 starts here, this is the XMLHttpRequest intercept code.
** Note that it will not work in GM's scope. We must inject the code to the
** page scope.
*******************************************************************************
*******************************************************************************
*/
funkyFunc = ( (<><![CDATA[
DEBUG = false;
//--- This is where we will put the data we scarf. It will be a FIFO stack.
payloadArray = []; //--- PHASE 3a
(function (open) {
XMLHttpRequest.prototype.open = function (method, url, async, user, pass)
{
this.addEventListener ("readystatechange", function (evt)
{
if (this.readyState == 4 && this.status == 200) //-- Done, & status "OK".
{
var jsonObj = null;
try {
jsonObj = JSON.parse (this.responseText); // FF code. Chrome??
}
catch (err) {
//if (DEBUG) console.log (err);
}
//if (DEBUG) console.log (this.readyState, this.status, this.responseText);
/******************************************************************************
*******************************************************************************
** PHASE 2: Filter as much as possible, at this stage.
** For this site, jsonObj should be an object like so:
** { s="1bjqo", a=[15], tau="0"}
** Where a is an array of objects, like:
** a 417387
** p 1
** t 826
** w "bart69"
** x 7
*******************************************************************************
*******************************************************************************
*/
//if (DEBUG) console.log (jsonObj);
if (jsonObj && jsonObj.a && jsonObj.a.length > 1) {
/*--- For demonstration purposes, we will only get the 2nd row in
the `a` array. (Probably stands for "auction".)
*/
payloadArray.push (jsonObj.a[1]);
if (DEBUG) console.log (jsonObj.a[1]);
}
//--- Done at this stage! Rest is up to the GM scope.
}
}, false);
open.call (this, method, url, async, user, pass);
};
} ) (XMLHttpRequest.prototype.open);
]]></>).toString () );
function addJS_Node (text, s_URL)
{
var scriptNode = document.createElement ('script');
scriptNode.type = "text/javascript";
if (text) scriptNode.textContent = text;
if (s_URL) scriptNode.src = s_URL;
var targ = document.getElementsByTagName('head')[0] || d.body || d.documentElement;
targ.appendChild (scriptNode);
}
addJS_Node (funkyFunc);
/******************************************************************************
*******************************************************************************
** PHASE 3b:
** Set up a timer to check for data from our ajax intercept.
** Probably best to make it slightly faster than the target's
** ajax frequency (about 1 second?).
*******************************************************************************
*******************************************************************************
*/
timerHandle = setInterval (function() { SendAnyResultsToServer (); }, 888);
function SendAnyResultsToServer ()
{
if (unsafeWindow.payloadArray) {
var payload = unsafeWindow.payloadArray;
while (payload.length) {
var dataRow = JSON.stringify (payload[0]);
payload.shift (); //--- pop measurement off the bottom of the stack.
if (DEBUG) console.log ('GM script, pre Ajax: ', dataRow);
/******************************************************************************
*******************************************************************************
** PHASE 4: Send the data, one row at a time, to the our server.
** The server would grab the data with:
** $jsonData = json_decode ($HTTP_RAW_POST_DATA);
*******************************************************************************
*******************************************************************************
*/
GM_xmlhttpRequest ( {
method: "POST",
url: "http://localhost/db_test/ShowJSON_PostedData.php",
data: dataRow,
headers: {"Content-Type": "application/json"},
onload: function (response) {
if (DEBUG) console.log (response.responseText);
}
} );
}
}
}
//--- EOF
Misc notes:
I tested it on the main page of that site, without logging in (I'm not about to to create an account there).
I tested with AdBlock, FlashBlock, NoSCript, and RequestPolicy all in full effect. JS was turned on for bidcactus.com (it has to be) but no others. Turning all that crud back on shouldn't cause side effects -- but if it does, I'm not going to debug it.
Code like this has to be tuned for the site and for how you browse said site1. It's up to you to do that. Hopefully the code is self-documented enough.
Enjoy!
1 Mainly: the #include and #exclude directives, the JSON data selection and filtering, and whether iFrames need to be blocked. Also it is recommended that the 2 DEBUG variables (one for GM scope and one for the page scope) be set to false when the tuning is done.
This isn't achievable with javascript/jquery's ajax request, because of Same origin policy
I'm not experienced with greasemonkey, through