presence.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. const presence = new Presence({
  2. clientId: "733216959382159400",
  3. });
  4. let currentURL = new URL(document.location.href),
  5. currentPath = currentURL.pathname.replace(/^\/|\/$/g, "").split("/");
  6. const browsingTimestamp = Math.floor(Date.now() / 1000);
  7. let presenceData: PresenceData = {
  8. details: "Viewing an unsupported page",
  9. largeImageKey:
  10. "https://cdn.rcd.gg/PreMiD/websites/W/Wikivoyage/assets/logo.png",
  11. startTimestamp: browsingTimestamp,
  12. };
  13. const updateCallback = {
  14. _function: null as () => void,
  15. get function(): () => void {
  16. return this._function;
  17. },
  18. set function(parameter) {
  19. this._function = parameter;
  20. },
  21. get present(): boolean {
  22. return this._function !== null;
  23. },
  24. },
  25. /**
  26. * Initialize/reset presenceData.
  27. */
  28. resetData = (
  29. defaultData: PresenceData = {
  30. details: "Viewing an unsupported page",
  31. largeImageKey:
  32. "https://cdn.rcd.gg/PreMiD/websites/W/Wikivoyage/assets/logo.png",
  33. startTimestamp: browsingTimestamp,
  34. }
  35. ): void => {
  36. currentURL = new URL(document.location.href);
  37. currentPath = currentURL.pathname.replace(/^\/|\/$/g, "").split("/");
  38. presenceData = { ...defaultData };
  39. },
  40. /**
  41. * Search for URL parameters.
  42. * @param urlParam The parameter that you want to know about the value.
  43. */
  44. getURLParam = (urlParam: string): string => {
  45. return currentURL.searchParams.get(urlParam);
  46. };
  47. ((): void => {
  48. if (currentURL.hostname === "www.wikivoyage.org")
  49. presenceData.details = "On the home page";
  50. else {
  51. let title: string;
  52. const actionResult = (): string =>
  53. getURLParam("action") || getURLParam("veaction"),
  54. [lang] = currentURL.hostname.split("."),
  55. titleFromURL = (): string => {
  56. return decodeURI(
  57. (currentPath[1] === "index.php"
  58. ? getURLParam("title")
  59. : currentPath.slice(1).join("/")
  60. ).replaceAll("_", " ")
  61. );
  62. };
  63. try {
  64. title = document.querySelector("h1:not(:empty)").textContent;
  65. } catch (e) {
  66. title = titleFromURL();
  67. }
  68. /**
  69. * Returns details based on the namespace.
  70. * @link https://en.wikivoyage.org/wiki/Special:PrefixIndex
  71. */
  72. const namespaceDetails = (): string => {
  73. const details: { [index: string]: string } = {
  74. "-2": "Viewing a media",
  75. "-1": "Viewing a special page",
  76. 0: "Reading an article",
  77. 1: "Viewing a talk page",
  78. 2: "Viewing a user page",
  79. 3: "Viewing a user talk page",
  80. 4: "Viewing a project page",
  81. 5: "Viewing a project talk page",
  82. 6: "Viewing a file",
  83. 7: "Viewing a file talk page",
  84. 8: "Viewing an interface page",
  85. 9: "Viewing an interface talk page",
  86. 10: "Viewing a template",
  87. 11: "Viewing a template talk page",
  88. 12: "Viewing a help page",
  89. 13: "Viewing a help talk page",
  90. 14: "Viewing a category",
  91. 15: "Viewing a category talk page",
  92. 828: "Viewing a module",
  93. 829: "Viewing a module talk page",
  94. 2300: "Viewing a gadget",
  95. 2301: "Viewing a gadget talk page",
  96. 2302: "Viewing a gadget definition page",
  97. 2303: "Viewing a gadget definition talk page",
  98. 2600: "Viewing a topic",
  99. };
  100. return (
  101. details[
  102. [...document.querySelector("body").classList]
  103. .find(v => /ns--?\d/.test(v))
  104. .slice(3)
  105. ] || "Viewing a page"
  106. );
  107. };
  108. //
  109. // Important note:
  110. //
  111. // When checking for the current location, avoid using the URL.
  112. // The URL is going to be different in other languages.
  113. // Use the elements on the page instead.
  114. //
  115. if (
  116. (
  117. document.querySelector<HTMLAnchorElement>("#n-mainpage a") ??
  118. document.querySelector<HTMLAnchorElement>("#p-navigation a") ??
  119. document.querySelector<HTMLAnchorElement>(".mw-wiki-logo")
  120. ).href === currentURL.href
  121. )
  122. presenceData.details = "On the main page";
  123. else if (document.querySelector("#wpLoginAttempt"))
  124. presenceData.details = "Logging in";
  125. else if (document.querySelector("#wpCreateaccount"))
  126. presenceData.details = "Creating an account";
  127. else if (document.querySelector(".searchresults")) {
  128. presenceData.details = "Searching for a page";
  129. presenceData.state =
  130. document.querySelector<HTMLInputElement>("input[type=search]").value;
  131. } else if (actionResult() === "history") {
  132. presenceData.details = "Viewing revision history";
  133. presenceData.state = titleFromURL();
  134. } else if (getURLParam("diff")) {
  135. presenceData.details = "Viewing difference between revisions";
  136. presenceData.state = titleFromURL();
  137. } else if (getURLParam("oldid")) {
  138. presenceData.details = "Viewing an old revision of a page";
  139. presenceData.state = titleFromURL();
  140. } else if (
  141. document.querySelector("#ca-ve-edit") ||
  142. getURLParam("veaction")
  143. ) {
  144. presenceData.state = `${
  145. title.toLowerCase() === titleFromURL().toLowerCase()
  146. ? `${title}`
  147. : `${title} (${titleFromURL()})`
  148. }`;
  149. updateCallback.function = (): void => {
  150. if (actionResult() === "edit" || actionResult() === "editsource")
  151. presenceData.details = "Editing a page";
  152. else presenceData.details = namespaceDetails();
  153. };
  154. } else if (actionResult() === "edit") {
  155. presenceData.details = document.querySelector("#ca-edit")
  156. ? "Editing a page"
  157. : "Viewing source";
  158. presenceData.state = titleFromURL();
  159. } else {
  160. presenceData.details = namespaceDetails();
  161. presenceData.state = `${
  162. title.toLowerCase() === titleFromURL().toLowerCase()
  163. ? `${title}`
  164. : `${title} (${titleFromURL()})`
  165. }`;
  166. }
  167. if (lang !== "en") {
  168. if (presenceData.state) presenceData.state += ` (${lang})`;
  169. else presenceData.details += ` (${lang})`;
  170. }
  171. }
  172. })();
  173. if (updateCallback.present) {
  174. const defaultData = { ...presenceData };
  175. presence.on("UpdateData", async () => {
  176. resetData(defaultData);
  177. updateCallback.function();
  178. presence.setActivity(presenceData);
  179. });
  180. } else {
  181. presence.on("UpdateData", async () => {
  182. presence.setActivity(presenceData);
  183. });
  184. }