Updated 2018-08-19: Hide comments that have already been hidden by user flagging (this is mostly useful if the hideReplies boolean is set true).


Updated 2018-08-15: Added hideLoggedOut. If set true, then the script will hide any user who isn't logged in, unless their name is in the whitelist array.

Added hideReplies. If set true, then when the script hides a comment it will also hide all the replies to the comment.

If you set both hideLoggedOut and hideReplies to true, then the Techdirt comments section gets much quieter.


Updated 2018-08-09: Some doofus has been impersonating me. Script will now automatically flag and hide posts by fake Thad.

In addition to hiding posts if their subject line is too long, the script will now also hide posts if the username is too long. Additionally, the script can automatically flag posts if the subject or username exceeds a specified length.

This thing's gotten complicated enough that I think it's probably subject to copyright now. I've added a license. I chose a 3-Clause BSD License.


Updated 2018-06-20: Ignore mixed-case and non-alpha characters.


Updated 2018-03-06: Fixed case where usernames inside links were not being blocked.


Updated 2018-03-04: Added function to hide long subject lines, because some trolls like to write manifesto-length gibberish in the Subject: line.

There is now a maxSubjectLength variable (default value: 50). Any subject line exceeding that length will be hidden. If you reply to a post with a subject line exceeding that length, your reply's subject line will default to "Re: tl;dr".


Updated 2017-07-12: Added @include.


In my previous post, I mentioned that I spend too much of my life responding to trolls on Techdirt.

With that realization, I whipped up a quick Greasemonkey/Tampermonkey script to block all posts from specified usernames.

// ==UserScript==
// @name          Hide Techdirt Comments
// @namespace     http://corporate-sellout.com
// @description	  Hide comments on Techdirt, based on user and comment length.
// @include       https://www.techdirt.com/articles/*
// @include       https://www.techdirt.com/blog/*
// @require       https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js
// ==/UserScript==

// Maximum length of Subject and Name before hiding/flagging contents
const subjectLengthToHide = 50,
  subjectLengthToFlag = 80,
  nameLengthToHide = 26,  // length of "Anonymous Anonymous Coward"
  nameLengthToFlag = 30,
      
// Boolean settings:
// if true, hide all posts from users who aren't logged in
  hideLoggedOut = true,
  
// if true, hide all replies to hidden posts
  hideReplies = true,

// After this date, anyone posting as "Thad" who is not logged in is an imposter
  fakeThadDate = new Date('2018-08-01');

// List of users whose comments you want to hide -- collect 'em all!
var blacklist = [
  'Anonymous Coward',
  'MyNameHere',
  'Richard Bennett',
  'John Smith',
  'ROGS',
  'JEDIDIAH'
];

// List of users whose comments you don't want to hide
const whitelist = [
  'Chip',
  'Thad'
];

const clearInput = function() {
  $('#replysubject').val('Re: tl;dr');
};

// Convert string to all-lowercase and remove non-alpha characters
function trimString(str) {
  str = str.toLowerCase();
  return str.replace(/[^a-z+]+/g, '');
}

// get div that contains username / login information from comment
function nameBlock(cmt) {
  return $('.commentname > div', cmt);
}

// Check whether user is logged-in
function isLoggedIn(cmt) {
  return $('> :nth-child(2)', nameBlock(cmt)).text() === 'profile';
}

// Check whether post has already been hidden by the community
function alreadyHidden(cmt) {
  return $('> .abusivecomment', cmt).length > 0;
}

// Flag a comment
function flag(cmt) {
  var flagBtn = $('.report-button', cmt);
  if(!flagBtn.hasClass('down')) {
    var clickEvent = document.createEvent('MouseEvents');
    clickEvent.initEvent ('click', true, true);
    flagBtn[0].dispatchEvent(clickEvent);
  }
}

// Hide replies to a comment (requires threaded view)
function hideRepliesToComment(cmt) {
  var next = cmt.next();
  if(next.hasClass('nest')) {
  // Comment has replies; remove them.
    next.remove();
  }
}

// Check if user is not logged in and name length exceeds nameLengthToHide
function longName(cmt, name, loggedIn) {
  if(!loggedIn && name.length > nameLengthToHide && !whitelist.includes(name)) {
    // If name exceeds nameLengthToFlag, flag post
    if(name.length > nameLengthToFlag) {
      flag(cmt);
    }
    return true;
  }
  return false;
}

// Determine whether poster is Fake Thad
function fakeThad(cmt, name, loggedIn) {
  if(loggedIn === true) {
    // logged-in; user is not fake Thad.
    return false;
  }
  
  if(name === 'thad') {
    // Poster is "Thad", but is not logged in.
    // If post is newer than fakeThadDate, poster is Fake Thad.
    var dateString = $('i', nameBlock(cmt)).text();
      
    dateString = dateString.split(' @ ')[0];

    var date = new Date(dateString);
    if(date > fakeThadDate) {
      flag(cmt);
      return true;
    }
    
    // Post is older than fakeThadDate; do nothing.
    return false;
  }
  
  // User is not logged in and name is not exact match for 'Thad'.
  // Check whether it contains 'Thad' as a substring.
  if(name.includes('thad')) {
    flag(cmt);
    return true;
  }
  return false;
}

function checkName(cmt) {
  var fullName = $('.commentname > div > :first-child', cmt).text(),
    trimmedName = trimString(fullName),
    loggedIn = isLoggedIn(cmt);
  
  if(alreadyHidden(cmt)
    || longName(cmt, fullName, loggedIn)
    || blacklist.includes(trimmedName)
    || fakeThad(cmt, trimmedName, loggedIn)
    || (loggedIn === false && hideLoggedOut === true && !whitelist.includes(fullName))
  ) {
    if(hideReplies === true) {
      hideRepliesToComment(cmt);
      cmt.remove();
    } else {
      // replace comment with 'removed'
      // -- because replies will still be visible, this is necessary
      // so you can tell there's a missing post that they're replying to.
      cmt.text('removed');
    }
    return true;
  }
  
  return false;
}

function trimSubject(cmt) {
  var subjectNode = $('.commentsubject', cmt),
    subjectText = subjectNode.text(),
    len = subjectText.length;

  if(len > subjectLengthToHide) {
    subjectNode.empty();

    var cmtId = cmt.attr('id').substr(1),
      replyLink = $('#cmmt_link_' + cmtId);

    replyLink.click(clearInput);
    
    // If subject exceeds subjectLengthToFlag, user is not logged-in, and post is not a reply, then flag.
    if(len > subjectLengthToFlag && !isLoggedIn(cmt) && !subjectText.startsWith('Re:')) {
      flag(cmt);
    }
  }
}

for(var i=0; i<blacklist.length; i++) {
  blacklist[i] = trimString(blacklist[i]);
}

$('.cmt').each(function() {
  var cmt = $(this);
  
  // skip comment if it's already been removed
  if(document.contains(cmt[0])) {
    var removed = checkName(cmt);

    if(!removed) {
      trimSubject(cmt);
    }
  }
});

License

Copyright 2017-2018 Thaddeus R R Boyd

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Further Thoughts

(Note: The script was much smaller when I originally wrote this part of the post.)

This is a blunt instrument; it took about five minutes to write. It lacks subtlety and nuance.

Blocking all anonymous posters on Techdirt is not an ideal solution; most anons aren't trolls. (Most trolls, however, are anons.) I apologize to all the innocent anons blocked by this script.

I could make the script more precise. Techdirt's trolls are creatures of habit with certain noticeable verbal tics (more on that below); if I had a good parser, I think I could whip up a scoring system that could recognize troll posts with a high degree of accuracy.

The question is, how much time do I want to spend on that?

On the one hand, "five minutes in a text editor" is the appropriate amount of time for dealing with forum trolls. Anything else seems like more effort and attention than they deserve.

On the other hand, it's a potentially interesting project, I've always wanted to spend some time studying natural language processing, and any programming project is time well-spent if it teaches you a new skill.

So I haven't decided yet. Here's the script as it stands, in its initial, blunt-instrument-that-took-five-minutes form. If I update the script, I'll update this post.

Chip Tips

Lastly, as I can no longer see anonymous posts, this means I will likely have to give up my beloved sockpuppet, Chip, the man who hates all government regulations and loves to eat leaded paint chips. To anyone and everyone else who wants to keep the spirit of Chip alive, you have my blessing to post under his name.

A few tips on how to write as Chip:

  • Never use the backspace key.
  • Remember to add random Capital Letters and "quotation marks" to your posts, in Places where they "don't" make Sense!
  • Most sentences should end with Exclamation Points!
  • I told you So!
  • I have "lots" of Solutions! So many I can't Name a single "one"!
  • Sycophantic Idiots!
  • Every Nation eats the Paint chips it Deserves!

Boy, my regular readers are going to have no fucking idea what I'm talking about in this post.

Come back tomorrow; I plan on having a post about online privacy that should be a little less niche.