Camamba User

User represents a camamba User, UserSearch represents a search-request for one or many users

Version vom 19.06.2020. Aktuellste Version

Dieses Skript sollte nicht direkt installiert werden. Es handelt sich hier um eine Bibliothek für andere Skripte, welche über folgenden Befehl in den Metadaten eines Skriptes eingebunden wird // @require https://update.greasyforks.org/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://greasyforks.org/scripts/405143-simplecache/code/SimpleCache.js
// @require      https://greasyforks.org/scripts/405144-httprequest/code/HttpRequest.js
// @require      https://greasyforks.org/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;
        }
    };
})();
长期地址
遇到问题?请前往 GitHub 提 Issues。