presence.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. const presence = new Presence({
  2. clientId: "802964241179082822",
  3. });
  4. const enum Assets {
  5. Logo = "https://cdn.rcd.gg/PreMiD/websites/K/KickAssAnime/assets/logo.png",
  6. }
  7. async function getStrings() {
  8. return presence.getStrings(
  9. {
  10. play: "general.playing",
  11. pause: "general.paused",
  12. viewSeries: "general.buttonViewSeries",
  13. viewMovie: "general.buttonViewMovie",
  14. watchEpisode: "general.buttonViewEpisode",
  15. viewing: "general.viewing",
  16. searching: "general.searchFor",
  17. episode: "general.episode",
  18. browse: "general.browsing",
  19. },
  20. await presence.getSetting<string>("lang").catch(() => "en")
  21. );
  22. }
  23. let browsingTimestamp = Math.floor(Date.now() / 1000),
  24. video = {
  25. exists: false,
  26. duration: 0,
  27. currentTime: 0,
  28. paused: true,
  29. },
  30. lastPlaybackState: boolean = null,
  31. playback: boolean,
  32. strings: Awaited<ReturnType<typeof getStrings>>,
  33. oldLang: string = null;
  34. presence.on(
  35. "iFrameData",
  36. (data: {
  37. exists: boolean;
  38. duration: number;
  39. currentTime: number;
  40. paused: boolean;
  41. }) => {
  42. video = data;
  43. playback = video.duration !== null ? true : false;
  44. if (lastPlaybackState !== playback) {
  45. lastPlaybackState = playback;
  46. browsingTimestamp = Math.floor(Date.now() / 1000);
  47. }
  48. }
  49. );
  50. presence.on("UpdateData", async () => {
  51. const presenceData: PresenceData = {
  52. largeImageKey: Assets.Logo,
  53. startTimestamp: browsingTimestamp,
  54. },
  55. [buttons, newLang, cover] = await Promise.all([
  56. presence.getSetting<boolean>("buttons"),
  57. presence.getSetting<string>("lang"),
  58. presence.getSetting<boolean>("episode-cover"),
  59. ]),
  60. { pathname, hostname, href } = document.location,
  61. fullUrl = (string: string) =>
  62. string ? `https://${hostname}${string}` : Assets.Logo;
  63. if (oldLang !== newLang) {
  64. oldLang = newLang;
  65. strings = await getStrings();
  66. }
  67. switch (true) {
  68. case video.exists: {
  69. if (playback && !isNaN(video.duration)) {
  70. presenceData.smallImageKey = video.paused ? Assets.Pause : Assets.Play;
  71. presenceData.smallImageText = video.paused ? "Paused" : "Playing";
  72. if (!video.paused) {
  73. [presenceData.startTimestamp, presenceData.endTimestamp] =
  74. presence.getTimestamps(video.currentTime, video.duration);
  75. }
  76. presenceData.buttons = [
  77. {
  78. label: "Watch Video",
  79. url: href,
  80. },
  81. ];
  82. }
  83. delete presenceData.startTimestamp;
  84. presenceData.details =
  85. document
  86. .querySelector('[name="og:title"]')
  87. ?.getAttribute("content")
  88. ?.split("-")[1] ??
  89. document
  90. .evaluate(
  91. "//script[contains(., 'layout:')]",
  92. document,
  93. null,
  94. XPathResult.ANY_TYPE,
  95. null
  96. )
  97. ?.iterateNext()
  98. ?.textContent?.match(/title_en:".{1,256}",/gm)?.[0]
  99. ?.replace(/(title_en:")|(",)/gm, "");
  100. presenceData.state = document
  101. .querySelector('[name="og:title"]')
  102. ?.getAttribute("content")
  103. ?.split("-")[2];
  104. presenceData.largeImageKey = fullUrl(
  105. document.querySelector('[name="og:image"]')?.getAttribute("content")
  106. );
  107. presenceData.buttons = [
  108. {
  109. label: strings.viewSeries,
  110. url: href,
  111. },
  112. ];
  113. break;
  114. }
  115. case pathname.includes("schedule"): {
  116. presenceData.details = strings.viewing;
  117. presenceData.state = "The schedule";
  118. break;
  119. }
  120. case pathname.includes("recent"): {
  121. presenceData.details = strings.viewing;
  122. presenceData.state = "Recently added anime";
  123. break;
  124. }
  125. case pathname.includes("popular"): {
  126. presenceData.details = strings.viewing;
  127. presenceData.state = "Popular anime";
  128. break;
  129. }
  130. case pathname.includes("anime"): {
  131. presenceData.details = strings.viewing;
  132. presenceData.state = "All anime";
  133. break;
  134. }
  135. case pathname.includes("trending"): {
  136. presenceData.details = strings.viewing;
  137. presenceData.state = "Trending anime";
  138. break;
  139. }
  140. default: {
  141. presenceData.details = strings.browse;
  142. break;
  143. }
  144. }
  145. if (!buttons && presenceData.buttons) delete presenceData.buttons;
  146. if (!cover && presenceData.largeImageKey !== Assets.Logo)
  147. presenceData.largeImageKey = Assets.Logo;
  148. presence.setActivity(presenceData);
  149. });