presence.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. type Functionlize<T> = {
  2. [P in keyof T]: () => T[P];
  3. };
  4. interface Route extends Functionlize<Partial<PresenceData>> {
  5. path: RegExp;
  6. playback?(): boolean;
  7. run?(): PresenceData;
  8. }
  9. const enum LoAssets {
  10. Logo = "https://cdn.rcd.gg/PreMiD/websites/M/Mahara-Tech/assets/logo.png",
  11. }
  12. enum Settings {
  13. TIMESTAMP = "timestamp",
  14. BUTTONS = "buttons",
  15. }
  16. let video = { duration: 0, currentTime: 0, paused: true };
  17. const presence = new Presence({
  18. clientId: "1146100707959783495",
  19. }),
  20. startTimestamp: number = Math.floor(Date.now() / 1000),
  21. router = ({
  22. path,
  23. presenceData,
  24. }: {
  25. path: string;
  26. presenceData: PresenceData;
  27. }): Route => {
  28. const routes: Route[] = [
  29. {
  30. path: /^\/my\//,
  31. details: () => "On Homepage",
  32. state: () => {
  33. return "Dashboard";
  34. },
  35. smallImageKey: () => Assets.Reading,
  36. smallImageText: () => "Browsing Courses",
  37. },
  38. {
  39. path: /^\/user\//,
  40. details: () => "Viewing a profile",
  41. state: () => {
  42. return `${
  43. document.querySelector("h4.breadcrumb_title").textContent
  44. }'s profile`;
  45. },
  46. smallImageKey: () => Assets.Reading,
  47. buttons: () => [
  48. {
  49. label: "Visit Profile",
  50. url: (() => {
  51. return document.location.href;
  52. })(),
  53. },
  54. ],
  55. },
  56. {
  57. path: /^\/mod\/hvp\/*/,
  58. run: () => {
  59. [presenceData.startTimestamp, presenceData.endTimestamp] =
  60. presence.getTimestamps(
  61. Math.floor(video.currentTime),
  62. Math.floor(video.duration)
  63. );
  64. if (video.paused) presence.getTimestamps;
  65. return presenceData;
  66. },
  67. playback: () => !video.paused,
  68. smallImageKey: () => (video.paused ? Assets.Pause : Assets.Play),
  69. smallImageText: () => (video.paused ? "Paused" : "Playing"),
  70. details: () => document.title,
  71. state: () => {
  72. return document.querySelector("h4.title.float-left").textContent;
  73. },
  74. buttons: () => [
  75. {
  76. label: "View Course",
  77. url: (() => {
  78. const href = document
  79. .querySelector(
  80. ".btn.btn-primary.ccn-btn-backtocourse.float-left"
  81. )
  82. .getAttribute("href");
  83. return href;
  84. })(),
  85. },
  86. ],
  87. },
  88. {
  89. path: /^\/mod\/quiz\/*/,
  90. smallImageKey: () => Assets.Writing,
  91. smallImageText: () => "taking a quiz...",
  92. details: () => document.title,
  93. state: () => {
  94. return document.querySelector("h4.title.float-left").textContent;
  95. },
  96. buttons: () => [
  97. {
  98. label: "View Course",
  99. url: (() => {
  100. const href = document
  101. .querySelector(
  102. ".btn.btn-primary.ccn-btn-backtocourse.float-left"
  103. )
  104. .getAttribute("href");
  105. return href;
  106. })(),
  107. },
  108. ],
  109. },
  110. {
  111. path: /^\/course\/(.*)/,
  112. smallImageKey: () => Assets.Viewing,
  113. smallImageText: () => "Viewing",
  114. details: () => "Viewing course",
  115. state: () => {
  116. return document.querySelector("h4.breadcrumb_title").textContent;
  117. },
  118. buttons: () => [
  119. {
  120. label: "View Course",
  121. url: (() => {
  122. return document.location.href;
  123. })(),
  124. },
  125. ],
  126. },
  127. {
  128. path: /^\/mod\/*/,
  129. details: () => "Browsing Courses",
  130. state: () => "Choosing a Course",
  131. smallImageKey: () => Assets.Search,
  132. buttons: () => [
  133. {
  134. label: "Search with me?",
  135. url: (() => {
  136. return document.location.href;
  137. })(),
  138. },
  139. ],
  140. },
  141. {
  142. path: /.*$/,
  143. details: () => "On Homepage",
  144. smallImageKey: () => Assets.Search,
  145. smallImageText: () => "Browsing website",
  146. },
  147. ];
  148. return routes.find(route => route.path?.test(path));
  149. };
  150. presence.on(
  151. "iFrameData",
  152. (data: { duration: number; currentTime: number; paused: boolean }) => {
  153. video = data;
  154. }
  155. );
  156. presence.on("UpdateData", async () => {
  157. const [showTimestamp, showButtons] = await Promise.all([
  158. presence.getSetting<boolean>(Settings.TIMESTAMP),
  159. presence.getSetting<boolean>(Settings.BUTTONS),
  160. ]);
  161. let presenceData: PresenceData = {
  162. largeImageKey: LoAssets.Logo,
  163. };
  164. if (showTimestamp) presenceData.startTimestamp = startTimestamp;
  165. const route = router({
  166. presenceData,
  167. path: document.location.href.replace(
  168. `https://${document.location.hostname}`,
  169. ""
  170. ),
  171. });
  172. if (!route) return presence.setActivity(presenceData);
  173. if (route.run) presenceData = route.run();
  174. if (route.state) presenceData.state = route.state();
  175. if (route.details) presenceData.details = route.details();
  176. if (showButtons && route.buttons) presenceData.buttons = route.buttons();
  177. if (route.largeImageKey) presenceData.largeImageKey = route.largeImageKey();
  178. if (route.smallImageKey) presenceData.smallImageKey = route.smallImageKey();
  179. if (route.smallImageText)
  180. presenceData.smallImageText = route.smallImageText();
  181. if (showTimestamp && route.endTimestamp)
  182. presenceData.endTimestamp = route.endTimestamp();
  183. presence.setActivity(presenceData, route.playback ? route.playback() : false);
  184. });