presence.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. const presence = new Presence({
  2. clientId: "959109938779684874",
  3. }),
  4. browsingTimestamp = Math.floor(Date.now() / 1000);
  5. presence.on("UpdateData", async () => {
  6. const presenceData: PresenceData = {
  7. details: "Browsing",
  8. largeImageKey:
  9. "https://cdn.rcd.gg/PreMiD/websites/W/Webnovel/assets/logo.png",
  10. },
  11. [privacy, timestamp, cover, buttons] = await Promise.all([
  12. presence.getSetting<boolean>("privacy"),
  13. presence.getSetting<number>("timestamp"),
  14. presence.getSetting<boolean>("cover"),
  15. presence.getSetting<boolean>("buttons"),
  16. ]),
  17. { pathname, hostname, href, search } = document.location,
  18. [book, comic, stories, ranking] = [
  19. pathname.startsWith("/book/"),
  20. pathname.startsWith("/comic/"),
  21. pathname.startsWith("/stories/"),
  22. pathname.startsWith("/ranking/"),
  23. ];
  24. switch (hostname) {
  25. case "www.webnovel.com": {
  26. if (pathname === "/") presenceData.details = "Home Page";
  27. else if (stories || ranking) {
  28. if (stories) presenceData.details = "Browsing Categories";
  29. else if (ranking) presenceData.details = "Viewing Rankings";
  30. if (!privacy) {
  31. const activeTab =
  32. document.querySelectorAll<HTMLAnchorElement>("a[class~='_on']");
  33. presenceData.details = `Viewing ${activeTab[0].title.replace(
  34. ",",
  35. ""
  36. )}`;
  37. presenceData.state = activeTab[1].title;
  38. }
  39. presenceData.smallImageKey = Assets.Search;
  40. } else if (book || comic) {
  41. if (cover) {
  42. presenceData.largeImageKey = `https://img.webnovel.com/bookcover/${
  43. pathname.split("/")[2].split("_")[1]
  44. }/600/600.jpg`;
  45. }
  46. if (document.querySelector(".cha-hd-mn")) {
  47. const novelInfo = document
  48. .querySelector<HTMLSpanElement>(".cha-hd-mn-text")
  49. .textContent.split(" / ");
  50. if (book) presenceData.details = "Reading a Novel";
  51. else if (comic) presenceData.details = "Reading a Comic";
  52. if (!privacy) {
  53. presenceData.details = novelInfo[0].trim();
  54. presenceData.state = novelInfo[1].trim();
  55. presenceData.smallImageKey = Assets.Reading;
  56. presenceData.smallImageText = "Reading";
  57. presenceData.buttons = [
  58. { label: "Read Chapter", url: document.URL },
  59. {
  60. label: "Read Book",
  61. url: document.querySelector<HTMLAnchorElement>(".dib.ell").href,
  62. },
  63. ];
  64. }
  65. } else {
  66. if (book) presenceData.details = "Viewing a Novel";
  67. else if (comic) presenceData.details = "Viewing a Comic";
  68. if (!privacy) {
  69. presenceData.state = document
  70. .querySelector<HTMLHeadingElement>("h2")
  71. .innerHTML.split(" <")[0];
  72. presenceData.buttons = [{ label: "View Book", url: document.URL }];
  73. }
  74. }
  75. } else if (pathname.startsWith("/profile/")) {
  76. presenceData.details = "Viewing a Profile";
  77. if (cover) {
  78. presenceData.largeImageKey =
  79. document.querySelector<HTMLImageElement>(".avatar-area img").src;
  80. }
  81. if (!privacy) {
  82. presenceData.state =
  83. document.querySelector<HTMLAnchorElement>("h3").textContent;
  84. presenceData.buttons = [{ label: "View Profile", url: document.URL }];
  85. }
  86. } else if (pathname.startsWith("/search")) {
  87. presenceData.details = "Searching";
  88. presenceData.smallImageKey = Assets.Search;
  89. if (!privacy) {
  90. presenceData.details = "Searching for:";
  91. presenceData.state =
  92. document.querySelector<HTMLInputElement>("input").value;
  93. }
  94. } else if (pathname.startsWith("/library"))
  95. presenceData.details = "Viewing Library";
  96. else if (pathname.startsWith("/history"))
  97. presenceData.details = "Viewing History";
  98. else if (pathname.startsWith("/tags")) {
  99. presenceData.details = "Browsing Tags";
  100. presenceData.smallImageKey = Assets.Search;
  101. if (!privacy) {
  102. presenceData.state =
  103. document.querySelector<HTMLHeadingElement>("h2").textContent;
  104. }
  105. }
  106. break;
  107. }
  108. case "forum.webnovel.com": {
  109. const params = new URLSearchParams(search);
  110. if (params.has("q") && pathname === "/") {
  111. presenceData.details = "Searching Forum";
  112. presenceData.smallImageKey = Assets.Search;
  113. if (!privacy) {
  114. presenceData.details = "Searching Forum for";
  115. presenceData.state = params.get("q");
  116. }
  117. } else if (pathname === "/") presenceData.details = "Forum Home Page";
  118. else if (pathname.startsWith("/following"))
  119. presenceData.details = "Viewing Followed discussions";
  120. else if (pathname.startsWith("/tags"))
  121. presenceData.details = "Browsing Tags";
  122. else if (pathname.startsWith("/t")) {
  123. presenceData.details = "Browsing Topics";
  124. presenceData.smallImageKey = Assets.Search;
  125. if (!privacy) {
  126. presenceData.state =
  127. document.querySelector<HTMLHeadingElement>(
  128. ".Hero-title"
  129. ).textContent;
  130. }
  131. } else if (pathname.startsWith("/d")) {
  132. presenceData.details = "Reading Discussion";
  133. presenceData.smallImageKey = Assets.Reading;
  134. if (!privacy) {
  135. presenceData.state =
  136. document.querySelector<HTMLHeadingElement>("h2").textContent;
  137. presenceData.buttons = [
  138. {
  139. label: "View Discussion",
  140. url: href.split("/").splice(0, 5).join("/"),
  141. },
  142. ];
  143. }
  144. } else if (pathname.startsWith("/u")) {
  145. presenceData.details = "Viewing User Profile";
  146. if (cover) {
  147. presenceData.largeImageKey = document.querySelector<HTMLImageElement>(
  148. ".UserCard-profile .Avatar"
  149. ).src;
  150. }
  151. if (!privacy) {
  152. presenceData.state = document.querySelector(
  153. ".UserCard-profile .username"
  154. ).textContent;
  155. presenceData.buttons = [
  156. {
  157. label: "View Profile",
  158. url: href.split("/").splice(0, 5).join("/"),
  159. },
  160. ];
  161. }
  162. } else if (pathname.startsWith("/p")) {
  163. presenceData.details = "Reading a Post";
  164. presenceData.smallImageKey = Assets.Reading;
  165. if (!privacy) {
  166. presenceData.state =
  167. document.querySelector<HTMLHeadingElement>(
  168. ".PageHero-title"
  169. ).textContent;
  170. presenceData.buttons = [{ label: "Read Post", url: document.URL }];
  171. }
  172. }
  173. break;
  174. }
  175. case "inkstone.webnovel.com": {
  176. if (pathname.includes("/dashboard"))
  177. presenceData.details = "Author's Dashboard";
  178. else if (pathname.startsWith("/academy")) {
  179. presenceData.details = "Writers Academy";
  180. presenceData.smallImageKey = Assets.Reading;
  181. if (pathname.includes("/column")) {
  182. presenceData.details = "Viewing a Column";
  183. if (!privacy)
  184. presenceData.state = document.querySelector("h2").textContent;
  185. } else if (pathname.includes("/article")) {
  186. presenceData.details = "Reading an Article";
  187. if (cover && document.querySelector('[class^="cover"] > img')) {
  188. presenceData.largeImageKey =
  189. document.querySelector<HTMLImageElement>(
  190. '[class^="cover"] > img'
  191. ).src;
  192. }
  193. if (!privacy) {
  194. presenceData.state =
  195. document.querySelector<HTMLDivElement>(".fs32.lh40").textContent;
  196. }
  197. }
  198. } else if (pathname.includes("/list"))
  199. presenceData.details = "Viewing their Novel List";
  200. else if (pathname.includes("/create")) {
  201. presenceData.details = "Making a Novel";
  202. presenceData.smallImageKey = Assets.Writing;
  203. }
  204. break;
  205. }
  206. }
  207. switch (presenceData.smallImageKey) {
  208. case "search":
  209. presenceData.smallImageText = "Searching";
  210. break;
  211. case "reading":
  212. presenceData.smallImageText = "Reading";
  213. break;
  214. }
  215. if (timestamp) presenceData.startTimestamp = browsingTimestamp;
  216. if (!buttons) delete presenceData.buttons;
  217. presence.setActivity(presenceData);
  218. });