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.

Version au 26/12/2014. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==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.4.20141226
// @grant			GM_addStyle
// @run-at			document-end
// @require			http://code.jquery.com/jquery-2.1.1.min.js
// ==/UserScript==
/*-----------------------------------*/	
const DEBUG = false;
// TODO broken in FF, now
function debug() {
	if (DEBUG && console) {
		console.log.apply(console, arguments);
	}
}
/*-----------------------------------*/
(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 = '';
/* 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 )
	{
		setContainers(pageUsers)
		debug("listContainers: "+listContainers);

		drawBlock();

		$(Ctrls).click(function()
		{
			$('#'+STRING_VAF+'Content').toggle("slow")
			console.log(this)
		});
		
		setNext(nextPage);
		$('#'+STRING_VAF+'ButtonGo').click(function()
		{
			$(this).attr("disabled",'true');
			if(!scriptLaunched)
			{
				$('#'+STRING_VAF+'ShowCount').html("loading ...")
				updateFilters();
				debug(filters);
				lookPage();
				lookAhead();
				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"> \
					<u>filters</u> <br />\
					&nbsp;name: &nbsp;\
						<input id="'+STRING_VAF+'NameContains" type="text" class="filter"></input>\
					&nbsp;location: &nbsp;\
						<input id="'+STRING_VAF+'LocContains" type="text" class="filter" ></input>\
					\
					age: &nbsp;\
						min: <input id="'+STRING_VAF+'AgeMin" type="text" class="filter" size="2"></input>\
						&nbsp; \
						max: <input id="'+STRING_VAF+'AgeMax" type="text" class="filter" size="2"></input>\
					<br />\
					&nbsp; gender &nbsp;\
						<select id="'+STRING_VAF+'Gender" class="filter" name="gender" multiple="multiple" size="3">\
							<option value="" selected="selected">none specified</option>\
							'+options_gender+
						'</select>\
					\
					&nbsp; Role &nbsp;\
						<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 />\
					<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( 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 lookAhead ()
{
	if( next != '' || ! next.match(/\s*/) )
	{
		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();
				}
			});
		}
		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];
}
/*-----------------------------------*/
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);