presence.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  1. import {
  2. clearMetadata,
  3. fetchMetadata,
  4. metadata,
  5. } from "./functions/fetchMetadata";
  6. import {
  7. clearLiveMetadata,
  8. fetchLiveMetadata,
  9. liveMetadata,
  10. } from "./functions/fetchLiveMetadata";
  11. const presence = new Presence({
  12. clientId: "1325519017527476316",
  13. }),
  14. getStrings = async () => {
  15. return presence.getStrings(
  16. {
  17. play: "general.playing",
  18. pause: "general.paused",
  19. browse: "general.browsing",
  20. watchingMovie: "general.watchingMovie",
  21. watchingSeries: "general.watchingSeries",
  22. watchingLive: "general.watchingLive",
  23. viewSeries: "general.buttonViewSeries",
  24. viewMovies: "general.buttonViewMovie",
  25. watchEpisode: "general.buttonViewEpisode",
  26. watchMovie: "general.buttonWatchMovie",
  27. watchStream: "general.buttonWatchStream",
  28. seriesDisplayFull: "u-next.seriesDisplay.full",
  29. seriesDisplayShort: "u-next.seriesDisplay.short",
  30. movieDisplay: "u-next.movieDisplay",
  31. liveDisplay: "u-next.liveDisplay",
  32. },
  33. await presence.getSetting<string>("lang").catch(() => "en")
  34. );
  35. };
  36. let oldLang: string = null,
  37. strings: Awaited<ReturnType<typeof getStrings>>;
  38. presence.on("UpdateData", async () => {
  39. const [
  40. lang,
  41. usePresenceName,
  42. showTimestamp,
  43. showBrowsingStatus,
  44. showCover,
  45. showSeries,
  46. showMovies,
  47. showSmallImages,
  48. privacyMode,
  49. ] = await Promise.all([
  50. presence.getSetting<string>("lang").catch(() => "en"),
  51. presence.getSetting<boolean>("usePresenceName"),
  52. presence.getSetting<boolean>("timestamp"),
  53. presence.getSetting<boolean>("showBrowsingStatus"),
  54. presence.getSetting<boolean>("showCover"),
  55. presence.getSetting<boolean>("showSeries"),
  56. presence.getSetting<boolean>("showMovies"),
  57. presence.getSetting<boolean>("showSmallImages"),
  58. presence.getSetting<boolean>("privacy"),
  59. ]);
  60. if (oldLang !== lang) {
  61. oldLang = lang;
  62. strings = await getStrings();
  63. }
  64. const path = document.location.href,
  65. //* Match /title/sid and get sid (When you load the page / reload while browsing)
  66. browsingMediaId =
  67. path.match(/\/title\/(\w+)/) ??
  68. //* ?td=td when normally browsing and clicking on smth
  69. path.match(/td=(\w+)/);
  70. if (browsingMediaId) {
  71. if (privacyMode) return presence.clearActivity();
  72. await fetchMetadata(browsingMediaId[1]);
  73. return await presence.setActivity({
  74. details: metadata.data.webfrontTitleStage.titleName,
  75. state: metadata.data.webfrontTitleStage.attractions.slice(0, 128),
  76. largeImageKey: !showCover
  77. ? "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png"
  78. : `https://${metadata.data.webfrontTitleStage.thumbnail.standard}`,
  79. ...(showSmallImages && {
  80. smallImageKey: Assets.Reading,
  81. }),
  82. smallImageText: strings.browse,
  83. buttons: [
  84. {
  85. label: metadata.data.webfrontTitleStage.keyEpisodes.current
  86. .existsRelatedEpisode
  87. ? strings.viewMovies
  88. : strings.viewSeries,
  89. url: document.location.href,
  90. },
  91. ],
  92. });
  93. }
  94. //* Match /play/sid/ed and get ed
  95. const watchingMediaId = path.match(/\/play\/(\w+)\/(\w+)/);
  96. if (watchingMediaId) {
  97. await fetchMetadata(watchingMediaId[1]);
  98. const video = document.querySelector("video");
  99. if (!video) return;
  100. const { paused } = video,
  101. [startTimestamp, endTimestamp] = presence.getTimestampsfromMedia(video);
  102. if (
  103. metadata.data.webfrontTitleStage.keyEpisodes.current
  104. .existsRelatedEpisode &&
  105. showSeries
  106. ) {
  107. if (privacyMode) {
  108. return await presence.setActivity({
  109. type: ActivityType.Watching,
  110. details: strings.watchingSeries,
  111. largeImageKey:
  112. "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png",
  113. });
  114. }
  115. const episode = metadata.data.webfrontTitleTitleEpisodes.episodes.find(
  116. e => !e.completeFlag
  117. );
  118. return await presence.setActivity({
  119. type: ActivityType.Watching,
  120. details: metadata.data.webfrontTitleStage.titleName,
  121. state: strings.seriesDisplayShort
  122. .replace("{0}", episode.displayNo)
  123. .replace("{1}", episode.episodeName),
  124. largeImageKey: !showCover
  125. ? "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png"
  126. : `https://${metadata.data.webfrontTitleStage.thumbnail.standard}`,
  127. ...(showSmallImages && {
  128. smallImageKey: paused ? Assets.Pause : Assets.Play,
  129. }),
  130. smallImageText: paused ? strings.pause : strings.play,
  131. ...(showTimestamp &&
  132. !paused && {
  133. startTimestamp,
  134. endTimestamp,
  135. }),
  136. ...(usePresenceName && {
  137. name: metadata.data.webfrontTitleStage.titleName,
  138. details: episode.episodeName,
  139. state: strings.seriesDisplayFull.replace("{0}", episode.displayNo),
  140. }),
  141. buttons: [
  142. {
  143. label: strings.watchEpisode,
  144. url: document.location.href.split("?")[0],
  145. },
  146. {
  147. label: strings.viewSeries,
  148. url: `https://video.unext.jp/?td=${metadata.data.webfrontTitleStage.id}`,
  149. },
  150. ],
  151. });
  152. }
  153. if (
  154. !metadata.data.webfrontTitleStage.keyEpisodes.current
  155. .existsRelatedEpisode &&
  156. showMovies
  157. ) {
  158. if (privacyMode) {
  159. return await presence.setActivity({
  160. type: ActivityType.Watching,
  161. details: strings.watchingMovie,
  162. largeImageKey:
  163. "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png",
  164. });
  165. }
  166. return await presence.setActivity({
  167. type: ActivityType.Watching,
  168. details: metadata.data.webfrontTitleStage.titleName,
  169. state: strings.movieDisplay
  170. .replace("{0}", metadata.data.webfrontTitleStage.productionYear)
  171. .replace(
  172. "{1}",
  173. Math.floor(
  174. metadata.data.webfrontTitleStage.keyEpisodes.current.duration / 60
  175. ).toString()
  176. ),
  177. largeImageKey: !showCover
  178. ? "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png"
  179. : `https://${metadata.data.webfrontTitleStage.thumbnail.standard}`,
  180. ...(showSmallImages && {
  181. smallImageKey: paused ? Assets.Pause : Assets.Play,
  182. }),
  183. smallImageText: paused ? strings.pause : strings.play,
  184. ...(showTimestamp &&
  185. !paused && {
  186. startTimestamp,
  187. endTimestamp,
  188. }),
  189. ...(usePresenceName && {
  190. name: metadata.data.webfrontTitleStage.titleName,
  191. }),
  192. buttons: [
  193. {
  194. label: strings.watchMovie,
  195. url: document.location.href.split("?")[0],
  196. },
  197. ],
  198. });
  199. }
  200. //* show Series & Movies disabled, clearactivity, nothing to show?
  201. return presence.clearActivity();
  202. }
  203. //* Reset because no data can be fetched
  204. clearMetadata();
  205. //* Match /livedetail/liv and get liv (When you load the page / reload while browsing)
  206. const browsingLiveId =
  207. path.match(/\/livedetail\/(\w+)/) ??
  208. //* ?lc=lc when normally browsing and clicking on smth
  209. path.match(/lc=(\w+)/);
  210. if (browsingLiveId) {
  211. if (privacyMode) return presence.clearActivity();
  212. await fetchLiveMetadata(browsingLiveId[1]);
  213. return await presence.setActivity({
  214. details: liveMetadata.data.webfrontGetLive.name,
  215. state: liveMetadata.data.webfrontGetLive.attractions.slice(0, 128),
  216. largeImageKey: !showCover
  217. ? "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png"
  218. : `https://${liveMetadata.data.webfrontGetLive.notices[0].thumbnail.standard}`,
  219. ...(showSmallImages && {
  220. smallImageKey: Assets.Reading,
  221. }),
  222. smallImageText: strings.browse,
  223. buttons: [
  224. {
  225. label: strings.watchStream,
  226. url: document.location.href,
  227. },
  228. ],
  229. });
  230. }
  231. //* Match /live/liv and get liv
  232. const watchingLiveId = path.match(/\/live\/(\w+)/);
  233. if (watchingLiveId) {
  234. await fetchLiveMetadata(watchingLiveId[1]);
  235. const video = document.querySelector("video");
  236. if (!video) return;
  237. const { paused } = video,
  238. [startTimestamp, endTimestamp] = presence.getTimestampsfromMedia(video);
  239. if (privacyMode) {
  240. return await presence.setActivity({
  241. type: ActivityType.Watching,
  242. details: strings.watchingLive,
  243. largeImageKey:
  244. "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png",
  245. });
  246. }
  247. return await presence.setActivity({
  248. type: ActivityType.Watching,
  249. details: liveMetadata.data.webfrontGetLive.name,
  250. state: strings.liveDisplay
  251. .replace(
  252. "{0}",
  253. new Date(liveMetadata.data.webfrontGetLive.deliveryStartDateTime)
  254. .getFullYear()
  255. .toString()
  256. )
  257. .replace(
  258. "{1}",
  259. Math.floor(
  260. (new Date(
  261. liveMetadata.data.webfrontGetLive.deliveryEndDateTime
  262. ).getTime() -
  263. new Date(
  264. liveMetadata.data.webfrontGetLive.deliveryStartDateTime
  265. ).getTime()) /
  266. 1000 /
  267. 60
  268. ).toString()
  269. ),
  270. largeImageKey: !showCover
  271. ? "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png"
  272. : `https://${liveMetadata.data.webfrontGetLive.notices[0].thumbnail.standard}`,
  273. ...(showSmallImages && {
  274. smallImageKey: paused ? Assets.Pause : Assets.Play,
  275. }),
  276. smallImageText: paused ? strings.pause : strings.play,
  277. ...(showTimestamp &&
  278. !paused && {
  279. startTimestamp,
  280. endTimestamp,
  281. }),
  282. ...(usePresenceName && {
  283. name: liveMetadata.data.webfrontGetLive.name,
  284. }),
  285. buttons: [
  286. {
  287. label: strings.watchStream,
  288. url: document.location.href.split("?")[0],
  289. },
  290. ],
  291. });
  292. }
  293. //* Reset because no data can be fetched
  294. clearLiveMetadata();
  295. if (showBrowsingStatus && !privacyMode) {
  296. return await presence.setActivity({
  297. details: strings.browse,
  298. largeImageKey:
  299. "https://cdn.rcd.gg/PreMiD/websites/U/U-NEXT/assets/logo.png",
  300. smallImageKey: Assets.Reading,
  301. smallImageText: strings.browse,
  302. });
  303. }
  304. return presence.clearActivity();
  305. });