제미니랑 챗지피티를 써서 해당 기능을 구현한 Tampermonkey 스크립트를 만들었습니다. 저만 쓰기 아까워 공유합니다.
모바일 브라우저는 Mises 앱을 쓰면 Tampermonkey를 비롯한 크롬 확장 프로그램들 쓸 수 있습니다.
최신 정보, 알구몬 랭킹, 댓글들 화면에 적용됩니다.
많이 샀어요는 구UI라 그런지 여러번 수정해도 적용이 잘 안돼서 포기했습니다.
// ==UserScript==
// @name 알구몬 키워드 필터
// @namespace local.algumon.keyword.filter
// @version 0.3
// @match https://www.algumon.com/*
// @grant none
// @run-at document-idle
// ==/UserScript==
(function () {
‘use strict’;
const DEBUG = true;
const SETTINGS_URL = '/n/settings/ignored-keywords';
const STORAGE_KEY = 'algumon_ignored_keywords_cache_v03';
function log(...args) {
if (DEBUG) console.log('[AlgumonKeywordFilter]', ...args);
}
function normalize(text) {
return String(text || '')
.replace(/\s+/g, ' ')
.trim()
.toLowerCase();
}
function saveCache(keywords) {
try {
localStorage.setItem(STORAGE_KEY, JSON.stringify(keywords));
} catch (e) {
log('cache save failed', e);
}
}
function loadCache() {
try {
const raw = localStorage.getItem(STORAGE_KEY);
if (!raw) return [];
const parsed = JSON.parse(raw);
return Array.isArray(parsed) ? parsed : [];
} catch (e) {
log('cache load failed', e);
return [];
}
}
async function getKeywords() {
try {
const res = await fetch(SETTINGS_URL, {
credentials: 'include',
cache: 'no-store'
});
const html = await res.text();
const doc = new DOMParser().parseFromString(html, 'text/html');
const keywords = [];
for (const el of doc.querySelectorAll('input, textarea, div, span, p, li')) {
const text = (el.value || el.getAttribute?.('value') || el.textContent || '').trim();
if (!text) continue;
if (text.length < 2 || text.length > 40) continue;
if (text.includes('\n')) continue;
if (!/[0-9A-Za-z가-힣]/.test(text)) continue;
if ([
'설정',
'추가',
'키워드 추가',
'예외 키워드 관리',
'예외 키워드 등록 팁',
'로그아웃'
].includes(text)) continue;
keywords.push(normalize(text));
}
const unique = [...new Set(keywords)];
if (unique.length) {
saveCache(unique);
log('keywords loaded', unique);
return unique;
}
throw new Error('no keywords found');
} catch (e) {
const cached = loadCache();
log('using cache', cached, e);
return cached;
}
}
function shouldHide(title, keywords) {
const t = normalize(title);
return keywords.some(k => t.includes(k));
}
function hideCard(card) {
card.style.setProperty('display', 'none', 'important');
}
function showCard(card) {
card.style.removeProperty('display');
}
function filterDealPage(keywords) {
const cards = document.querySelectorAll('[id^="deal-"]');
cards.forEach(card => {
const titleEl =
card.querySelector('h3') ||
card.querySelector('a[href*="/deal/"]') ||
card.querySelector('a[href*="/n/deal/"]') ||
card.querySelector('.card-title') ||
card.querySelector('.title') ||
card.querySelector('.subject');
const title = titleEl ? titleEl.textContent.trim() : '';
if (!title) return;
if (shouldHide(title, keywords)) {
hideCard(card);
} else {
showCard(card);
}
});
}
function filterBoughtTodayPage(keywords) {
const cards = document.querySelectorAll(‘[id^=“post-”]’);
cards.forEach(card => {
const candidates = [
card.querySelector('h3'),
card.querySelector('h4'),
card.querySelector('.title'),
card.querySelector('.subject'),
card.querySelector('.product'),
card.querySelector('a[href*="/deal/"]'),
card.querySelector('a[href*="/post/"]'),
card.querySelector('a')
].filter(Boolean);
let title = '';
for (const el of candidates) {
const text = (el.textContent || '').trim();
if (text.length >= 2) {
title = text;
break;
}
}
if (!title) {
const allText = (card.innerText || '')
.split('\n')
.map(v => v.trim())
.filter(Boolean);
title = allText.find(v =>
v.length >= 4 &&
!v.includes('사고싶다') &&
!v.includes('샀어요') &&
!v.includes('댓글') &&
!v.includes('공유') &&
!/^\d+[,.]?\d*원/.test(v) &&
!/배송/.test(v)
) || '';
}
if (!title) return;
if (shouldHide(title, keywords)) {
hideCard(card);
} else {
showCard(card);
}
});
}
function filterCommentPage(keywords) {
const cards = document.querySelectorAll('[id^="comment-"]');
cards.forEach(card => {
const titleEl =
card.querySelector('a[href*="/deal/"]') ||
card.querySelector('a[href*="/n/deal/"]') ||
card.querySelector('h3') ||
card.querySelector('.title') ||
card.querySelector('.subject');
const title = titleEl ? titleEl.textContent.trim() : '';
if (!title) return;
if (shouldHide(title, keywords)) {
hideCard(card);
} else {
showCard(card);
}
});
}
function applyFilter(keywords) {
if (!keywords.length) return;
const path = location.pathname;
if (path.startsWith('/n/comment')) {
filterCommentPage(keywords);
return;
}
if (path.startsWith('/deal/bought-today')) {
filterBoughtTodayPage(keywords);
return;
}
if (path.startsWith('/n/deal')) {
filterDealPage(keywords);
return;
}
}
async function run() {
const keywords = await getKeywords();
const observer = new MutationObserver(() => {
applyFilter(keywords);
});
observer.observe(document.body, {
childList: true,
subtree: true
});
applyFilter(keywords);
}
run();
})();