Update
This commit is contained in:
+20
-7
@@ -1,34 +1,47 @@
|
|||||||
console.log('[XAI Background] ✅ Service worker started');
|
console.log('[XAI Background] ✅ Service worker started');
|
||||||
|
|
||||||
// ===== TẠO MENU =====
|
// ===== TẠO MENU: XÓA CŨ → TẠO MỚI, KHÔNG GỘP =====
|
||||||
chrome.runtime.onInstalled.addListener(() => {
|
chrome.runtime.onInstalled.addListener(() => {
|
||||||
|
chrome.contextMenus.removeAll(() => {
|
||||||
|
// Menu 1: Comment — KHÔNG cần bôi đen, chỉ trên X
|
||||||
chrome.contextMenus.create({
|
chrome.contextMenus.create({
|
||||||
id: 'writeComment',
|
id: 'writeComment',
|
||||||
title: '✍️ Viết comment',
|
title: '✍️ Viết comment',
|
||||||
contexts: ['all'],
|
contexts: ['all'],
|
||||||
documentUrlPatterns: ['https://x.com/*']
|
documentUrlPatterns: ['https://x.com/*']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Menu 2: Dịch — CHỈ hiện khi đã bôi đen text, có thể dùng trên mọi trang
|
||||||
chrome.contextMenus.create({
|
chrome.contextMenus.create({
|
||||||
id: 'translateText',
|
id: 'translateText',
|
||||||
title: '🌐 Dịch văn bản',
|
title: '🌐 Dịch văn bản',
|
||||||
contexts: ['selection'],
|
contexts: ['selection'],
|
||||||
documentUrlPatterns: ['https://x.com/*', 'http://*/*', 'https://*/*']
|
documentUrlPatterns: ['https://x.com/*', 'http://*/*', 'https://*/*']
|
||||||
});
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// ===== CONTEXT MENU CLICK =====
|
// ===== XỬ LÝ CLICK MENU =====
|
||||||
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
chrome.contextMenus.onClicked.addListener((info, tab) => {
|
||||||
if (!tab?.id) return;
|
if (!tab?.id) return;
|
||||||
|
|
||||||
if (info.menuItemId === 'writeComment') {
|
if (info.menuItemId === 'writeComment') {
|
||||||
|
// Gửi xuống content: mở form comment
|
||||||
chrome.tabs.sendMessage(tab.id, { action: 'OPEN_FORM' }).catch(() => {});
|
chrome.tabs.sendMessage(tab.id, { action: 'OPEN_FORM' }).catch(() => {});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.menuItemId === 'translateText' && info.selectionText) {
|
if (info.menuItemId === 'translateText' && info.selectionText) {
|
||||||
chrome.tabs.sendMessage(tab.id, { action: 'OPEN_TRANSLATE_FORM', text: info.selectionText }).catch(() => {});
|
// Gửi xuống content: mở tab Dịch + fill text sẵn
|
||||||
|
chrome.tabs.sendMessage(tab.id, {
|
||||||
|
action: 'OPEN_TRANSLATE_FORM',
|
||||||
|
text: info.selectionText
|
||||||
|
}).catch(() => {});
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ===== MESSAGE LISTENER =====
|
// ===== NHẬN MESSAGE TỪ CONTENT =====
|
||||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||||
if (request.action === 'GENERATE_COMMENT') {
|
if (request.action === 'GENERATE_COMMENT') {
|
||||||
handleGenerate(request.data, sender.tab.id);
|
handleGenerate(request.data, sender.tab.id);
|
||||||
@@ -44,7 +57,7 @@ chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// ===== COMMENT API =====
|
// ===== GỌI API COMMENT =====
|
||||||
async function handleGenerate({ text, lang, tone, angle }, tabId) {
|
async function handleGenerate({ text, lang, tone, angle }, tabId) {
|
||||||
const cfg = await chrome.storage.local.get(['apiUrl', 'apiKey']);
|
const cfg = await chrome.storage.local.get(['apiUrl', 'apiKey']);
|
||||||
if (!cfg.apiUrl || !cfg.apiKey) {
|
if (!cfg.apiUrl || !cfg.apiKey) {
|
||||||
@@ -78,7 +91,7 @@ async function handleGenerate({ text, lang, tone, angle }, tabId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== TRANSLATE API =====
|
// ===== GỌI API DỊCH =====
|
||||||
async function handleTranslate({ text, target_lang }, tabId) {
|
async function handleTranslate({ text, target_lang }, tabId) {
|
||||||
const cfg = await chrome.storage.local.get(['apiUrl','apiKey','translateUrl','translateKey']);
|
const cfg = await chrome.storage.local.get(['apiUrl','apiKey','translateUrl','translateKey']);
|
||||||
const url = cfg.translateUrl || cfg.apiUrl;
|
const url = cfg.translateUrl || cfg.apiUrl;
|
||||||
@@ -87,7 +100,7 @@ async function handleTranslate({ text, target_lang }, tabId) {
|
|||||||
if (!url || !key) {
|
if (!url || !key) {
|
||||||
await chrome.tabs.sendMessage(tabId, {
|
await chrome.tabs.sendMessage(tabId, {
|
||||||
action: 'SHOW_TRANSLATE_ERROR',
|
action: 'SHOW_TRANSLATE_ERROR',
|
||||||
error: '⚠️ Chưa cấu hình API.\n\n👉 Vào tab ⚙️ Config để nhập URL và Key.'
|
error: '⚠️ Chưa cấu hình API.'
|
||||||
}).catch(() => {});
|
}).catch(() => {});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -70,14 +70,16 @@
|
|||||||
const sel = window.getSelection().toString().trim();
|
const sel = window.getSelection().toString().trim();
|
||||||
if (sel) lastSelectedText = sel;
|
if (sel) lastSelectedText = sel;
|
||||||
|
|
||||||
// Lưu tweet text
|
// Lưu tweet text — CHỈ khi click đúng vào article
|
||||||
const article = e.target.closest('article');
|
const article = e.target.closest('article');
|
||||||
if (!article) { lastTweetText = ''; return; }
|
if (article) {
|
||||||
const textEl =
|
const textEl =
|
||||||
article.querySelector('[data-testid="tweetText"]') ||
|
article.querySelector('[data-testid="tweetText"]') ||
|
||||||
article.querySelector('div[lang]') ||
|
article.querySelector('div[lang]') ||
|
||||||
article.querySelector('div[dir="auto"]');
|
article.querySelector('div[dir="auto"]');
|
||||||
lastTweetText = textEl ? textEl.innerText.trim() : article.innerText.trim().slice(0, 600);
|
lastTweetText = textEl ? textEl.innerText.trim() : article.innerText.trim().slice(0, 600);
|
||||||
|
}
|
||||||
|
// ⚠️ KHÔNG xóa lastTweetText nếu không có article (tránh lỗi click vào padding/lề)
|
||||||
});
|
});
|
||||||
|
|
||||||
// ===== B. LISTENER =====
|
// ===== B. LISTENER =====
|
||||||
@@ -188,7 +190,6 @@
|
|||||||
|
|
||||||
function openSidebar(tweetText) {
|
function openSidebar(tweetText) {
|
||||||
if (sidebarHost) {
|
if (sidebarHost) {
|
||||||
// Nếu sidebar đã mở, chỉ cần mở drawer
|
|
||||||
const drawer = sidebarHost.shadowRoot.querySelector('.drawer');
|
const drawer = sidebarHost.shadowRoot.querySelector('.drawer');
|
||||||
if (drawer) drawer.classList.add('open');
|
if (drawer) drawer.classList.add('open');
|
||||||
return;
|
return;
|
||||||
@@ -435,7 +436,6 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Comment buttons
|
|
||||||
copyBtn.addEventListener('click', async () => {
|
copyBtn.addEventListener('click', async () => {
|
||||||
const text = statusEl.textContent;
|
const text = statusEl.textContent;
|
||||||
if (!text || text.startsWith('⏳') || text.startsWith('Lỗi') || text.startsWith('⚠️')) {
|
if (!text || text.startsWith('⏳') || text.startsWith('Lỗi') || text.startsWith('⚠️')) {
|
||||||
@@ -556,12 +556,11 @@
|
|||||||
const url = urlIn.value.trim(), key = keyIn.value.trim();
|
const url = urlIn.value.trim(), key = keyIn.value.trim();
|
||||||
if (!url || !key) { showCfgStatus('❌ Comment URL và Key không được để trống!', true); return; }
|
if (!url || !key) { showCfgStatus('❌ Comment URL và Key không được để trống!', true); return; }
|
||||||
try { new URL(url); } catch { showCfgStatus('❌ URL không hợp lệ', true); return; }
|
try { new URL(url); } catch { showCfgStatus('❌ URL không hợp lệ', true); return; }
|
||||||
const tUrl = transUrlIn.value.trim() || url;
|
const tUrl = transUrlIn.value.trim();
|
||||||
const tKey = transKeyIn.value.trim() || key;
|
const tKey = transKeyIn.value.trim();
|
||||||
chrome.storage.local.set({
|
chrome.storage.local.set({
|
||||||
apiUrl: url, apiKey: key,
|
apiUrl: url, apiKey: key,
|
||||||
translateUrl: tUrl === url ? '' : tUrl,
|
translateUrl: tUrl, translateKey: tKey
|
||||||
translateKey: transKeyIn.value.trim()
|
|
||||||
}, () => {
|
}, () => {
|
||||||
showCfgStatus('✅ Đã lưu!', false);
|
showCfgStatus('✅ Đã lưu!', false);
|
||||||
cfgBadge.style.display = 'none';
|
cfgBadge.style.display = 'none';
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class XCacheService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async setCacheTwRefreshToken(refreshToken: string) {
|
async setCacheTwRefreshToken(refreshToken: string) {
|
||||||
await this.cacheManager.set('tw_app_refresh_token', refreshToken, 30 * 24 * 3600);
|
await this.setCachedKey('tw_app_refresh_token', refreshToken, 30 * 24 * 3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getCacheTwRefreshToken() {
|
async getCacheTwRefreshToken() {
|
||||||
@@ -61,16 +61,16 @@ export class XCacheService {
|
|||||||
async changeStateXCookiesIsAlive() {
|
async changeStateXCookiesIsAlive() {
|
||||||
const cacheKey = 'state_xcookie_status';
|
const cacheKey = 'state_xcookie_status';
|
||||||
const currentState = await this.isXCookiesAlive();
|
const currentState = await this.isXCookiesAlive();
|
||||||
return this.cacheManager.set(cacheKey, currentState ? 0 : 1, 365 * 24 * 3600);
|
return this.setCachedKey(cacheKey, currentState ? 0 : 1, 365 * 24 * 3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
async setStateXCookiesIsDie() {
|
async setStateXCookiesIsDie() {
|
||||||
const cacheKey = 'state_xcookie_status';
|
const cacheKey = 'state_xcookie_status';
|
||||||
return this.cacheManager.set(cacheKey, 0, 365 * 24 * 3600);
|
return this.setCachedKey(cacheKey, 0, 3 * 24 * 3600);
|
||||||
}
|
}
|
||||||
async setStateXCookiesIsSillALive() {
|
async setStateXCookiesIsSillALive() {
|
||||||
const cacheKey = 'state_xcookie_status';
|
const cacheKey = 'state_xcookie_status';
|
||||||
return this.cacheManager.set(cacheKey, 1, 365 * 24 * 3600);
|
return this.setCachedKey(cacheKey, 1, 3 * 24 * 3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
async isXCookiesAlive() {
|
async isXCookiesAlive() {
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
|
|||||||
this.logger.debug('isCookieLive?');
|
this.logger.debug('isCookieLive?');
|
||||||
if (page.url().includes('/home')) {
|
if (page.url().includes('/home')) {
|
||||||
this.logger.log('Cookies live');
|
this.logger.log('Cookies live');
|
||||||
// await this.xCacheService.setStateXCookiesIsSillALive();
|
await this.xCacheService.setStateXCookiesIsSillALive();
|
||||||
if (sendNotiWhenAlive) {
|
if (sendNotiWhenAlive) {
|
||||||
// await this.notifyService.sendMessageToTele('✅Verify cookie pass')
|
// await this.notifyService.sendMessageToTele('✅Verify cookie pass')
|
||||||
}
|
}
|
||||||
@@ -330,6 +330,7 @@ export class XBrowserService implements OnModuleInit, OnModuleDestroy {
|
|||||||
// const composer = page.locator('a[href="/compose/post"]').first();
|
// const composer = page.locator('a[href="/compose/post"]').first();
|
||||||
// await page.waitForTimeout(2000 + (Math.random()+Math.random()) * 3000);
|
// await page.waitForTimeout(2000 + (Math.random()+Math.random()) * 3000);
|
||||||
// await composer.click();
|
// await composer.click();
|
||||||
|
this.logger.debug('Bắt đầu nhập tweet ...');
|
||||||
|
|
||||||
const textarea = page.locator('div[data-testid="tweetTextarea_0"]');
|
const textarea = page.locator('div[data-testid="tweetTextarea_0"]');
|
||||||
await page.waitForTimeout(2000 + (Math.random() + Math.random()) * 3000);
|
await page.waitForTimeout(2000 + (Math.random() + Math.random()) * 3000);
|
||||||
|
|||||||
Reference in New Issue
Block a user