2

So guys, I'm editing the design of a music site for my performances. For that, I made a little script to put in Tampermonkey.

Somehow, I just need to get the song title, author and all the paragraphs. How can I do this?

Example song: Lyrics.

<script>
window.onload = () => {
    // Removal of page elements
    document.getElementsByClassName("main-header g-mb")[0].remove(); // Header
    document.querySelector('#breadcrumb').remove(); // Index
    document.querySelector('.cnt-space-top').remove(); // Advertising
    document.querySelector(".cnt-head > a").remove(); // Artist Image
    document.querySelector('.cnt-info_exib').remove(); // Info above the video
    document.querySelector('.cnt-info').remove(); // Info above the video
    document.querySelector('.letra-menu').remove(); // Letter-side info
    document.querySelector('.pl_media').remove(); // Music video
    document.querySelector('.letra-info').remove(); // Info under the letter
    document.querySelector('.letra-share').remove(); // Info under the letter
    document.querySelector('#comments').remove(); // Comments Section
    document.querySelector('#cnt_footer').remove(); // Most Listened Section
    document.getElementsByClassName("g-1")[1].remove(); // Music Footer
    document.getElementsByClassName("g-1")[2].remove(); // Music Footer

    let headerMusic = document.querySelector(".cnt-head"); // Music header
    //headerMusic.style.padding = "0px";
    headerMusic.style.margin = "auto"; // Letter margin
    headerMusic.style.position = "relative";

    let nameMusic = document.querySelector("h1"); // Name of the song
    nameMusic.style.fontSize = "45px";
    nameMusic.style.fontWeight = "bold";

    let artistMusic = document.querySelector("h2 > a"); // Music artist
    artistMusic.style.padding = "0px";
    artistMusic.style.fontSize = "30px";
    artistMusic.style.fontWeight = "bold";

    let letterMusic = document.querySelector('.cnt-letra'); // Lyrics
    letterMusic.style.padding = "0px";
    letterMusic.style.fontSize = "40px";
    letterMusic.style.fontWeight = "bold";

    let allBody = document.querySelector('body');
    allBody.style.textAlign = "center"; // Leave letter centered
    allBody.style.margin = "0px 100px"; // Letter margin
</script>
  • 1
    And what problem are you facing trying to do this? – EternalHour Sep 09 '19 at 06:10
  • Isn't it easier (start) opposite way to keep lyrics only for example like this ? But this way it will rebuild page and get some JS errors after document.body.innerHTML = document.getElementsByTagName("P")[0].parentElement.innerHTML – Jan Sep 09 '19 at 07:29

1 Answers1

0

In case you have IE >=9 compatible with DOMParser, you can simply read and parse page like this.
In Chrome & FF you end-up with CORS problem. But same logic can be used in monkey - song name is in 1 of 2 H1 tags, band name in 1st H2 and song inside P tags block with a DIV around. Or also in node.js you can do it similar way without CORS problem including file access, etc.

<script>
loadPage("https://www.letras.mus.br/queen/64295/");
function loadPage(url) {
    var http = new XMLHttpRequest();
    http.open('GET', url, true);
    http.onloadend = function () {
        var html = new DOMParser().parseFromString(this.responseText, "text/html")
        html = html.documentElement;
        var el = html.getElementsByTagName("H1");
        var interesting = el[el.length-1].outerHTML + "\n";
        el = html.getElementsByTagName("H2")[0];
        el.innerHTML = el.innerText;
        interesting += el.outerHTML  + "\n";
        interesting += html.getElementsByTagName("P")[0].parentElement.innerHTML
        document.write(
    "<style>\nbody { background-color:transparent; font-family:Arial, sans-serif; font-size:19px; opacity:1; word-wrap:break-word; margin:0px; }\n" +
    "h1 { color: rgb(255, 102, 0); font-size: 25px; font-weight: 700; letter-spacing: -1px; margin:0px; }\n" +
    "h2,a { color:rgb(183, 183, 0); font-size: 19px; font-weight: 700; letter-spacing: -1px; text-decoration: none; margin:0px; }\n" +
    "p { color: rgb(68, 68, 68); font-weight: 400; line-height: 30.4px; margin-bottom: 30.4px; }\n</style>\n"
        + interesting);
        document.close();
    }

    http.send();
}
</script>

And here node.js version saving content you are looking for to file:

const request = require('request');
const jsdom = require("jsdom");
var fs = require('fs');

loader("https://www.letras.mus.br/queen/64295/");

function processDOM(body) {
    var dom = new jsdom.JSDOM(body);
    var html = dom.window.document;
    // Song name
    var el = html.querySelectorAll("H1");
    el = el[el.length - 1];
    var items = [el.textContent];
    var interesting = "<style>\nbody { background-color:transparent; font-family:Arial, sans-serif; font-size:19px; opacity:1; word-wrap:break-word; margin:0px; }\n" +
    "h1 { color: rgb(255, 102, 0); font-size: 25px; font-weight: 700; letter-spacing: -1px; margin:0px; }\n" +
    "h2,a { color:rgb(183, 183, 0); font-size: 19px; font-weight: 700; letter-spacing: -1px; text-decoration: none; margin:0px; }\n" +
    "p { color: rgb(68, 68, 68); font-weight: 400; line-height: 30.4px; margin-bottom: 30.4px; }\n</style>\n" +
    el.outerHTML + "\n";
    // Band
    el = html.querySelector("H2");
    items.push(el.textContent.trim());
    el.innerHTML = items[1];
    interesting += el.outerHTML + "\n";
    // Lyrics
    el = html.querySelector("P").parentElement.innerHTML;
    interesting += el.replace(/<br>/g, '<br>\n').replace(/<\/p>/g, '</p>\n');
    items.push(interesting);
    return items;
}

// Based on https://stackoverflow.com/questions/38428027/why-await-is-not-working-for-node-request-module#38428075
async function loader(url) {
    var res = await doRequest(url);
    // Save new simple page
    var pageName = res[0].replace(/\s/g, '_') + ".htm"; // song_name.htm
    fs.writeFile(pageName, res[2], function (err) { // html data
        if (err) throw err;
        console.log(pageName + ' saved.');
    });
}

function doRequest(url) {
    return new Promise(function (resolve, reject) {
        request(url, function (error, res, body) {
            if (!error && res.statusCode == 200) {
                resolve(processDOM(body));
            } else {
                reject(error);
            }
        });
    });
}

Small sugar - element computed style printer - it will create empty element, get computed styles of your and print different values.

var el=prompt('Element:',"body"), defaultStyles, computedStyles;
defaultStyles = getStyles({}, window.getComputedStyle(document.createElement(el)));
computedStyles = el + ' ' + JSON.stringify(getStyles(defaultStyles, window.getComputedStyle(document.querySelector(el))), null, 3)
.replace(/\"([^\"]+)\": \"([^\"]+)\",/g,"$1: $2;").replace(/\n/g, "\r\n");
function getStyles(defaultStyles, computedStyles) {
    var content = {};
    for (var i=0; i<computedStyles.length; i++) {
        cssProperty = computedStyles[i];
        cssValue = computedStyles.getPropertyValue(cssProperty);
        if(defaultStyles[cssProperty] != cssValue)
            content[cssProperty] = cssValue;
    }
    return content;
}
console.log(computedStyles)
//prompt('Styles: ', computedStyles);

prompt("Copy bookmarklet:", 'javascript:var el=prompt("Element:","body"), defaultStyles, computedStyles;defaultStyles = getStyles({}, window.getComputedStyle(document.createElement(el)));computedStyles = el + " " + JSON.stringify(getStyles(defaultStyles, window.getComputedStyle(document.querySelector(el))), null, 3).replace(/\\"([^\\"]+)\\": \\"([^\\"]+)\\",/g,"$1: $2;").replace(/\\n/g, "\\r\\n");function getStyles(defaultStyles, computedStyles) {var content = {};for (var i=0; i<computedStyles.length; i++) {cssProperty = computedStyles[i];cssValue = computedStyles.getPropertyValue(cssProperty);if(defaultStyles[cssProperty] != cssValue)content[cssProperty] = cssValue;}return content;}prompt("Styles: ", computedStyles),undefined')
Jan
  • 2,178
  • 3
  • 14
  • 26
  • So my request wasn't quite that, I'll update the question to try to make it clear. Regarding your answer, I really liked this first code, it will help me a lot, but as I can change the first line of this script (`loadPage ("https://www.letras.mus.br/queen/64295/");`) to apply to all general music on this site? Already this version node.js I don't understand very well, for not yet have much knowledge about, but thank you very much for the answer. –  Sep 09 '19 at 14:18
  • Sure, it is a general function, you can put here any URL with page organized like this example and it will work. Node.js is separate install which can run JavaScript client or server application without restrictions like CORS, etc. (if they are not on server side). So 1st version is IE only and 2nd in case you have node.js installed and request, jsdom and fs packages, it will work anywhere including linux. In case you like it, you can accept answer. – Jan Sep 09 '19 at 14:33
  • Wondering how can you collect all links, but not impossible - in case you point me where to start, I can try to get a list for that function ;-) In case you do not know how to do it... – Jan Sep 09 '19 at 14:37
  • But how can I put the URL of the song automatically? I don't understand yet. –  Sep 09 '19 at 14:48
  • var songs = [url1, url2, ...]; for(var s in songs) loader(songs[s]); would be easy, but suppose you have only some pages with links, that would need a bit more effort then... – Jan Sep 09 '19 at 14:52
  • Got it got it. One last question, how can I add style to headings, paragraphs, ... now with this code? –  Sep 11 '19 at 00:04