// ==UserScript==
// @name Camamba Chat Helpers
// @namespace dannysaurus.camamba
// @version 0.1.4
// @description decorates "knownUsers" and "rooms" objects with functions useful for console and other scripts
// @license MIT License
// @include https://www.camamba.com/chat/
// @include https://www.de.camamba.com/chat/
// @include https://www.camamba.com/chat/
// @include https://www.de.camamba.com/chat/
// @grant none
// ==/UserScript==
/* jslint esversion: 9 */
/* global me, camData, rooms, blockList, friendList, friendRequests, adminMessages, jsLang, byId, myRooms, knownUsers, activeRoom, selectedUser, settings, onMessageHandlers, postMessageHandlers */
(function() {
function decorateUsers(users = {}) {
const isUser = (user) => {
return user.id;
};
const toArray = () => {
if (Array.isArray(users)) {
return [...users];
}
if (users.id && users.name) {
return [ users ];
}
return Object.values(users);
};
const toString = () => {
return toArray().map(u => {
return Object.entries(u)
.map(([prop, val]) => prop + ':' + val)
.join('\t');
}).join('\n');
};
const by = (userPredicateFnc) => {
const result = [], excluded = [];
Object.values(users).filter(u => isUser(u)).forEach(u => {
if(userPredicateFnc(u)) {
result.push(u);
} else {
excluded.push(u);
}
});
if (excluded.length) {
result.excluded = decorateUsers(excluded);
result.excludedAll = decorateUsers([ ...excluded, ...users.excludedAll ]);
}
return decorateUsers(result);
};
const byId = (id) => {
return by(user => user.id == id);
};
const byName = (name) => {
const nameLower = String(name).toLowerCase();
return by(user => {
return user.name.toLowerCase().includes(nameLower);
});
};
const byGender = (gender) => {
const genderLower = String(gender).toLowerCase();
return by(user => {
return user.gender.toLowerCase().startsWIth(genderLower);
});
};
const bySelected = () => {
const selectedUserId = selectedUser ? selectedUser.dataset.id : 0;
if (!selectedUserId) {
return by(user => false);
}
return byId(selectedUserId);
};
const byIsCammed = () => {
if (!camData) return false;
const camDataUserIds = new Set(
Object.values(camData)
.filter(cd => cd.user)
.map(cd => String(cd.user))
);
return by(user => {
return camDataUserIds.has(String(user.id));
});
};
const byViewing = () => {
return users.by(user => {
return user.viewing;
});
};
const byPos = (pos) => {
return toArray()[pos];
};
const stopViewing = () => {
return byViewing().forEach(user => {
janusSend('remove', user.id);
});
};
const save = () => toArray().forEach(user => {
user.original = {...user};
});
const restore = () => by(user => user.original).forEach(user => {
Object.assign(user, user.original);
delete user.original;
});
return Object.defineProperties(users, Object.fromEntries(Object.entries({
excluded: users.excluded || [],
excludedAll: users.excludedAll || [],
toArray,
toString,
by,
byId,
bySelected,
byName,
byGender,
byPos,
byIsCammed,
byIsNotCammed: () => byIsCammed().excluded,
byViewing,
stopViewing,
save,
restore
}).map(([propName, value]) => {
return [propName, { value, configurable: true }];
})));
}
function decorateRooms(rooms = {}) {
const roomsByName = (name) => {
const nameLower = String(name).toLowerCase();
const result = {};
Object.entries(rooms).forEach(([roomId, roomName]) => {
if (roomName.toLowerCase().includes(nameLower)) {
result[roomId] = roomName;
}
});
return result;
};
return Object.defineProperties(rooms, {
byName: { value: roomsByName, configurable: true },
});
}
const patchObject = function(getExpectedObjFnc, patchFnc, timeOutRetryMillis = 200, maxPeriodTryMillis = 5000) {
const expectedObj = getExpectedObjFnc();
if (!expectedObj && timeOutRetryMillis <= maxPeriodTryMillis) {
setTimeout(() => patchObject(getExpectedObjFnc, patchFnc, timeOutRetryMillis), maxPeriodTryMillis - timeOutRetryMillis);
return;
}
patchFnc(expectedObj);
};
patchObject(() => knownUsers, users => decorateUsers(users));
patchObject(() => rooms, rooms => decorateRooms(rooms));
})();