// ==UserScript==
// @name Nomad's Quick Revive
// @namespace http://tampermonkey.net/
// @version 1.1.0
// @description The fastest way to request a revive from Nomad Medical: with a button on your main page, you're just a click away from being in the hands of our great revivers. Never hesitate to use the Nomad Medical revive service!
// @author LilyWaterbug
// @match https://www.torn.com/*
// @grant GM_xmlhttpRequest
// @license MIT
// ==/UserScript==
(function () {
'use strict';
let currentUrl = ''; // To detect URL changes
let profileButtonAdded = false; // To track if the profile button is added
// Initialize the script
function initialize() {
currentUrl = window.location.href;
handlePageLoad();
// Set up a MutationObserver to monitor dynamic changes
const observer = new MutationObserver(() => {
if (currentUrl !== window.location.href) {
// URL has changed
currentUrl = window.location.href;
profileButtonAdded = false; // Reset the flag on URL change
}
handlePageLoad();
});
observer.observe(document.body, { childList: true, subtree: true });
}
// Handle page load or dynamic DOM changes
function handlePageLoad() {
const currentUrl = window.location.href;
// Check for profile pages
if (currentUrl.includes('/profiles.php?XID=')) {
handleProfilePage();
}
// Check for the main page
const mainPageContainer = document.querySelector('.toggle-content___BJ9Q9 .content___GVtZ_');
if (mainPageContainer && !document.getElementById('quick-revive-button')) {
addMainPageButton(mainPageContainer);
}
}
// Handle logic for profile pages
function handleProfilePage() {
const buttonsWrap = document.querySelector('.buttons-wrap .buttons-list');
const userId = window.location.href.match(/XID=(\d+)/)?.[1];
// Ensure the button is only added once
if (buttonsWrap && !document.getElementById('profile-revive-button') && userId) {
checkIfUserCanBeRevived(userId, (canBeRevived) => {
if (canBeRevived) {
addProfilePageButton(buttonsWrap, userId);
profileButtonAdded = true;
}
});
}
}
// Función para agregar botón en la página principal
function addMainPageButton(container) {
const button = document.createElement('button');
button.id = 'quick-revive-button';
button.innerText = 'Nurse Nomad';
// Estilos del botón
styleButton(button);
button.addEventListener('click', () => {
const nameElement = document.querySelector('.menu-info-row___YG31c .menu-value___gLaLR');
const userLink = nameElement?.getAttribute('href');
const userName = nameElement?.textContent.trim();
const userIdMatch = userLink?.match(/XID=(\d+)/);
const userId = userIdMatch ? userIdMatch[1] : null;
if (userName && userId) {
handleReviveRequest(userName, userId);
} else {
alert('Error: Unable to extract user information.');
}
});
container.appendChild(button);
}
// Función para agregar botón en la página de perfil
function addProfilePageButton(container, targetUserId) {
if (document.getElementById('profile-revive-button')) return;
const profileButton = document.createElement('a');
profileButton.id = 'profile-revive-button';
profileButton.href = '#';
profileButton.className = 'profile-button profile-button-revive active';
profileButton.setAttribute('aria-label', 'Request Revive');
profileButton.innerHTML = `
<svg xmlns="http://www.w3.org/2000/svg" class="default___XXAGt profileButtonIcon svgShadowWhiteFilter___Nse17" filter="" fill="url(#linear-gradient)" stroke="#d4d4d4" stroke-width="0" viewBox="0 0 512 512" style="width: 36px; height: 36px; margin: 5px;">
<path d="M249.84 479.52c-6.048 0-12.024 0-18.144-.216-.504-.576-1.008-1.08-1.512-1.44-3.96-2.952-8.424-5.472-11.952-8.928-16.92-16.632-33.624-33.48-50.472-50.256-.864-.936-1.872-1.8-2.88-2.664-3.888 2.736-7.272 5.976-11.304 7.992-14.544 7.272-29.736 7.848-45.072 2.664-12.168-4.104-20.376-12.888-25.992-24.192-4.32-8.784-4.536-18.36-4.68-27.864-.288-14.04-.144-28.08 0-42.12 0-2.664-.72-4.608-2.664-6.624-20.736-20.52-41.256-41.184-61.92-61.704-4.68-4.608-8.784-9.432-11.088-15.624-.144-.432-.936-.576-1.44-.864 0-4.608 0-9.144.216-13.896.576-.576 1.08-1.008 1.224-1.512 1.872-5.4 4.896-10.008 9-14.04 21.456-21.384 42.912-42.912 64.296-64.368.936-.936 1.944-2.304 2.016-3.528.144-9.144-.072-18.36.144-27.576.288-15.264.36-30.6 1.224-45.864.72-11.232 6.192-20.736 14.256-28.296 11.664-10.872 25.848-13.824 41.4-12.384 10.8 1.008 19.8 5.4 27.432 13.032 2.88 2.952 6.048 5.688 9.288 8.784.576-.576 1.44-1.296 2.304-2.16 15.264-15.264 30.456-30.528 45.72-45.72C222.912 6.48 226.8 3.168 232.056 2.088c.288 0 .36-.864.504-1.368 5.328 0 10.584 0 15.984.216 8.208 3.168 13.608 9.648 19.44 15.48 15.408 15.408 30.888 30.888 46.368 46.296 1.8 1.8 3.816 3.528 5.904 5.544.36-.864.576-1.224.72-1.656 4.968-12.888 13.896-22.176 26.712-27.216 9.504-3.816 19.584-4.176 29.736-2.808 9.288 1.296 17.28 5.184 24.192 11.16 12.24 10.512 15.984 24.768 16.2 40.104.36 23.832.36 47.736 0 71.568 0 5.04 1.584 8.496 4.968 11.88 16.488 16.272 32.832 32.616 49.104 49.176 2.376 2.448 3.816 5.76 5.832 8.64.72 1.008 1.656 1.8 2.52 2.736 0 5.328 0 10.584-.216 15.984-.576.36-1.152.576-1.224.936-1.224 4.752-3.744 8.568-7.416 11.808-3.744 3.312-7.128 6.912-10.584 10.512-4.176 4.32-8.208 8.784-12.456 13.032-4.32 4.32-8.856 8.352-13.248 12.672-5.184 5.112-10.368 10.224-15.408 15.48-.936 1.008-1.656 2.664-1.728 4.032-.144 8.568 0 17.136-.072 25.704 0 11.016.216 22.032-.288 32.976-.36 7.704-.72 15.696-2.952 22.968-4.464 13.896-13.536 24.408-28.008 28.872-20.52 6.336-39.528 4.392-55.44-11.736-2.304-2.376-4.824-4.536-7.56-7.056-1.728 1.944-3.528 4.176-5.472 6.192-3.888 3.96-7.776 7.92-11.736 11.808-4.824 4.68-9.792 9.216-14.544 13.968-4.032 4.032-7.704 8.28-11.664 12.312-4.824 4.68-9.936 9.072-14.544 13.968-4.392 4.752-8.928 9-14.832 11.808-.432.216-.648.936-1.008 1.44M401.832 335.16c0-81 0-162-.072-243 0-4.392-.072-8.784-.792-13.104-1.584-10.08-6.696-18-15.984-22.68-8.208-4.248-17.064-3.672-25.776-2.664-3.384.36-6.84 1.728-9.864 3.384-11.448 6.264-15.84 16.92-15.912 29.16-.216 61.2-.072 122.4-.072 183.6 0 1.368 0 2.808 0 4.392-3.744 0-7.128.072-10.44-.072-1.08-.072-2.376-.576-3.024-1.296-2.52-2.88-4.752-5.904-7.056-8.928-10.44-13.464-20.736-27-31.248-40.32-10.296-12.96-20.88-25.704-31.176-38.664-10.152-12.672-20.016-25.632-30.024-38.448-6.912-8.712-13.896-17.352-20.808-26.064-8.064-10.08-15.912-20.232-23.976-30.312-6.192-7.776-12.312-15.624-19.008-22.968-3.816-4.248-8.424-8.064-13.176-11.16-5.76-3.672-12.6-2.736-19.08-2.808-14.256-.288-26.784 9.936-29.16 23.688-1.152 6.624-.864 13.536-.864 20.304-.072 96.696-.072 193.392.072 290.088 0 6.696 2.592 12.744 7.056 17.64 10.8 11.88 24.984 13.32 38.88 9.144 14.976-4.536 21.456-14.76 21.528-30.24.432-61.56.144-123.12.144-184.68 0-1.296 0-2.52 0-4.032 3.744 0 7.056-.144 10.44.072 1.296.144 3.024.792 3.816 1.872 7.704 9.36 15.264 18.864 22.824 28.44 10.224 13.104 20.376 26.28 30.672 39.312 11.304 14.328 22.68 28.512 33.984 42.696s22.68 28.296 33.912 42.48c10.008 12.672 19.8 25.56 29.736 38.232 3.384 4.32 6.84 8.64 10.584 12.744 5.76 6.264 11.808 12.528 20.664 14.04 4.968.864 10.224.504 15.336.36 2.304-.072 4.68-.576 6.84-1.368 13.896-5.328 20.736-16.56 20.952-31.32.144-15.624.072-31.176.072-47.52m-179.28-54.792C208.08 262.08 193.608 243.792 178.56 224.712c0 2.088 0 3.24 0 4.392 0 49.896 0 99.792-.072 149.688 0 2.088-.504 4.248-.648 6.336-.216 2.376.072 4.392 2.088 6.408 10.8 10.512 21.384 21.312 32.04 32.04 9.576 9.576 19.08 19.152 28.512 28.656 22.104-22.176 44.064-44.136 66.024-66.096-6.48-8.064-13.176-16.344-19.872-24.552-2.664-3.384-5.256-6.912-7.992-10.368-5.976-7.56-11.952-15.12-18-22.68-3.312-4.248-6.696-8.424-10.008-12.672-5.4-6.84-10.728-13.752-16.128-20.592-3.888-4.824-7.704-9.648-11.952-14.904M235.44 33.48c-15.408 15.408-30.816 30.816-46.296 46.296 42.48 53.712 84.744 107.208 127.656 161.496 0-1.584 0-2.016 0-2.448 0-44.208.072-88.344-.072-132.48 0-1.368-.72-3.024-1.656-3.96-4.608-4.824-9.432-9.504-14.112-14.184-12.816-12.816-25.632-25.704-38.448-38.52-7.272-7.2-14.472-14.4-21.6-21.6-1.872 1.872-3.528 3.456-5.472 5.4m-158.328 190.08c0-10.368 0-20.736 0-31.464-16.272 16.344-32.184 32.256-48.24 48.312 15.48 16.128 31.104 32.4 46.656 48.672.504-.504 1.08-1.008 1.584-1.512 0-21.096 0-42.192 0-64.008m341.136 6.48c0 14.688 0 29.304 0 45 11.52-11.592 22.248-22.464 33.048-33.264 1.944-1.944.36-2.88-.792-4.032-10.152-10.152-20.304-20.304-30.528-30.528-.432-.432-.936-.72-1.584-1.296-.072.648-.072.864-.072 1.08 0 7.488 0 14.904-.072 23.04Z" />
</svg>
`;
const svg = profileButton.querySelector('svg');
svg.setAttribute('width', '36');
svg.setAttribute('height', '36');
svg.style.margin = '5px';
svg.style.fill = 'url(#linear-gradient)';
svg.style.stroke = '#d4d4d4';
profileButton.addEventListener('click', (e) => {
e.preventDefault();
const requesterNameElement = document.querySelector('.menu-info-row___YG31c .menu-value___gLaLR');
const requesterLink = requesterNameElement?.getAttribute('href');
const requesterName = requesterNameElement?.textContent.trim();
const requesterIdMatch = requesterLink?.match(/XID=(\d+)/);
const requesterId = requesterIdMatch ? requesterIdMatch[1] : null;
if (requesterName && requesterId) {
fetchRequesterFaction(requesterId, (requesterFaction) => {
fetchTargetInfo(targetUserId, (targetInfo) => {
handleReviveRequestProfile(requesterName, requesterId, requesterFaction, targetInfo);
});
});
} else {
alert('Error: Unable to extract requester information.');
}
});
container.appendChild(profileButton);
}
// Obtener información de la facción del solicitante
function fetchRequesterFaction(requesterId, callback) {
const apiUrl = `https://api.torn.com/user/${requesterId}?selections=&key=yVgFxDZ3FxdruqSr`;
GM_xmlhttpRequest({
method: 'GET',
url: apiUrl,
onload: function (response) {
if (response.status === 200) {
const apiData = JSON.parse(response.responseText);
const factionName = apiData.faction?.faction_name || 'No Faction';
const factionUrl = apiData.faction?.faction_id ? `https://www.torn.com/factions.php?step=profile&ID=${apiData.faction.faction_id}#/` : 'No Faction URL';
callback({ name: factionName, url: factionUrl });
} else {
alert('Failed to fetch requester faction data.');
}
},
onerror: function () {
alert('An error occurred while fetching requester faction data.');
},
});
}
// Obtener información del usuario objetivo
function fetchTargetInfo(targetUserId, callback) {
const apiUrl = `https://api.torn.com/user/${targetUserId}?selections=&key=yVgFxDZ3FxdruqSr`;
GM_xmlhttpRequest({
method: 'GET',
url: apiUrl,
onload: function (response) {
if (response.status === 200) {
const apiData = JSON.parse(response.responseText);
callback({
name: apiData.name || 'Unknown',
id: targetUserId,
status: apiData.status?.description || 'N/A',
faction: apiData.faction?.faction_name || 'No Faction',
faction_url: apiData.faction?.faction_id ? `https://www.torn.com/factions.php?step=profile&ID=${apiData.faction.faction_id}#/` : 'No Faction URL',
details: apiData.status?.details || 'No Details',
});
} else {
alert('Failed to fetch target user data.');
}
},
onerror: function () {
alert('An error occurred while fetching target user data.');
},
});
}
// Solicitud personalizada para el botón de perfil
function handleReviveRequestProfile(requesterName, requesterId, requesterFaction, targetInfo) {
const formattedRequester = `${requesterName} [${requesterId}]`;
const formattedTarget = `${targetInfo.name} [${targetInfo.id}]`;
const data = {
function: 'profile-revive',
requester: formattedRequester,
requester_faction: requesterFaction.name,
requester_faction_url: requesterFaction.url,
target: formattedTarget,
target_status: targetInfo.status,
target_faction: targetInfo.faction,
target_faction_url: targetInfo.faction_url,
details: targetInfo.details,
};
GM_xmlhttpRequest({
method: 'POST',
url: 'http://lilywaterbug.art/webhook',
headers: { 'Content-Type': 'application/json' },
data: JSON.stringify(data),
onload: function (response) {
if (response.status === 200) {
alert('Profile revive request sent successfully!');
alert('Disclaimer: Remember to pay 1M or a Xanax to the person reviving your target.');
} else {
alert('Failed to send profile revive request.');
}
},
onerror: function () {
alert('An error occurred while sending the profile revive request.');
},
});
}
// Función para manejar la solicitud de revive
function handleReviveRequest(userName = 'Unknown', userId = 'Unknown') {
const formattedUser = `${userName} [${userId}]`;
// Llamada a la API de Torn
const apiUrl = `https://api.torn.com/user/${userId}?selections=&key=yVgFxDZ3FxdruqSr`;
GM_xmlhttpRequest({
method: 'GET',
url: apiUrl,
onload: function (response) {
if (response.status === 200) {
const apiData = JSON.parse(response.responseText);
const statusState = apiData.status?.state || 'N/A';
const revivable = apiData.revivable || 0;
if (statusState !== 'Hospital') {
alert('This user is not hospitalized right now.');
return;
}
if (revivable === 0) {
alert('Turn on your revives!');
return;
}
const data = {
function: 'revive',
usuario: formattedUser,
status: apiData.status?.description || 'N/A',
faction: apiData.faction?.faction_name || 'No Faction',
faction_url: apiData.faction?.faction_id ? `https://www.torn.com/factions.php?step=profile&ID=${apiData.faction.faction_id}#/` : 'No Faction URL',
details: apiData.status?.details || 'No Details',
};
GM_xmlhttpRequest({
method: 'POST',
url: 'http://lilywaterbug.art/webhook',
headers: { 'Content-Type': 'application/json' },
data: JSON.stringify(data),
onload: function (webhookResponse) {
if (webhookResponse.status === 200) {
alert('Revive request sent successfully!');
alert('Disclaimer: Please pay 1M or a Xanax to the person reviving you.');
} else {
alert('Failed to send revive request.');
}
},
onerror: function () {
alert('An error occurred while sending the revive request.');
},
});
} else {
alert('Failed to fetch Torn API data.');
}
},
onerror: function () {
alert('An error occurred while fetching Torn API data.');
},
});
}
// Función para verificar si el usuario puede ser revivido
function checkIfUserCanBeRevived(userId, callback) {
const apiUrl = `https://api.torn.com/user/${userId}?selections=&key=yVgFxDZ3FxdruqSr`;
GM_xmlhttpRequest({
method: 'GET',
url: apiUrl,
onload: function (response) {
if (response.status === 200) {
const apiData = JSON.parse(response.responseText);
const statusState = apiData.status?.state || 'N/A';
const revivable = apiData.revivable || 0;
callback(statusState === 'Hospital' && revivable === 1);
} else {
callback(false);
}
},
onerror: function () {
callback(false);
},
});
}
// Función para dar estilo a un botón
function styleButton(button) {
button.style.margin = '10px auto';
button.style.padding = '2.5px 15px';
button.style.display = 'block';
button.style.fontSize = '14px';
button.style.backgroundColor = '#D32F2F';
button.style.color = '#FFFFFF';
button.style.border = 'none';
button.style.borderRadius = '5px';
button.style.cursor = 'pointer';
button.style.fontWeight = 'bold';
button.style.webkitTextStroke = '0.2px #FFFFFF';
button.style.textAlign = 'center';
button.style.boxShadow = `
0 0 0 2px #f2f2f2,
0 0 0 4px #D32F2F
`;
}
initialize();
})();