presence.ts 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import { Assets } from 'premid'
  2. const presence = new Presence({
  3. clientId: '1139510267311562842',
  4. })
  5. const browsingTimestamp = Math.floor(Date.now() / 1000)
  6. enum ActivityAssets {
  7. Logo = 'https://cdn.rcd.gg/PreMiD/websites/M/Moopa/assets/logo.png',
  8. }
  9. function getTitle(titleLang: number) {
  10. const metaTitle = document.querySelector('meta[name="title"]')
  11. const romajiTitle = metaTitle?.getAttribute('data-title-romaji')
  12. switch (titleLang) {
  13. case 0: {
  14. return romajiTitle
  15. }
  16. case 1: {
  17. return metaTitle?.getAttribute('data-title-english') || romajiTitle
  18. }
  19. case 2: {
  20. return metaTitle?.getAttribute('data-title-native') || romajiTitle
  21. }
  22. default: {
  23. return null
  24. }
  25. }
  26. }
  27. presence.on('UpdateData', async () => {
  28. const presenceData: PresenceData = {
  29. largeImageKey: ActivityAssets.Logo,
  30. startTimestamp: browsingTimestamp,
  31. }
  32. const titleLang = (await presence.getSetting('title')) as number
  33. const { pathname, href } = document.location
  34. if (pathname === '/' || pathname === '/en/') {
  35. presenceData.details = 'Browsing Homepage'
  36. }
  37. else if (pathname.includes('/id/')) {
  38. presenceData.details = 'Browsing Anime/Manga'
  39. }
  40. else if (pathname.includes('/profile/')) {
  41. presenceData.details = document.querySelector('h1.font-karla.font-bold.text-2xl.pt-7')
  42. ?.textContent || 'Getting data...'
  43. presenceData.state = 'Viewing profile'
  44. }
  45. else if (pathname === '/en/anime/trending/') {
  46. presenceData.details = 'Browsing trending Anime'
  47. }
  48. else if (pathname === '/en/anime/popular/') {
  49. presenceData.details = 'Browsing popular Anime'
  50. }
  51. else if (
  52. pathname.includes('/anime/')
  53. && !pathname.includes('/watch/')
  54. && !pathname.includes('/search/')
  55. ) {
  56. if (document.querySelector('img[alt="404"]')) {
  57. presenceData.state = '404 | Not Found'
  58. presenceData.details = 'Browsing Anime/Manga'
  59. }
  60. else {
  61. delete presenceData.startTimestamp
  62. const title = getTitle(titleLang)
  63. presenceData.largeImageKey = document
  64. .querySelector('img[alt="poster anime"]')
  65. ?.getAttribute('src') || ActivityAssets.Logo
  66. presenceData.details = title || 'Getting data...'
  67. presenceData.state = 'Viewing info'
  68. if (title) {
  69. presenceData.buttons = [
  70. {
  71. label: 'View Anime',
  72. url: href,
  73. },
  74. ]
  75. }
  76. }
  77. }
  78. else if (
  79. pathname.includes('/manga/')
  80. && !pathname.includes('/read/')
  81. && !pathname.includes('/search/')
  82. ) {
  83. if (document.querySelector('img[alt="404"]')) {
  84. presenceData.state = '404 | Not Found'
  85. presenceData.details = 'Browsing Anime/Manga'
  86. }
  87. else {
  88. delete presenceData.startTimestamp
  89. const title = document.querySelector('h1.title')?.textContent
  90. presenceData.largeImageKey = document.querySelector('img[alt="cover image"]')?.getAttribute('src')
  91. || ActivityAssets.Logo
  92. presenceData.details = title || 'Getting data...'
  93. presenceData.state = 'Viewing info'
  94. if (title) {
  95. presenceData.buttons = [
  96. {
  97. label: 'View Manga',
  98. url: href,
  99. },
  100. ]
  101. }
  102. }
  103. }
  104. else if (pathname.includes('/watch/')) {
  105. if (document.querySelector('img[alt="404"]')) {
  106. presenceData.state = '404 | Not Found'
  107. presenceData.details = 'Browsing Anime/Manga'
  108. }
  109. else {
  110. const playingEpisode = document
  111. .querySelector('h3')
  112. ?.textContent
  113. ?.replace('Episode ', '')
  114. const video = document.querySelector<HTMLVideoElement>('video')
  115. if (video && !Number.isNaN(Number(video.duration))) {
  116. [presenceData.startTimestamp, presenceData.endTimestamp] = presence.getTimestampsfromMedia(video)
  117. if (video.paused) {
  118. presenceData.smallImageText = 'Paused'
  119. presenceData.smallImageKey = Assets.Pause
  120. delete presenceData.startTimestamp
  121. delete presenceData.endTimestamp
  122. }
  123. else {
  124. presenceData.smallImageText = 'Playing'
  125. presenceData.smallImageKey = Assets.Play
  126. }
  127. }
  128. const total = document
  129. .querySelector('div.grid.w-full.pl-5')
  130. ?.getAttribute('data-episode')
  131. const title = getTitle(titleLang)
  132. if (title) {
  133. presenceData.buttons = [
  134. {
  135. label: 'Stream Anime',
  136. url: href,
  137. },
  138. ]
  139. }
  140. presenceData.largeImageKey = document.querySelector('img[alt="Anime Cover"]')?.getAttribute('src')
  141. || ActivityAssets.Logo
  142. presenceData.details = title || 'Getting data...'
  143. if (playingEpisode) {
  144. presenceData.state = `Episode ${playingEpisode} of ${
  145. total === '0' ? '???' : total
  146. }`
  147. }
  148. }
  149. }
  150. else if (pathname.includes('/read/')) {
  151. const title = document
  152. .querySelector('title')
  153. ?.textContent
  154. ?.replace('Manga - ', '')
  155. presenceData.largeImageKey = document
  156. .querySelector('meta[id="CoverImage"]')
  157. ?.getAttribute('data-manga-cover') || ActivityAssets.Logo
  158. presenceData.details = title || 'Getting data...'
  159. presenceData.state = `Reading Chapter ${document
  160. .querySelector('input[id="chapter-progress"]')
  161. ?.getAttribute('value')}`
  162. presenceData.smallImageKey = Assets.Reading
  163. presenceData.smallImageText = 'Reading'
  164. if (title) {
  165. presenceData.buttons = [
  166. {
  167. label: 'Read Manga',
  168. url: href,
  169. },
  170. ]
  171. }
  172. }
  173. else if (pathname.includes('/search/') && pathname.includes('/anime/')) {
  174. presenceData.details = 'Browsing Anime'
  175. presenceData.state = 'Searching...'
  176. presenceData.smallImageKey = Assets.Search
  177. }
  178. else if (pathname.includes('/search/') && pathname.includes('/manga/')) {
  179. presenceData.details = 'Browsing Manga'
  180. presenceData.state = 'Searching...'
  181. presenceData.smallImageKey = Assets.Search
  182. }
  183. else {
  184. presenceData.details = 'Browsing Anime/Manga'
  185. }
  186. if (presenceData.details)
  187. presence.setActivity(presenceData)
  188. else presence.setActivity()
  189. })