This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/446112/1060781/Camamba%20Forums%20Search%20Library.js
- // ==UserScript==
- // @name Camamba Forums Search Library
- // @namespace hoehleg.userscripts.private
- // @version 0.0.3
- // @description fetches forums, threads and posts
- // @author Gerrit Höhle
- // @license MIT
- //
- // @require https://greatest.deepsurf.us/scripts/405144-httprequest/code/HttpRequest.js?version=1060129
- //
- // @grant GM_xmlhttpRequest
- //
- // ==/UserScript==
-
- /* jslint esversion: 9 */
-
- /**
- * @typedef ForumDef
- * @property {number} id
- * @property {string} lng
- * @property {string} title
- */
-
- /**
- * @typedef ThreadDef
- * @property {string} title
- * @property {number} id
- * @property {number} forumId
- * @property {number} postCount
- */
-
- /**
- * @typedef PostDef
- * @property {number} forumId
- * @property {number} threadId
- * @property {number} page
- * @property {number} id
- * @property {Date} postDate
- * @property {string} text
- * @property {string} uname
- * @property {number} uid
- */
-
- /**
- * @typedef ThreadIdentifier
- * @property {number} forumId
- * @property {number} threadId
- */
-
- class Post {
- /**
- * @param {PostDef} param0
- */
- constructor({ forumId, threadId, page, id, postDate, text, uname, uid }) {
- /** @type {number} */
- this.forumId = forumId;
- /** @type {number} */
- this.threadId = threadId;
- /** @type {number} */
- this.page = page;
- /** @type {number} */
- this.id = id;
- /** @type {Date} */
- this.postDate = postDate;
- /** @type {string} */
- this.text = text;
- /** @type {string} */
- this.uname = uname;
- /** @type {number} */
- this.uid = uid;
- }
-
- async delete() {
- return await HttpRequest.send({
- method: 'GET', url: "https://www.camamba.com/forum_view.php", params: {
- thread: this.threadId,
- forum: this.forumId,
- delete: this.id,
- page: this.page,
- }
- });
- }
- }
-
- class Thread {
-
- /**
- * @param {ThreadDef} param0
- */
- constructor({ title, id, forumId, postCount }) {
- /** @type {string} */
- this.title = title;
- /** @type {number} */
- this.id = id;
- /** @type {number} */
- this.forumId = forumId;
- /** @type {number} */
- this.postCount = postCount;
- }
-
- /**
- * @returns {Promise<Array<Post>>}
- */
- async getPosts(resultSizeLimit = 0) {
- return Thread.getPosts({ threadId: this.id, forumId: this.forumId, resultSizeLimit });
- }
-
- async delete() {
- for (const post of await this.getPosts()) {
- post.delete();
- }
- }
-
- /**
- * @param {ThreadIdentifier} param0
- * @returns {Promise<Array<Post>>}
- */
- static async getPosts({ threadId, forumId, resultSizeLimit = 0 }) {
- return (await HttpRequestHtml.send({
- url: "https://www.camamba.com/forum_view.php",
- params: {
- thread: threadId,
- forum: forumId,
- },
- pageNr: 1,
- pagesMaxCount: resultSizeLimit ? Math.ceil(resultSizeLimit / 10) : 10000,
- paramsConfiguratorForPageNr: (params, pageNr) => ({ ...params, page: pageNr - 1 }),
- hasNextPage: (res, _req) => res.html.querySelectorAll("td.psmallbox").length >= 30,
- resultTransformer: (res, req) => {
-
- return [...res.html.querySelectorAll("td.psmallbox")].map(td => {
- let postId = null, text = "", postDate = null;
-
- const div = td.querySelector("div");
- if (div) {
- const deleteLink = div.querySelector('a[href^="javascript:deletePost"]');
-
- if (deleteLink) {
- const postIdMatch = /(?<=javascript:deletePost)\d+(?=\(\))/.exec(deleteLink.href);
- postId = postIdMatch === null ? null : Number.parseInt(postIdMatch[0]);
- }
-
- text = [...div.childNodes]
- .filter(el => el.tagName !== "SCRIPT")
- .filter(el => el.tagName !== "A" || (!["javascript:deletePost", "javascript:parent.location", "javascript:var noop="].some(s => el.href.startsWith(s))))
- .map(el => el.textContent).join("").trim();
- }
-
- let uname = "", uid = null;
-
- const tdLeft = td.previousElementSibling;
- if (tdLeft && [...tdLeft.classList].includes("psmallbox2")) {
- const linkOpenProfile = tdLeft.querySelector('a[href^="javascript:openProfile("]');
- if (linkOpenProfile) {
- const unameMatch = /(?<=javascript:openProfile\(['"])\w+(?=['"]\))/.exec(linkOpenProfile.href);
- if (unameMatch) {
- uname = unameMatch[0];
- }
- }
-
- const imgUserpic = tdLeft.querySelector('img[src^="/userpics"]');
- if (imgUserpic) {
- const uidMatch = /(?<=userpics\/)\d+(?=\.s\.jpg)/.exec(imgUserpic.src);
- if (uidMatch) {
- uid = uidMatch[0];
- }
- }
-
- const divDate = tdLeft.querySelector('div.smalltext');
- if (divDate) {
- const postDateMatch = /(\d{2}).(\d{2}).(\d{4})\s(\d{1,2}):(\d{2}):(\d{2})/.exec(divDate.innerText.trim());
- if (postDateMatch) {
- const day = postDateMatch[1];
- const month = postDateMatch[2];
- const year = postDateMatch[3];
- const hour = postDateMatch[4];
- const minute = postDateMatch[5];
- const second = postDateMatch[6];
- postDate = new Date(year, month - 1, day, hour, minute, second);
- }
- }
- }
-
- let page = req.params.page;
- return { forumId, threadId, page, id: postId, postDate, text, uname, uid };
- }).filter(p => p.id && p.text).map(p => new Post(p));
- },
- })).flat();
- }
- }
-
- const Forum = (() => {
-
- /**
- * @param {number} forumId
- * @param {number} [resultSizeLimit]
- * @returns {HttpRequestHtml}
- */
- const createRequest = (forumId, resultSizeLimit = 0) => new HttpRequestHtml({
- url: "https://www.camamba.com/forum_view.php",
- params: { forum: forumId },
- pageNr: 1,
- pagesMaxCount: resultSizeLimit ? Math.ceil(resultSizeLimit / 10) : 10000,
- paramsConfiguratorForPageNr: (params, pageNr) => ({ ...params, page: pageNr - 1 }),
- hasNextPage: (res, _req) => res.html.querySelectorAll('a[href^="?thread="]').length >= 10,
- resultTransformer: (res, _req) => {
- return [...res.html.querySelectorAll('a[href^="?thread="]')].map(a => {
-
- const matchThreadId = new RegExp(`(?<=\\?thread=)\\d+(?=&forum=${forumId})`).exec(a.href);
- const threadId = matchThreadId === null ? null : Number.parseInt(matchThreadId[0]);
-
- let postCount = (() => {
-
- let postCountTD = a.parentElement;
-
- while (postCountTD !== null && postCountTD.tagName !== 'TD') {
- postCountTD = postCountTD.parentElement;
- }
-
- for (let i = 0; i < 2 && postCountTD !== null; i++) {
- postCountTD = postCountTD.nextElementSibling;
- }
-
- if (postCountTD != null) {
- let postCountMatch = /^\d+$/.exec(postCountTD.innerText.trim());
- if (postCountMatch && postCountMatch.length) {
- return Number.parseInt(postCountMatch[0]);
- }
- }
-
- return 0;
- })();
-
- return { title: a.innerHTML, id: threadId, forumId, postCount };
-
- }).filter(t => t.id && t.forumId && t.postCount).map(t => new Thread(t));
- },
- });
-
- return class Forum {
- /** @param {ForumDef} param0 */
- constructor({ id, lng, title }) {
- /** @type {number} */
- this.id = id;
- /** @type {string} */
- this.lng = lng;
- /** @type {string} */
- this.title = title;
- }
-
- /**
- * @returns {Promise<Array<Thread>>}
- */
- async getThreads(resultSizeLimit = 0) {
- this.request = createRequest(this.id, resultSizeLimit);
- this.lastResults = (await this.request.send()).flat();
- return this.lastResults;
- }
-
- /**
- * @returns {Promise<Array<Thread>>}
- */
- async getNextThreads() {
- if (!(this.request && this.lastResults && this.lastResults.length)) {
- return [];
- }
- this.request.pageNr += (this.request.pagesMaxCount);
- return (await this.request.send()).flat();
- }
-
- /**
- * @param {number} forumId
- * @returns {Promise<Array<Thread>>}
- */
- static async getThreads(forumId, resultSizeLimit = 0) {
- return (await createRequest(forumId, resultSizeLimit).send()).flat();
- }
- };
- })();
-
-
-
- const Foren = (() => {
-
- /**
- * @type {Promise<Array<Forum>>}
- */
- const foren = HttpRequestHtml.send({
- url: 'https://www.camamba.com/forum.php',
- params: { mode: 'all' },
- resultTransformer: (resp, _req) => [...resp.html.querySelectorAll('a[href^="/forum_view"]')].map(a => {
-
- const idMatch = /(?<=forum=)\d{1,2}$/.exec(a.href);
- const id = idMatch === null ? null : Number.parseInt(idMatch[0]);
-
- const lngMatch = /(?<=^\[)\D\D(?=\])/g.exec(a.textContent);
- const lng = lngMatch === null ? null : lngMatch[0].toLowerCase();
-
- const titleMatch = /(?<=^\[\D\D\]\s).+$/.exec(a.textContent);
- const title = titleMatch === null ? null : titleMatch[0];
-
- return { id, lng, title };
-
- }).filter(forum => forum.id && forum.lng).map(f => new Forum(f)),
- });
-
- return {
- /**
- * @returns {Promise<Array<Forum>>}
- */
- getAll: async () => await foren,
-
- /**
- * @param {string} lng
- * @returns {Promise<Array<Forum>>}
- */
- byLanguage: async (lng) => (await foren).filter(f => f.lng.toUpperCase() === lng.toUpperCase()),
-
- /**
- * @param {number} id
- * @returns {Promise<Forum>}
- */
- byId: async (id) => (await foren).find(f => f.id == id),
- };
- })();