/** * Thư viện ứng dụng trò chuyện Supabase * Chức năng: * 1. Khởi tạo và quản lý máy khách Supabase * 2. Xác thực người dùng ẩn danh * 3. Quản lý tin nhắn và giao tiếp thời gian thực * * Hướng dẫn sử dụng: 1. Thêm thư viện vào kịch bản Tampermonkey của bạn. * 2. Khởi tạo bằng cách sử dụng SbCLi.init() * 3. Sử dụng các phương thức được cung cấp để thực hiện các thao tác trò chuyện. / const SbCLi = (function() { 'sử dụng nghiêm ngặt'; // Phiên bản thư viện const VERSION = '1.0'; // Cấu hình mặc định const CONFIG = { SUPABASE_URL: 'https://icaugjyuwenraxxgwvzf.supabase.co', SUPABASE_KEY: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImljYXVnanl1d2VucmF4eGd3dnpmIiwicm9 sZSI6ImFub24iLCJpYXQiOjE3NDI4ODcwNjcsImV4cCI6MjA1ODQ2MzA2N30.-IsrU3_NyoqDxFeNH1l2d6SgVv9pPA0uIVEA44FmuSQ', SUPABASE_AUTH_TOKEN: 'sb-icaugjyuwenraxxgwvzf-auth-token', // Cấu hình liên quan đến mã kích hoạt KÍCH HOẠT: { ID KỊCH BẢN: 'script_id', VERIFY_ENDPOINT: `https://icaugjyuwenraxxgwvzf.supabase.co/functions/v1/activate_script` } }; // Quản lý trạng thái nội bộ let supabaseClient = null; let userId = null; let messageChannel = null; let activation_info = null; let scriptConfig = null; //Lấy cấu hình tập lệnh hàm bất đồng bộ getScriptConfig(script_id = CONFIG.ACTIVATION.SCRIPT_ID) { if(scriptConfig) return scriptConfig; const res = await supabaseClient .from('script_catalog') .lựa chọn('*') .eq('script_id', script_id) .đơn(); GM_log('===Lấy cấu hình tập lệnh===', script_id, res); nếu (res.error) { //GM_log('===Không thể truy xuất cấu hình tập lệnh===', res.error); scriptConfig = { script_id: null, tên: SbCLi.getScriptId(), phiên bản: null, URL: null, applicable_sites: [], Sự miêu tả: '', is_free: false, URL mua hàng: '', latest_notice: null, // Mặc định là không hiển thị updated_at: new Date().toISOString(), cờ tính năng: { activation_info: true, menu: đúng, my_history: false, my_likes: true, Thông báo hệ thống: đúng, world_channel: true, đỉnh thế giới: đúng } } }khác{ scriptConfig = res.data; } Trả về scriptConfig; } /** * Khởi tạo máy khách Supabase * @returns {Object} Thể hiện máy khách Supabase / hàm bất đồng bộ initSupabaseClient() { nếu (!window.supabase) { throw new Error('Chưa tải được SDK Supabase, vui lòng nhập Supabase.js trước'); } supabaseClient = window.supabase.createClient( CONFIG.SUPABASE_URL, CONFIG.SUPABASE_KEY, { thời gian thực: { tham số: { sự kiện mỗi giây: 10 } } } ); Trả về supabaseClient; } /** * Khởi tạo người dùng: Kiểm tra trạng thái đăng nhập; nếu không, hãy đăng nhập ẩn danh. * @param {Object} client - Thể hiện của client Supabase / hàm không đồng bộ initUser(client) { thử { // Đăng nhập ẩn danh ✅ const res = await client.auth.getSession(); // Hàm này phải được gọi đầu tiên vì mã thông báo cần được làm mới định kỳ. GM_log('===Lấy phiên cục bộ===', res); userId = res?.data?.session?.user?.id; // ID hợp lệ nếu (userId) { // Phiên cục bộ đã tồn tại, ghi vào bộ nhớ GM GM_setValue(CONFIG.SUPABASE_AUTH_TOKEN, res.data.session); trở lại; } let gm_auth_token = await GM_getValue(CONFIG.SUPABASE_AUTH_TOKEN); // Sử dụng GM_getValue để đạt được tính nhất quán giữa các miền GM_log('===Lấy phiên kịch bản===', gm_auth_token); userId = gm_auth_token?.user?.id; //ID của gm nếu (userId) { // Phiên làm việc đã tồn tại; hãy ghi nó vào localStorage. // Đã kiểm thử và hoạt động hiệu quả; nó có thể đồng bộ hóa ID người dùng với một miền khác. Điều này chắc chắn sẽ không hoạt động nếu chỉ dựa vào client.auth.getSession(). localStorage.setItem(CONFIG.SUPABASE_AUTH_TOKEN, JSON.stringify(gm_auth_token)); //const { data: anonData, error: anonError } = await client.auth.getSession(); //GM_log('===Lấy phiên cục bộ 1===', anonData?.session || anonError); trở lại; } // Việc đăng ký và đăng nhập với tư cách người dùng ẩn danh sẽ tự động ghi phiên làm việc vào localStorage sau khi đăng ký thành công. Lần tiếp theo sử dụng getSession() sẽ truy xuất phiên làm việc thành công. const { data, error } = await client.auth.signInAnonymously({ tùy chọn: { dữ liệu: { thông tin thiết bị: { Độ phân giải màn hình: `${screen.width}x${screen.height}`, color_depth: screen.colorDepth + 'bit', preferred_language: navigator.language, timezone_offset: new Date().getTimezoneOffset() / 60, hardware_concurrency: navigator.hardwareConcurrency || 'unknown', os_platform: navigator.platform, user_agent: navigator.userAgent.substring(0, 100) } } } }); GM_log('===Đăng ký người dùng ẩn danh===', data, error); Nếu tìm thấy (lỗi), hãy ném lỗi; userId = data.session.user.id; Sau khi đăng ký thành công, phiên làm việc sẽ tự động được ghi vào localStorage. // localStorage.setItem(CONFIG.SUPABASE_AUTH_TOKEN, data.session); // Ghi thủ công vào bộ nhớ GM GM_setValue(CONFIG.SUPABASE_AUTH_TOKEN, data.session); } bắt lỗi (error) { console.error('Khởi tạo người dùng thất bại:', error); báo lỗi? } } /** * Thiết lập kênh liên lạc thời gian thực * @param {Function} messageCallback - Hàm gọi lại thông báo * @param {Function} presenceCallback - Hàm gọi lại trạng thái trực tuyến / hàm bất đồng bộ setupRealtime(messageCallback, presenceCallback) { nếu (!supabaseClient) { ném lỗi mới ('Máy khách Supabase chưa được khởi tạo'); } nếu (!userId) { ném lỗi mới ('Người dùng chưa được khởi tạo'); } // Kênh truyền thông hợp nhất messageChannel = supabaseClient.channel('chat-room2', { cấu hình: { sự hiện diện: { khóa: userId, Khoảng thời gian giữa các nhịp tim: 15, trạng thái TTL: 60 } } }) .on('postgres_changes', { sự kiện: 'CHÈN', lược đồ: 'công khai', bảng: 'video_bookmarks' }, payload => messageCallback(payload.new)) .on('presence', { event: 'sync' }, () => { thử { const states = messageChannel.presenceState(); const onlineCount = Object.values(states).length; presenceCallback(onlineCount); } bắt (e) { console.error('[Lỗi đồng bộ trạng thái hiện diện]', e); } }) .đặt mua(); // Theo dõi trạng thái trực tuyến của người dùng chờ đợi kênh tin nhắn.track({ user_id: userId, online_at: new Date().toISOString() }); // Dọn dẹp tài nguyên khi trang đóng window.addEventListener('beforeunload', () => cleanup()); } /** * Tải lịch sử tin nhắn * @param {number} limit - Số lượng tin nhắn được tải * @param {string} flag - Cờ tải. Mặc định là tải tin nhắn từ người dùng hiện tại. 'my_likes' tải các tin nhắn tôi thích, 'all_likes' tải tất cả các tin nhắn đã thích và 'all' tải tất cả các tin nhắn. * @returns {Array} Mảng lịch sử tin nhắn / hàm bất đồng bộ loadHistory(limit = 20, flag = userId) { nếu (!supabaseClient) { ném lỗi mới ('Máy khách Supabase chưa được khởi tạo'); } thử { let baseQuery = supabaseClient.from('video_bookmarks').select('*'); nếu (cờ === userId) { // Lịch sử của tôi baseQuery = baseQuery.eq('user_id', userId); } ngược lại nếu (cờ === 'my_likes') { // Những điều tôi thích baseQuery = baseQuery.filter('like_list', 'cs', `{"${userId}"}`).order('likes', { ascending: false }); } ngược lại nếu (cờ === 'tất cả lượt thích') { // Tất cả lượt thích baseQuery = baseQuery.filter('likes', 'gt', 0).order('likes', { ascending: false }); } ngược lại nếu (cờ === 'tất cả') { // Tất cả tin nhắn, không cần xử lý } // Thực thi truy vấn const { data, error } = await baseQuery .order('created_at', { ascending: false }) .limit(limit); Nếu tìm thấy (lỗi), hãy ném lỗi; trả về dữ liệu || []; } bắt lỗi (error) { console.error('Không thể tải lịch sử tin nhắn:', error); trở lại []; } } /** Gửi tin nhắn * @param {Object} msginfo - Đối tượng thông tin tin nhắn * @param {string} msginfo.content - Nội dung thông báo * @returns {boolean} Kết quả gửi / hàm bất đồng bộ sendMessage(msginfo) { nếu (!supabaseClient) { ném lỗi mới ('Máy khách Supabase chưa được khởi tạo'); } nếu (!userId) { ném lỗi mới ('Người dùng chưa được khởi tạo'); } thử { const { data, error } = await supabaseClient .from('video_bookmarks') .upsert({ "user_id": msginfo.user_id || userId, "url": msginfo.url || location.href, "nội dung": msginfo.content || document.title, "video_url": msginfo.video_url, "image_url": msginfo.image_url, "likes": msginfo.likes, "like_list": msginfo.like_list, }, { onConflict: 'user_id,url' }); Trả về dữ liệu || lỗi; } bắt lỗi (error) { console.error('Thông báo gửi không thành công:', error); Trả về false; } } /** * Chức năng xác minh mã kích hoạt và quản lý trạng thái / /** * Xác minh mã kích hoạt * @param {string} code - Mã kích hoạt * @returns {Promise<{success: boolean, message: string, data?: any}>} Kết quả xác thực / hàm bất đồng bộ verifyActivation(code) { thử { // Sử dụng GM_xmlhttpRequest để gọi trực tiếp các hàm đám mây nhằm tránh các vấn đề về CORS trả về Promise mới((resolve, reject) => { GM_xmlhttpRequest({ Phương thức: 'POST', URL: CONFIG.ACTIVATION.VERIFY_ENDPOINT, tiêu đề: { 'Content-Type': 'application/json', 'Ủy quyền': `Người mang ${CONFIG.SUPABASE_KEY}` }, dữ liệu: JSON.stringify({ mã số, script_id: CONFIG.ACTIVATION.SCRIPT_ID, user_id: userId }), onload: function(response) { thử { const result = JSON.parse(response.responseText); activation_info = result; console.log('===Kết quả xác minh mã kích hoạt===', activation_info); GM_setValue('activation_info', result); giải quyết(kết quả); } bắt lỗi (error) { resolve({ success: false, message: 'Kích hoạt thất bại, máy chủ trả về định dạng không chính xác' }); } }, onerror: function(error) { console.error('Lỗi mạng trong quá trình xác minh mã kích hoạt:', error); resolve({ success: false, message: 'Kích hoạt thất bại, lỗi mạng' }); }, ontimeout: function() { resolve({ success: false, message: 'Kích hoạt thất bại, yêu cầu hết thời gian chờ' }); } }); }); } bắt lỗi (error) { console.error('Không thể xác minh mã kích hoạt:', error); } } /** * Dọn dẹp tài nguyên / hàm bất đồng bộ cleanup() { nếu (!supabaseClient || !messageChannel) { trở lại; } supabaseClient.removeChannel(messageChannel); messageChannel = null; } /** Khởi tạo dịch vụ trò chuyện * @param {string} [scriptId] - ID của tập lệnh, mặc định là 'script_id' * `@returns {Promise}` khởi tạo kết quả, bao gồm cả ID người dùng. / async function init(scriptId = 'script_id') { thử { // Cập nhật SCRIPT_ID trong cấu hình mặc định CONFIG.ACTIVATION.SCRIPT_ID = scriptId; // Khởi tạo máy khách Supabase const client = await initSupabaseClient(); // Khởi tạo người dùng chờ initUser(client); // Xác minh thông tin mã kích hoạt // GM_deleteValue('activation_info'); //test const { success, message, data } = GM_getValue('activation_info') || {}; GM_log('Thông tin mã kích hoạt được lưu trữ cục bộ:', { success, message, data }); const activationCode = data?.activation_code || null; nếu (mã kích hoạt) { const activationResult = await SbCLi.verifyActivation(activationCode); //GM_log('Kết quả xác minh mã kích hoạt:', activationResult); } // Lấy cấu hình tập lệnh chờ getScriptConfig(); Trả về userId; } bắt lỗi (error) { console.error('Khởi tạo dịch vụ trò chuyện thất bại:', error); báo lỗi? } } // Giảm số lượng bản xem trước hàm decreaseTrialCount() { console.log('== Đã kích hoạt chế độ Bất Tử bởi người dùng =='); // Luôn trả về 1 để script tưởng rằng bạn còn lượt xem return 1; } /** * API công khai của thư viện / trở lại { PHIÊN BẢN khởi tạo, dọn dẹp, gửi tin nhắn, thiết lập thời gian thực, loadHistory, // API liên quan đến mã kích hoạt Xác minh kích hoạt, // API liên quan đến số lượng bản xem trước giảm số lần thử, // Các API liên quan đến cấu hình tập lệnh getScriptConfig, // Lấy ID người dùng getUserId: () => userId, // Lấy ID tập lệnh getScriptId: () => CONFIG.ACTIVATION.SCRIPT_ID }; })();