您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
greasemonkey script to find fetlife members when it's possible. Search by name, gender, role, age, location or status.
当前为
// ==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.20150313 // @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>></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> \ <label for="'+STRING_VAF+'AgeMin">min:</label>\ <input id="'+STRING_VAF+'AgeMin" type="text" class="filter" size="2"></input>\ \ <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 += ' Into \ <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 all"></input>\ <input id="'+STRING_VAF+'ButtonStop" type="button" value=" stop "></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 )?true:false; 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 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);