Begin improving filters

This commit is contained in:
calzoneman 2013-04-29 12:29:31 -05:00
parent 9350ef6d75
commit 4b0e920dc6
6 changed files with 96 additions and 55 deletions

View file

@ -21,6 +21,7 @@ var io = require("./server.js").io;
var Rank = require("./rank.js"); var Rank = require("./rank.js");
var Auth = require("./auth.js"); var Auth = require("./auth.js");
var ChatCommand = require("./chatcommand.js"); var ChatCommand = require("./chatcommand.js");
var Filter = require("./filter.js").Filter;
var Channel = function(name) { var Channel = function(name) {
Logger.syslog.log("Opening channel " + name); Logger.syslog.log("Opening channel " + name);
@ -52,10 +53,9 @@ var Channel = function(name) {
chat_antiflood: false chat_antiflood: false
}; };
this.filters = [ this.filters = [
[/`([^`]+)`/g , "<code>$1</code>" , true], new Filter("monospace", "`([^`]+)`", "g", "<code>$1</code>"),
[/\*([^\*]+)\*/g , "<strong>$1</strong>", true], new Filter("bold", "\\*([^\\*]+)\\*", "g", "<strong>$1</strong>"),
[/(^| )_([^_]+)_/g , "$1<em>$2</em>" , true], new Filter("italic", "(^| )_([^_]+)_", "g", "$1<em>$2</em>"),
[/\\\\([-a-zA-Z0-9]+)/g, "[](/$1)" , true]
]; ];
this.motd = { this.motd = {
motd: "", motd: "",
@ -117,9 +117,16 @@ Channel.prototype.loadDump = function() {
if(data.filters) { if(data.filters) {
this.filters = new Array(data.filters.length); this.filters = new Array(data.filters.length);
for(var i = 0; i < data.filters.length; i++) { for(var i = 0; i < data.filters.length; i++) {
this.filters[i] = [new RegExp(data.filters[i][0], "g"), var f = data.filters[i];
data.filters[i][1], // Backwards compatibility
data.filters[i][2]]; if(f[0] != undefined) {
this.filters[i] = new Filter("", f[0], "g", f[1]);
this.filters[i].active = f[2];
}
else {
this.filters[i] = new Filter(f.name, f.source, f.flags, f.replace);
this.filters[i].active = f.active;
}
} }
} }
if(data.motd) { if(data.motd) {
@ -136,9 +143,7 @@ Channel.prototype.loadDump = function() {
Channel.prototype.saveDump = function() { Channel.prototype.saveDump = function() {
var filts = new Array(this.filters.length); var filts = new Array(this.filters.length);
for(var i = 0; i < this.filters.length; i++) { for(var i = 0; i < this.filters.length; i++) {
filts[i] = [this.filters[i][0].source, filts[i] = this.filters[i].pack();
this.filters[i][1],
this.filters[i][2]];
} }
var dump = { var dump = {
position: this.position, position: this.position,
@ -400,7 +405,7 @@ Channel.prototype.sendRankStuff = function(user) {
if(Rank.hasPermission(user, "chatFilter")) { if(Rank.hasPermission(user, "chatFilter")) {
var filts = new Array(this.filters.length); var filts = new Array(this.filters.length);
for(var i = 0; i < this.filters.length; i++) { for(var i = 0; i < this.filters.length; i++) {
filts[i] = [this.filters[i][0].source, this.filters[i][1], this.filters[i][2]]; filts[i] = this.filters[i].pack();
} }
user.socket.emit("chatFilters", {filters: filts}); user.socket.emit("chatFilters", {filters: filts});
} }
@ -545,7 +550,7 @@ Channel.prototype.broadcastRankTable = function() {
Channel.prototype.broadcastChatFilters = function() { Channel.prototype.broadcastChatFilters = function() {
var filts = new Array(this.filters.length); var filts = new Array(this.filters.length);
for(var i = 0; i < this.filters.length; i++) { for(var i = 0; i < this.filters.length; i++) {
filts[i] = [this.filters[i][0].source, this.filters[i][1], this.filters[i][2]]; filts[i] = this.filters[i].pack();
} }
for(var i = 0; i < this.users.length; i++) { for(var i = 0; i < this.users.length; i++) {
if(Rank.hasPermission(this.users[i], "chatFilter")) { if(Rank.hasPermission(this.users[i], "chatFilter")) {
@ -1054,10 +1059,10 @@ Channel.prototype.trySetLock = function(user, data) {
Channel.prototype.updateFilter = function(filter) { Channel.prototype.updateFilter = function(filter) {
var found = false; var found = false;
for(var i = 0; i < this.filters.length; i++) { for(var i = 0; i < this.filters.length; i++) {
if(this.filters[i][0].source == filter[0].source) { if(this.filters[i].name == filter.name
&& this.filters[i].source == filter.source) {
found = true; found = true;
this.filters[i][1] = filter[1]; this.filters[i] = filter;
this.filters[i][2] = filter[2];
} }
} }
if(!found) { if(!found) {
@ -1066,9 +1071,10 @@ Channel.prototype.updateFilter = function(filter) {
this.broadcastChatFilters(); this.broadcastChatFilters();
} }
Channel.prototype.removeFilter = function(regex) { Channel.prototype.removeFilter = function(name, source) {
for(var i = 0; i < this.filters.length; i++) { for(var i = 0; i < this.filters.length; i++) {
if(this.filters[i][0].source == regex) { if(this.filters[i].name == name
&& this.filters[i].source == source) {
this.filters.splice(i, 1); this.filters.splice(i, 1);
break; break;
} }
@ -1086,23 +1092,23 @@ Channel.prototype.tryChangeFilter = function(user, data) {
} }
if(data.cmd == "update") { if(data.cmd == "update") {
var re = data.filter[0]; var re = data.filter.source;
var flags = "g"; var flags = data.filter.flags;
var slash = re.lastIndexOf("/");
if(slash > 0 && re[slash-1] != "\\") {
flags = re.substring(slash+1);
re = re.substring(0, slash);
}
try { try {
data.filter[0] = new RegExp(re, flags); new RegExp(re, flags);
} }
catch(e) { catch(e) {
return; return;
} }
this.updateFilter(data.filter); var f = new Filter(data.filter.name,
data.filter.source,
data.filter.flags,
data.filter.replace);
f.active = data.filter.active;
this.updateFilter(f);
} }
else if(data.cmd == "remove") { else if(data.cmd == "remove") {
this.removeFilter(data.filter[0]); this.removeFilter(data.filter.name, data.filter.source);
} }
} }
@ -1182,11 +1188,9 @@ Channel.prototype.filterMessage = function(msg) {
msg = msg.replace(/(((https?)|(ftp))(:\/\/[0-9a-zA-Z\.]+(:[0-9]+)?[^\s$]+))/g, "<a href=\"$1\" target=\"_blank\">$1</a>"); msg = msg.replace(/(((https?)|(ftp))(:\/\/[0-9a-zA-Z\.]+(:[0-9]+)?[^\s$]+))/g, "<a href=\"$1\" target=\"_blank\">$1</a>");
// Apply other filters // Apply other filters
for(var i = 0; i < this.filters.length; i++) { for(var i = 0; i < this.filters.length; i++) {
if(!this.filters[i][2]) if(!this.filters[i].active)
continue; continue;
var regex = this.filters[i][0]; msg = this.filters[i].filter(msg);
var replace = this.filters[i][1];
msg = msg.replace(regex, replace);
} }
return msg; return msg;
} }

24
filter.js Normal file
View file

@ -0,0 +1,24 @@
var Filter = function(name, regex, flags, replace) {
this.name = name;
this.source = regex;
this.flags = flags;
this.regex = new RegExp(this.source, this.flags);
this.replace = replace;
this.active = true;
}
Filter.prototype.pack = function() {
return {
name: this.name,
source: this.source,
flags: this.flags,
replace: this.replace,
active: this.active
}
}
Filter.prototype.filter = function(text) {
return text.replace(this.regex, this.replace);
}
exports.Filter = Filter;

View file

@ -2,7 +2,7 @@
"author": "Calvin Montgomery", "author": "Calvin Montgomery",
"name": "CyTube", "name": "CyTube",
"description": "Online media synchronizer and chat", "description": "Online media synchronizer and chat",
"version": "1.4.3", "version": "1.4.4",
"repository": { "repository": {
"url": "http://github.com/calzoneman/sync" "url": "http://github.com/calzoneman/sync"
}, },

View file

@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
const VERSION = "1.4.3"; const VERSION = "1.4.4";
var fs = require("fs"); var fs = require("fs");
var Logger = require("./logger.js"); var Logger = require("./logger.js");

View file

@ -618,24 +618,29 @@ function updateChatFilters(entries) {
$(tbl.children()[1]).remove(); $(tbl.children()[1]).remove();
} }
for(var i = 0; i < entries.length; i++) { for(var i = 0; i < entries.length; i++) {
var f = entries[i];
var tr = $("<tr/>").appendTo(tbl); var tr = $("<tr/>").appendTo(tbl);
var remove = $("<button/>").addClass("btn btn-mini btn-danger") var remove = $("<button/>").addClass("btn btn-mini btn-danger")
.appendTo($("<td/>").appendTo(tr)); .appendTo($("<td/>").appendTo(tr));
$("<i/>").addClass("icon-remove-circle").appendTo(remove); $("<i/>").addClass("icon-remove-circle").appendTo(remove);
var regex = $("<code/>").text(entries[i][0]) var name = $("<code/>").text(f.name)
.appendTo($("<td/>").appendTo(tr)); .appendTo($("<td/>").appendTo(tr));
var replace = $("<code/>").text(entries[i][1]) var regex = $("<code/>").text(f.source)
.appendTo($("<td/>").appendTo(tr));
var flags = $("<code/>").text(f.flags)
.appendTo($("<td/>").appendTo(tr));
var replace = $("<code/>").text(f.replace)
.appendTo($("<td/>").appendTo(tr)); .appendTo($("<td/>").appendTo(tr));
var activetd = $("<td/>").appendTo(tr); var activetd = $("<td/>").appendTo(tr);
var active = $("<input/>").attr("type", "checkbox") var active = $("<input/>").attr("type", "checkbox")
.prop("checked", entries[i][2]).appendTo(activetd); .prop("checked", f.active).appendTo(activetd);
var remcallback = (function(filter) { return function() { var remcallback = (function(filter) { return function() {
socket.emit("chatFilter", { socket.emit("chatFilter", {
cmd: "remove", cmd: "remove",
filter: filter filter: filter
}); });
} })(entries[i]); } })(f);
remove.click(remcallback); remove.click(remcallback);
var actcallback = (function(filter) { return function() { var actcallback = (function(filter) { return function() {
@ -644,33 +649,33 @@ function updateChatFilters(entries) {
// changed before this callback // changed before this callback
// [](/amgic) // [](/amgic)
var enabled = active.prop("checked"); var enabled = active.prop("checked");
filter[2] = (filter[2] == enabled) ? !enabled : enabled; filter.active = (filter.active == enabled) ? !enabled : enabled;
socket.emit("chatFilter", { socket.emit("chatFilter", {
cmd: "update", cmd: "update",
filter: filter filter: filter
}); });
} })(entries[i]); } })(f);
active.click(actcallback); active.click(actcallback);
} }
var newfilt = $("<tr/>").appendTo(tbl); var newfilt = $("<tr/>").appendTo(tbl);
$("<td/>").appendTo(newfilt); $("<td/>").appendTo(newfilt);
var name = $("<input/>").attr("type", "text")
.appendTo($("<td/>").appendTo(newfilt));
var regex = $("<input/>").attr("type", "text") var regex = $("<input/>").attr("type", "text")
.appendTo($("<td/>").appendTo(newfilt)); .appendTo($("<td/>").appendTo(newfilt));
var flags = $("<input/>").attr("type", "text")
.val("g")
.appendTo($("<td/>").appendTo(newfilt));
var replace = $("<input/>").attr("type", "text") var replace = $("<input/>").attr("type", "text")
.appendTo($("<td/>").appendTo(newfilt)); .appendTo($("<td/>").appendTo(newfilt));
var add = $("<button/>").addClass("btn btn-primary") var add = $("<button/>").addClass("btn btn-primary")
.text("Add Filter") .text("Add Filter")
.appendTo($("<td/>").appendTo(newfilt)); .appendTo($("<td/>").appendTo(newfilt));
var cback = (function(regex, replace) { return function() { var cback = (function(name, regex, fg, replace) { return function() {
if(regex.val() && replace.val()) { if(regex.val() && replace.val()) {
var re = regex.val(); var re = regex.val();
var flags = "g"; var flags = fg.val();
var slash = re.lastIndexOf("/");
if(slash > 0 && re[slash-1] != "\\") {
flags = re.substring(slash+1);
re = re.substring(0, slash);
}
try { try {
var dummy = new RegExp(re, flags); var dummy = new RegExp(re, flags);
} }
@ -679,10 +684,16 @@ function updateChatFilters(entries) {
} }
socket.emit("chatFilter", { socket.emit("chatFilter", {
cmd: "update", cmd: "update",
filter: [regex.val(), replace.val(), true] filter: {
name: name.val(),
source: re,
flags: flags,
replace: replace.val(),
active: true
}
}); });
} }
} })(regex, replace); } })(name, regex, flags, replace);
add.click(cback); add.click(cback);
} }

View file

@ -124,7 +124,7 @@
</div> </div>
</div> </div>
<div class="row" style="display: none;" id="modnav"> <div class="row" style="display: none;" id="modnav">
<div class="span10 offset1" id="modtabs"> <div class="span12" id="modtabs">
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"> <li class="active">
<a href="javascript:void(0)" id="show_chancontrols">Channel Controls</a> <a href="javascript:void(0)" id="show_chancontrols">Channel Controls</a>
@ -145,10 +145,10 @@
</div> </div>
</div> </div>
<div class="row modonly" style="display: none" id="chancontrols"> <div class="row modonly" style="display: none" id="chancontrols">
<div class="span10 offset1"> <div class="span12">
<form action="javascript:void(0)"> <form action="javascript:void(0)">
<fieldset> <fieldset>
<div class="span4"> <div class="span5">
<label>When the queue is open:</label> <label>When the queue is open:</label>
<label class="checkbox"> <label class="checkbox">
<input type="checkbox" id="opt_qopen_allow_qnext"> <input type="checkbox" id="opt_qopen_allow_qnext">
@ -203,7 +203,7 @@
</div> </div>
</div> </div>
<div class="row modonly" id="banlist" style="display: none;"> <div class="row modonly" id="banlist" style="display: none;">
<div class="span10 offset1"> <div class="span12">
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<th></th> <th></th>
@ -215,17 +215,19 @@
</div> </div>
</div> </div>
<div class="row modonly" id="motdeditor" style="display: none;"> <div class="row modonly" id="motdeditor" style="display: none;">
<div class="span10 offset1"> <div class="span12">
<textarea rows="10" id="motdtext"></textarea> <textarea rows="10" id="motdtext"></textarea>
<button class="btn btn-primary" id="updatemotd">Update</button> <button class="btn btn-primary" id="updatemotd">Update</button>
</div> </div>
</div> </div>
<div class="row modonly" id="filtereditor" style="display: none;"> <div class="row modonly" id="filtereditor" style="display: none;">
<div class="span10 offset1"> <div class="span12">
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<th></th> <th></th>
<th>Name</th>
<th>Regex</th> <th>Regex</th>
<th>Flags</th>
<th>Replacement</th> <th>Replacement</th>
<th>Active</th> <th>Active</th>
</thead> </thead>
@ -233,7 +235,7 @@
</div> </div>
</div> </div>
<div class="row modonly" id="channelranks" style="display: none;"> <div class="row modonly" id="channelranks" style="display: none;">
<div class="span10 offset1"> <div class="span12">
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<th>Name</th> <th>Name</th>