fetlife_all_members (ASL+role+status search)

greasemonkey script to find fetlife members when it's possible. Search by name, gender, role, age, location or status.

Mint 2015.02.23.. Lásd a legutóbbi verzió

// ==UserScript==
// @name			fetlife_all_members (ASL+role+status search)
// @namespace		bewam.free.fr
// @description		greasemonkey script to find fetlife members when it's possible. Search by name, gender, role, age, location or status.
// @include			http*://fetlife.com/*
// @version			1.8.5.20150223
// @grant			GM_addStyle
// @run-at			document-end
// @require			http://code.jquery.com/jquery-2.1.1.min.js
// ==/UserScript==
/*-----------------------------------*/	
const DEBUG = false;
function debug() {
	if (DEBUG && console) {
		console.log.apply(console, arguments);
	}
}
/*-----------------------------------*/

var useCurrentPageAsDefault = false;

(function ($){

/*const*/ STRING_USERS = 'div.user_in_list',
	STRING_VAF = 'viewAllForm',
	ARRAY_GENDER = ['M','F','CD/TV','MtF','FtM','TG','GF','GQ','IS','B','FEM'],
	ARRAY_GENDER_LABEL = ['Male','Female','CD/TV','Trans-MtF','Trans-FtM','Transgender','Gender Fluid','Genderqueer','Intersex','Butch','Femme'],
	ARRAY_ROLE = ['Dom','Domme','Switch','sub','Master','Mistress','slave','pet','kajira','kajirus','Top','Bottom','Sadist','Masochist','Sadomasochist','Ageplayer','Daddy','babygirl','babyboy','Mommy','brat','Primal','Fetishist','Kinkster','Hedonist','Vanilla','Unsure'],
	ARRAY_ROLE_LABEL = ARRAY_ROLE,
	ARRAY_INTO_STATUS = ['is into', 'is curious about'],
	ARRAY_INTO_ACTIVITY = ['giving', 'receiving', 'watching', 'wearing', 'watching others wear', 'everything to do with it']
;

var placeAfter = '#header_v2';

var next = '';
var lastPageNumber,
	currentPageNumber,
	InputcurrentPageDefaultVal
;
/* balance columns */
var altPos = 0,
	currentCount = 0
;
var members = [], // user html storage
	/** NOTE mCache = ARRAY( { i: { [0]'name':'', [1]'age':XX, [2]'gender':WW, [3]'role':'', [4]'location':'', [5]url:'', [6]"hasAvatar":boolean } }) */
	mCache = [],
	listContainers = [] // columns where lists appear
;
var userRegExp = new RegExp('([0-9]{2})('+ARRAY_GENDER.join('|')+')? ('+ARRAY_ROLE.join('|')+')?','i');

/** modified, value, default value*/
var filters = {
	'NameContains': [false,'',''],
	'AgeMin': [false,'',''],
	'AgeMax': [false,'',''],
	'Gender': [false, [], []],
	'Role': [false, [], []],
	'LocContains': [false,'',''],
	'IntoStatus': [false,'',''],
	'IntoActivity': [false,'','']
// has_avatar: @see function
};
var ajaxLocked = false,
	scriptLaunched = false,
	 is_fetishes_page = /^\/fetishes/.test(unsafeWindow.location.pathname)
;
/*-----------------------------------*/
function init()
{
	var nextPage = $('a.next_page'),
		previousPage = $('a.previous_page'),
		pageUsers = $(STRING_USERS),
		Ctrls = "#"+STRING_VAF+"Controls"
	;
	
	/** a next_page link and a list of members are on current page ? go on */
	if( ( nextPage.length > 0 || previousPage.length > 0) && pageUsers.length > 0 )
	{
		currentPageNumber = parseInt($('em.current').text());
		
		setContainers(pageUsers)
		debug("listContainers: "+listContainers);
		
		debug($('em.current').text()+' currentPageNumber   '+currentPageNumber );

		drawBlock();
		
		$('#'+STRING_VAF+'FromPage').val(useCurrentPageAsDefault ? currentPageNumber:1);

		lastPageNumber = parseInt($(nextPage).prev().text());
		$('#'+STRING_VAF+'ToPage').val(lastPageNumber);
		debug("lastPageNumber: " + lastPageNumber );
		
		$(Ctrls).click(function()
		{
			$('#'+STRING_VAF+'Content').toggle("slow")
			console.log(this)
		});
		$('#'+STRING_VAF+'ButtonCurrentPage').click( function()
		{
			$('#'+STRING_VAF+'FromPage').val(currentPageNumber);
		});
		setNext(nextPage);
		$('#'+STRING_VAF+'ButtonGo').click( function()
		{
			$(this).attr("disabled", 'true');
			launchSearch();
		});
	}
};
function launchSearch()
{
	var FromPage = parseInt($('#'+STRING_VAF+'FromPage').val());
	debug('from page: '+FromPage);
	if( ! scriptLaunched )
	{
		$('#'+STRING_VAF+'ShowCount').html("loading ...")
		updateFilters();
		debug(filters);
		// TODO delete it when "?page=1"
//		lookPage();
		$('#'+STRING_VAF+'ButtonCurrentPage').attr("disabled", 'true');
		$('#'+STRING_VAF+'FromPage').attr("disabled", 'true');
		cleanPage();
		lookAhead(FromPage);
		scriptLaunched = true;
	}
}
GM_addStyle(
	'#'+STRING_VAF+'Container { \
		background-color: rgba(255, 255, 255, 0.4);\
		color: white !important;/**/ \
		padding:5px;\
		min-height:15px !important;\
		vertical-align:middle;\
	} \
	#'+STRING_VAF+'Controls { \
		display: block;/**/ \
		min-height:15px !important;\
	}\
	#'+STRING_VAF+'Content { \
		display: none;/**/ \
	}\
	#'+STRING_VAF+'ButtonStop{ \
		display: none;\
	}\
	'
);

function drawBlock(){

		var options_gender = '',
			options_role = '',
			options_into_activity = '',
			options_into_status = ''
		;
		$.each(ARRAY_GENDER, function(i,v){options_gender+='<option value="'+v+'" >'+ARRAY_GENDER_LABEL[i]+'</option>'});
		$.each(ARRAY_ROLE, function(i,v){options_role+='<option value="'+v+'" >'+ARRAY_ROLE_LABEL[i]+'</option>'});
		$.each(ARRAY_INTO_ACTIVITY, function(i,v){options_into_activity+='<option value="'+v+'" >'+ARRAY_INTO_ACTIVITY[i]+'</option>'});
		$.each(ARRAY_INTO_STATUS, function(i,v){options_into_status+='<option value="'+v+'" >'+ARRAY_INTO_STATUS[i]+'</option>'});
		
		var BLOCK = '<div id="'+STRING_VAF+'Container"> \
				<div id="'+STRING_VAF+'Controls">\
					<b>&gt;</b> \
					<u>view all members</u>\
				</div>\
				<div id="'+STRING_VAF+'Content"> \
						<label for="'+STRING_VAF+'NameContains">name:</label>\
						<input id="'+STRING_VAF+'NameContains" type="text" class="filter"></input>\
					<br />\
						<label for="'+STRING_VAF+'LocContains">location:</label>\
						<input id="'+STRING_VAF+'LocContains" type="text" class="filter" ></input>\
					\
					<br />\
					<u>age</u>&nbsp;\
					<label for="'+STRING_VAF+'AgeMin">min:</label>\
					<input id="'+STRING_VAF+'AgeMin" type="text" class="filter" size="2"></input>\
					&nbsp; \
					<label for="'+STRING_VAF+'AgeMax">max:</label>\
					<input id="'+STRING_VAF+'AgeMax" type="text" class="filter" size="2"></input>\
					<br />\
					<label for="'+STRING_VAF+'Gender">gender:</label>\
					<select id="'+STRING_VAF+'Gender" class="filter" name="gender" multiple="multiple" size="3">\
						<option value="" selected="selected">none specified</option>\
						'+options_gender+
					'</select>\
					\
					<label for="'+STRING_VAF+'Role">role:</label>\
					<select id="'+STRING_VAF+'Role" class="filter" name="role" multiple="multiple" size="5">\
						<option value="" selected="selected">none specified</option>\
						'+options_role+
					'</select>'
		;
				if(is_fetishes_page)
				{
					BLOCK +=
							'&nbsp; Into &nbsp;\
							<select id="'+STRING_VAF+'IntoStatus"  multiple="multiple" size="3">\
								<option value="" selected="selected">All</option>\
								'+options_into_status+
							'</select>\
							<select id="'+STRING_VAF+'IntoActivity" multiple="multiple" size="3">\
								<option value="" selected="selected">All</option>\
								'+options_into_activity+
							'</select>'
					;
				}
				BLOCK +=
					'<br />\
 					<input type="hidden" name="'+STRING_VAF+'HasAvatar" ></input>\
					<input type="checkbox" id="'+STRING_VAF+'HasAvatar" name="'+STRING_VAF+'HasAvatar" checked="false"></input>\
					<label for="'+STRING_VAF+'HasAvatar">only with avatar</label>\
					<br />\
					<label for="'+STRING_VAF+'FromPage">From page:</label>\
					<input id="'+STRING_VAF+'FromPage" type="text" class="filter" size="3" value="'+InputcurrentPageDefaultVal+'"></input>\
					<input id="'+STRING_VAF+'ButtonCurrentPage" type="button" value="current"></input>'+
//					'\
//					<label for="'+STRING_VAF+'ToPage">to page:</label>\
//					<input id="'+STRING_VAF+'ToPage" type="text" class="filter" size="3"></input>\
//					'+
					'<br />\
					<span id="'+STRING_VAF+'Buttons" style="display:inline;">\
					<input id="'+STRING_VAF+'ButtonGo" type="button" value="view&nbsp;all"></input>\
					<input id="'+STRING_VAF+'ButtonStop" type="button" value="&nbsp;stop&nbsp;"></input>\
					</span> <br />\
					<span id="'+STRING_VAF+'ShowCount">\
					</span> \
				</div> \
				</div>'
				;
		
			
			if($(placeAfter).length > 0)
				$(placeAfter).after(BLOCK)
			else
				$('body').prepend(BLOCK);
			
			
}
function updateFilters()
{
	$('#'+STRING_VAF+'Container').find('select, input[type=text]').each(function(){

		var name = $(this).attr('id').replace(STRING_VAF,'');
		debug(name);
		if(! filters[name])
			return;
		if( typeof filters[name][2] != 'string')
		{
			var options = $(this).find('option:selected');
			
			filters[name][0] = false;
			filters[name][1] = [];
			$(options).each( function()
			{
					filters[name][0] = true;
					filters[name][1].push($(this).val());
			});
			if(filters[name][1].length == 1 && filters[name][1][0] == "" )
				filters[name][0] = false;
		}
		else
			if(filters[name][2] != $(this).val())
			{
				filters[name][0] = true;
				filters[name][1] = $(this).val();
			}
			else
			{
				filters[name][0] = false;
				filters[name][1] = filters[name][2];
			}
	});
};
/** due to recursive function*/
function seekingEnded()
{
	debug("total members: "+ members.length);
	showReFilter();
	showCount();
}
/*-----------------------------------*/
function setContainers(pageUsers){
	var parent;
	$(pageUsers).each(function(){
		parent = $(this).parent().get(0);
// 		debug("parent: "+$(parent).attr("class"))

		if($.inArray(parent, listContainers) == -1)
			listContainers.push(parent);
	});
}
function setNext(anchor)
{
	next = ( anchor.length > 0 )? 'https://fetlife.com' + anchor.attr('href'):'';
}
/*-----------------------------------*/
function filter(n)
{
	return (
		filter_role(n)
		&& filter_name(n)
		&& filter_location(n)
		&& filter_has_avatar(n)
		&& filter_gender(n)
		&& filter_role(n)
		&& filter_age_min(n)
		&& filter_age_max(n)
		&& filter_intoStatus(n)
		&& filter_intoActivity(n)
	);
}
function filter_has_avatar(n){
	debug(' '+n+' '+getCache(n)[6])
	debug("val() "+$('#'+STRING_VAF+'HasAvatar:checked'))

	if( $('#'+STRING_VAF+'HasAvatar:checked').length > 0 )
	{
		if( ! mCache[n][6]){
			debug('don\'t show')
			return false;
		}
		else
			debug('show')
	}
	else
		debug($('#'+STRING_VAF+'HasAvatar:checked').length > 0)

	return true;
}
function filter_name(n)
{
	if(filters['NameContains'][0])
		if( mCache[n][0].toLowerCase().indexOf(filters['NameContains'][1].toLowerCase()) < 0 )
			return false;
	return true;
}
/** TODO age */
function filter_age_min(n)
{
	if(filters['AgeMin'][0])
		if( mCache[n][1] <= parseInt(filters['AgeMin'][1]) )
			return false;
	return true;
}
function filter_age_max(n)
{
	if(filters['AgeMax'][0])
		if( mCache[n][1] >= parseInt(filters['AgeMax'][1]) )
			return false;
	return true;
}
function filter_role(n)
{
	if(filters['Role'][0])
		if($.inArray(mCache[n][3], filters['Role'][1]) < 0)
			return false;
	return true;
}
function filter_gender(n)
{
	if(filters['Gender'][0])
		if($.inArray(mCache[n][2], filters['Gender'][1]) < 0)
			return false;
	return true;
}
function filter_location(n)
{
	if(filters['LocContains'][0])
		if( mCache[n][4].toLowerCase().indexOf(filters['LocContains'][1].toLowerCase()) < 0 )
			return false;
	return true;
}
function filter_intoStatus(n)
{
	
	if(filters['IntoStatus'][0])
		if($.inArray(mCache[n][7], filters['IntoStatus'][1]) < 0)
			return false;
	return true;
}
function filter_intoActivity(n)
{
	if(filters['IntoActivity'][0])
		if($.inArray(mCache[n][8], filters['IntoActivity'][1]) < 0)
			return false;
	return true;
}
/*-----------------------------------*/
function lookPage()
{
//	var currentUsers = $(STRING_USERS);
//	var index = 0
//	currentUsers.each(function()
//	{
//		index = storeUser(this);
//		$(this).remove();
//		show(index);
//	});
}
function cleanPage(){
	$(STRING_USERS).remove();
	$("div.pagination").remove();
}
function lookAhead (firstPage)
{
	var myPage = 1;
	if( firstPage )
	{
		if( isInt(parseInt(firstPage)) )
			myPage = firstPage;

		next = location.href + ( location.search.toString().length > 0 ? "&page="+myPage : "?page=" +myPage);
	}
debug("next: "+next);
	if( next != '' || ! next.match(/\s*/) /* || currentPageNumber != lastPageNumber */ )
	{
		debug("next: "+next);
		if(! ajaxLocked){
			ajaxLocked = true;
			$.ajax({
				url: next,
				dataType: 'html',
				useCache: false,
				success: function(data)
				{
					setNext($(data).find('a.next_page'));
					$(data).find(STRING_USERS).each(function(){show(storeUser(this))});
					ajaxLocked = false;
 					lookAhead(false);
				}
			});
		}
		showCount();
	}
	else
	{
		/*seeking END (current and other pages), now all users are stored in members array*/
		seekingEnded();
	}
}
/*-----------------------------------*/

function showCount(){
	$('#'+STRING_VAF+'ShowCount').html("members: "+currentCount+" of "+members.length)
}
function show(n)
{
	if(filter(n))
	{
		$(listContainers[altPos]).append(members[n]);
		currentCount++;
		altPos = ( altPos == (listContainers.length -1) )? 0 : (altPos+1);
	}
}
/*-----------------------------------*/
function storeUser(user){
    var i = (members.push(user) - 1);
	var M = []; /* match: [whole, age (not null), gender, role ] */
	var firstSpan = $(user).find('div:eq(1) span:first');
	var C, into, regInto;
	var avatar = $(user).find('img.profile_avatar');
	
	mCache[i] = ['', 0, '', '', '', '', false, '', ''];
	C = mCache[i];
	/* name */
	C[0] = firstSpan.text();
	/** profile url */
	C[5] = firstSpan.find('a:first').attr('href');

	/** hasAvatar, need to be false if user has */
	C[6] = ( avatar.attr('src').indexOf('/images/avatar_missing') < 0 );

	M = $(user).find('div span:nth-child(2)').text().match(userRegExp);
// 	debug("match: "+(M[1]||"")+", "+(M[2]||"")+", "+(M[3]||""));
	/* age */
	C[1] = M[1];
	/* gender */
	C[2] = M[2];
	/* role */
	C[3] = M[3];
	
	/* location*/
	C[4] = $(user).find('div:eq(1) em').text()||'';
	
	/* into */
	if(is_fetishes_page)
	{
		M = []; /* match: ["into status", "rest aka into activity" ] */
		into = $(user).find('div:eq(1) span:eq(2)').text()||'';
		regInto = new RegExp('^('+ARRAY_INTO_STATUS.join('|')+') ?(.*$)?');
		
		M = into.match(regInto);
		if(M)
		{
			C[7] = M[1]||'';
			C[8] = M[2]||'';
		}
// 		debug("mCache[i][7] = "+C[7]+"  &&  mCache[i][8] = "+C[8])
	}
	debug(C);
	return i;
}
function getCache(n){
	return gC(n);
}
function gC(n){
	return mCache[n];
}
/*--------------helpers---------------*/
function isInt(n){
	return( ! isNaN(n) );
}
/*-----------------------------------*/
function showReFilter()
{
	$('#'+STRING_VAF+'Buttons').append(
		'<input id="'+STRING_VAF+'ButtonReFilter" type="button" value="filter&nbsp;again"></input>'
	)
	$('#'+STRING_VAF+'ButtonGo').remove();
	$('#'+STRING_VAF+'ButtonReFilter').click(function()
	{
		altPos = 0, currentCount = 0;
		window.scrollTo(0,0);
		updateFilters();
		debug(filters);
		$(STRING_USERS).remove();
		for(var i = 0; i < members.length; i++){
			show(i)
		}
		showCount();
	});
}
var count=0;

if(typeof $ == 'function')
	init();
else
{ setTimeout( 5000, function(){ if(typeof $ != 'function') alert('fetlife is modified, script '+ GM_info.script.name +'can\'t run please contact the author OR visit http://'+GM_info.script.namespace+'.')});}
/*-----------------------------------*/
})(jQuery)

jQuery.noConflict(true);