presence.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. const presence = new Presence({ clientId: "1095377958241304586" }),
  2. browsingTimestamp = Math.floor(Date.now() / 1000);
  3. const enum Assets {
  4. Logo = "https://cdn.rcd.gg/PreMiD/websites/M/Memrise/assets/logo.png",
  5. }
  6. presence.on("UpdateData", async () => {
  7. const { pathname } = document.location,
  8. pathArr = pathname.split("/"),
  9. { details, smallImageKey, largeImageKey, state, buttons } = getPageData(
  10. pathArr[1],
  11. pathArr[2],
  12. pathArr[3],
  13. pathArr[4]
  14. ),
  15. presenceData: PresenceData = {
  16. largeImageKey: largeImageKey || Assets.Logo,
  17. startTimestamp: browsingTimestamp,
  18. details,
  19. };
  20. if (buttons) presenceData.buttons = buttons;
  21. if (smallImageKey) presenceData.smallImageKey = smallImageKey;
  22. if (state) presenceData.state = state;
  23. if (details) presence.setActivity(presenceData);
  24. });
  25. function getPageData(
  26. page: string,
  27. pageDetail: string,
  28. title: string,
  29. subtitle: string
  30. ): {
  31. details?: string;
  32. smallImageKey?: string;
  33. largeImageKey?: string;
  34. state?: string;
  35. buttons?: [ButtonData, ButtonData?];
  36. } {
  37. switch (page) {
  38. case "dashboard":
  39. return {
  40. details: `Viewing their ${page}...`,
  41. state: document.querySelector("h1").textContent,
  42. smallImageKey: Assets.Search,
  43. };
  44. case "course":
  45. return {
  46. details: document.querySelector(".course-name")?.textContent,
  47. state: document.querySelector(".progress-box-title")?.textContent,
  48. largeImageKey:
  49. document.querySelector<HTMLImageElement>(".course-photo img")?.src,
  50. buttons: [
  51. {
  52. label: "Go to Course",
  53. url: `https://app.memrise.com/course/${pageDetail}/${title}`,
  54. },
  55. ],
  56. };
  57. case "aprender": {
  58. const translate = document.querySelector(
  59. 'div[data-testid="testLearnableCard"] > div > div > div'
  60. ),
  61. points = document.querySelector("span > div > span"),
  62. completed = document.querySelector(
  63. 'div[data-testid="endOfSession"] h2'
  64. );
  65. let state = "";
  66. if (translate?.textContent && points?.textContent)
  67. state = `translate: ${translate.textContent} | ${points.textContent} points`;
  68. else if (completed?.textContent) state = completed.textContent;
  69. return {
  70. details: document.querySelector("header > div > a").textContent,
  71. state,
  72. smallImageKey: Assets.Reading,
  73. };
  74. }
  75. case "courses":
  76. return {
  77. details: "Browsing...",
  78. state: document.querySelector(".category-header").textContent,
  79. smallImageKey: Assets.Search,
  80. };
  81. case "dictionary": {
  82. const lang = pageDetail.charAt(0).toUpperCase() + pageDetail.slice(1);
  83. return title
  84. ? {
  85. details: `Learning ${lang} phrase:`,
  86. state: `${
  87. document.querySelector("mark:nth-child(1)").textContent
  88. } =
  89. ${document.querySelector("h2").textContent}`,
  90. smallImageKey: Assets.Reading,
  91. }
  92. : {
  93. details: `Looking up ${lang} phrases...`,
  94. smallImageKey: Assets.Search,
  95. };
  96. }
  97. case "user":
  98. return {
  99. details: "Viewing profile...",
  100. state: `Knows ${
  101. document.querySelector("li:nth-child(3) > div > strong").textContent
  102. } words | ${
  103. document.querySelector(".stat-value-xs").textContent
  104. } points`,
  105. };
  106. case "home":
  107. return getHomeDetail(pageDetail);
  108. case "settings":
  109. return getSettingsDetail(pageDetail);
  110. case "categories": // community domain
  111. return {
  112. details: "Browsing Community forums...",
  113. state: "All categories",
  114. smallImageKey: Assets.Search,
  115. };
  116. case "top":
  117. return {
  118. details: "Browsing Community forums...",
  119. state: "Top posted",
  120. smallImageKey: Assets.Search,
  121. };
  122. case "latest":
  123. return {
  124. details: "Browsing Community forums...",
  125. state: "Latest posts",
  126. smallImageKey: Assets.Search,
  127. };
  128. case "badges":
  129. return {
  130. details: "Browsing Community forums...",
  131. state: "All badges",
  132. smallImageKey: Assets.Search,
  133. };
  134. case "tags":
  135. return {
  136. details: "Browsing Community forums...",
  137. state: "Filter tags",
  138. smallImageKey: Assets.Search,
  139. };
  140. case "c": {
  141. // category, topic and post forum level
  142. return subtitle
  143. ? {
  144. details: `Forum: ${pageDetail.replaceAll("-", " ")}`,
  145. state: `Topic: ${title.replaceAll("-", " ")}`,
  146. smallImageKey: Assets.Search,
  147. }
  148. : {
  149. details: "Browsing forum category...",
  150. state: pageDetail.replaceAll("-", " "),
  151. smallImageKey: Assets.Search,
  152. };
  153. }
  154. case "t": {
  155. return {
  156. details: `Forum: ${
  157. document.querySelector(
  158. "a:nth-child(1) > span.badge-category.clear-badge > span"
  159. ).textContent
  160. } > ${
  161. document.querySelector(
  162. "a:nth-child(2) > span.badge-category.clear-badge > span"
  163. ).textContent
  164. }`,
  165. state: `Post: ${document.querySelector(".fancy-title").textContent}`,
  166. smallImageKey: Assets.Reading,
  167. };
  168. }
  169. case "about": // general memrise domain
  170. return { details: "Viewing About us page..." };
  171. case "team":
  172. return { details: `Viewing Memrise ${page}...` };
  173. case "philosophy":
  174. return { details: `Reading Memrise ${page}...` };
  175. case "jobs":
  176. return { details: `Searching Memrise ${page}...` };
  177. case "blog":
  178. return {
  179. details: `Reading Memrise ${page}s...`,
  180. state: document.querySelector("#hs_cos_wrapper_name").textContent, //blog title
  181. smallImageKey: Assets.Reading,
  182. };
  183. case "contact":
  184. return { details: `Viewing Memrise ${page} page` };
  185. case "terms":
  186. return { details: `Reading Memrise ${page}` };
  187. case "privacy":
  188. return { details: `Reading Memrise ${page} policy` };
  189. case "cookies":
  190. return { details: `Reading Memrise ${page} policy` };
  191. default:
  192. return { details: "Browsing...", smallImageKey: Assets.Search };
  193. }
  194. }
  195. function getHomeDetail(pageDetail: string) {
  196. switch (pageDetail) {
  197. case "learning-statistics":
  198. return {
  199. details: "Viewing their learning stats...",
  200. state: `${document.querySelector(".rank").textContent}
  201. [Best Streak ${
  202. document.querySelector("#attendance-grid-label2 .large").textContent
  203. } |
  204. Current ${
  205. document.querySelector("#attendance-grid-label3 .large").textContent
  206. } |
  207. Total ${
  208. document.querySelector("#attendance-grid-label1 .large").textContent
  209. } days in the last 365 days]`,
  210. };
  211. case "difficult-words":
  212. return {
  213. details: `Viewing their ${
  214. document.querySelector(".tabbed-main > div.left").textContent
  215. }`,
  216. };
  217. case "leaderboard":
  218. return {
  219. details: "Viewing their group leaderboard...",
  220. state: `${
  221. document.querySelector("li.btn.btn-small.active").textContent
  222. }:
  223. ${document.querySelector(".row-points").textContent} points`,
  224. };
  225. default:
  226. return { details: "browsing home..." };
  227. }
  228. }
  229. function getSettingsDetail(pageDetails: string) {
  230. switch (pageDetails) {
  231. case "":
  232. return { details: "Changing their profile settings..." };
  233. case "personal_data":
  234. return { details: "Requesting their Personal Data..." };
  235. case "premium":
  236. return { details: "Changing their subscription settings..." };
  237. case "change_password":
  238. return { details: "Changing their password settings..." };
  239. case "deactivate":
  240. return { details: "Viewing their delete account settings..." };
  241. default:
  242. return { details: "Changing settings..." };
  243. }
  244. }