// ==UserScript==
// @name Weverse Extra
// @namespace Weverse Enhancements
// @description Enable Picture-in-picture, Livestream notifications, Auto Dismiss Notice
// @match *://weverse.io/*
// @include *://weverse.io/*/live*
// @connect global.apis.naver.com
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_addStyle
// @grant GM_notification
// @grant GM_openInTab
// @grant GM_xmlhttpRequest
// @grant GM_getResourceURL
// @antifeature ads
// @require https://cdn.jsdelivr.net/npm/[email protected]/build/global/luxon.min.js
// @resource banner https://cdn-contents.weverseshop.io/public/shop/dc3feec0dfa0f1c3a3fa8d93fc0ca9c0.png
// @version 5.0.2
// @author jho
// @run-at document-end
// @license Unlicense
// @icon https://cdn-v2pstatic.weverse.io/wev_web_fe/assets/1.0.0/icons/logo192.png
// ==/UserScript==
/* -------------------------------------------------------------------------- */
/* Skip Iframes */
/* -------------------------------------------------------------------------- */
if (window.top !== window.self)
{
console.log("[DEBUG] In iframe, skipping script execution.");
return;
}
/* -------------------------------------------------------------------------- */
/* Variables */
/* -------------------------------------------------------------------------- */
const DateTime = luxon.DateTime;
const css = String.raw;
const style =
css`
:root {
--color-primary: rgba(252, 146, 205, 1);
--color-secondary: rgba(33, 225, 255, 1) ;
}
.fancy {
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-image: linear-gradient(
45deg,
var(--color-primary) 17%,
var(--color-secondary) 100%
);
background-size: 400% auto;
background-position: 0% 50%;
animation: animate-gradient 12s linear infinite;
}
@keyframes animate-gradient {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
`;
let is_logging_enabled = true;
let auto_remove_landing_promos = GM_getValue("autoRemoveLandingPromos", true);
let auto_dismiss_digital_membership_reminder = GM_getValue("autoDissmissDigitalMembershipReminder", true);
let endorsement_enabled = GM_getValue("toggle5050Endorsement", true);
let cookieAllow = GM_getValue("cookieAllow", true);
const pip_btn_icon = `
<span class="pzp-pc-ui-button__tooltip pzp-pc-ui-button__tooltip--top">Toggle Picture-in-picture</span>
<span focusable="false" class="pzp-ui-icon pzp-pc-pip-button__icon pzp-pc-viewmode-button__icon" >
<svg class="pzp-ui-icon__svg" width="36" height="36" viewBox="0 0 36 36">
<g id="Layer_1" data-name="Layer 1" focusable="false">
<path fill="currentColor" d="M26.8,11.77c-.13-.24-.32-.44-.57-.57-.24-.13-.49-.2-1.16-.2H10.92c-.67,0-.91,.07-1.16,.2-.24,.13-.44,.32-.57,.57-.13,.24-.2,.49-.2,1.16v9.49c0,.67,.07,.91,.2,1.16,.13,.24,.33,.44,.57,.57,.24,.13,.49,.2,3.21,.2h14.15c-1.39,0-1.14-.07-.9-.2,.24-.13,.44-.32,.57-.57,.13-.24,.2-.49,.2-1.16V12.92c0-.67-.07-.91-.2-1.16Zm-1.8,9.53c0,.55-.45,1-1,1h-6.94c-.55,0-1-.45-1-1v-3.5c0-.55,.45-1,1-1h6.94c.55,0,1,.45,1,1v3.5Z" style="fill-rule: evenodd;"/></g>
</svg>
</span>
`;
/* -------------------------------------------------------------------------- */
/* Functions */
/* -------------------------------------------------------------------------- */
GM_addStyle(style);
function log(...args)
{
if (is_logging_enabled && args && args.length > 0)
{
console.log(...args);
}
}
/* ---------------------------------- Menus --------------------------------- */
const menuCommands = [
{
label: () => `Auto Remove Landing Promos: ${auto_remove_landing_promos ? "ON" : "OFF"}`,
toggle: function toggleAutoRemoveLandingPromos()
{
auto_remove_landing_promos = !auto_remove_landing_promos;
GM_setValue("autoRemoveLandingPromos", auto_remove_landing_promos);
updateMenuCommands();
window.location.reload();
},
id: undefined,
},
{
label: () => `Auto Dismiss Membership Notice On Live: ${auto_dismiss_digital_membership_reminder ? "ON" : "OFF"}`,
toggle: function toggleAutoDismissDigitalMembershipReminder()
{
auto_dismiss_digital_membership_reminder = !auto_dismiss_digital_membership_reminder;
GM_setValue("autoDissmissDigitalMembershipReminder", auto_dismiss_digital_membership_reminder);
updateMenuCommands();
window.location.reload();
},
id: undefined,
},
{
label: () => `Auto Allow Cookie Banner: ${cookieAllow ? "ON" : "OFF"}`,
toggle: function autoRemoveCookieBanner()
{
cookieAllow = !cookieAllow;
GM_setValue("cookieAllow", cookieAllow);
updateMenuCommands();
window.location.reload();
},
id: undefined,
},
{
label: () => `💖 5050 Endorsement: ${endorsement_enabled ? "ON" : "OFF"}`,
toggle: function toggle5050Endorsement()
{
endorsement_enabled = !endorsement_enabled;
GM_setValue("toggle5050Endorsement", endorsement_enabled);
updateMenuCommands();
window.location.reload();
},
id: undefined,
},
];
function registerMenuCommands()
{
for (const command of menuCommands)
{
command.id = GM_registerMenuCommand(command.label(), command.toggle);
}
}
function updateMenuCommands()
{
for (const command of menuCommands)
{
if (command.id)
{
GM_unregisterMenuCommand(command.id);
}
command.id = GM_registerMenuCommand(command.label(), command.toggle);
}
}
function toggleAutoRemoveLandingPromos()
{
auto_remove_landing_promos = !auto_remove_landing_promos;
GM_setValue("autoRemoveLandingPromos", auto_remove_landing_promos);
updateMenuCommands();
window.location.reload();
}
function toggleAutoDissmissDigitalMembershipReminder()
{
auto_dismiss_digital_membership_reminder = !auto_dismiss_digital_membership_reminder;
GM_setValue("autoDissmissDigitalMembershipReminder", auto_dismiss_digital_membership_reminder);
updateMenuCommands();
window.location.reload();
}
function autoRemoveCookieBanner()
{
cookieAllow = !cookieAllow;
GM_setValue("cookieAllow", cookieAllow);
updateMenuCommands();
window.location.reload();
}
function toggle5050Endorsement()
{
endorsement_enabled = !endorsement_enabled;
GM_setValue("toggle5050Endorsement", endorsement_enabled);
updateMenuCommands();
window.location.reload();
}
registerMenuCommands();
/* -------------------------------- Menus End ------------------------------- */
/* --------------------------------- Onload --------------------------------- */
function onLoadCleanUp()
{
console.log("Removing old notifications.");
let processedNotifications = GM_getValue('processedNotifications', []);
console.log("Stored Notification Items:", processedNotifications);
const now = DateTime.now();
function isRecent(item)
{
const from = DateTime.fromMillis(item.timestamp);
const hoursDifference = now.diff(from, 'hours').hours;
console.log("From:", from.toISO());
console.log("To:", now.toISO());
console.log("Hours Diff:", hoursDifference);
console.log("Older than 168 hours?", Math.floor(hoursDifference) > 168);
console.log("----------------------------------------------------------------------");
return Math.floor(hoursDifference) <= 168;
// Keep only items not older than a week as debug info.
// Most livestream will not be here as any notification older than 2 hours is skipped.
}
processedNotifications = processedNotifications.filter(isRecent);
console.log("Cleaned Notification Items:", processedNotifications);
GM_setValue('processedNotifications', processedNotifications);
}
onLoadCleanUp();
/* -------------------------------- Onload End ----------------------------- */
/* ------------------------------- Dom Changes ------------------------------ */
function domManipulator(changes, observer)
{
const videoPlayer = document.querySelector(".webplayer-internal-video");
const isFirefox = /firefox/i.test(navigator.userAgent);
const page = document.location.href;
const togglePictureInPicture = () =>
{
if (!videoPlayer) return;
if (document.pictureInPictureElement)
{
document.exitPictureInPicture().catch(log);
}
else
{
videoPlayer.requestPictureInPicture().catch(log);
}
};
if (videoPlayer)
{
if (videoPlayer.hasAttribute("disablepictureinpicture"))
{
videoPlayer.removeAttribute("disablepictureinpicture");
log(" Picture-in-picture is re-enabled.");
}
// Firefox does not support requestPictureInPicture(). Removing the attribute is enough. User can use built in pip button.
// Chromium (at least edge) has also added their own pip button on video player that has no disablepictureinpicture attribute.
// Thus, the following still works, but it's now redundant and can be removed if you want.
if (!isFirefox)
{
const locations = document.querySelectorAll(".pzp-pc__bottom-buttons-right, .pzp-mobile-bottom.pzp-mobile__bottom");
if (locations.length > 0)
{
const pipButtonExist = Array.from(locations).some(location => location.querySelector(".pzp-button-pip"));
if (!pipButtonExist)
{
const button = document.createElement("button");
button.setAttribute("aria-label", "Toggle Picture-in-picture");
const btn_class_names = locations[0].classList.contains("pzp-mobile-bottom")
? ["pzp-button", "pzp-setting-button", "pzp-mobile__setting-button", "pzp-button-pip"]
: ["pzp-button", "pzp-button-pip", "pzp-pc-viewmode-button", "pzp-pc__viewmode-button", "pzp-pc-ui-button"];
btn_class_names.forEach(item => button.classList.add(item));
button.innerHTML = pip_btn_icon;
button.addEventListener("click", () => togglePictureInPicture());
locations[0].insertBefore(button, locations[0].lastChild);
}
}
}
}
if (auto_dismiss_digital_membership_reminder)
{
const elems = document.querySelectorAll("div#custom_flash_message");
//Only while watching livestream because of 1 min preview. VOD doesn't count as you need membership to get ai-subtitles.
const isLive = document.querySelector("em.LiveBadgeView_badge__o2vFt.LiveBadgeView_-live__4P2PU span.blind")?.innerText === "live";
if (elems && isLive)
{
elems.forEach(elem =>
{
const elems_to_find = elem.querySelectorAll('div');
const matchedElements = Array.from(elems_to_find).filter(element =>
{
const matched = /Digital Membership/.test(element.innerText);
return matched;
});
if (matchedElements.length === 0) return;
log(matchedElements);
matchedElements.forEach(matchedElement =>
{
const buttons = matchedElement.parentElement.querySelectorAll('button:has(span.blind)');
log(buttons);
buttons.forEach(button =>
{
if (button && button.innerText === "close")
{
log("👇 Autoclicking membership notice.", button);
button.dispatchEvent(new MouseEvent("click", {
view: document.defaultView,
bubbles: true,
cancelable: true
}));
}
});
});
});
}
}
if (page === "https://weverse.io/")
{
const modalButtons = document.querySelector("button.BaseModalView_bottom_button__XNhOi");
const cookieButtons = document.querySelector("button.w_button_allow");
// w_button_allow : allow cookie usage
// w_button_continue : reject and continue
{
if (auto_remove_landing_promos && modalButtons)
{
if (modalButtons.innerText === "Don't show again for 3 days")
{
log("👇 Autoclicking landing promo.");
log(modalButtons, modalButtons.innerText);
queueMicrotask(() =>
{
modalButtons.dispatchEvent(new MouseEvent("click", {
view: document.defaultView,
bubbles: true,
cancelable: true
}));
document.body.style.overflow = '';
});
}
}
if (cookieAllow && cookieButtons)
{
log("👇 Autoclicking cookie notice");
queueMicrotask(() =>
{
cookieButtons.dispatchEvent(new MouseEvent("click", {
view: document.defaultView,
bubbles: true,
cancelable: true
}));
});
}
}
}
// -- THIS SCRIPT IS BROUGHT TO YOU BY FIFTY FIFTY SUPPORT GROUP --
if (endorsement_enabled)
{
if (page === "https://weverse.io/")
{
const titles = document.querySelectorAll("div.MarqueeView_content__2Qs2H:not(.fancy),span.MarqueeView_content__2Qs2H:not(.fancy)");
titles.forEach(title =>
{
const parentOnlyText = Array.from(title.childNodes)
.filter(node => node.nodeType === Node.TEXT_NODE)
.map(node => node.textContent.trim())
.join('');
if (parentOnlyText === "FIFTY FIFTY")
{
title.classList.add("fancy");
}
});
}
if (page.startsWith("https://weverse.io/fiftyfifty/"))
{
const titles = document.querySelectorAll("span.HeaderCommunityDropdownWrapperView_name__FZXsx:not(.fancy)");
titles.forEach(title =>
{
const parentOnlyText = Array.from(title.childNodes)
.filter(node => node.nodeType === Node.TEXT_NODE)
.map(node => node.textContent.trim())
.join('');
if (parentOnlyText === "FIFTY FIFTY")
{
title.classList.add("fancy");
}
});
}
}
// -- THIS SCRIPT IS BROUGHT TO YOU BY FIFTY FIFTY SUPPORT GROUP --
}
const mutation_config = { childList: true, subtree: true };
const elem_appender_observer = new MutationObserver(domManipulator);
elem_appender_observer.observe(document, mutation_config);
/* -------------------------------------------------------------------------- */
/* Notification Listener */
/* -------------------------------------------------------------------------- */
//listen to weverse-fired api calls and only fetch more detail notification api endpoint if needed
//since this is fired by weverse, we are not creating unecessary api calls
const originalOpen = XMLHttpRequest.prototype.open;
function getCookie(name)
{
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
return null;
}
async function generateWeverseUrl(targetUrl, targetPath, queryParamsData)
{
const baseUrl = targetUrl;
const encoder = new TextEncoder();
const queryParams = queryParamsData;
const wmsgpad = DateTime.now().ts;
const apiPath = `${targetPath}${queryParams.toString()}`;
const truncatedPath = apiPath.substring(0, 255);
const keyStr = '1b9cb6378d959b45714bec49971ade22e6e24e42';
const cryptoKey = await crypto.subtle.importKey(
'raw',
encoder.encode(keyStr),
{ name: 'HMAC', hash: 'SHA-1' },
false,
['sign']
);
const dataStr = truncatedPath + wmsgpad.toString();
const signature = await crypto.subtle.sign(
'HMAC',
cryptoKey,
encoder.encode(dataStr)
);
const byteArray = new Uint8Array(signature);
let binary = '';
byteArray.forEach(byte => binary += String.fromCharCode(byte));
const wmd = btoa(binary);
const finalParams = new URLSearchParams(queryParams);
finalParams.append('wmsgpad', wmsgpad);
finalParams.append('wmd', wmd);
return `${baseUrl}${targetPath}${finalParams.toString()}`;
}
async function fetchNotifications()
{
// bearer token for api call.
const accessToken = getCookie('we2_access_token');
const deviceId = getCookie('we2_device_id');
if (!accessToken || !deviceId) return;
const queryParams = new URLSearchParams({
appId: 'be4d79eb8fc7bd008ee82c8ec4ff6fd4',
excludeGroup: 'COLLECTION,CO_HOST_LIVE,PARTY',
language: 'en',
os: 'WEB',
platform: 'WEB',
seen: 'true',
wpf: 'pc',
});
const notificationUrl = await generateWeverseUrl('https://global.apis.naver.com/weverse/wevweb', '/noti/feed/v2.0/activities?', queryParams);
log(notificationUrl);
//return;
GM_xmlhttpRequest({
method: "GET",
url: notificationUrl,
headers: {
"Authorization": `Bearer ${accessToken}`,
"User-Agent": navigator.userAgent,
"Accept": "application/json, text/plain, */*",
"Accept-Language": "en-GB,en;q=0.5",
"Referer": "https://weverse.io/",
"Origin": "https://weverse.io",
"DNT": "1",
"WEV-device-Id": deviceId,
"WEV-open-community": "A"
},
onload: function (response)
{
if (response.status === 200)
{
try
{
//log("API Response:", response);
const data = JSON.parse(response.responseText);
checkForLivestream(data);
} catch (e)
{
log("Error parsing response:", e);
}
} else
{
log(response);
log(`Failed to fetch data. Status: ${response}`);
}
},
onerror: function (error)
{
log("Request failed:", error);
}
});
}
async function checkForLivestream(data)
{
const cleanTitle = (title) => title.replace(/##ARTISTMARK##/g, '').replace(/##(.*?)##/g, '$1');
const cleanPostId = (id) => id.replace(/:(.*?):/g, '');
const now = DateTime.now();
if (!data) return;
log("Notification Data:", data);
for (const notification of data?.data || [])
{
const apiId = notification?.messageId;
const apiPostId = cleanPostId(apiId);
const apiCommunityId = notification?.community.communityId;
const apiActivityType = notification?.activityType; // "ARTIST_LIVE_ON_AIR".
const apiArtistName = notification?.title;
const apiNotificationTitle = cleanTitle(notification?.message?.values?.en ?? '');
const apiNotificationImage = notification?.imageUrl ??
notification?.logoUrl ??
'';
const apiNotificationUrl = "https://weverse.io" + notification?.webUrl;
const apiTimestamp = notification?.time;
const apiNotificationObject = {
id: apiPostId,
communityId: apiCommunityId,
type: apiActivityType,
artistName: apiArtistName,
title: apiNotificationTitle,
image: apiNotificationImage,
url: apiNotificationUrl,
timestamp: apiTimestamp
};
// Check if the notification is a livestream.
if (apiActivityType === "ARTIST_LIVE_ON_AIR")
{
log("Livestream found:", notification);
let processedNotification = GM_getValue('processedNotifications', []);
const exist = processedNotification.some((item) => item.id === apiPostId);
const from = DateTime.fromMillis(apiTimestamp);
const diffs = now.diff(from, "hours");
const hoursDiffs = diffs.toObject().hours;
//log("From: ", from);
//log("To: ", now);
//log("Hours Diff: ", hoursDiffs);
//log("Older than 1 hour ago? ", Math.floor(hoursDiffs) > 1);
if (Math.floor(hoursDiffs) < 2)
{
// Most livestream is less than 1 hour long, and at best less than 2 hours.
log(`Livestream is less than 2 hour ago [${Math.floor(hoursDiffs)} hour(s)]. Fetching livestream status...`);
if (!exist)
{
log("Notification is not yet processed: ", exist);
log("Checking live status now...");
processedNotification.push(apiNotificationObject);
GM_setValue('processedNotifications', processedNotification);
const accessToken = getCookie('we2_access_token');
const deviceId = getCookie('we2_device_id');
const queryParamsHasOnAirLivePost = new URLSearchParams({
appId: 'be4d79eb8fc7bd008ee82c8ec4ff6fd4',
language: 'en',
os: 'WEB',
platform: 'WEB',
wpf: 'pc',
fields: 'hasOnAirLivePost'
});
const queryParamsPostId = new URLSearchParams({
appId: 'be4d79eb8fc7bd008ee82c8ec4ff6fd4',
language: 'en',
os: 'WEB',
platform: 'WEB',
wpf: 'pc',
fieldSet: 'postV1'
});
//// Checking via post details
//const livestreamStatusUrlPostId = await generateWeverseUrl('https://global.apis.naver.com/weverse/wevweb', `/post/v1.0/post-${apiPostId}?`, queryParamsPostId);
// data.extension.video.type === "LIVE"
// data.extension.video.status === "ONAIR"
//// Checking via community tab status
const livestreamStatusUrlHasOnAirLivePost = await generateWeverseUrl('https://global.apis.naver.com/weverse/wevweb', `/community/v1.0/community-${apiCommunityId}?`, queryParamsHasOnAirLivePost);
GM_xmlhttpRequest({
method: "GET",
url: livestreamStatusUrlHasOnAirLivePost,
headers: {
"Authorization": `Bearer ${accessToken}`,
"User-Agent": navigator.userAgent,
"Accept": "application/json, text/plain, */*",
"Accept-Language": "en-GB,en;q=0.5",
"Referer": "https://weverse.io/",
"Origin": "https://weverse.io",
"DNT": "1",
"WEV-device-Id": deviceId,
"WEV-open-community": "A"
},
onload: function (response)
{
// livestreamStatusUrlPostId
// if (response.status === 200)
// {
// try
// {
// const data = JSON.parse(response.responseText);
// if (data?.extension?.video?.type === "LIVE" && data?.extension?.video?.status === "ONAIR")
// {
// GM_notification({
// text: apiNotificationTitle,
// title: apiArtistName,
// image: apiNotificationImage,
// onClick: () =>
// {
// GM_openInTab(apiNotificationUrl);
// }
// });
// }
// } catch (e)
// {
// log("Error parsing response:", e);
// }
// } else
// {
// try
// {
// const data = JSON.parse(response.responseText);
// if (data.errorCode === "digital_membership_710")
// {
// GM_notification({
// text: apiNotificationTitle,
// title: apiArtistName,
// image: apiNotificationImage,
// onClick: function ()
// {
// GM_openInTab(apiNotificationUrl, { active: true, insert: true });
// }
// });
// } else
// {
// log(response);
// log(`Failed to fetch data. Status: ${response}`);
// }
// } catch (e)
// {
// log("Error parsing response:", e);
// }
// }
// console.timeEnd('API Request Time'); // End the timer and log the time
// },
// onerror: function (error)
// {
// log("Request failed:", error);
// console.timeEnd('API Request Time'); // End the timer in case of error
// }
// livestreamStatusUrlPostId End
if (response.status === 200)
{
log(response);
try
{
const data = JSON.parse(response.responseText);
if (data?.hasOnAirLivePost === true)
{
GM_notification({
text: apiNotificationTitle,
title: apiArtistName,
image: apiNotificationImage,
onclick: function ()
{
log("Opening Livestream...", apiNotificationUrl);
GM_openInTab(apiNotificationUrl, { active: true, insert: true });
}
});
}
} catch (e)
{
log("Error parsing response:", e);
}
} else
{
log(`Failed to fetch data. Status: ${response}`);
}
},
onerror: function (error)
{
log("Request failed:", error);
}
});
} else
{
log(`Livestream has been processed. Skipping status check...`);
log("----------------------------------------------------------------------");
}
} else
{
log(`Livestream is more than 2 hour ago [${Math.floor(hoursDiffs)} hour(s)]. Skipping...`);
log("----------------------------------------------------------------------");
}
}
}
}
XMLHttpRequest.prototype.open = function (method, url, ...rest)
{
const shouldIntercept = url.includes('https://global.apis.naver.com/weverse/wevweb/noti/feed/v2.0/activities/community',);
const shouldIntercept2 = url.includes('https://global.apis.naver.com/weverse/wevweb/home/v1.0/home/pc',);
if (shouldIntercept)
{
const originalOnLoad = this.onload;
this.addEventListener('load', function ()
{
try
{
const toCompare = GM_getValue('lastNotiV2ActivitiesCommunity', undefined);
const timestamp = DateTime.now().toLocaleString(DateTime.DATETIME_MED_WITH_SECONDS);
const data = JSON.parse(this.responseText);
//data.data?.[0];
const newData = data.data;
if (JSON.stringify(newData) === JSON.stringify(toCompare))
{
//data is the same
console.log(`⚠️ No new Notification(s) available - ${timestamp}`);
return;
} else
{
console.log(`🚨 New Notification(s) available - ${timestamp}`);
GM_setValue('lastNotiV2ActivitiesCommunity', newData);
fetchNotifications();
}
} catch (e)
{
log('🚨 Failed to parse response:', e);
}
if (originalOnLoad) originalOnLoad.apply(this, arguments);
}, { once: true }); // Listen once
}
const now = DateTime.now();
const expiryDate = DateTime.fromISO('2025-06-01');
let bannerImageUrl = GM_getResourceURL("banner") || "https://i.postimg.cc/L84gDf2X/dc3feec0dfa0f1c3a3fa8d93fc0ca9c0.png";
if (shouldIntercept2 && endorsement_enabled && (now < expiryDate))
{
const originalOnLoad = this.onload;
this.addEventListener('load', function ()
{
try
{
let data = JSON.parse(this.responseText);
const toPush = {
"bannerId": 5050,
"startDate": 0,
"endDate": 97195420800000,
"contentType": "IMAGE_TITLE_SUBTITLE",
"content": {
"imageUrl": bannerImageUrl,
"firstTitle": "3rd Mini Album",
"secondTitle": "Day & Night",
"subTitle": "I’m your pookie in the morning,",
"secondSubTitle": "I'm your pookie in the night! 💖",
"textColor": "#000000"
},
"landingUrl": "https://weverse.io/fiftyfifty/feed",
"landingUrlType": "EXTERNAL_WEBLINK",
"communityName": "FIFTY FIFTY"
};
data.mainBanners.splice(1, 0, toPush);
const modifiedResponseText = JSON.stringify(data);
Object.defineProperty(this, 'responseText', {
value: modifiedResponseText,
writable: true,
configurable: true
});
this.responseXML = new DOMParser().parseFromString('<root></root>', 'application/xml');
} catch (e)
{
console.error('🚨 Failed to parse response:', e);
}
if (originalOnLoad) originalOnLoad.apply(this, arguments);
}, { once: true });
}
return originalOpen.apply(this, [method, url, ...rest]);
};