המלצה | תוסף להורדת הודעות אודיו בגוגל צ'אט
-
לבקשת @מים-אחרונים
יצרתי תוסף להורדת הודעות אודיו מגוגל צ'אט
אם יש שיפורים או בקשות לעוד תוספים שלחו כאן בקשה
או במייל שבפרופיל...
תוסף להורדת אודיו מגוגל צ'אט.zip
-
ר רפי סאם התייחס לנושא זה
-
לבקשת @מים-אחרונים
יצרתי תוסף להורדת הודעות אודיו מגוגל צ'אט
אם יש שיפורים או בקשות לעוד תוספים שלחו כאן בקשה
או במייל שבפרופיל...
תוסף להורדת אודיו מגוגל צ'אט.zip
לכל המעוניין
הנה קוד לטפרמונקי// @name GChat Audio Download // @namespace https://chat.google.com/ // @version 1.0 // @description מוסיף כפתור הורדה להודעות שמע ב-Google Chat // @author You // @match https://chat.google.com/* // @grant none // @run-at document-idle // ==/UserScript== (() => { const DONE = 'gchat-dl-done'; function makeBtn(url) { const b = document.createElement('button'); b.textContent = '⬇ הורד שמע'; b.style.cssText = ` all: initial; display: block !important; margin: 4px 8px 6px 8px !important; padding: 4px 16px !important; background: #1a73e8 !important; color: white !important; border: none !important; border-radius: 20px !important; font: 500 12px "Google Sans",Arial,sans-serif !important; cursor: pointer !important; direction: rtl !important; box-sizing: border-box !important; `; b.onmouseenter = () => b.style.setProperty('background', '#1557b0', 'important'); b.onmouseleave = () => b.style.setProperty('background', '#1a73e8', 'important'); b.onclick = async (e) => { e.stopPropagation(); e.preventDefault(); b.textContent = '⏳ מוריד…'; b.style.setProperty('background', '#f9ab00', 'important'); b.style.setProperty('color', '#000', 'important'); try { const r = await fetch(url, { credentials: 'include' }); if (!r.ok) throw new Error(r.status); const blob = await r.blob(); const ext = blob.type.includes('ogg') ? 'ogg' : blob.type.includes('webm') ? 'webm' : blob.type.includes('wav') ? 'wav' : 'mp3'; const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `gchat-${Date.now()}.${ext}`; document.body.appendChild(a); a.click(); setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(a.href); }, 9000); b.textContent = '✓ הורד!'; b.style.setProperty('background', '#34a853', 'important'); b.style.setProperty('color', 'white', 'important'); setTimeout(() => { b.textContent = '⬇ הורד שמע'; b.style.setProperty('background', '#1a73e8', 'important'); b.style.setProperty('color', 'white', 'important'); }, 3000); } catch(err) { b.textContent = '✗ שגיאה'; b.style.setProperty('background', '#ea4335', 'important'); b.style.setProperty('color', 'white', 'important'); setTimeout(() => { b.textContent = '⬇ הורד שמע'; b.style.setProperty('background', '#1a73e8', 'important'); b.style.setProperty('color', 'white', 'important'); }, 3000); } }; return b; } function tryInject(el) { if (!(el instanceof Element)) return; if (el.hasAttribute(DONE)) return; const url = el.getAttribute('data-media-url'); if (!url || !url.includes('get_attachment_url')) return; el.setAttribute(DONE, '1'); const parent = el.closest('.DwygBd') || el.parentElement; if (parent) { parent.appendChild(makeBtn(url)); console.log('[DL] ✅ injected'); } } function scan() { document.querySelectorAll('[data-media-url]').forEach(tryInject); } new MutationObserver(muts => { for (const m of muts) { for (const n of m.addedNodes) { if (n.nodeType !== 1) continue; tryInject(n); n.querySelectorAll?.('[data-media-url]').forEach(tryInject); } if (m.type === 'attributes' && m.target instanceof Element) { tryInject(m.target); } } }).observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['data-media-url'] }); [0, 500, 1000, 2000, 4000, 8000].forEach(t => setTimeout(scan, t)); })(); -
ר רפי סאם התייחס לנושא זה
-
לכל המעוניין
הנה קוד לטפרמונקי// @name GChat Audio Download // @namespace https://chat.google.com/ // @version 1.0 // @description מוסיף כפתור הורדה להודעות שמע ב-Google Chat // @author You // @match https://chat.google.com/* // @grant none // @run-at document-idle // ==/UserScript== (() => { const DONE = 'gchat-dl-done'; function makeBtn(url) { const b = document.createElement('button'); b.textContent = '⬇ הורד שמע'; b.style.cssText = ` all: initial; display: block !important; margin: 4px 8px 6px 8px !important; padding: 4px 16px !important; background: #1a73e8 !important; color: white !important; border: none !important; border-radius: 20px !important; font: 500 12px "Google Sans",Arial,sans-serif !important; cursor: pointer !important; direction: rtl !important; box-sizing: border-box !important; `; b.onmouseenter = () => b.style.setProperty('background', '#1557b0', 'important'); b.onmouseleave = () => b.style.setProperty('background', '#1a73e8', 'important'); b.onclick = async (e) => { e.stopPropagation(); e.preventDefault(); b.textContent = '⏳ מוריד…'; b.style.setProperty('background', '#f9ab00', 'important'); b.style.setProperty('color', '#000', 'important'); try { const r = await fetch(url, { credentials: 'include' }); if (!r.ok) throw new Error(r.status); const blob = await r.blob(); const ext = blob.type.includes('ogg') ? 'ogg' : blob.type.includes('webm') ? 'webm' : blob.type.includes('wav') ? 'wav' : 'mp3'; const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `gchat-${Date.now()}.${ext}`; document.body.appendChild(a); a.click(); setTimeout(() => { document.body.removeChild(a); URL.revokeObjectURL(a.href); }, 9000); b.textContent = '✓ הורד!'; b.style.setProperty('background', '#34a853', 'important'); b.style.setProperty('color', 'white', 'important'); setTimeout(() => { b.textContent = '⬇ הורד שמע'; b.style.setProperty('background', '#1a73e8', 'important'); b.style.setProperty('color', 'white', 'important'); }, 3000); } catch(err) { b.textContent = '✗ שגיאה'; b.style.setProperty('background', '#ea4335', 'important'); b.style.setProperty('color', 'white', 'important'); setTimeout(() => { b.textContent = '⬇ הורד שמע'; b.style.setProperty('background', '#1a73e8', 'important'); b.style.setProperty('color', 'white', 'important'); }, 3000); } }; return b; } function tryInject(el) { if (!(el instanceof Element)) return; if (el.hasAttribute(DONE)) return; const url = el.getAttribute('data-media-url'); if (!url || !url.includes('get_attachment_url')) return; el.setAttribute(DONE, '1'); const parent = el.closest('.DwygBd') || el.parentElement; if (parent) { parent.appendChild(makeBtn(url)); console.log('[DL] ✅ injected'); } } function scan() { document.querySelectorAll('[data-media-url]').forEach(tryInject); } new MutationObserver(muts => { for (const m of muts) { for (const n of m.addedNodes) { if (n.nodeType !== 1) continue; tryInject(n); n.querySelectorAll?.('[data-media-url]').forEach(tryInject); } if (m.type === 'attributes' && m.target instanceof Element) { tryInject(m.target); } } }).observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['data-media-url'] }); [0, 500, 1000, 2000, 4000, 8000].forEach(t => setTimeout(scan, t)); })();@רפי-סאם כתב בהמלצה | תוסף להורדת הודעות אודיו בגוגל צ'אט:
קוד לטפרמונקי
מישהו ניסה?
כי ג'יימיני טוען שזה לא יעבוד (כאילו אפשר לסמוך עליו בזה...
)"הקוד שכתבת נראה כמו ניסיון יפה "לדוג" את קבצי השמע מתוך הממשק של Google Chat, אבל ב-Google כמו ב-Google, העניינים קצת יותר מורכבים מסריקה פשוטה של ה-DOM. יש כמה סיבות טכניות למה הקוד הזה כנראה לא יספק את הסחורה:
-
בעיית ה-Selector והמבנה הדינמי
הסתמכת על ה-Attribute בשם data-media-url. גוגל משנה לעיתים קרובות את שמות המחלקות (Classes) והמאפיינים של האלמנטים שלהם. אם המאפיין הזה לא קיים בדיוק בשם הזה על האלמנט שחיפשת, ה-MutationObserver וה-querySelectorAll פשוט לא ימצאו כלום. -
הזרקה ל-Shadow DOM (אולי)
חלק מהרכיבים החדשים ביישומי Google משתמשים ב-Shadow DOM. אם נגן השמע נמצא בתוך Shadow Root, ה-document.querySelectorAll הרגיל שלך לא "רואה" אותו, ולכן לא יכול להזריק את הכפתור. -
מדיניות אבטחה (CORS & CSP)
גם אם הצלחת להזריק את הכפתור, הפקודה fetch(url) כנראה תיחסם:
CSP (Content Security Policy): גוגל מגבילה לעיתים קרובות מאיזה מקורות מותר להוריד נתונים בדף.
CORS: השרת שמארח את קבצי השמע (לרוב googleusercontent.com) עשוי לא לאפשר בקשות Fetch ישירות מהסקריפט ללא הגדרות מתאימות.
- זיהוי האלמנט הלא נכון
השתמשת ב-.closest('.DwygBd'). השם DwygBd הוא שם מחלקה מעורבל (obfuscated). שמות כאלו משתנים בכל עדכון גרסה של Google Chat. ברגע שהם מעדכנים גרסה, הסקריפט שלך הופך להיסטוריה.
מה אפשר לעשות?
כדי שזה יעבוד באמת, כדאי לשנות גישה:זיהוי גנרי יותר: במקום לחפש data-media-url, חפש אלמנטים של audio או source בתוך הודעות, או אלמנטים עם role="button" שיש להם טקסט או תיאור שקשור להשמעה.
שימוש ב-GM_xmlhttpRequest: אם אתה משתמש ב-Tampermonkey, כדאי להשתמש ב-GM_xmlhttpRequest (במקום fetch) כדי לעקוף מגבלות CORS.
בדיקת ה-Network: לפעמים ה-URL של השמע נוצר רק ברגע שלוחצים על Play. במקרה כזה, הסקריפט שלך שמחפש בטעינה ראשונית לא ימצא כלום.
תרצה שאנסה לעזור לך למצוא סלקטור (Selector) יותר יציב או לכתוב פונקציה שתעקוף את בעיית ה-CORS?"
-
-
@רפי-סאם כתב בהמלצה | תוסף להורדת הודעות אודיו בגוגל צ'אט:
קוד לטפרמונקי
מישהו ניסה?
כי ג'יימיני טוען שזה לא יעבוד (כאילו אפשר לסמוך עליו בזה...
)"הקוד שכתבת נראה כמו ניסיון יפה "לדוג" את קבצי השמע מתוך הממשק של Google Chat, אבל ב-Google כמו ב-Google, העניינים קצת יותר מורכבים מסריקה פשוטה של ה-DOM. יש כמה סיבות טכניות למה הקוד הזה כנראה לא יספק את הסחורה:
-
בעיית ה-Selector והמבנה הדינמי
הסתמכת על ה-Attribute בשם data-media-url. גוגל משנה לעיתים קרובות את שמות המחלקות (Classes) והמאפיינים של האלמנטים שלהם. אם המאפיין הזה לא קיים בדיוק בשם הזה על האלמנט שחיפשת, ה-MutationObserver וה-querySelectorAll פשוט לא ימצאו כלום. -
הזרקה ל-Shadow DOM (אולי)
חלק מהרכיבים החדשים ביישומי Google משתמשים ב-Shadow DOM. אם נגן השמע נמצא בתוך Shadow Root, ה-document.querySelectorAll הרגיל שלך לא "רואה" אותו, ולכן לא יכול להזריק את הכפתור. -
מדיניות אבטחה (CORS & CSP)
גם אם הצלחת להזריק את הכפתור, הפקודה fetch(url) כנראה תיחסם:
CSP (Content Security Policy): גוגל מגבילה לעיתים קרובות מאיזה מקורות מותר להוריד נתונים בדף.
CORS: השרת שמארח את קבצי השמע (לרוב googleusercontent.com) עשוי לא לאפשר בקשות Fetch ישירות מהסקריפט ללא הגדרות מתאימות.
- זיהוי האלמנט הלא נכון
השתמשת ב-.closest('.DwygBd'). השם DwygBd הוא שם מחלקה מעורבל (obfuscated). שמות כאלו משתנים בכל עדכון גרסה של Google Chat. ברגע שהם מעדכנים גרסה, הסקריפט שלך הופך להיסטוריה.
מה אפשר לעשות?
כדי שזה יעבוד באמת, כדאי לשנות גישה:זיהוי גנרי יותר: במקום לחפש data-media-url, חפש אלמנטים של audio או source בתוך הודעות, או אלמנטים עם role="button" שיש להם טקסט או תיאור שקשור להשמעה.
שימוש ב-GM_xmlhttpRequest: אם אתה משתמש ב-Tampermonkey, כדאי להשתמש ב-GM_xmlhttpRequest (במקום fetch) כדי לעקוף מגבלות CORS.
בדיקת ה-Network: לפעמים ה-URL של השמע נוצר רק ברגע שלוחצים על Play. במקרה כזה, הסקריפט שלך שמחפש בטעינה ראשונית לא ימצא כלום.
תרצה שאנסה לעזור לך למצוא סלקטור (Selector) יותר יציב או לכתוב פונקציה שתעקוף את בעיית ה-CORS?"
@בנימין-מחשבים התוסף עובד לי
מה שג'ימיני אומר זה חרתא
זה סה"כ שולף את הקישור שכבר קיים ופותח אותו בכרטיסייה חדשההטפרמונקי לא נוסה על ידי...
-
-
י יאיר דניאל התייחס לנושא זה