presence.ts 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. const presence = new Presence({
  2. clientId: "631803867708915732",
  3. }),
  4. browsingTimestamp = Math.floor(Date.now() / 1000);
  5. function lowercaseIt(str: string) {
  6. if (!str) return "";
  7. else return str.toLowerCase();
  8. }
  9. async function getStrings() {
  10. return presence.getStrings(
  11. {
  12. browse: "general.browsing",
  13. buttonViewProfile: "general.buttonViewProfile",
  14. buttonViewEpisode: "general.buttonViewEpisode",
  15. paused: "general.paused",
  16. play: "general.playing",
  17. search: "general.searchSomething",
  18. searchFor: "general.searchFor",
  19. viewCategory: "general.viewCategory",
  20. viewHome: "general.viewHome",
  21. viewMovie: "general.viewMovie",
  22. viewShow: "general.viewShow",
  23. live: "general.live",
  24. buttonWatchStream: "general.buttonWatchStream",
  25. buttonWatchVideo: "general.buttonWatchVideo",
  26. viewAProfile: "general.viewAProfile",
  27. viewProfileOf: "general.viewProfileOf",
  28. watchingLive: "general.watchingLive",
  29. watchingVid: "general.watchingVid",
  30. ofUser: "general.ofUser",
  31. },
  32. "en"
  33. );
  34. }
  35. const enum Assets {
  36. Logo = "https://cdn.rcd.gg/PreMiD/websites/F/Facebook/assets/logo.png",
  37. MessengerLogo = "https://cdn.rcd.gg/PreMiD/websites/F/Facebook/assets/0.png",
  38. WatchLogo = "https://cdn.rcd.gg/PreMiD/websites/F/Facebook/assets/1.png",
  39. ReelLogo = "https://cdn.rcd.gg/PreMiD/websites/F/Facebook/assets/2.png",
  40. GamingLogo = "https://cdn.rcd.gg/PreMiD/websites/F/Facebook/assets/3.png",
  41. MarketplaceLogo = "https://cdn.rcd.gg/PreMiD/websites/F/Facebook/assets/4.png",
  42. }
  43. let strings: Awaited<ReturnType<typeof getStrings>>,
  44. cached: { id: string; element: HTMLVideoElement },
  45. playingVid: HTMLVideoElement,
  46. playingVidClose: HTMLElement;
  47. presence.on("UpdateData", async () => {
  48. let presenceData: PresenceData = {
  49. largeImageKey: Assets.Logo,
  50. startTimestamp: browsingTimestamp,
  51. };
  52. const { pathname, href } = document.location,
  53. [
  54. privacyMode,
  55. showCover,
  56. showTimestamp,
  57. showSeachQuery,
  58. messagerUsername,
  59. showButtons,
  60. ] = await Promise.all([
  61. presence.getSetting<boolean>("privacyMode"),
  62. presence.getSetting<boolean>("cover"),
  63. presence.getSetting<boolean>("timestamp"),
  64. presence.getSetting<boolean>("searchQuery"),
  65. presence.getSetting<boolean>("messagerUsername"),
  66. presence.getSetting<boolean>("buttons"),
  67. ]),
  68. video = document.querySelector("video"),
  69. liveCheck = document
  70. .querySelector('[class="x78zum5 xxk0z11 x10l6tqk x1i5ckhj xoyzfg9"]')
  71. ?.querySelector("span")?.textContent;
  72. let dontShowTmp = false;
  73. if (!strings) strings = await getStrings();
  74. switch (true) {
  75. case pathname === "/": {
  76. presenceData.details = "Viewing home page";
  77. break;
  78. }
  79. case pathname.includes("/stories/"): {
  80. const storyUser = document
  81. .querySelector('[class=" x15w6uyq"]')
  82. ?.querySelector("span")?.textContent;
  83. if (pathname.match(/[0-9]{15}/gm)) {
  84. presenceData.details =
  85. privacyMode || !storyUser
  86. ? "Viewing a story"
  87. : `Viewing ${storyUser}'s story`;
  88. }
  89. break;
  90. }
  91. case pathname.includes("/messages"): {
  92. presenceData.largeImageKey = Assets.MessengerLogo;
  93. switch (true) {
  94. case pathname.includes("/t/"): {
  95. const username = document
  96. .querySelector("div.t6p9ggj4.tkr6xdv7")
  97. .querySelector("span > span")?.textContent;
  98. if (document.querySelector('[data-text="true"]')?.textContent) {
  99. presenceData.details = privacyMode
  100. ? "Writing to someone"
  101. : "Writing to:";
  102. presenceData.state = messagerUsername ? username : "(Hidden)";
  103. } else {
  104. presenceData.details = privacyMode
  105. ? "Reading messages"
  106. : "Reading messages from:";
  107. presenceData.state = messagerUsername ? username : "(Hidden)";
  108. }
  109. break;
  110. }
  111. case pathname.includes("/new"): {
  112. presenceData.details = privacyMode
  113. ? "Browsing messages"
  114. : "Composing a new message";
  115. break;
  116. }
  117. case pathname.includes("/groupcall/"): {
  118. presenceData.details = privacyMode
  119. ? "Browsing groupchats"
  120. : "In a group call";
  121. break;
  122. }
  123. case !!video && !!liveCheck: {
  124. const parseInfo = JSON.parse(
  125. document.querySelector('[data-content-len="40325"]')?.innerHTML
  126. );
  127. presenceData.smallImageKey = Assets.Live;
  128. presenceData.details = `Watch - ${strings.watchingLive}`;
  129. presenceData.state = `${strings.ofUser} ${
  130. parseInfo
  131. ? parseInfo.require[0][3][0].__bbox.require[3][3][1].__bbox.result.data.node.section_renderer.section.section_components.edges[1].node.feed_unit.attachments[0].media.owner.name?.trim()
  132. : document
  133. .querySelector('[class="x1lliihq x6ikm8r x10wlt62 x1n2onr6"]')
  134. ?.textContent?.trim()
  135. }`;
  136. break;
  137. }
  138. case pathname.includes("/videos/"): {
  139. presenceData.details = privacyMode
  140. ? `Watching a ${strings.watchingVid}`
  141. : "Watching a video on:";
  142. presenceData.state = `${
  143. document.querySelector("span.x193iq5w > strong > span")
  144. ?.textContent ??
  145. document.querySelector(
  146. "span.x193iq5w > h2 > span > a > strong > span"
  147. )?.textContent
  148. }'s profile`;
  149. presenceData.smallImageKey = video.paused
  150. ? Assets.Pause
  151. : Assets.Play;
  152. presenceData.smallImageText = video.paused
  153. ? strings.paused
  154. : strings.play;
  155. if (video.paused) dontShowTmp = true;
  156. else {
  157. [presenceData.startTimestamp, presenceData.endTimestamp] =
  158. presence.getTimestampsfromMedia(video);
  159. }
  160. presenceData.buttons = [
  161. {
  162. label: strings.buttonWatchVideo,
  163. url: href,
  164. },
  165. ];
  166. break;
  167. }
  168. }
  169. break;
  170. }
  171. case pathname.includes("/photo"): {
  172. presenceData.details = privacyMode
  173. ? "Viewing a photo"
  174. : "Viewing a photo on:";
  175. presenceData.state = `${
  176. document.querySelector("span.nc684nl6 > span")?.textContent ??
  177. document.querySelector("span.nc684nl6 > a > strong > span")
  178. ?.textContent ??
  179. document.querySelector('[href*="?__tn__=-UC*F"]')?.textContent
  180. }'s profile`;
  181. presenceData.buttons = [
  182. {
  183. label: "View photo",
  184. url: href,
  185. },
  186. ];
  187. break;
  188. }
  189. case pathname.includes("/watch"): {
  190. presenceData.largeImageKey = Assets.WatchLogo;
  191. const hrefReplaced = href
  192. .replace(/\/[?]ref=.*/gm, "")
  193. .replace("web.facebook.com", "www.facebook.com");
  194. switch (true) {
  195. case !!hrefReplaced.match(/watch[?]v=[0-9]{15}/gm)?.[0]: {
  196. delete presenceData.startTimestamp;
  197. playingVid = document.querySelector<HTMLVideoElement>("video");
  198. presenceData.details = `Watch - ${strings.watchingVid} ${
  199. document.querySelector('[class="xzueoph x1k70j0n"]')?.textContent
  200. }`;
  201. presenceData.smallImageKey = playingVid.paused
  202. ? Assets.Pause
  203. : Assets.Play;
  204. presenceData.state = `Uploaded by ${
  205. document
  206. .querySelector('[id="watch_feed"]')
  207. ?.querySelector('[class="x78zum5 xdt5ytf xz62fqu x16ldp7u"]')
  208. ?.querySelector('[class="xt0psk2"]')?.textContent ?? "Unknown"
  209. }`;
  210. if (!playingVid.paused) {
  211. [presenceData.startTimestamp, presenceData.endTimestamp] =
  212. presence.getTimestampsfromMedia(playingVid);
  213. }
  214. presenceData.buttons = [
  215. {
  216. label: strings.buttonWatchVideo,
  217. // short link:
  218. url: document
  219. .querySelector('[class="xh99ass"]')
  220. ?.parentElement?.querySelector("a")
  221. ?.getAttribute("href"),
  222. },
  223. ];
  224. break;
  225. }
  226. case hrefReplaced === "https://www.facebook.com/watch": {
  227. switch (true) {
  228. case !!document
  229. .querySelector('[aria-label*="ause"]')
  230. ?.closest('[class="x78zum5 xdt5ytf"]')
  231. ?.querySelector("video"): {
  232. playingVid = document
  233. .querySelector('[aria-label*="ause"]')
  234. ?.closest('[class="x78zum5 xdt5ytf"]')
  235. ?.querySelector<HTMLVideoElement>("video");
  236. break;
  237. }
  238. default: {
  239. const allVideos: NodeListOf<HTMLVideoElement> =
  240. document.querySelectorAll("video"),
  241. videoArray: HTMLVideoElement[] = [];
  242. let vidElement: HTMLVideoElement;
  243. for (const i in allVideos)
  244. videoArray.push(allVideos[i] as HTMLVideoElement);
  245. for (vidElement of videoArray)
  246. if (!vidElement.paused) playingVid = vidElement;
  247. }
  248. }
  249. switch (true) {
  250. case cached?.element && !!cached?.id: {
  251. delete presenceData.startTimestamp;
  252. playingVidClose = cached.element.closest(
  253. 'div[class="x78zum5 xdt5ytf"]'
  254. );
  255. presenceData.details = `Watch - ${strings.watchingVid} ${
  256. playingVidClose?.querySelector('[class="x14vqqas"]')
  257. ?.textContent
  258. }`;
  259. presenceData.smallImageKey = cached.element.paused
  260. ? Assets.Pause
  261. : Assets.Play;
  262. presenceData.state = `Uploaded by ${playingVidClose
  263. ?.querySelector('[class="xh8yej3"]')
  264. ?.querySelector('a[aria-label*=" "]')
  265. ?.getAttribute("aria-label")}`;
  266. if (!cached.element.paused) {
  267. [presenceData.startTimestamp, presenceData.endTimestamp] =
  268. presence.getTimestampsfromMedia(cached.element);
  269. }
  270. presenceData.buttons = [
  271. {
  272. label: strings.buttonWatchVideo,
  273. // short link:
  274. url: `https://www.facebook.com/watch/?v=${
  275. playingVidClose
  276. ?.querySelector('[class="xh8yej3"]')
  277. .querySelector('[class="xh99ass"]')
  278. .parentElement.firstElementChild.getAttribute("href")
  279. .split("?v=")[1]
  280. .split("_")[0]
  281. }`,
  282. },
  283. ];
  284. break;
  285. }
  286. case !!playingVid.getAttribute("src") &&
  287. (!cached ||
  288. cached.id !== playingVid.getAttribute("src") ||
  289. cached.element !== playingVid): {
  290. cached = {
  291. id: playingVid.getAttribute("src"),
  292. element: playingVid,
  293. };
  294. playingVidClose = playingVid.closest(
  295. 'div[class="x78zum5 xdt5ytf"]'
  296. );
  297. presenceData.details = `Watch - ${strings.watchingVid}: ${
  298. playingVidClose?.querySelector('[class="x14vqqas"]')
  299. ?.textContent
  300. }`;
  301. presenceData.smallImageKey = playingVid.paused
  302. ? Assets.Pause
  303. : Assets.Play;
  304. presenceData.state = `Uploaded by: ${playingVidClose
  305. ?.querySelector('[class="xh8yej3"]')
  306. ?.querySelector('a[aria-label*=" "]')
  307. ?.getAttribute("aria-label")}`;
  308. break;
  309. }
  310. default: {
  311. presenceData.details = `Watch - ${strings.browse}`;
  312. }
  313. }
  314. break;
  315. }
  316. case hrefReplaced === "https://www.facebook.com/watch/saved": {
  317. presenceData.details = "Watch - Viewing saved videos";
  318. break;
  319. }
  320. case hrefReplaced === "https://www.facebook.com/watch/shows": {
  321. presenceData.details = "Watch - Browsing shows";
  322. break;
  323. }
  324. case hrefReplaced === "https://www.facebook.com/watch/live": {
  325. const parseInfo = document.querySelector(
  326. '[data-bootloader-hash="UhexK6g"]'
  327. )?.nextElementSibling?.nextElementSibling?.nextElementSibling
  328. ?.nextElementSibling?.innerHTML;
  329. presenceData.smallImageKey = Assets.Live;
  330. presenceData.details = `Watch - ${strings.watchingLive}`;
  331. presenceData.state = `${strings.ofUser} ${
  332. document
  333. .querySelector(
  334. '[class="x14ctfv x1nxh6w3 x10l6tqk xoie2o3 xfyf068"]'
  335. )
  336. ?.closest('[class="x78zum5 x1n2onr6 xh8yej3"]')
  337. ?.querySelector('[class*="xi81zsa xo1l8bm"]')
  338. ?.textContent?.trim() ??
  339. JSON.parse(
  340. parseInfo
  341. )?.require?.[0]?.[3]?.[0]?.__bbox?.require?.[15]?.[3]?.[1]?.__bbox?.result?.data?.video_home_www_live?.video_home_sections?.edges?.[0]?.node?.section_renderer?.section?.section_components?.edges?.[0]?.node?.feed_unit?.attachments?.[0]?.media?.owner?.name?.trim() ??
  342. document
  343. .querySelector('[class="x1lliihq x6ikm8r x10wlt62 x1n2onr6"]')
  344. ?.textContent?.trim()
  345. }`;
  346. break;
  347. }
  348. default:
  349. {
  350. //profile while /watch
  351. if (
  352. href.includes("/profile.php?id=") ||
  353. document.querySelector(
  354. '[data-imgperflogname="profileCoverPhoto"]'
  355. ) ||
  356. document.querySelector(
  357. '[aria-label="Link to open profile cover photo"]'
  358. ) ||
  359. document.querySelector('[style*="padding-top: 37"]') ||
  360. document.querySelector('[style*="padding-top:37"]')
  361. ) {
  362. const selected = document.querySelector(
  363. "[style='background-color: var(--accent);']"
  364. )?.parentElement?.textContent,
  365. profileUsername = document.querySelector(
  366. '[class="xy1j3rs xurb0ha x1n2onr6"]'
  367. )?.parentElement?.textContent;
  368. if (profileUsername) {
  369. if (privacyMode) presenceData.details = strings.viewAProfile;
  370. else if (selected)
  371. presenceData.details = `Viewing ${profileUsername}'s ${selected}`;
  372. else
  373. presenceData.details = `Viewing ${profileUsername}'s Profile`;
  374. }
  375. }
  376. }
  377. break;
  378. }
  379. break;
  380. }
  381. case pathname.includes("/reel"): {
  382. presenceData.details = "Watching a reel";
  383. presenceData.largeImageKey = Assets.ReelLogo;
  384. presenceData.state = `From ${document
  385. .querySelector<HTMLLinkElement>("h2 > span > span > a.oajrlxb2")
  386. .textContent.trim()}`;
  387. presenceData.buttons = [
  388. {
  389. label: "Watch Reel",
  390. url: href,
  391. },
  392. ];
  393. break;
  394. }
  395. case pathname.includes("/marketplace"): {
  396. presenceData.largeImageKey = Assets.MarketplaceLogo;
  397. switch (true) {
  398. case pathname.includes("/search/"): {
  399. presenceData.smallImageKey = Assets.Search;
  400. presenceData.details = `Marketplace - ${lowercaseIt(
  401. strings.searchFor
  402. )}:`;
  403. presenceData.state = showSeachQuery
  404. ? decodeURI(new URLSearchParams(location.search).get("q"))
  405. : "(Hidden)";
  406. break;
  407. }
  408. case pathname.includes("/item/"): {
  409. presenceData.details = privacyMode
  410. ? "Marketplace - Viewing item"
  411. : "Marketplace - Viewing item:";
  412. presenceData.state =
  413. document
  414. .querySelector('[class="x1s85apg x4fpnxs"]')
  415. ?.previousElementSibling?.querySelector("span")?.textContent ??
  416. document
  417. .querySelector("head > title")
  418. ?.textContent?.split(" | Facebook")[0]
  419. .split("– ")[1];
  420. break;
  421. }
  422. default: {
  423. presenceData.details = `Marketplace - ${strings.browse}`;
  424. }
  425. }
  426. break;
  427. }
  428. case pathname.includes("/groups/"): {
  429. switch (pathname.split("/")[2]) {
  430. case "discover":
  431. presenceData.details = privacyMode
  432. ? "Browsing groups"
  433. : "Groups - Discover";
  434. break;
  435. case "feed":
  436. presenceData.details = privacyMode
  437. ? "Browsing groups"
  438. : "Groups - Feed";
  439. break;
  440. case "notifications":
  441. presenceData.details = privacyMode
  442. ? "Browsing groups"
  443. : "Groups - Notifications";
  444. break;
  445. default: {
  446. const groupName = document.querySelector(
  447. "div:nth-child(1) > div div:nth-child(1) > h1 > span > div"
  448. )?.textContent;
  449. if (groupName && !privacyMode) {
  450. presenceData.details = "Viewing group:";
  451. presenceData.state = groupName;
  452. } else presenceData.details = "Browsing groups";
  453. }
  454. }
  455. break;
  456. }
  457. case pathname.includes("/friends"): {
  458. presenceData.details = "Friends";
  459. switch (true) {
  460. case pathname.includes("/friends/requests"): {
  461. if (
  462. document.querySelector(
  463. "div.cjfnh4rs.l9j0dhe7.du4w35lb.j83agx80.cbu4d94t"
  464. )
  465. ) {
  466. presenceData.details = privacyMode
  467. ? "Friends"
  468. : "Friends - Sent requests";
  469. } else
  470. presenceData.state = privacyMode ? "Friends" : "Friends - Requests";
  471. break;
  472. }
  473. case pathname === "/friends/suggestions": {
  474. presenceData.details = presenceData.state = privacyMode
  475. ? "Friends"
  476. : "Friends - Requests";
  477. break;
  478. }
  479. case pathname.includes("/friends/suggestions/"): {
  480. presenceData.details = "Friends - Suggestions";
  481. presenceData.state = `${strings.viewProfileOf} ${document
  482. .querySelector("head > title")
  483. .innerHTML.replace(/(\(.*\))/gm, "")
  484. .replace("| Facebook", "")
  485. .trim()}`;
  486. break;
  487. }
  488. case pathname.includes("/friends/list"): {
  489. presenceData.details = presenceData.state = privacyMode
  490. ? "Friends"
  491. : "Friends - All Friends";
  492. break;
  493. }
  494. case pathname.includes("/friends/birthdays"): {
  495. presenceData.details = presenceData.state = privacyMode
  496. ? "Friends"
  497. : "Friends - Birthdays";
  498. break;
  499. }
  500. case pathname.includes("/friends/friendlist"): {
  501. presenceData.details = presenceData.state = privacyMode
  502. ? "Friends"
  503. : "Friends - Custom lists";
  504. break;
  505. }
  506. }
  507. break;
  508. }
  509. case pathname.includes("/events"): {
  510. if (/events\/[0-9]/g.test(pathname)) {
  511. presenceData.details = privacyMode
  512. ? "Events - Viewing an event"
  513. : "Events - Viewing event:";
  514. presenceData.state = document.querySelector(
  515. "span > span.a8c37x1j.ni8dbmo4.stjgntxs.l9j0dhe7.pby63qed"
  516. )?.textContent;
  517. presenceData.buttons = [
  518. {
  519. label: "View Event",
  520. url: `https://www.facebook.com/events/${pathname.replace(
  521. /^\D+/g,
  522. ""
  523. )}`,
  524. },
  525. ];
  526. } else {
  527. presenceData.details = privacyMode
  528. ? "Events - Home "
  529. : `Events - ${strings.browse}`;
  530. }
  531. break;
  532. }
  533. case pathname.includes("/gaming/"): {
  534. presenceData.largeImageKey = Assets.GamingLogo;
  535. presenceData.details = "Gaming";
  536. switch (true) {
  537. case /gaming\/play\/[0-9]/g.test(pathname): {
  538. if (!privacyMode) {
  539. presenceData.state = document.querySelector(
  540. "span > span.a8c37x1j.ni8dbmo4.stjgntxs.l9j0dhe7.ltmttdrg.g0qnabr5.ojkyduve"
  541. )?.textContent;
  542. presenceData.buttons = [
  543. {
  544. label: "Play Game",
  545. url: `https://www.facebook.com/gaming/play/${pathname.replace(
  546. /^\D+/g,
  547. ""
  548. )}`,
  549. },
  550. ];
  551. } else presenceData.details = "Gaming - Playing";
  552. break;
  553. }
  554. case pathname.includes("gaming/play"): {
  555. presenceData.details = "Gaming - Playing";
  556. break;
  557. }
  558. }
  559. break;
  560. }
  561. case pathname.includes("/search"): {
  562. presenceData.smallImageKey = Assets.Search;
  563. presenceData.details = privacyMode ? strings.search : strings.searchFor;
  564. presenceData.state = showSeachQuery
  565. ? new URLSearchParams(location.search).get("q")
  566. : "(Hidded)";
  567. break;
  568. }
  569. // if post is open
  570. case !!document.querySelector(
  571. "h2.gmql0nx0.l94mrbxd.p1ri9a11.lzcic4wl.d2edcug0.hpfvmrgz span.d2edcug0.hpfvmrgz.qv66sw1b.c1et5uql.lr9zc1uh.a8c37x1j.keod5gw0.nxhoafnm.aigsh9s9.fe6kdd0r.mau55g9w.c8b282yb.embtmqzv.hrzyx87i.m6dqt4wy.h7mekvxk.hnhda86s.oo9gr5id.hzawbc8m > span"
  572. ) ||
  573. !!document.querySelector(
  574. "span.d2edcug0.hpfvmrgz.qv66sw1b.c1et5uql.lr9zc1uh.a8c37x1j.keod5gw0.nxhoafnm.aigsh9s9.fe6kdd0r.mau55g9w.c8b282yb.l1jc4y16.rwim8176.mhxlubs3.p5u9llcw.hnhda86s.oo9gr5id.hzawbc8m > h1"
  575. ) ||
  576. !!document.querySelectorAll('[data-pagelet="ProfileActions"]')[0]: {
  577. const hasCommentInput = document.querySelector(
  578. "div.m9osqain.a5q79mjw.gy2v8mqq.jm1wdb64.k4urcfbm.qv66sw1b span.a8c37x1j.ni8dbmo4.stjgntxs.l9j0dhe7"
  579. );
  580. presenceData.details = `Viewing ${hasCommentInput ? "user" : "page"}${
  581. privacyMode ? "" : ":"
  582. }`;
  583. presenceData.state = document.title.slice(0, -11) || "Unknown";
  584. break;
  585. }
  586. // if profile is open
  587. case href.includes("/profile.php?id=") ||
  588. !!document.querySelector('[data-imgperflogname="profileCoverPhoto"]') ||
  589. !!document.querySelector(
  590. '[aria-label="Link to open profile cover photo"]'
  591. ) ||
  592. !!document.querySelector('[style*="padding-top: 37"]') ||
  593. !!document.querySelector('[style*="padding-top:37"]'): {
  594. const selected = document.querySelector(
  595. "[style='background-color: var(--accent);']"
  596. )?.parentElement?.textContent,
  597. profileUsername = document
  598. .querySelector("head > title")
  599. .innerHTML.replace(/(\(.*\))/gm, "")
  600. .replace("| Facebook", "")
  601. .trim();
  602. presenceData.largeImageKey =
  603. privacyMode || !showCover
  604. ? Assets.Logo
  605. : document
  606. .querySelector('[mask*="url(#js"]')
  607. ?.firstElementChild?.getAttribute("xlink:href") ?? Assets.Logo;
  608. if (profileUsername) {
  609. if (privacyMode) presenceData.details = strings.viewAProfile;
  610. else if (selected) {
  611. presenceData.details = `Viewing ${profileUsername}'s profile`;
  612. presenceData.state = selected;
  613. } else presenceData.details = `Viewing ${profileUsername}'s Profile`;
  614. presenceData.buttons = [
  615. {
  616. label: "View Profile",
  617. url: href,
  618. },
  619. ];
  620. } else presenceData.details = strings.viewAProfile;
  621. break;
  622. }
  623. }
  624. const pages: Record<string, PresenceData> = {
  625. "/events/calendar/": {
  626. details: privacyMode ? `Events - ${strings.browse}` : "Events - Calendar",
  627. },
  628. "/events/going/": {
  629. details: privacyMode
  630. ? `Events - ${strings.browse}`
  631. : "Events - Confirmed",
  632. },
  633. "/events/invites/": {
  634. details: privacyMode ? `Events - ${strings.browse}` : "Events - Invires",
  635. },
  636. "/events/interested/": {
  637. details: privacyMode
  638. ? `Events - ${strings.browse}`
  639. : "Events - Interested",
  640. },
  641. "/events/birthdays/": {
  642. details: privacyMode
  643. ? `Events - ${strings.browse}`
  644. : "Events - Birthdays",
  645. },
  646. "/events/notifications/": {
  647. details: privacyMode
  648. ? `Events - ${strings.browse}`
  649. : "Events - Notifcations",
  650. },
  651. "/events/create/": {
  652. details: privacyMode
  653. ? `Events - ${strings.browse}`
  654. : "Events - Creating an event",
  655. },
  656. "/events/search/": {
  657. details: privacyMode
  658. ? `Events - ${strings.browse}`
  659. : `Events - ${strings.search}`,
  660. },
  661. "/pages/": {
  662. details: privacyMode
  663. ? `Pages - ${strings.browse}`
  664. : `Pages - ${lowercaseIt(strings.browse)}`,
  665. },
  666. "/oculus/": {
  667. details: privacyMode
  668. ? "Ocoulus - Browsing oculus"
  669. : `Oculus - ${lowercaseIt(strings.browse)}`,
  670. },
  671. "/gaming/instantgames": {
  672. details: privacyMode
  673. ? `Gaming - ${strings.browse}`
  674. : "Gaming - Instant games",
  675. },
  676. "/salesgroups/": {
  677. details: `SaleGroups - ${strings.browse}`,
  678. },
  679. "/jobs/": {
  680. details: `Jobs - ${strings.browse}`,
  681. },
  682. "/ads/": {
  683. details: `Ads - ${strings.browse}`,
  684. },
  685. "/weather/": {
  686. details: privacyMode
  687. ? `Weather - ${strings.browse}`
  688. : "Weather - Viewing today",
  689. },
  690. "/saved/": {
  691. details: `Saved - ${strings.browse}`,
  692. },
  693. "/offers/": {
  694. details: `Offers - ${strings.browse}`,
  695. },
  696. "/recommendations/": {
  697. details: `Recommendations - ${strings.browse}`,
  698. },
  699. "/bookmarks": {
  700. details: `Bookmarks - ${strings.browse}`,
  701. },
  702. "/news": {
  703. details: `News - ${strings.browse}`,
  704. },
  705. "/gaming/feed": {
  706. details: privacyMode
  707. ? `Gaming - ${strings.browse}`
  708. : "Gaming - Browsing the feed",
  709. },
  710. "/gaming/following": {
  711. details: privacyMode
  712. ? `Gaming - ${strings.browse}`
  713. : "Gaming - Viewing following list",
  714. },
  715. "/gaming/browse": {
  716. details: `Gaming - ${strings.browse}`,
  717. },
  718. "/gaming/browse/live": {
  719. details: privacyMode
  720. ? `Gaming videos - ${strings.browse}`
  721. : "Gaming - Browsing livestreams",
  722. },
  723. "/gaming/browse/streamers": {
  724. details: privacyMode
  725. ? `Gaming videos - ${strings.browse}`
  726. : "Gaming - Browsing streamers",
  727. },
  728. "/gaming/recent": {
  729. details: privacyMode
  730. ? `Gaming - ${strings.browse}`
  731. : "Gaming - Browsing livestreams",
  732. },
  733. "/gaming/recent/activity": {
  734. details: privacyMode
  735. ? `Gaming - ${strings.browse}`
  736. : "Gaming - Browsing in recent livestreams",
  737. },
  738. "/gaming/recent/steamers": {
  739. details: privacyMode
  740. ? `Gaming - ${strings.browse}`
  741. : "Gaming - Browsing in recent streamers",
  742. },
  743. "/gaming/recent/history": {
  744. details: privacyMode
  745. ? `Gaming - ${strings.browse}`
  746. : "Gaming - Browsing in recent history",
  747. },
  748. "/games/recent": {
  749. details: privacyMode
  750. ? `Gaming - ${strings.browse}`
  751. : "Gaming - Browsing in recent games",
  752. },
  753. "/gaming/tournaments/hosted": {
  754. details: privacyMode
  755. ? `Gaming tournaments - ${strings.browse}`
  756. : "Gaming tournaments - Hosted",
  757. },
  758. "/gaming/tournaments/registered": {
  759. details: privacyMode
  760. ? `Gaming tournaments - ${strings.browse}`
  761. : "Gaming tournaments - Registered",
  762. },
  763. "/gaming/tournaments/completed": {
  764. details: privacyMode
  765. ? `Gaming tournaments - ${strings.browse}`
  766. : "Gaming tournaments - Completed",
  767. },
  768. "/gaming/play/registered": {
  769. details: privacyMode
  770. ? `Gaming - ${strings.browse}`
  771. : "Gaming - Registered",
  772. },
  773. "/gaming/tournaments": {
  774. details: `Gaming tournaments - ${strings.browse}`,
  775. },
  776. "/gaming/play/completed": {
  777. details: privacyMode
  778. ? `Gaming - ${strings.browse}`
  779. : "Gaming - Completed",
  780. },
  781. "/marketplace/you": {
  782. details: privacyMode
  783. ? `Marketplace - ${strings.browse}`
  784. : "Marketplace - Viewing your recent activity",
  785. },
  786. "/marketplace/groups": {
  787. details: privacyMode
  788. ? `Marketplace - ${strings.browse}`
  789. : "Marketplace - Viewing groups",
  790. },
  791. "/marketplace/stores": {
  792. details: privacyMode
  793. ? `Marketplace - ${strings.browse}`
  794. : "Marketplace - Viewing stores",
  795. },
  796. "/marketplace/you/buying": {
  797. details: privacyMode
  798. ? `Marketplace - ${strings.browse}`
  799. : "Marketplace - Viewing buying",
  800. },
  801. "/marketplace/you/selling": {
  802. details: privacyMode
  803. ? `Marketplace - ${strings.browse}`
  804. : "Marketplace - Viewing selling",
  805. },
  806. "/marketplace/you/saved": {
  807. details: privacyMode
  808. ? `Marketplace - ${strings.browse}`
  809. : "Marketplace - Viewing saved",
  810. },
  811. "/marketplace/you/dashboard": {
  812. details: privacyMode
  813. ? `Marketplace - ${strings.browse}`
  814. : "Marketplace - Viewing the dashboard",
  815. },
  816. "/marketplace/notifications": {
  817. details: privacyMode
  818. ? `Marketplace - ${strings.browse}`
  819. : "Marketplace - Viewing notifications",
  820. },
  821. "/marketplace/you/seller_announcement_center": {
  822. details: privacyMode
  823. ? `Marketplace - ${strings.browse}`
  824. : "Marketplace - Viewing seller announcement center",
  825. },
  826. "/marketplace/you/insights": {
  827. details: privacyMode
  828. ? `Marketplace - ${strings.browse}`
  829. : "Marketplace - Viewing seller insights",
  830. },
  831. "/settings": {
  832. details: `Settings - ${strings.browse}`,
  833. },
  834. "/places": {
  835. details: `Places - ${strings.browse}`,
  836. },
  837. };
  838. for (const [path, data] of Object.entries(pages))
  839. if (pathname.includes(path)) presenceData = { ...presenceData, ...data };
  840. if (!showTimestamp || dontShowTmp || privacyMode) {
  841. delete presenceData.startTimestamp;
  842. delete presenceData.endTimestamp;
  843. }
  844. if ((!showButtons || privacyMode) && presenceData.buttons)
  845. delete presenceData.buttons;
  846. if (privacyMode && presenceData.state) delete presenceData.state;
  847. if (presenceData.details) presence.setActivity(presenceData);
  848. else presence.setActivity();
  849. });