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.

От 26.12.2014. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==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);