Greasy Fork

Greasy Fork is available in English.

Stig's Last.fm Album Linkr

Adding album links and headers to tracks on Last.Fm's recent plays listings - plus linkifying About Me section on profiles

当前为 2016-10-19 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name        Stig's Last.fm Album Linkr
// @namespace   dk.rockland.userscript.lastfm.linkr
// @description Adding album links and headers to tracks on Last.Fm's recent plays listings - plus linkifying About Me section on profiles
// @version     2016.10.19.0
// @author      Stig Nygaard, http://www.rockland.dk
// @homepageURL http://www.rockland.dk/userscript/lastfm/linkr/
// @supportURL  http://www.rockland.dk/userscript/lastfm/linkr/
// @match       *://*.last.fm/*
// @match       *://*.lastfm.de/*
// @match       *://*.lastfm.es/*
// @match       *://*.lastfm.fr/*
// @match       *://*.lastfm.it/*
// @match       *://*.lastfm.ja/*
// @match       *://*.lastfm.pl/*
// @match       *://*.lastfm.pt/*
// @match       *://*.lastfm.ru/*
// @match       *://*.lastfm.sv/*
// @match       *://*.lastfm.tr/*
// @match       *://*.lastfm.zh/*
// @grant       none
// @noframes
// ==/UserScript==


var linkr = linkr || {
    // CHANGELOG - The most important updates/versions:
    changelog: [
        {version: '2016.10.19.0', description: 'Bonus-feature added: Linkifying urls written in About Me sections.'},
        {version: '2016.07.08.1', description: 'Fine-tuning album-headers with light red background color and more...'},
        {version: '2016.07.08.0', description: 'Don\'t put album-header at very top of Recent Tracks if the 1st track is scrobbling now.'},
        {version: '2016.07.07.0', description: 'Album "headers" in play listings added.'},
        {version: '2016.07.04.0', description: '1st release'}
    ],
    INFO: true,
    DEBUG: false,
    observed: null,
    linking_running: false,
    log: function(s, info) {
        if ((info && window.console) || (linkr.DEBUG && window.console)) {
            window.console.log('*Linkr* '+s);
        }
    },
    insertStyle: function() {
        if (!document.getElementById('linkrStyle')) {
            var style = document.createElement('style');
            style.type = 'text/css';
            style.id = 'linkrStyle';
            style.innerHTML = 'tr.albumlink-row,  tr.albumlink-row > td {background-color:#f1cccc !important; font-style:italic} tr.albumlink-row:hover,  tr.albumlink-row:hover > td {background-color:#f9d4d4 !important;}';
            document.getElementsByTagName('head')[0].appendChild(style);
            linkr.log('linkrStyle has been ADDED');
        } else {
            linkr.log('linkrStyle was already present');
        }
    },
    linking: function (mutations) {
        if(linkr.linking_running) return;
        linkr.linking_running = true;
        function altvalue(elem) {
            if (elem && elem.firstElementChild) {
                if (elem.firstElementChild.classList.contains('albumlink-row')) {
                    return null;
                } else if (elem.firstElementChild.firstElementChild && elem.firstElementChild.firstElementChild.firstElementChild && elem.firstElementChild.firstElementChild.firstElementChild.firstElementChild) {
                    return elem.firstElementChild.firstElementChild.firstElementChild.firstElementChild.alt;
                }
            }
            return null;
        }
        linkr.log('Running linking()... ', linkr.INFO);
        var l = document.querySelectorAll('table.chartlist tr div > img');
        for (var i=0; i < l.length; i++) {
            linkr.log('iteration '+ i + ' of ' + l.length);
            if (l[i].alt && l[i].alt!='') {
                l[i].title = l[i].alt;
                var tr = parent = l[i].parentNode;
                while (tr.tagName.toUpperCase()!=='TR') tr = tr.parentNode;
                var a = tr.querySelector('span.chartlist-artists a');
                if (a) {
                    linkr.log('Found img.alt='+l[i].alt);
                    var albumlink = a.href + '/' + encodeURIComponent(l[i].alt).replace(/%20/g,'+') + '/';
                    linkr.log('giving albumlink='+albumlink);
                    var link = document.createElement('a');
                    link.setAttribute('href', albumlink);
                    parent.replaceChild(link, l[i]);
                    link.appendChild(l[i]);
                } else {
                    linkr.log('Artist link not found');
                }
            }
        }

        var tlists = document.querySelectorAll('section#recent-tracks-section table.chartlist tbody, section.tracklist-section tbody');
        linkr.log('tlists.length='+tlists.length);
        for (var j=0; j<tlists.length; j++) {
            linkr.log('Loop with tlists['+j+'].');
            if (tlists[j] && tlists[j].children && tlists[j].children.length > 2) {
                linkr.log('tlists['+j+'] has ' + tlists[j].children.length + ' children');
                var loopstart=1;
                if (j===0 && tlists[j].children[0].classList.contains('now-scrobbling')) {
                    loopstart=2; // Don't put album-header at very top of Recent Tracks if the 1st row is a currently scrobbling track
                }
                for (i = loopstart; i < tlists[j].children.length; i++) {
                    linkr.log('for-loop. i=' + i);
                    if (i===1 || !tlists[j].children[i - 2].classList.contains('albumlink-row')) {
                        linkr.log('for-loop. i=' + i + ' og i-2 er IKKE allerede albumlink-row');
                        if (    altvalue(tlists[j].children[i])
                                && altvalue(tlists[j].children[i - 1])
                                && altvalue(tlists[j].children[i]) != ''
                                && altvalue(tlists[j].children[i]) === altvalue(tlists[j].children[i - 1])
                                && (i===1 || altvalue(tlists[j].children[i]) != altvalue(tlists[j].children[i - 2]))) {
                            linkr.log('for-loop. i=' + i + ' og vi har fundet en album-gruppes start', linkr.INFO);
                            var artistlink = tlists[j].children[i].querySelector('td.chartlist-name span.chartlist-artists > a');
                            var albumtitle = altvalue(tlists[j].children[i]);
                            var albumcover = tlists[j].children[i].querySelector('td.chartlist-play a > img');
                            if (albumcover) albumcover=albumcover.src;
                            if (artistlink) {
                                var artistname = artistlink.textContent;
                                artistlink = artistlink.href;
                                albumlink = artistlink + '/' + encodeURIComponent(altvalue(tlists[j].children[i])).replace(/%20/g,'+') + '/';
                                tr = document.createElement("tr");
                                tr.classList.add('albumlink-row','js-link-block','js-lazy-buylinks-focus-container');
                                tr.innerHTML = '<td class="chartlist-play"><div class="chartlist-play-image"><a href="'+albumlink+'"><img title="'+albumtitle+'" src="'+albumcover+'" class="cover-art"></a></div></td><td class="chartlist-loved"><a href="'+albumlink.replace(/\/user\/[^\/]+\/library\//,'/')+'"><img src="http://www.rockland.dk/img/album244c.png" class="cover-art" alt="album" /></a></td><td class="chartlist-name"><span class="chartlist-ellipsis-wrap"><span class="chartlist-artists"><a href="'+artistlink+'" title="'+artistname+'">'+artistname+'</a></span><span class="artist-name-spacer"> — </span><a href="'+albumlink+'" class="link-block-target" title="'+artistname+' — '+albumtitle+'">'+albumtitle+'</a></span></td><td class="chartlist-buylinks"><div class="lazy-buylinks"><button class="disclose-trigger lazy-buylinks-toggle" aria-expanded="false" data-lazy-buylink="" data-lazy-buylink-url="'+albumlink.replace(/\/user\/[^\/]+\/library\//,'/')+'/+partial/buylinks">Buy</button></div></td><td class="chartlist-timestamp"></td><td class="chartlist-delete"></td>';
                                linkr.log('Now trying to add tr...');
                                tlists[j].insertBefore(tr, tlists[j].children[i - 1]);
                                linkr.log('and should be added now!?');
                                i += 2; // or http://stackoverflow.com/questions/8766910/is-there-a-loop-start-over ?
                            }
                        }
                    }
                }

            } else {
                linkr.log('but not enough children found...');
            }
        }

        // extras here?...
        // .about-me-sidebar p
        linkr.linkifySidebar();
        //var b = document.querySelector('.stationlinks');
        //b.insertAdjacentHTML('beforeend','<div style="margin:1em 0;width:300px"><img src="http://www.tapmusic.net/collage.php?user=rockland&amp;type=3month&amp;size=2x8" alt="" style="display:block;margin:0;padding:0;width:300px;height:900px" /><em>Album collage by <a href="http://www.tapmusic.net/lastfm/">www.tapmusic.net/lastfm/</a></em></div>');

        linkr.linking_running = false;
    },
    setupObserver: function () {
        linkr.log('Running setupObserver()');
        linkr.insertStyle();
        linkr.observed = document.querySelector('table.chartlist > tbody');
        if (!linkr.observed || !linkr.observed.classList) {
            linkr.log('Object to observe NOT found - re-trying later...');
        } else if (linkr.observed.classList.contains('hasObserver')) {
            linkr.log('Everything is okay! - But checking again later...');
        } else {
            linkr.linking();
            linkr.log('Now adding Observer and starting...', linkr.INFO);
            var observer = new MutationObserver(linkr.linking);
            var config = {attributes: false, childList: true, subtree: false, characterData: false};
            observer.observe(linkr.observed, config);
            linkr.observed.classList.add('hasObserver');
            linkr.log('Observer added and running...');
        }
    },
    linkifyStr: function (str, attributes) {
        var a1 = '<a ' + (attributes ? attributes+' ' : '') + 'href="';
        var a2 = '">';
        var a3 = '</a>';
        var url = /(^|\s|\(|>)([fhtpsr]+:\/\/[^\s]+?)([\.,;\]"]?(\s|$|\))|<)/igm;
        // var url2 = /(^|\s|\()([fhtpsr]+:\/\/[^\s]+?)([\.,;\]"]?(\s|$|\)))/igm;
        // This looks a bit weird, but we have to do a replace twice to catch URLs
        // which immediately follow each other. This is because leading and trailing
        // whitespaces are part of the expressions, and if a trailing whitespace of
        // a match needs to be a leading whitespace of the next URL to match, it
        // won't be caught.
        var s = str.replace(url, '$1' + a1 + '$2' + a2 + '$2' + a3 + '$3$4');
        return(s.replace(url, '$1' + a1 + '$2' + a2 + '$2' + a3 + '$3$4'));
        // var s2 = s.replace(url2,"$1"+a1+"$2"+a2+"$2"+a3+"$3$4"); alert(s2); return(s2);
    },
    linkifySidebar: function() {
        var a = document.querySelectorAll('.about-me-sidebar p');
        for(var i=0;i<a.length;i++)
        {
            // a[i].innerHTML = linkr.linkifyStr(a[i].innerHTML,'target="_blank"');
            a[i].innerHTML = linkr.linkifyStr(a[i].innerHTML);
        }
    },
    init: function () {
        linkr.log('Running init() on last.fm');
        linkr.setupObserver();
        setInterval(linkr.setupObserver,2000);

        // .about-me-sidebar p
        //linkr.linkifySidebar();

        // .stationlinks
        //var b = document.querySelector('.stationlinks');
        //b.insertAdjacentHTML('beforeend','<div style="margin:1em 0;width:300px"><img src="http://www.tapmusic.net/collage.php?user=rockland&amp;type=3month&amp;size=2x8" alt="" style="display:block;margin:0;padding:0;width:300px;height:900px" /><em>Album collage by <a href="http://www.tapmusic.net/lastfm/">www.tapmusic.net/lastfm/</a></em></div>');
    }
};

linkr.init();