🏠 Home 

Camamba Chat Helpers Library

decorates "knownUsers" and "rooms" objects with functions useful for console and other scripts

สคริปต์นี้ไม่ควรถูกติดตั้งโดยตรง มันเป็นคลังสำหรับสคริปต์อื่น ๆ เพื่อบรรจุด้วยคำสั่งเมทา // @require https://update.greasyfork.org/scripts/423722/960246/Camamba%20Chat%20Helpers%20Library.js

  1. // ==UserScript==
  2. // @name Camamba Chat Helpers Library
  3. // @namespace dannysaurus.camamba
  4. // @version 0.2.2
  5. // @description decorates "knownUsers" and "rooms" objects with functions useful for console and other scripts
  6. // @license MIT License
  7. // @include https://www.camamba.com/chat/
  8. // @include https://www.de.camamba.com/chat/
  9. // @include https://www.camamba.com/chat/
  10. // @include https://www.de.camamba.com/chat/
  11. // @grant none
  12. // ==/UserScript==
  13. /* jslint esversion: 9 */
  14. /* global me, camData, rooms, blockList, friendList, friendRequests, adminMessages, jsLang, byId, myRooms, knownUsers, activeRoom, selectedUser, settings, onMessageHandlers, postMessageHandlers, janusSend, wsSend, activeMainRoom, postToSite */
  15. /* globals SimpleCache, HttpRequest, HttpRequestHtml, Enum, User, UserSearch, $, jQuery */
  16. (function() {
  17. function decorateUsers(users = {}) {
  18. const isUser = (user) => {
  19. return user.hasOwnProperty("id") && !Object.getOwnPropertyDescriptor(user, "id").get;
  20. };
  21. const toArray = () => {
  22. if (Array.isArray(users)) {
  23. return [...users];
  24. }
  25. // single user object
  26. if (isUser(users)) {
  27. return [ users ];
  28. }
  29. return Object.values(users);
  30. };
  31. const toString = () => {
  32. return toArray().map(u => {
  33. return Object.entries(u)
  34. .map(([prop, val]) => prop + ':' + val)
  35. .join('\t');
  36. }).join('\n');
  37. };
  38. const by = (userPredicateFnc) => {
  39. const r###lt = [], excluded = [];
  40. Object.values(users).filter(u => isUser(u)).forEach(u => {
  41. if(userPredicateFnc(u)) {
  42. r###lt.push(u);
  43. } else {
  44. excluded.push(u);
  45. }
  46. });
  47. if (excluded.length) {
  48. r###lt.excluded = decorateUsers(excluded);
  49. r###lt.excludedAll = decorateUsers([ ...excluded, ...users.excludedAll ]);
  50. }
  51. return decorateUsers(r###lt);
  52. };
  53. const byId = (id) => {
  54. return by(user => user.id == id);
  55. };
  56. const byName = (name) => {
  57. const nameLower = String(name).toLowerCase();
  58. return by(user => {
  59. return user.name.toLowerCase().includes(nameLower);
  60. });
  61. };
  62. const byGender = (gender) => {
  63. const genderLower = String(gender).toLowerCase();
  64. return by(user => {
  65. return user.gender.toLowerCase().startsWith(genderLower);
  66. });
  67. };
  68. const bySelected = () => {
  69. const selectedUserId = selectedUser ? selectedUser.dataset.id : 0;
  70. if (!selectedUserId) {
  71. return by(user => false);
  72. }
  73. return byId(selectedUserId);
  74. };
  75. const byIsCammed = () => {
  76. if (!camData) return false;
  77. const camDataUserIds = new Set(
  78. Object.values(camData)
  79. .filter(cd => cd.user)
  80. .map(cd => String(cd.user))
  81. );
  82. return by(user => {
  83. return camDataUserIds.has(String(user.id));
  84. });
  85. };
  86. const byViewing = () => {
  87. return users.by(user => {
  88. return user.viewing;
  89. });
  90. };
  91. const byPos = (pos) => {
  92. return toArray()[pos];
  93. };
  94. const stopViewing = () => {
  95. return byViewing().forEach(user => {
  96. janusSend('remove', user.id);
  97. });
  98. };
  99. const save = () => toArray().forEach(user => {
  100. user.original = {...user};
  101. });
  102. const restore = () => by(user => user.original).forEach(user => {
  103. Object.assign(user, user.original);
  104. delete user.original;
  105. });
  106. const ban = (text, time, config = { isPublic: false, isPerma: false, suppressBanLog: false }) => {
  107. const { isPublic, isPerma, suppressBanLog } = config;
  108. if (me.admin && toArray(users).length === 1) {
  109. const currentAdminTarget = users[0].id;
  110. // ban
  111. wsSend( { command: "ban", target: currentAdminTarget, reason: text, time: time * 3600 } );
  112. // notify user
  113. wsSend( { command: "admin", type: "admin", msg: { text: knownUsers[me.id].name + " banned " + knownUsers[currentAdminTarget].name+" for "+time+" hours.", room: activeMainRoom, notify: true }} );
  114. // to banlog
  115. if (!suppressBanLog) {
  116. postToSite("/adm_banned.php", "duration="+time+"&myname="+escape(knownUsers[me.id].name)+"&banname="+escape(knownUsers[currentAdminTarget].name)+"&roomname="+escape(activeMainRoom)+"&reason="+escape(text));
  117. }
  118. // to chat
  119. if (isPublic) {
  120. wsSend( { command: "admin", type: "room", msg: { text: knownUsers[currentAdminTarget].name+" has been banned.", room: activeMainRoom }} );
  121. }
  122. // do perma
  123. if (isPerma) {
  124. postToSite("/adm_set.php", "uID="+currentAdminTarget+"&ban=-1");
  125. }
  126. }
  127. };
  128. const banPerma = (text) => ban(text, 24, { isPublic: false, isPerma: true, suppressBanLog: false });
  129. // { nick = '', gender = User.GENDERS.ANY, isOnline = false, hasPicture = false, isPremium = false, isReal = false, isSuper = false, page = 0 } = {}
  130. const add = (name, byNameExact = false) => {
  131. return UserSearch.execute({ nick: name }).then(searchR###lt => {
  132. if (byNameExact) {
  133. searchR###lt = searchR###lt.filter(u => u.nick === name);
  134. }
  135. searchR###lt.forEach(u => {
  136. users[u.uid] = {
  137. id: u.uid,
  138. name: u.nick,
  139. age: u.age,
  140. level: u.userLevel,
  141. real: u.isReal ? 1 : 0,
  142. premium: (() => {
  143. if (u.isSuper) {
  144. return 3;
  145. }
  146. if (u.isPremium){
  147. return 1;
  148. }
  149. return 0;
  150. })(),
  151. gender: (() => {
  152. if (u.gender === User.GENDERS.MALE) {
  153. return "male";
  154. }
  155. if (u.gender === User.GENDERS.FEMALE) {
  156. return "female";
  157. }
  158. if (u.gender === User.GENDERS.COUPLE) {
  159. return "couple";
  160. }
  161. return "";
  162. })(),
  163. };
  164. console.log(`found user with uid ${u.uid}, username ${u.nick}, level ${u.userLevel}`);
  165. });
  166. return searchR###lt;
  167. });
  168. };
  169. const banPermaByName = (name, text) => {
  170. // fast ban
  171. byName(name).banPermaFast(text);
  172. // via user search
  173. add(name, true).then(searchR###lt => {
  174. // only permaban new users and with an exact unique search r###lt
  175. const uid = (searchR###lt.length === 1) ? searchR###lt[0].uid : -1;
  176. if (uid > 1279501) {
  177. byId(uid).banPermaFast(text);
  178. }
  179. });
  180. };
  181. const userPropertiesDescriptor = Object.fromEntries([
  182. "age",
  183. "audio",
  184. "blocked",
  185. "cam",
  186. "camWantPending",
  187. "camWantProcessed",
  188. "friend",
  189. "gender",
  190. "id",
  191. "initPriv",
  192. "level",
  193. "moderator",
  194. "name",
  195. "premium",
  196. "real",
  197. "requestDeAnnoy",
  198. "video",
  199. "viewing",
  200. ].map(propName => ([ propName, {
  201. get() {
  202. return Object.values(users)
  203. .filter(u => isUser(u))
  204. .map(u => u[propName]);
  205. },
  206. configurable: true,
  207. }])));
  208. const metaPropertiesDescriptor = Object.fromEntries(Object.entries({
  209. excluded: users.excluded || [],
  210. excludedAll: users.excludedAll || [],
  211. toArray,
  212. toString,
  213. by,
  214. byId,
  215. bySelected,
  216. byName,
  217. byGender,
  218. byPos,
  219. byIsCammed,
  220. byIsNotCammed: () => byIsCammed().excluded,
  221. byViewing,
  222. add,
  223. addExact: (name) => add(name, true),
  224. stopViewing,
  225. ban,
  226. ban24: (text, config = { isPublic: false, isPerma: false, suppressBanLog: false }) => ban(text, 24, config),
  227. banPerma: (name) => {
  228. const text = "Du bist dauerhaft gebannt. Bitte erstelle keine weiteren Konten!";
  229. if (typeof name === "undefined" || !name.length) {
  230. banPerma(text);
  231. } else {
  232. banPermaByName(name, text);
  233. }
  234. },
  235. banPermaEn: (name) => {
  236. const text = "You are permanently banned from Camamba. Please do not create any additional accounts!";
  237. if (typeof name === "undefined" || !name.length) {
  238. banPerma(text);
  239. } else {
  240. banPermaByName(name, text);
  241. }
  242. },
  243. banPermaFast: (text) => banPerma(text),
  244. banSilent: (text, time) => ban(text, time, { isPublic: false, isPerma: false, suppressBanLog: true }),
  245. banSilentPerma: (text, time) => ban(text, time, { isPublic: false, isPerma: true, suppressBanLog: true }),
  246. save,
  247. restore,
  248. }).map(([propName, value]) => {
  249. return [propName, { value, configurable: true }];
  250. }));
  251. return Object.defineProperties(users, { ...userPropertiesDescriptor, ...metaPropertiesDescriptor });
  252. }
  253. function decorateRooms(rooms = {}) {
  254. const roomsByName = (name) => {
  255. const nameLower = String(name).toLowerCase();
  256. const r###lt = {};
  257. Object.entries(rooms).forEach(([roomId, roomName]) => {
  258. if (roomName.toLowerCase().includes(nameLower)) {
  259. r###lt[roomId] = roomName;
  260. }
  261. });
  262. return r###lt;
  263. };
  264. return Object.defineProperties(rooms, {
  265. byName: { value: roomsByName, configurable: true },
  266. });
  267. }
  268. const patchObject = ({ getExpected, doPatch, confirmAvailable = null, timeOutRetryMillis = 200, maxPeriodTryMillis = 5000 }) => {
  269. const expected = getExpected();
  270. const isAvailable = confirmAvailable ? confirmAvailable(expected) : !!expected;
  271. if (!isAvailable) {
  272. if (timeOutRetryMillis <= maxPeriodTryMillis) {
  273. setTimeout(() => {
  274. maxPeriodTryMillis -= timeOutRetryMillis;
  275. patchObject({ getExpected, doPatch, confirmAvailable, timeOutRetryMillis, maxPeriodTryMillis });
  276. }, timeOutRetryMillis);
  277. }
  278. return;
  279. }
  280. doPatch(expected);
  281. };
  282. patchObject({
  283. getExpected: () => {
  284. return knownUsers;
  285. },
  286. doPatch: (users) => {
  287. decorateUsers(users);
  288. }
  289. });
  290. patchObject({
  291. getExpected: () => {
  292. return rooms;
  293. },
  294. doPatch: (rooms) => {
  295. decorateRooms(rooms);
  296. }
  297. });
  298. })();