Auto-start new chat on disconnect and keep chat input focused.
目前為
// ==UserScript==
// @name Auto Karma
// @namespace https://greasyfork.org/
// @version 1.4
// @description Auto-start new chat on disconnect and keep chat input focused.
// @author Zach
// @license GPL-3.0
// @icon https://emeraldchat.com/logo7.svg
// @match https://emeraldchat.com/app
// @grant none
// @compatible Firefox
// @compatible Violentmonkey
// ==/UserScript==
'use strict';
function focusChat() {
const chatInput = document.getElementById("room-input");
if (!chatInput) return;
document.body.addEventListener("keydown", (event) => {
if (!document.querySelector("#ui-hatch > *, #ui-hatch-2 > *, #interests") && event.key !== "`") {
chatInput.focus();
}
}, { once: true });
}
function createUI() {
const topUI = document.createElement("div");
topUI.id = "top-ui";
topUI.innerHTML = `
<div id="profile-info" class="section">
<p id="user-gender">Gender: Not Available</p>
<p id="user-interests">Interests: None</p>
</div>
<style>
#top-ui {
position: fixed;
top: 0;
left: 0;
width: 100%;
background: rgba(200, 200, 255, 0.15);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
z-index: 1000;
display: flex;
flex-direction: column;
font-family: "Segoe UI", Roboto, sans-serif;
transition: transform 0.15s;
}
.hidden {
transform: translateY(-100%);
}
.section {
display: flex;
flex-direction: column;
padding: 10px 20px;
gap: 8px;
}
#user-gender, #user-interests {
background: rgba(255, 255, 255, 0.2);
border-radius: 12px;
padding: 12px;
font-size: 16px;
color: #fff;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
margin: 5px 0;
backdrop-filter: blur(8px);
}
/* Default (gender not available) */
#user-gender {
background: rgba(255, 255, 255, 0.3);
}
#user-interests {
background: rgba(255, 255, 255, 0.3);
}
/* When gender is male (m) - blue */
#user-gender.male {
background: rgba(0, 120, 255, 0.3);
}
/* When gender is female (f) - pink */
#user-gender.female {
background: rgba(255, 105, 180, 0.3);
}
.ui-btn {
background: linear-gradient(135deg, rgba(120, 120, 255, 0.5), rgba(100, 100, 230, 0.35));
color: #ffffff;
padding: 10px 20px;
border-radius: 14px;
border: none;
font-size: 15px;
font-weight: 500;
cursor: pointer;
transition: background 0.3s, transform 0.2s;
box-shadow: 0 0 10px rgba(120, 120, 255, 0.5);
backdrop-filter: blur(8px);
}
.ui-btn:hover {
background: linear-gradient(135deg, rgba(140, 140, 255, 0.7), rgba(120, 120, 255, 0.6));
transform: scale(1.04);
}
.ui-btn:active {
transform: scale(0.97);
}
</style>
`;
document.body.appendChild(topUI);
// The settings button is now always visible and toggles the UI
const settingsButton = document.createElement("button");
settingsButton.classList.add("ui-btn");
settingsButton.id = "settings-toggle";
settingsButton.textContent = "Settings";
document.body.appendChild(settingsButton);
// Ensure settings button is always visible
settingsButton.style.position = "fixed";
settingsButton.style.top = "10px";
settingsButton.style.right = "10px";
settingsButton.style.zIndex = "1001"; // Place above the top UI
// Toggle UI visibility on settings button click
settingsButton.addEventListener("click", () => {
const ui = document.getElementById("top-ui");
ui.classList.toggle("hidden");
});
}
createUI();
let lastMatchedId = null; // Keep lastMatchedId persistent across function calls
function simulateProfileRequest() {
const userId = document.querySelector('#room .room-component-center #messages .room-component-print #matched-message[data-matched-id]')?.dataset.matchedId;
if (!userId || userId === lastMatchedId) return;
console.log(`Matched message found with ID: ${userId}`);
lastMatchedId = userId; // Update lastMatchedId here
fetch(`https://emeraldchat.com/profile_json?id=${userId}`)
.then(res => res.json())
.then(data => {
const { gender, interests = [] } = data.user || {};
// Update the UI with the fetched data
const genderElem = document.getElementById("user-gender");
const interestsElem = document.getElementById("user-interests");
if (gender) {
genderElem.textContent = `Gender: ${gender === 'm' ? 'Male' : 'Female'}`;
genderElem.classList.remove("male", "female");
genderElem.classList.add(gender === 'm' ? "male" : "female");
}
if (interests.length) {
interestsElem.textContent = `Interests: ${interests.map(i => i.name).join(", ")}`;
} else {
interestsElem.textContent = `Interests: None`;
}
})
.catch(err => console.error(`Failed to simulate fetch for user ID: ${userId}`, err));
}
function simulateClick(element) {
element.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true }));
element.dispatchEvent(new MouseEvent("mouseup", { bubbles: true, cancelable: true }));
element.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
}
function nextChat() {
const next = document.querySelector("div.ui-button-match-mega");
if (!next) return;
simulateClick(next);
}
function giveKarma() {
const [good, bad] = document.querySelectorAll("a.ui-button-match-mega");
if (!good || !bad) return;
const messages = document.querySelectorAll("#messages > .room-component-message-container").length;
if (messages > 5) {
simulateClick(good);
}
else if (messages < 2) {
simulateClick(bad);
}
}
function observeChanges() {
const container = document.getElementById("container");
if (!container) return;
const observer = new MutationObserver(() => {
giveKarma();
nextChat();
simulateProfileRequest();
focusChat();
});
observer.observe(container, { childList: true, subtree: true });
}
observeChanges();