Subversion Repositories JSX

Compare Revisions

Last modification

Regard whitespace Rev 659 → Rev 660

/trunk/Greasemonkey/ggSpamFilter.user.js
1,7 → 1,7
/**
* ggSpamFilter -- Junk filter for Google Groups
*
* Copyright (C) 2010 Thomas Lahn <cljs@PointedEars.de>
* Copyright (C) 2010, 2016 Thomas Lahn <cljs@PointedEars.de>
*
* 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
19,111 → 19,146
 
// ==UserScript==
// @name ggSpamFilter
// @version 0.2
// @namespace http://PointedEars.de/scripts/Greasemonkey
// @description Junk filter for Google Groups
// @include http://groups.google.*/*
// @include http*://groups.google.*/*
// @require ../object.js
// @require ../regexp.js
// @require ../dom.js
// @require ../dom/xpath.js
// @require ../httprequest.js
// @require ../dom/css.js
// @not_yet_required ../httprequest.js
// ==/UserScript==
 
try
{
/* DEBUG */
// throw new Error();
/*
* Class name to be set on rows for spam threads (spam rows);
* use in user stylesheet to format spam as you want
*/
var spamClass = "is-spam";
/*
* Set this to “true” to format spam rows (see stylesheet definition below);
* no user stylesheet modifications are necessary.
*/
var formatSpam = true;
 
/*
* Stylesheet to be applied to a spam row if formatSpam === true;
* Note that you break GG’s continuous scrolling if you use "display: none"
*/
var spamStyle = "opacity: 0.25";
 
/* Add the strings you want to be blacklisted below */
 
/**
* Words (strings separated by non-word characters) that are indicative of spam
* (case-insensitive)
*/
var aBlacklistWords = [
"\\$\\d+",
var prescriptionDrugsWords = [
"abilify", "aceon", "ambien",
"gifts?",
"soma",
"u", "ultram"
"ultram"
];
var aBlacklistWords = [].concat(
prescriptionDrugsWords,
"\\$\\d+", /* price in dollars */
"gifts?",
"u"
);
/**
* Infixes (sub-strings) that are indicative of spam
* Infixes (sub-strings) that are indicative of spam (case-insensitive)
*/
var aBlacklistInfixes = [
"accupril", "accutane", "acyclovir", "actos",
"adsense", "adderall", "adipex", "alesse", "amiodarone",
"allegra", "alprazolam", "amoxicillin", "armani",
"bactrim", "bipasa", "buspar", "butalbital",
"carisoprodol", "calvin\\s*klein", "caverta", "celexa", "cialis",
"codeine",
"desyrel", "diazepam", "diflucan", "diovan",
"fake\\s*id\\s*card", "fake\\s*passports", "fioricet", "fosamax",
"geodon", "girls?",
var counterfeitInfixes = [
"armani",
"calvin\\s*klein",
"sell", "shoes?(\\s*trade)?",
"wholesale"
];
var prescriptionDrugsInfixes = [
"accupril", "accutane", "acyclovir", "actos", "adderall", "adipex",
"alesse", "amiodarone", "allegra", "alprazolam", "amoxicillin",
"aricept", "ativan",
"baclofen", "bactrim", "benzos", "bipasa", "buspar", "butalbital",
"carisoprodol", "caverta", "celexa", "cialis", "clonazepam", "codeine",
"dapoxetine", "desyrel", "diazepam", "diflucan", "diovan", "doxycycline",
"fioricet", "fosamax",
"geodon", "glucophage",
"hydrocodone",
"imitrex",
"lamisil", "levitra", "lortab",
"kamagra", "klonopin",
"meridia", "microzide",
"norco", "nude",
"online\\s*roulette", "oxycodone", "oxycontin",
"paypal", "percocet", "phentermine", "propecia",
"neurontin", "norco",
"oxycodone", "oxycontin", "opiate",
"percocet", "phentermine", "propecia",
"ritalin",
"sell", "sexy?", "shoes?(\\s*trade)?", "sildenafil", "singulair",
"tadalafil", "terrorism", "tramadol",
"sildenafil", "singulair",
"tadalafil", "tramadol",
"valium", "valtrex", "viagra", "vicodin",
"wholesale",
"xanax", "xenical",
"zithromax", "zolpidem", "zovirax", "zyprexa"
];
var pr0nInfixes = [
"girls?",
"nude",
"sexy?",
];
var aBlacklistInfixes = [].concat(
counterfeitInfixes,
prescriptionDrugsInfixes,
pr0nInfixes,
"adsense",
"fake\\s*id\\s*card", "fake\\s*passports",
"online\\s*roulette",
"paypal",
"terrorism"
);
/* Don't modify anything below this */
/* DO NOT modify anything below this (unless you know what you are doing) */
 
var intv = window.setInterval(function () {
var threadList = document.getElementById("f-ic");
if (!threadList) return;
 
window.clearInterval(intv);
 
try
{
/* DEBUG */
// throw new Error();
 
var dom = jsx.dom;
 
Array.prototype.toAlternation = function () {
return this.slice().sort(function (a, b) {
/* Longest match wins */
return b.length - a.length;
}).join("|");
};
 
var
rxWords = (aBlacklistWords.length > 0)
? new RegExp("\\b(?:" + aBlacklistWords.join('|') + ")\\b", "i")
? new RegExp("\\b(?:" + aBlacklistWords.toAlternation() + ")\\b", "i")
: null,
rxInfixes = (aBlacklistInfixes.length > 0)
? new RegExp("(?:" + aBlacklistInfixes.join('|') + ")", "i")
? new RegExp("(?:" + aBlacklistInfixes.toAlternation() + ")", "i")
: null;
if (rxWords || rxInfixes)
{
var
aRes = jsx.dom.xpath.evaluate(
'.//div[@class="maincontoutboxatt"]//a[@href and not(@class="st")]',
document.body, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE),
count = 0;
if (aRes.length > 0)
{
var prepareTable = function(table) {
var cell = table.rows[0].insertCell(1);
var bold = document.createElement("b");
bold.appendChild(document.createTextNode("Spam?"));
cell.appendChild(bold);
cell = table.rows[1].insertCell(1);
};
/**
* Inserts a cell for a "report as spam" link
*
* @param row
*/
var prepareRow = function(row) {
var cell = row.insertCell(1);
return cell;
};
/**
* Marks a row as spam
*
* @param row
* @param link
*/
var markAsSpam = function(row, domEl) {
var spamCell = row.cells[1];
var markAsSpam = function(row, link) {
//var spamCell = row.cells[1];
 
/* for the Bayesian filter */
var link = document.createElement("a");
//var link = document.createElement("a");
// link.href = "";
// link.appendChild(document.createTextNode("Unmark"));
//
131,10 → 166,10
// spamCell.appendChild(document.createTextNode(" "));
//
// link = document.createElement("a");
link.href = "";
link.addEventListener("click", function(e) {
//link.href = "";
//link.addEventListener("click", function(e) {
/* DEBUG */
var request = jsx.HTTPRequest(domEl.href);
//var request = jsx.HTTPRequest(domEl.href);
// request.setAsync(false);
// request.setSuccessListener(function(response) {
// window.alert(response.responseText);
141,12 → 176,13
// });
// request.send();
//
window.alert("Sorry, reporting spam is not yet implemented.");
e.preventDefault();
}, false);
link.appendChild(document.createTextNode("Report"));
spamCell.appendChild(link);
domEl.style.opacity = "0.5";
//window.alert("Sorry, reporting spam is not yet implemented.");
//e.preventDefault();
//}, false);
//link.appendChild(document.createTextNode("Report"));
//spamCell.appendChild(link);
 
dom.addClassName(row, spamClass, true);
};
/**
154,7 → 190,7
*
* @param row
*/
var markAsHam = function(row, domEl) {
var markAsHam = function(row, link) {
/* for the Bayesian filter */
// var link = document.createElement("a");
// link.href = "";
162,59 → 198,75
// row.cells[1].appendChild(link);
};
 
prepareTable(aRes[0].parentNode.parentNode.parentNode);
if (formatSpam)
{
var styleSheet = document.createElement("style");
styleSheet.type = "text/css";
styleSheet.id = "ggSpamFilter-style";
styleSheet.textContent = "." + spamClass + " { " + spamStyle + "; }";
(document.head || document.getElementsByTagName("head")[0]).appendChild(styleSheet);
}
for (var len = i = aRes && aRes.length; i--;)
{
var
domEl = aRes[i],
table = threadList.querySelector(".IVILX2C-p-V"),
rows = table.rows,
prevSpamCount = 0;
/* Link is nested in a table-cell which is nested in a table-row */
row = domEl.parentNode.parentNode;
//window.clearInterval(intv);
/*intv =*/ window.setInterval(function () {
var spamCount = 0;
subject = domEl.textContent,
[].forEach.call(rows, function (row) {
var
link = row.querySelector("a"),
subject = link.textContent,
mWord = subject.match(rxWords),
mInfix = subject.match(rxInfixes),
m = mWord || mInfix;
prepareRow(row);
if (m)
{
markAsSpam(row, domEl);
if (!dom.hasClassName(row, spamClass))
{
markAsSpam(row, link);
jsx.dmsg('ggSpamFilter:'
+ ' Filtered "' + subject + '"\nbecause it contains'
+ (mWord ? ' the word' : '') + ' "' + m[0] + '"', 'info');
+ (mWord ? ' the word' : '') + ' "' + m[0] + '".', 'info');
}
count++;
spamCount++;
}
else
});
 
if (spamCount !== prevSpamCount)
{
markAsHam(row, domEl);
var rowCount = rows.length;
jsx.dmsg('ggSpamFilter: Filtered ' + spamCount + ' out of ' + rowCount
+ ' ' + (rowCount > 1 ? 'posting' : 'postings')
+ " (" + ((spamCount / rowCount) * 100).toFixed(1) + "\xA0%).", 'info');
}
}
jsx.dmsg('google-groups: Filtered ' + count + ' out of ' + len
+ ' posting(s).', 'info');
prevSpamCount = spamCount;
}, 500);
}
}
}
catch (e)
{
var sError = "Unhandled exception in ggSpamFilter Greasemonkey script:"
var
sError = "Unhandled exception in ggSpamFilter Greasemonkey script:"
+ "\n" + e.message + " [" + e.name + "]"
+ "\nFile: " + e.filename
+ "\nLine: " + e.lineNumber
+ "\nStack trace:\n " + e.stack;
var sMessage = "\n\nPlease confirm to report this bug via e-mail.";
+ "\nStack trace:\n " + e.stack,
sMessage = "\n\nPlease confirm to report this bug via e-mail.";
 
if (window.confirm(sError + sMessage))
{
var sTo = "cljs@PointedEars.de";
var sSubject = "ggSpamFilter Error Report";
var sBody =
"Hello PointedEars,\n\nI got the following error message:\n\n"
var
sTo = "cljs@PointedEars.de",
sSubject = "ggSpamFilter Error Report",
sBody = "Hello PointedEars,\n\nI got the following error message:\n\n"
+ sError
+ "\n\nPlease look into it ASAP.\n\nRegards";
255,3 → 307,4
jsx.dmsg(e, "error");
}
}, 500);