// ==UserScript== // @name Decentralized Block Script // @namespace http://www.cgranade.com/ // @version 1 // @description Performs blocking on social media sites based on user-selected // blocklists. // @require http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js // @require http:////netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js // @match http://twitter.com/* // @match https://twitter.com/* // @grant GM_xmlhttpRequest // @copyright 2013, Christopher E. Granade. Licensed under the AGPLv3 (see // source code). // ==/UserScript== /** * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 . */ // FUNCTIONS /////////////////////////////////////////////////////////////////// function loadBlockList() { blockList = []; blockListSources.forEach(function(url) { GM_xmlhttpRequest({ method: "GET", url: url, onload: function(response) { console.log('got response for URL: ' + url); blockees = $.parseJSON(response.responseText).twitter; blockees.forEach(function (blockee) { blockList = blockList.concat([blockee["screen-name"]]); }); applyBlockList(); } }); }); } function applyBlockList() { style.text(""); blockList.forEach(function(blockee) { txt = style.text(); console.log('applying block to: ' + blockee); style.text(txt + "*[data-screen-name=" + blockee + "] {display: none;}\n"); }); } function loadSettings() { if (localStorage["blockListSources"] == undefined) { // Since we don't have a configuration GUI at the moment, // we need a default. This WILL be removed once a GUI is in place, // as no one gets to be specially privileged by this script. // Right now, this blocklist only blocks the author of this script, // to demonstrate the concept. blockListSources = ['https://raw.github.com/cgranade/decentralized-blockscript/master/blocklist-example.json']; // Apply the default and save it back to the config store. saveSettings(); } else { // FIXME: Commas may not be in URLs yet! blockListSources = localStorage["blockListSources"].split(","); } console.log('loaded blockListSources: ' + blockListSources); } function gui_loadSettings() { loadSettings(); srcs = blockListSources; if (srcs.length != 0) { // TODO: apply multiple URLs. $('#blkscript-settings-srcurl').val(srcs[0]); } } function saveSettings() { console.log('saving blockListSources: ' + blockListSources); localStorage["blockListSources"] = blockListSources.join(","); } function gui_saveSettings() { blockListSources = [$('#blkscript-settings-srcurl').val()]; saveSettings(); loadBlockList(); } function createSettingsGUI() { // Make an item in the settings dropdown. blockListSettingsItem = $('
  • Blocklist Settings
  • '); $('#user-dropdown .dropdown-menu').append(blockListSettingsItem); console.log('appended menu item'); // Make a panel on the dashboard. dashboardItem = $('
    '); dashboardItem.html( '
    ' + '
    ' + '

    Block Script Settings

    ' + '
    ' + '
    ' + '
    ' + '' + // TODO: make multiple URLs supported. '' + // TODO: put current value here. '' + '
    ' + '
    ' + '' + '
    '); dashboardItem.hide(); $('div.dashboard .mini-profile').after(dashboardItem); console.log('appended dashboard item'); // Hook up events to the dashboard. $('a', blockListSettingsItem).on("click", function() { gui_loadSettings(); dashboardItem.show(); }); $('#blkscript-settings-save').on("click", function() { gui_saveSettings(); dashboardItem.hide(); }); $('#blkscript-settings-cancel').on("click", function() { // Hide the panel. dashboardItem.hide(); }); console.log('attached events'); } // GLOBAL VARIABLES //////////////////////////////////////////////////////////// // Make a list of sources to load blocklists from. We will initialize this // when the DOM is ready, to avoid slowdown. blockListSources = []; // Note that this decision has ethical consequences! The block list is not // applied until well after the body is loaded, so harassing content may be seen // briefly. If this is unacceptable, we should modify this behavior to load // immediately, even at the cost of introducing slowdown and instabilty. // Make a list of whom to block so far. blockList = []; // How often should we refresh? refreshInterval = 120; // Units: [s] // Make a style container to hold the block styles. // TODO: make one per block source, so we can refresh independently. style = $(''); // MAIN //////////////////////////////////////////////////////////////////////// $('body').ready(function() { // Grab the block sources from the configuration store. loadSettings(); // Apply the initial blocklist. $('head').append(style); console.log('loading initial blocklist:\n\t' + blockListSources); loadBlockList(); // Create the settings GUI. createSettingsGUI(); // Reload the blocklist every once and a while. window.setInterval(function () { loadBlockList(); }, 1000 * refreshInterval); });