您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
User represents a camamba User, UserSearch represents a search-request for one or many users
当前为
此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.gf.qytechs.cn/scripts/405699/818213/Camamba%20User.js
// ==UserScript== // @name Camamba User // @namespace dannysaurus.camamba // // @include http://www.camamba.com/* // @include https://www.camamba.com/* // @include http://www.de.camamba.com/* // @include https://www.de.camamba.com/* // // @connect camamba.com // @grant GM_xmlhttpRequest // // @require https://gf.qytechs.cn/scripts/405143-simplecache/code/SimpleCache.js // @require https://gf.qytechs.cn/scripts/405144-httprequest/code/HttpRequest.js // @require https://gf.qytechs.cn/scripts/391854-enum/code/Enum.js // // @require https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js // // @version 0.1 // @license MIT License // @description User represents a camamba User, UserSearch represents a search-request for one or many users // @author Gerrit Höhle // ==/UserScript== /* jslint esnext: true */ /* globals SimpleCache, HttpRequest, HttpRequestHtml, Enum, $, jQuery */ const User = (() => { 'use strict'; const GENDERS = class GENDER extends Enum {}.init({ ANY: 'any' , FEMALE: 'female' , MALE: 'male', COUPLE: 'couple' }); return class User { constructor({ uid, nick, age, gender, location, distanceKm, latitudeDec, longitudeDec, isOnline, lastSeen, room, roomId, isReal, isPremium, isSuper, userLevel, timeStamp = new Date() } = {}) { Object.assign(this, { uid, nick, age, _gender: gender, location, distanceKm, latitudeDec, longitudeDec, isOnline, lastSeen, room, roomId, isReal, isPremium, isSuper, userLevel, timeStamp }); } get gender() { return this._gender instanceof GENDERS ? this._gender : GENDERS.ANY; } set gender(value) { this._gender = value; } static get GENDERS() { return GENDERS; } }; })(); const UserSearch = (() => { const UserController = (() => { const GENDERS = User.GENDERS; const getTextNodeValues = node => { if (node.nodeType === Node.TEXT_NODE) { const nodeValue = node.nodeValue.replace(/"/,''); return (/\S/.test(nodeValue)) ? [ nodeValue ] : []; } return Array.from(node.childNodes).flatMap(node => getTextNodeValues(node)); }; const fetchJsLinks = (html, user) => { const jsLinks = Object.assign( {}, ...[ 'openProfile', 'sendMail', 'openChat', 'openMap' ].map(fncName => { const linkElement = $(html).find(`a[href*="javascript:${fncName}("]`); if (linkElement.length > 0) { const href = linkElement.attr('href') || ''; const fncParam = ((href.match(/\((.+)\)/) || [])[1] || '').replace(/['"]/g,''); const innerHtml = (linkElement.html() || '').trim(); return { [fncName]: { href, fncParam, html: innerHtml } }; } })); if (typeof jsLinks.sendMail !== 'undefined') { user.uid = Number.parseInt(jsLinks.sendMail.fncParam); } if (typeof jsLinks.openProfile !== 'undefined') { user.nick = jsLinks.openProfile.fncParam; } if (typeof jsLinks.openChat !== 'undefined') { user.roomId = jsLinks.openChat.fncParam; user.room = jsLinks.openChat.html; } if (typeof jsLinks.openMap !== 'undefined') { const matchCoords = jsLinks.openMap.fncParam.match(/(-?\d{1,3}\.\d{8}),(-?\d{1,2}\.\d{8})/); if (matchCoords !== null) { user.longitudeDec = Number.parseFloat(matchCoords[1]); user.latitudeDec = Number.parseFloat(matchCoords[2]); } user.location = jsLinks.openMap.html; } }; const fetchTextNodes = (html, user) => { const textNodes = getTextNodeValues(html); for (let gender of [ GENDERS.FEMALE, GENDERS.MALE, GENDERS.COUPLE ].map(enm => enm.text)) { const match = textNodes[1].match(new RegExp(`^\\W*\(${gender}\),\\s\(\\d{1,3}\)`)); if (match !== null) { user.age = Number.parseInt(match[2]); user.gender = match[1]; break; } } const matches = textNodes[2].match(/Online\s((\d{1,4})\s(minutes|hours|days)\s)?(ago|now|never)/); if (matches !== null) { const term = matches[4]; if (term === 'never') { user.lastSeen = new Date(0); user.isOnline = false; } else { const timeStampShort = new Date(user.timeStamp.getFullYear(), user.timeStamp.getMonth(), user.timeStamp.getDate(), user.timeStamp.getHours(), user.timeStamp.getMinutes()); if (term === 'ago') { user.lastSeen = timeStampShort; user.isOnline = false; const value = Number.parseInt(matches[2]); const unit = matches[3]; switch (unit) { case 'minutes': user.lastSeen.setMinutes(user.lastSeen.getMinutes() - value); break; case 'hours': user.lastSeen.setMinutes(0); user.lastSeen.setHours(user.lastSeen.getHours() - value); break; case 'days': user.lastSeen.setMinutes(0); user.lastSeen.setHours(0); user.lastSeen.setDate(user.lastSeen.getDate() - value); break; } } else if (term === 'now') { user.lastSeen = timeStampShort; user.isOnline = true; } } } for (let txt of textNodes.slice(2)) { const distanceMatch = txt.match(/(\d{0,2},?\d{1,3})\skm\sfrom\syou/); if (distanceMatch !== null) { const distanceKm = Number.parseInt(distanceMatch[1].replace(/\D/g, '')); if (Number.isInteger(distanceKm)) { user.distanceKm = distanceKm; } } } }; const fetchImages = (html, user) => { const userData = {}; let foundImage = false; for (let [property, imageName] of Object.entries({ isPremium: 'premium.png', isSuper: 'super_premium.png', isReal: 'real.png' })) { userData[property] = $(html).find(`img[src$='/gfx/${imageName}']`).length > 0; foundImage |= userData[property]; } if (foundImage) { Object.assign(user, userData); } }; const fetchCustom = (html, user) => { const embedRankSrc = $(html).find("embed[src^='/levelRank.swf?displayRank']").attr('src') || ''; const match = embedRankSrc.match(/displayRank=(\d{1,3})/); if (match !== null) { user.userLevel = Number.parseInt(match[1]); } }; return class UserController { constructor(user = new User()) { this.user = user; } parseHtml(html = '') { fetchJsLinks(html, this.user); fetchTextNodes(html, this.user); fetchImages(html, this.user); fetchCustom(html, this.user); return this; } static parseHtml(user = new User(), html = '') { return new UserController(user).parseHtml(html); } }; })(); const createUrlParamsFromUserSearch = userSearch => Object.fromEntries( Object.entries({ nick: 'nick', gender: 'gender', page: 'page', isOnline: 'online', hasPicture: 'picture', isPremium: 'isprem', isReal: 'isreal', isSuper: 'issuper' }) .filter(([ propName, paramName ]) => userSearch[propName]) .map(([ propName, paramName ]) => { let paramValue = userSearch[propName]; paramValue = (typeof paramValue === 'boolean') ? (paramValue ? 1 : 0) : String(paramValue).replace(/\s/g, '+'); return [ paramName, paramValue ]; }) ); return class UserSearch { constructor({ nick = '', gender = User.GENDERS.ANY, isOnline = false, hasPicture = false, isPremium = false, isReal = false, isSuper = false, page = 0 } = {}) { Object.assign(this, { nick, gender, isOnline, hasPicture, isPremium, isReal, isSuper, page }); } execute() { return HttpRequestHtml.send({ url: 'https://www.camamba.com/search.php', params: createUrlParamsFromUserSearch(this) }).then((response) => { const userNodes = $(response.html).find('.searchNormal, .searchSuper').get(); return userNodes.map(node => new UserController().parseHtml(node).user); }).then(users => Promise.all( users.map(user => HttpRequestHtml.send({ url: 'https://www.camamba.com/user_level.php', params: { uid: user.uid } }).then((response) => new UserController(user).parseHtml(response.html).user)) )); } static execute(...args) { return new UserSearch(...args).execute(); } static get GENDERS() { return User.GENDERS; } }; })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址