您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Script to implement a history of the seen approach for some news sites. Details at https://github.com/theoky/HistoryOfTheSeen
当前为
- // ==UserScript==
- // @name History of the Seen
- // @namespace https://github.com/theoky/HistoryOfTheSeen
- // @description Script to implement a history of the seen approach for some news sites. Details at https://github.com/theoky/HistoryOfTheSeen
- // @author Theoky
- // @version 0.39
- // @lastchanges new urls, dot notation, changed dimming, hide more elements by looking up the hierarchy
- // @license GNU GPL version 3
- // @released 2014-02-20
- // @updated 2014-08-30
- // @homepageURL https://github.com/theoky/HistoryOfTheSeen
- //
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_deleteValue
- // @grant GM_registerMenuCommand
- // @grant GM_listValues
- //
- // for testing (set greasemonkey.fileIsGreaseable)
- // @include file://*testhistory.html
- //
- // @include http*://*.derstandard.at/*
- // @include http*://*.faz.net/*
- // @include http*://*.golem.de/*
- // @include http*://*.handelsblatt.com/*
- // @include http*://*.heise.de/newsticker/*
- // @include http*://*.kleinezeitung.at/*
- // @include http*://*.nachrichten.at/*
- // @include http*://*.oe24.at/*
- // @include http*://*.orf.at/*
- // @include http*://orf.at/*
- // @include http*://*.reddit.com/*
- // @include http*://*.spiegel.de/*
- // @include http*://*.sueddeutsche.de/*
- // @include http*://*.welt.de/*
- // @include http*://*.wirtschaftsblatt.at/*
- // @include http*://*.zeit.de/*
- // @include http*://dastandard.at/*
- // @include http*://derstandard.at/*
- // @include http*://diepresse.com/*
- // @include http*://diestandard.at/*
- // @include http*://kurier.at/*
- // @include http*://slashdot.org/*
- // @include http*://taz.de/*
- // @include http*://notalwaysright.com/
- // @require https://greasyfork.org/scripts/130-portable-md5-function/code/Portable%20MD5%20Function.js?version=10066
- // was require md5.js
- // was require http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/md5.js
- // ==/UserScript==
- // Copyright (C) 2014 T. Kopetzky - theoky
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- // Tested with Firefox 31 and GreaseMonkey 2.1
- //-------------------------------------------------
- //Functions
- //(function(){
- var defaultSettings = {
- ageOfUrl: 5, // age in days after a url is deleted from the store
- // < 0 erases all dates (disables history)
- targetOpacity: 0.3,
- targetOpacity4Dim: 0.65,
- steps: 10,
- dimInterval: 30000,
- expireAllDomains: true // On fast machines this can be true and expires
- // all domains in the database with each call. If false,
- // only the urls of the current domain are expired which
- // is slightly faster.
- }
- var perUrlSettings = [
- {
- url : '.*\.?derstandard\.at',
- // TODO: der, die, das standard
- upTrigger: "../a",
- parentHints : [
- "ancestor::div[contains(concat(' ', @class, ' '), ' text ')]",
- "ancestor::ul[@class='stories']" ]
- },
- {
- url : 'notalwaysright\.com',
- upTrigger: "../a",
- parentHints : [ "ancestor::div[contains(concat(' ', @class, ' '), ' post ')]" ]
- },
- {
- url : '.*\.?golem.de',
- upTrigger: "../a",
- parentHints : [ "ancestor::li",
- "ancestor::section[@id='index-promo']",
- "ancestor::section[contains(concat(' ', @class, ' '), ' promo ')]" ]
- },
- {
- url : '.*\.?reddit.com',
- // class="title may-blank srTagged imgScanned"
- upTrigger: "../a[contains(@class, 'title') and contains(@class, 'may-blank')]",
- parentHints : [ "ancestor::div[contains(concat(' ', @class, ' '), ' thing ')]" ]
- }
- ]
- var dimMap = {};
- var countDownTimer = defaultSettings.steps;
- var theHRefs = null;
- var curSettings = null;
- function resetAllUrls() {
- if (confirm('Are you sure you want to erase the complete seen history?')) {
- var keys = GM_listValues();
- for (var i=0, key=null; key=keys[i]; i++) {
- GM_deleteValue(key);
- }
- document.location.reload(true);
- }
- }
- function resetUrlsForCurrentHelper(dKey, domainOrUri) {
- if (confirm('Are you sure you want to erase the seen history for ' +
- domainOrUri + '?')) {
- var keys = GM_listValues();
- for (var i=0, key=null; key=keys[i]; i++) {
- var dict = JSON.parse(GM_getValue(key, "{}"));
- if(dict) {
- if (dict[dKey] == domainOrUri) {
- GM_deleteValue(key);
- }
- }
- }
- document.location.reload(true);
- }
- }
- function resetUrlsForCurrentDomain() {
- resetUrlsForCurrentHelper("domain", document.domain)
- }
- function resetUrlsForCurrentSite() {
- resetUrlsForCurrentHelper("base", document.baseURI)
- }
- function expireUrlsForCurrentSite() {
- // TODO: do this only once a day
- var keys = GM_listValues();
- if (!keys) {
- return;
- }
- var cutOffDate = calcCutOffDate(defaultSettings.ageOfUrl);
- for (var i=0, key=null; key=keys[i]; i++) {
- if (key == "lastExpire"){
- continue;
- }
- var dict = JSON.parse(GM_getValue(key, "{}"));
- if(dict) {
- try {
- // console.log(dict["domain"], cutOffDate.getTime(), dict["date"]);
- if (cutOffDate.getTime() > dict["date"]) {
- if (defaultSettings.expireAllDomains ||
- (dict["domain"] == document.domain))
- {
- GM_deleteValue(key);
- }
- }
- } catch (e) {
- console.log(e);
- }
- }
- else {
- console.log('Error! JSON.parse failed - dict is likely to be corrupted.');
- }
- }
- GM_setValue("lastExpire", new Date());
- }
- function calcCutOffDate(age) {
- var cutOffDate = new Date();
- if (age >= 0) {
- cutOffDate.setHours(0,0,0,0);
- cutOffDate.setDate((new Date()).getDate() - age);
- }
- return cutOffDate;
- }
- /*
- * Find the settings for a given URL
- */
- function findPerUrlSettings(theSettings, aDomain) {
- for (var i=0; i < theSettings.length; ++i) {
- var myRegExp = new RegExp(theSettings[i].url, 'i');
- if (aDomain.match(myRegExp)) {
- return theSettings[i];
- }
- }
- }
- /*
- * Find the parent element as specified in the settings.
- */
- function locateParentElem(curSettings, aDomain, aRoot) {
- if (!curSettings) {
- return null;
- }
- // console.log("locateParentElem 1", curSettings.url);
- var res = null;
- for (xpath = 0; xpath < curSettings.parentHints.length; ++xpath) {
- // console.log("locateParentElem 2", curSettings.parentHints[xpath], aRoot);
- res = document.evaluate(curSettings.parentHints[xpath], aRoot, null, 9, null).singleNodeValue
- if (res) {
- // console.log("locateParentElem found something");
- return res;
- }
- }
- return res;
- }
- /*
- * Check if the current node qualifies for looking up the hierarchy.
- */
- function goUp(curSettings, aRoot) {
- if (!curSettings) {
- return null;
- }
- res = null
- if (curSettings.upTrigger != "") {
- res = document.evaluate(curSettings.upTrigger, aRoot, null, 9, null).singleNodeValue
- }
- return res != null
- }
- function dimLinks() {
- interval = (1 - defaultSettings.targetOpacity4Dim)/defaultSettings.steps;
- countDownTimer = countDownTimer - 1;
- curOpacity = defaultSettings.targetOpacity4Dim + interval*countDownTimer;
- for(var i = 0; i < theHRefs.length; i++)
- {
- var hash = 'm' + hex_md5(theHRefs[i].href);
- if (hash in dimMap) {
- theHRefs[i].style.opacity = curOpacity;
- }
- }
- if (countDownTimer > 0) {
- to = setTimeout(dimLinks, defaultSettings.dimInterval);
- }
- }
- // Main part
- // Menus
- GM_registerMenuCommand("Remove the seen history for this site.", resetUrlsForCurrentSite);
- GM_registerMenuCommand("Remove the seen history for this domain.", resetUrlsForCurrentDomain);
- GM_registerMenuCommand("Remove all seen history (for all sites)!", resetAllUrls);
- function run_script() {
- // Vars
- var allHrefs = document.getElementsByTagName("a");
- var theBase = document.baseURI;
- var theDomain = document.domain;
- var elemMap = {};
- dimMap = {};
- curSettings = findPerUrlSettings(perUrlSettings, theDomain);
- // console.log(curSettings);
- // expire old data
- expireUrlsForCurrentSite();
- // Change the DOM
- // First loop: gather all new links and make already seen opaque.
- for(var i = 0; i < allHrefs.length; i++)
- {
- var hash = 'm' + hex_md5(allHrefs[i].href);
- // setValue needs letter in the beginning, thus use of 'm'
- var key = GM_getValue(hash);
- // console.log(allHrefs[i].href, hash.toString());
- if (typeof key != 'undefined') {
- // key found -> loaded this reference already
- done = false
- if(goUp(curSettings, allHrefs[i])) {
- pe = locateParentElem(curSettings, theDomain, allHrefs[i])
- // console.log("locate parent done", pe);
- if (pe) {
- pe.style.opacity = defaultSettings.targetOpacity;
- done = true
- }
- }
- if (!done) {
- // change display
- allHrefs[i].style.opacity = defaultSettings.targetOpacity;
- }
- } else {
- // key not found, store it with current date
- elemMap[hash] = {"domain":theDomain, "date":(new Date()).getTime(), "base":theBase};
- dimMap[hash] = allHrefs[i];
- }
- }
- // remember all new urls to hide the next time
- for (var e2 in elemMap) {
- GM_setValue(e2, JSON.stringify(elemMap[e2]));
- }
- theHRefs = allHrefs;
- to = setTimeout(dimLinks, defaultSettings.dimInterval);
- }
- run_script();
- //})();