Camamba Chat Helpers

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

当前为 2021-03-26 提交的版本,查看 最新版本

此脚本不应直接安装。它是供其他脚本使用的外部库,要使用该库请加入元指令 // @require https://update.cn-greasyfork.org/scripts/423722/915067/Camamba%20Chat%20Helpers.js

  1. // ==UserScript==
  2. // @name Camamba Chat Helpers
  3. // @namespace dannysaurus.camamba
  4. // @version 0.1.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.  
  14. /* jslint esversion: 9 */
  15. /* global me, camData, rooms, blockList, friendList, friendRequests, adminMessages, jsLang, byId, myRooms, knownUsers, activeRoom, selectedUser, settings, onMessageHandlers, postMessageHandlers */
  16.  
  17. (function() {
  18. function decorateUsers(users = {}) {
  19. const isUser = (user) => user.id;
  20.  
  21. const toArray = () => {
  22. if (Array.isArray(users)) {
  23. return [...users];
  24. }
  25.  
  26. if (users.id && users.name) {
  27. return [ users ];
  28. }
  29.  
  30. return Object.values(users);
  31. };
  32.  
  33. const toString = () => {
  34. return toArray().map(u => {
  35.  
  36. return Object.entries(u)
  37. .map(([prop, val]) => prop + ':' + val)
  38. .join('\t');
  39.  
  40. }).join('\n');
  41. };
  42.  
  43. const by = (userPredicateFnc) => {
  44. const result = [], excluded = [];
  45.  
  46. Object.values(users).filter(u => isUser(u)).forEach(u => {
  47. if(userPredicateFnc(u)) {
  48. result.push(u);
  49. } else {
  50. excluded.push(u);
  51. }
  52. });
  53.  
  54. if (excluded.length) {
  55. result.excluded = decorateUsers(excluded);
  56. result.excludedAll = decorateUsers([ ...excluded, ...users.excludedAll ]);
  57. }
  58.  
  59. return decorateUsers(result);
  60. };
  61.  
  62. const byId = (id) => {
  63. return by(user => user.id == id);
  64. };
  65.  
  66. const byName = (name) => {
  67. const nameLower = String(name).toLowerCase();
  68. return by(u => u.name.toLowerCase().includes(nameLower));
  69. };
  70.  
  71. const byGender = (gender) => {
  72. const genderLower = String(gender).toLowerCase();
  73. return by(u => u.gender.toLowerCase().startsWIth(genderLower));
  74. };
  75.  
  76. const byIsCammed = () => {
  77. if (!camData) return false;
  78.  
  79. const camDataUserIds = new Set(
  80. Object.values(camData)
  81. .filter(cd => cd.user)
  82. .map(cd => String(cd.user))
  83. );
  84.  
  85. return by(u => camDataUserIds.has(String(u.id)));
  86. };
  87.  
  88. const byViewing = () => {
  89. return users.by(user => user.viewing);
  90. };
  91. const byPos = (pos) => {
  92. return toArray()[pos];
  93. };
  94.  
  95. const stopViewing = () => byViewing.forEach(user => {
  96. janusSend('remove', user.id);
  97. });
  98.  
  99. const save = () => toArray().forEach(user => {
  100. user.original = {...user};
  101. });
  102.  
  103. const restore = () => by(user => user.original).forEach(user => {
  104. Object.assign(user, user.original);
  105. delete user.original;
  106. });
  107.  
  108. return Object.defineProperties(users, Object.fromEntries(Object.entries({
  109. excluded: users.excluded || [],
  110. excludedAll: users.excludedAll || [],
  111. toArray,
  112. toString,
  113. by,
  114. byId,
  115. byName,
  116. byGender,
  117. byPos,
  118. byIsCammed,
  119. byIsNotCammed: () => byIsCammed().excluded,
  120. byViewing,
  121. stopViewing,
  122. save,
  123. restore
  124. }).map(([propName, value]) => {
  125. return [propName, { value, configurable: true }];
  126. })));
  127. }
  128.  
  129. function decorateRooms(rooms = {}) {
  130. const roomsByName = (name) => {
  131. const nameLower = String(name).toLowerCase();
  132.  
  133. const result = {};
  134.  
  135. Object.entries(rooms).forEach(([roomId, roomName]) => {
  136.  
  137. if (roomName.toLowerCase().includes(nameLower)) {
  138. result[roomId] = roomName;
  139. }
  140. });
  141.  
  142. return result;
  143. };
  144.  
  145. return Object.defineProperties(rooms, {
  146. byName: { value: roomsByName, configurable: true },
  147. });
  148. }
  149.  
  150. const patchObject = function(getExpectedObjFnc, patchFnc, timeOutRetryMillis = 200, maxPeriodTryMillis = 5000) {
  151. const expectedObj = getExpectedObjFnc();
  152.  
  153. if (!expectedObj && timeOutRetryMillis <= maxPeriodTryMillis) {
  154. setTimeout(() => patchObject(getExpectedObjFnc, patchFnc, timeOutRetryMillis), maxPeriodTryMillis - timeOutRetryMillis);
  155. return;
  156. }
  157. patchFnc(expectedObj);
  158. };
  159.  
  160. patchObject(() => knownUsers, users => decorateUsers(users));
  161. patchObject(() => rooms, rooms => decorateRooms(rooms));
  162. })();