Untitled
unknown
plain_text
2 days ago
10 kB
17
No Index
// ==UserScript== // @name Custom Reddit notifications UI // @namespace https://reddit.com/ // @version 21.8 // @description Custom Reddit notifications UI // @author RaidPrincess // @match *://www.reddit.com/* // @grant none // @run-at document-end // ==/UserScript== (function () { 'use strict'; const baseUrl = 'https://www.reddit.com'; let open = false; const container = document.createElement('div'); container.className = 'rnqv-container'; container.style.display = 'none'; document.body.appendChild(container); const style = document.createElement('style'); style.textContent = ` .rnqv-container { position: fixed; top: 55px; right: 10px; width: 360px; max-height: 420px; background: #1a1a1b; color: #d7dadc; border: 1px solid #343536; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.4); z-index: 9999; padding: 12px; overflow-y: auto; font-size: 14px; } .rnqv-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; } .rnqv-actions { display: flex; gap: 8px; } .rnqv-btn { background-color: transparent; border: 1px solid #343536; border-radius: 4px; padding: 4px 10px; color: #d7dadc; cursor: pointer; font-size: 13px; } .rnqv-btn:hover { background-color: #272729; } .rnqv-container ul { list-style: none; margin: 0; padding: 0; } .rnqv-container li { margin-bottom: 10px; display: flex; align-items: center; gap: 8px; } .rnqv-container a { color: #58a6ff; text-decoration: none; flex: 1; } .rnqv-container a:hover { text-decoration: underline; } .rnqv-avatar { width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0; } .rnqv-dismiss { cursor: pointer; font-size: 16px; color: #888; } .rnqv-dismiss:hover { color: red; } .rnqv-fake-ping { position: absolute; top: 6px; right: 6px; width: 8px; height: 8px; background: red; border-radius: 50%; z-index: 10; } [data-testid="unread-indicator"], #notifications-inbox-button span[class*="icon"] > span { opacity: 0 !important; pointer-events: none !important; } #notifications-inbox-button[data-has-unread] { data-has-unread: false !important; } `; document.head.appendChild(style); function replaceInboxButton() { const btn = document.querySelector('#notifications-inbox-button'); if (!btn || btn.dataset.rnqv === '1') return; const clone = btn.cloneNode(true); clone.id = 'notifications-inbox-button'; clone.style.position = 'relative'; clone.dataset.rnqv = '1'; clone.addEventListener('click', (e) => { e.preventDefault(); e.stopImmediatePropagation(); e.stopPropagation(); open = !open; container.style.display = open ? 'block' : 'none'; if (open) { loadNotifications(); setSeenCookie(); } }, true); btn.replaceWith(clone); } function updateFakePing(shouldShow) { const btn = document.querySelector('#notifications-inbox-button'); if (!btn) return; const existing = btn.querySelector('.rnqv-fake-ping'); if (shouldShow && !existing) { const dot = document.createElement('span'); dot.className = 'rnqv-fake-ping'; btn.appendChild(dot); } else if (!shouldShow && existing) { existing.remove(); } } function setSeenCookie() { document.cookie = `rnqv_seen=true; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT`; } function getHiddenMessageIDs() { const match = document.cookie.match(/(?:^|; )rnqv_hidden=([^;]*)/); return match ? decodeURIComponent(match[1]).split(',') : []; } function setHiddenMessageIDs(ids) { const encoded = encodeURIComponent([...new Set(ids)].join(',')); document.cookie = `rnqv_hidden=${encoded}; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT`; } async function markMessageAsRead(id) { try { await fetch(`${baseUrl}/api/read_message`, { method: 'POST', credentials: 'include', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'id=' + encodeURIComponent(id) }); } catch {} } async function loadNotifications() { container.innerHTML = ''; const header = document.createElement('div'); header.className = 'rnqv-header'; const title = document.createElement('strong'); title.textContent = 'Notifications'; header.appendChild(title); const fullBtn = document.createElement('button'); fullBtn.textContent = 'Full'; fullBtn.className = 'rnqv-btn'; fullBtn.onclick = () => window.open('https://www.reddit.com/notifications', '_blank'); const actions = document.createElement('div'); actions.className = 'rnqv-actions'; actions.appendChild(fullBtn); header.appendChild(actions); container.appendChild(header); const list = document.createElement('ul'); container.appendChild(list); const hiddenIDs = getHiddenMessageIDs(); try { const res = await fetch(`${baseUrl}/message/unread.json`, { credentials: 'include' }); const items = (await res.json())?.data?.children?.slice(0, 10) || []; const visibleItems = items.filter(i => !hiddenIDs.includes(i.data.name)); updateFakePing(visibleItems.length > 0); if (!visibleItems.length) { const li = document.createElement('li'); li.textContent = 'No new notifications.'; list.appendChild(li); return; } for (const item of visibleItems) { const d = item.data; const li = document.createElement('li'); const avatar = document.createElement('img'); avatar.className = 'rnqv-avatar'; avatar.src = 'https://www.redditstatic.com/avatars/avatar_default_02_24A0ED.png'; li.appendChild(avatar); const a = document.createElement('a'); a.textContent = d.was_comment ? `u/${d.author}: ${(d.body || '').replace(/\s+/g, ' ').trim().slice(0, 80)}` : `${d.subject || '(no subject)'} (from u/${d.author})`; a.href = d.context ? baseUrl + d.context : baseUrl + '/message/messages/' + d.id; a.target = '_blank'; li.appendChild(a); const dismiss = document.createElement('span'); dismiss.className = 'rnqv-dismiss'; dismiss.textContent = '🅧'; dismiss.title = 'Dismiss & mark as read'; dismiss.onclick = async () => { li.remove(); hiddenIDs.push(d.name); setHiddenMessageIDs(hiddenIDs); await markMessageAsRead(d.name); const stillVisible = container.querySelectorAll('ul li').length - 1; updateFakePing(stillVisible > 0); }; li.appendChild(dismiss); list.appendChild(li); fetch(`${baseUrl}/user/${d.author}/about.json`, { credentials: 'include' }) .then(r => r.json()) .then(user => { const icon = user.data?.icon_img?.split('?')[0]; if (icon) avatar.src = icon; }).catch(() => {}); } } catch { const li = document.createElement('li'); li.textContent = 'Error loading notifications.'; list.appendChild(li); } } new MutationObserver(() => replaceInboxButton()).observe(document.body, { childList: true, subtree: true }); document.addEventListener('click', (e) => { if (open && !container.contains(e.target) && !e.target.closest('#notifications-inbox-button')) { container.style.display = 'none'; open = false; } }); document.addEventListener('keydown', (e) => { if (e.key === 'Escape' && open) { container.style.display = 'none'; open = false; } }); container.addEventListener('click', (e) => e.stopPropagation()); // Initial red dot check (async () => { const hiddenIDs = getHiddenMessageIDs(); try { const res = await fetch(`${baseUrl}/message/unread.json`, { credentials: 'include' }); const items = (await res.json())?.data?.children || []; const visibleItems = items.filter(i => !hiddenIDs.includes(i.data.name)); updateFakePing(visibleItems.length > 0); } catch {} })(); // Red dot polling every 30s setInterval(async () => { const hiddenIDs = getHiddenMessageIDs(); try { const res = await fetch(`${baseUrl}/message/unread.json`, { credentials: 'include' }); const items = (await res.json())?.data?.children || []; const visibleItems = items.filter(i => !hiddenIDs.includes(i.data.name)); updateFakePing(visibleItems.length > 0); } catch (err) { console.warn('Polling error:', err); } }, 30000); // Kill Reddit's dynamic-badge function removeDynamicBadge() { const badge = document.querySelector('dynamic-badge[data-id="notification-count-element"]'); if (badge) { badge.remove(); console.log('Dynamic badge removed.'); } } removeDynamicBadge(); new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { removeDynamicBadge(); } } }).observe(document.body, { childList: true, subtree: true }); setInterval(removeDynamicBadge, 5000); })(); // ==UserScript== // @name New script discord.com // @namespace Violentmonkey Scripts // @match https://discord.com/channels/@me/609570647718494209* // @grant none // @version 1.0 // @author - // @description 4/25/2025, 9:47:27 PM // ==/UserScript==// ==UserScript== // @name New script reddit.com // @namespace Violentmonkey Scripts // @match https://www.reddit.com/* // @grant none // @version 1.0 // @author - // @description 4/25/2025, 9:53:59 PM // ==/UserScript==
Editor is loading...
Leave a Comment