Youtube QR Code Generation UserScript not functioning - javascript

I'm trying to create a userscript that automatically adds a QR code image of the current url to the 'Share' menu on a youtube video page.
I know next to nothing of JavaScript, UserScript, HTML, etc.
But, this is what I have so far:
// ==UserScript==
// #name Youtube QR ShareLink
// #description Displays QR of youtube URL
// #version 0.1
// #match http://www.youtube.com/watch*
// #match https://www.youtube.com/?*
// #match http://www.youtube.com/?*
// #match https://www.youtube.com/watch*
// #include http://www.youtube.com/?*
// #include http://www.youtube.com/watch*
// #include https://www.youtube.com/?*
// #include https://www.youtube.com/watch*
// ==/UserScript==
(function () {
var shareDiv = document.getElementById('share-option-container ytg-box');
var qrIMG = 'http://chart.googleapis.com/chart?chl=' + window.location.href + '&chld=M%7C0&cht=qr&chs=125x125';
var img = document.createElement('qrcode');
img.src=qrIMG;
img.width=125;
img.height=125;
shareDiv.appendChild(img);
}());
Unsurprisingly, it doesn't work.
Could anyone please tell me what it is I'm doing wrong?
Thank you!

You're using document.getElementById with a value that isn't the id of the box - it's a list of the classes for that element. To use a selector like that, you could do it with a couple of calls to document.getElementsByClassName, or you could use document.querySelector('.share-option-container .ytg-box'), or you could use jQuery to perform that selection.
Your second problem is that you're creating an element called 'qrcode', but you should be creating an img element.
You're revised code should look like this:
// ==UserScript==
// #name Youtube QR ShareLink
// #description Displays QR of youtube URL
// #version 0.1
// #match http://www.youtube.com/watch*
// #match https://www.youtube.com/?*
// #match http://www.youtube.com/?*
// #match https://www.youtube.com/watch*
// #include http://www.youtube.com/?*
// #include http://www.youtube.com/watch*
// #include https://www.youtube.com/?*
// #include https://www.youtube.com/watch*
// ==/UserScript==
(function () {
var shareDiv = document.querySelector('.share-option-container .ytg-box');
var qrIMG = 'http://chart.googleapis.com/chart?chl=' + window.location.href + '&chld=M%7C0&cht=qr&chs=125x125';
var img = document.createElement('img');
img.src=qrIMG;
img.width=125;
img.height=125;
shareDiv.appendChild(img);
}());
Note that on YouTube, the element that you're grabbing doesn't exist until the share box is actually opened, so you'll need to actually handle opening the share box first before the rest of your code runs. I've tested this in my browser and the above code works well once the share box has been opened, but not before.
You can account for that by using a timer. Change the code to:
var shareBoxCheckInterval = setInterval (AddQR_Code, 200);
function AddQR_Code () {
var shareDiv = document.querySelector ('.share-option-container .ytg-box');
if (shareDiv) {
var qrIMG = 'http://chart.googleapis.com/chart?chl='
+ window.location.href + '&chld=M%7C0&cht=qr&chs=125x125';
var img = document.createElement ('img');
img.src = qrIMG;
img.width = 125;
img.height = 125;
shareDiv.appendChild (img);
/*-- If you want to continually check for new share boxes, on the
same page, comment out this next line.
*/
clearInterval (shareBoxCheckInterval);
}
}

Related

getting the images that load in a page dynamically

I'd like to get all the images in a facebook newsfeed as it is loaded. I'm running a tampermonkey script. I'm having a few problems:
the end result is including in the images with urls that I'm excluding (with facebook static urls).
it only includes some of the images in the newsfeed, and if i scroll down it does not re-evaluate its outputs. This is probably because of the load function, but how can I make it a dynamic load instead? Where could I add a function like .scroll for example?
I'm using jquery to run the functions only when the page is loaded. Should I do something else instead?
Below is some part of the code:
// ==UserScript==
// #name Accountability
// #namespace http://tampermonkey.net/
// #include https://www.facebook.com/*
// #include http*://*.facebook.com/*
// #exclude htt*://*static*.facebook.com*
// #version 0.1
// #description
// #author You
// #match http://tampermonkey.net/scripts.php
// #grant none
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// ==/UserScript==
/* jshint -W097 */
'use strict';
window.addEventListener('load', function() {
var all_images = document.evaluate('//img[#src]', document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var newsfeed = document.evaluate('//*[contains(#id, topnews_main_stream_408239535924329)]', document, null,XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
var imgSrcs = [];
for (var i=0; i < all_images.snapshotLength; i++){
var this_image = all_images.snapshotItem(i);
var src = this_image.src;
if(src.indexOf('static') > -1){
continue;
}
if(src.indexOf('external') > -1){
continue;
}
imgSrcs.push(src);
console.log(this_image.src);
this_image.addEventListener("click", my_func, false);
}
for (var i=0; i < newsfeed.snapshotLength; i++){
var this_news = newsfeed.snapshotItem(i);
var src = this_news.src;
if(this_news.children.length>0){
}
if(Object.getOwnPropertyNames(this_news)[0]== '_startTime'){
var x = this_news.onreadystatechange();
}
this_news.addEventListener("click", my_func, false);
this_news.addEventListener("mouseover", my_func, false);
}
var my_func = function(){
console.log("the list", imgSrcs);
}
}, false);
You can bind load on all img tags like
$("img").on("load", function() {
console.log($(this)[0].src)
});
If you really want to use pure javascript to mimic on, you can reference Emulate jQuery "on" with selector in pure javascript

How to make a GreaseMonkey script affect elements in a page before they're displayed?

I'm trying to ensure that images in a certain website are not displayed, but the alt text is still displayed. Initially I attempted to accomplish this with Stylish (using Firefox) and asked the following question:
How to force an image's alt text to display instead of the image?
The accepted answer provided me with an alternative solution using Greasemonkey. The script uses waitForKeyElements to hide images even if they're added using AJAX.
I changed the given script to the following:
// ==UserScript==
// #name _Hide pics except for alt text
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #grant GM_addStyle
// ==/UserScript==
GM_addStyle ( " \
* { \
background-image: none !important; \
} \
" );
waitForKeyElements ("img", hideImageExceptForAltText);
function hideImageExceptForAltText (jNode) {
var imgAlt = jNode.attr("alt");
var imgTitle = jNode.attr("title");
jNode.css("display", "none");
var newSpan = $("<span></span>");
newSpan.attr("title", imgTitle);
newSpan.append(imgAlt);
jNode.parent().append(newSpan);
}
Just like the original script, this has the problem that the images are still displayed for a few moments as the page is loading.
Is it possible to ensure that the given function will prevent images on a page from being displayed immediately, so that they won't be visible at all?
EDIT: Brock Adams' reply had the clue I was missing. In case anyone is looking for something like this, the following is what I ended up using. It works fine on the site I needed it for, but I can't guarantee it will work on other sites or other browsers than Firefox.
The following hides images and replaces them with a link (except for background images). Clicking that link will display the image.
// ==UserScript==
// #name TCRF images
// #namespace SOMETHING
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #version 1
// #grant GM_addStyle
// #run-at document-start
// ==/UserScript==
GM_addStyle ( "\
* {\
background-image: none !important;\
}\
\
img.gmImgHideHidden {\
display: none !important;\
}\
" );
var num = 0;
function gmImgHideShowImg(imgId, linkId)
{
// Using plain JavaScript because the page itself may not have jquery
var img = document.getElementById(imgId);
img.className = img.className.replace( /(?:^|\s)gmImgHideHidden(?!\S)/g , '' );
var lnk = document.getElementById(linkId);
lnk.parentNode.removeChild(lnk);
}
// Exporting the "show image" function so that it can be used in the webpage
unsafeWindow.gmImgHideShowImg = exportFunction(gmImgHideShowImg, unsafeWindow);
waitForKeyElements ("img", hideImageExceptForAltText);
function hideImageExceptForAltText (jNode) {
var imgId = jNode.attr("id");
// Ensuring an id exists so the image can be searched for later
if(typeof(imgId) == "undefined")
{
imgId = "gmImgHideImg" + num;
jNode.attr("id", imgId);
}
var imgDisp = jNode.css("display");
var imgAlt = jNode.attr("alt");
jNode.addClass("gmImgHideHidden");
var linkId = "gmImgHideLink" + num;
var linkNode = $("<a></a>");
linkNode.attr("id", linkId);
linkNode.append("Image: " + imgAlt);
linkNode.attr("onclick", "gmImgHideShowImg('" + imgId + "', '" + linkId + "'); return false;");
jNode.parent().append(linkNode);
num++;
}
MutationObserver is without a doubt the best solution here. Combined with early injection by #run-at document-start we can make the script pretty much bullet-proof. Check out this fiddle (tested with Firefox 40) to see it in action.
I think the code is pretty self-explanatory. I've annotated the subtleties, but leave a comment if there's anything you don't understand.
// ==UserScript==
// #run-at document-start
// ==/UserScript==
"use strict";
/* part one: <img> elements */
(new MutationObserver(function(Records, Obs) {
for (let R of Records) {/* examine each mutation record: */
/* if the record specifies an attribute mutation… */
if (
R.attributeName === "src" &&
(R.target instanceof Element) && /* this check might be necessary */
R.target.tagName.toLowerCase() === "img" &&
R.target.getAttribute("src") !== "" /* avoid infinite loop */
) {
R.target.setAttribute("src", "");
};
/* if the record specifies a sub-element mutation… */
for (let N of R.addedNodes) {
if (
(N instanceof Element) && /* this check might be necessary */
N.tagName.toLowerCase() === "img" &&
N.getAttribute("src") !== "" /* avoid infinite loop */
) {
N.setAttribute("src", "");
};
};
};
})).observe(document, {
/* changes wot we listen for */
childList : true,
subtree : true,
attributes : true
});
/* part two: background-image styles */
let check_for_head_elem = function(_, Obs) {
if (!document.head) {return;};
Obs.disconnect();
/* apply our style */
let Style = document.createElement("style");
document.head.appendChild(Style);
Style.sheet.insertRule("* {background-image : none !important;}", 0);
};
let check_for_root_elem = function(_, Obs) {
if (!document.documentElement) {return;};
Obs.disconnect();
/* observe until the <head> element is added */
Obs = new MutationObserver(check_for_head_elem)
Obs.observe(document.documentElement, {childList : true});
check_for_head_elem(null, Obs); /* check here because it might exist already */
};
{/* observe until the <html> element is added */
let Obs = new MutationObserver(check_for_root_elem);
Obs.observe(document, {childList : true});
check_for_root_elem(null, Obs); /* check here because it might exist already */
};
There are some other ways to get images on the page that I haven't taken into consideration (<iframe>, <svg>, <canvas>, <li> bullet points), but if necessary you should be able to use mutation observers or CSS to take care of those too.
A simple, robust way to do this is to set CSS first-thing, before any of the rest of the page loads.
#run-at document-start and GM_addStyle() do this. (on Firefox; not tested on latest Tampermonkey)
That way, the images are not displayed even for a fraction of a second, like they are with the original code or with a complicated, finicky MutationObserver approach.
This complete script shows the process:
// ==UserScript==
// #name _Hide pics except for alt text
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #grant GM_addStyle
// #run-at document-start
// ==/UserScript==
GM_addStyle ( " \
* { \
background-image: none !important; \
} \
img { \
display: none !important; \
} \
" );
/*--- $(document).ready() is not always needed for modern Firefox, but
use for maximum portability, when script runs at document-start.
*/
$(document).ready ( function () {
waitForKeyElements ("img", hideImageExceptForAltText);
} );
function hideImageExceptForAltText (jNode) {
var imgAlt = jNode.attr("alt") || "";
var imgTitle = jNode.attr("title") || "";
jNode.after ('<span title="' + imgTitle + '">' + imgAlt + '</span>');
}

Replace text with link to that text?

This is a follow up of my earlier question. I'm trying to use Greasemonkey to change the text in a <td> to a link that contains that text.
So the page contains
<td class="something"><div style="width: 200px;">
randomtext
</div></td>
And I want to change it using Greasemonkey to:
<td class="something"><div style="width: 200px;">
randomtext
</div></td>
So far, I've cobbled together this little bit of code, but I'm sure it's the wrong approach as I'm not getting anywhere:
// ==UserScript==
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js
// ==/UserScript==
(function() {
var reference = document.getElementsByTagName('something')
var replacement = reference.replace(reference, "www.somewhere.com/q?=" + reference)
document.getElementById("user-reference-value").innerHTML = replacement;
})();
What more do I need to do to make this work?
Forget jQuery, it'll just slow your pages down.
I haven't really tested this code, but it should work maybe with some debugging:
// ==UserScript==
// ==/UserScript==
(function() {
// collect variables
// you can change this to change which element you replace
var reference = document.querySelector('td.something>div:first-child');
var text = reference.innerText;
var replacement = text.replace(reference, "www.somewhere.com/q?=" + reference);
// create new anchor tag
var a = document.createElement('a');
a.href = replacement;
a.innerText = text;
// do the replacement
reference.innerHTML = ''; // clear the old contents of the reference
reference.appendChild(a); // append the new anchor tag into the element
})();
This is a fairly standard operation for a Greasemonkey script. jQuery's .wrapInner()Doc and waitForKeyElements()Example make it easy.
Your complete script would look like this:
// ==UserScript==
// #name _Select text (re)linker
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #grant GM_addStyle
// ==/UserScript==
/*- The #grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/
waitForKeyElements (".something > div", linkifyText);
function linkifyText (jNode) {
jNode.wrapInner ( function () {
var newHref = 'http:\/\/www.somewhere.com\/q?='
+ encodeURIComponent (this.textContent.trim () );
//-- Note that link text will be filled in automatically.
var newLink = '';
return newLink;
} );
}

Replace Facebook thumbnails in a RSS Reader (InoReader)

I'm looking to create a Greasemonkey script that will replace Facebook thumbnails in InoReader or any other RSS reader. Previously I had been successfully using the script below in Google Reader, but it doesn't work in InoReader, Feedly, or any non-Google RSS Reader.
// ==UserScript==
// #id greader-facebookurlreplacer
// #name Google Reader - Facebook URL Replacer
// #version 1.1
// #namespace
// #author
// #description
// #include https://www.google.com/reader/*
// #include https://www.feedspot.com/*
// ==/UserScript==
document.getElementById("chrome").addEventListener("DOMNodeInserted", function (e) {
if (e.target.tagName && e.target.tagName == "DIV" && /entry\s?/.test(e.target.className)) {
var t = e.target.getElementsByTagName("img");
for (var n in t) {
var r = t[n];
if (/.*akamaihd\.net.*_s\.\w+$/.test(r.src)) {
r.style.width = r.style.height = "inherit";
r.src = r.src.replace(/_s\.(\w+)$/, "_n.$1")
}
}
}
}, false)
I also tried using the following code retrieved from a similar post on stackoverflow, but it doesn't work either in InoReader.
$("img[src^='https://fbcdn-photos-a.akamaihd.net']")
.each(function()
{
this.src = this.src.replace(/(\/[^/]*)s\.jpg$/, '/s720x720$1n.jpg');
});​
Any help would be greatly appreciated.
DOMNodeInserted is deprecated. Don't use that approach anymore. Best to use a utility like waitForKeyElements.
After that, it's just a matter of finding the right jQuery selector for the images, and then the right regex to convert the src to the one for the larger image size. (But note that some sites deliberately make the regex approach impossible.)
For the sample RSS feed you listed, on inoreader.com, we can use Firebug to determine a CSS/jQuery path to the thumbnails of:
#reader_pane div.article_full_contents div.article_content a.underlink img
For the src changes/regex, see the code.
Here's how to replace the images, for that feed, on that reader:
// ==UserScript==
// #name _InoReader thumbnail replacer
// #include http://www.inoreader.com/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// #require https://gist.github.com/raw/2625891/waitForKeyElements.js
// #grant GM_addStyle
// ==/UserScript==
/*- The #grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/
waitForKeyElements (
"#reader_pane div.article_full_contents div.article_content a.underlink img",
swapOutFbcdnThumnails
);
function swapOutFbcdnThumnails (jNode) {
/*-- Change src from:
https://fbcdn-photos- ... _s.jpg
to:
https://fbcdn-sphotos- ... _n.jpg
*/
var newSrc = jNode[0].src.replace (/fbcdn\-photos\-/, "fbcdn-sphotos-");
newSrc = newSrc.replace (/_s\.jpg$/, "_n.jpg");
jNode[0].src = newSrc;
}

How do I remove the javascript blocking from some links?

For example, I am trying to change this:
<a href="javascript: void(null)" class="jv-redirectCandidate"
key="pcxe7gwP"
>Some Name</a>
Into this:
Some Name
I need the string "pcxe7gwP" that is currently part of
key="pcxe7gwp"
and then I want to attach it to part of a URL
https://www.foo.com/something.aspx?p=
and the use that as the href in place of the current
"javascript: void(null)"
I am using the Tampermonkey Chrome extension and trying to create a userscript to accomplish this. I am new to userscripts and would love any help. Thanks!
Test in Greasemonkey, don't need jquery.
// ==UserScript==
// #name Change link href with it's key
// #namespace test
// #grant none
// #version 1
// #include http://localhost:8000/*.html
// ==/UserScript==
var prefix = 'https://www.foo.com/something.aspx?p=';
var links = document.querySelectorAll('a.jv-redirectCandidate[key]');
for (var i = 0; i < links.length; i += 1) {
var link = links[i];
link.href = prefix + link.getAttribute('key');
}
If I understood right, this is what you are looking for:
<html>
<script type="text/javascript">
function changeHREF(element){
element.href = "https://www.foo.com/something.aspx?p=" + element.key;
}
</script>
<body>
Some Name
</body></html>
Another possible solution:
<html>
<script type="text/javascript">
function changeHREF(){
elements = document.getElementsByClassName("jv-redirectCandidate");
for(i = 0; i<elements.length; i++) {
elements[i].href = "https://www.foo.com/something.aspx?p=" + elements[i].getAttribute("key");
}
}
</script>
<body onload="javascript:changeHREF()">
Some Name
</body></html>
Well, there are other solutions to achieve the same results. But, I think that it is out of topic.
Cheers
Here is a complete script that will work in either Tampermonkey or Greasemonkey. It use's jQuery for ease and power:
// ==UserScript==
// #name _De-javascript links
// #include http://YOUR_SERVER.COM/YOUR_PATH/*
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// #grant GM_addStyle
// ==/UserScript==
/*- The #grant directive is needed to work around a design change
introduced in GM 1.0. It restores the sandbox.
*/
//-- Get links with the class "jv-redirectCandidate".
var linksToFix = $("a.jv-redirectCandidate");
//-- Loop through the links
linksToFix.each ( function () {
var jThis = $(this); //-- An individual link
var key = jThis.attr ("key");
jThis.attr ("href", "https://www.foo.com/something.aspx?p=" + key);
} );

Categories