Spaces:
Running
Running
Stronger HF-widget hide + (no_ai) clipboard lockdown
Browse files
app.py
CHANGED
|
@@ -697,7 +697,9 @@ EMOJI_SWAP_HEAD = """
|
|
| 697 |
|
| 698 |
HIDE_HF_WIDGET_HEAD = """
|
| 699 |
<style>
|
| 700 |
-
/* CSS targeting
|
|
|
|
|
|
|
| 701 |
.space-header, .hf-spaces-header, .spaces-banner,
|
| 702 |
[class*="space-header"],
|
| 703 |
[class*="spaces-header"],
|
|
@@ -705,7 +707,13 @@ HIDE_HF_WIDGET_HEAD = """
|
|
| 705 |
[class*="spaces-card"],
|
| 706 |
[class*="spaces-banner"],
|
| 707 |
[class*="hf-spaces"],
|
| 708 |
-
[
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 709 |
display: none !important;
|
| 710 |
visibility: hidden !important;
|
| 711 |
pointer-events: none !important;
|
|
@@ -713,58 +721,123 @@ HIDE_HF_WIDGET_HEAD = """
|
|
| 713 |
width: 0 !important;
|
| 714 |
overflow: hidden !important;
|
| 715 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 716 |
</style>
|
| 717 |
<script>
|
| 718 |
(function() {
|
| 719 |
-
// HF
|
| 720 |
-
//
|
| 721 |
-
//
|
|
|
|
|
|
|
|
|
|
| 722 |
const SIGNATURES = [
|
| 723 |
'AE-Talk-bot/',
|
| 724 |
-
'huggingface.co/
|
|
|
|
|
|
|
| 725 |
'Built with',
|
| 726 |
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 727 |
function looksLikeHfWidget(el) {
|
| 728 |
if (!el || el.nodeType !== 1) return false;
|
| 729 |
-
|
| 730 |
-
if (el.id === 'root' || el.id === 'gradio-app' ||
|
| 731 |
-
el.classList && el.classList.contains('gradio-container')) return false;
|
| 732 |
-
if (el.querySelector && el.querySelector('.gradio-container, #root, #gradio-app')) return false;
|
| 733 |
const txt = (el.textContent || '').trim();
|
| 734 |
-
|
| 735 |
-
|
| 736 |
-
|
| 737 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 738 |
}
|
| 739 |
-
//
|
| 740 |
const cls = (el.className && el.className.toString) ? el.className.toString() : '';
|
| 741 |
-
if (/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 742 |
return false;
|
| 743 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 744 |
function sweep() {
|
| 745 |
-
|
|
|
|
| 746 |
Array.from(document.body.children).forEach(el => {
|
| 747 |
-
if (looksLikeHfWidget(el))
|
| 748 |
-
|
| 749 |
-
|
| 750 |
-
|
| 751 |
-
|
|
|
|
| 752 |
});
|
|
|
|
|
|
|
| 753 |
}
|
| 754 |
if (document.readyState === 'loading') {
|
| 755 |
document.addEventListener('DOMContentLoaded', sweep);
|
| 756 |
} else {
|
| 757 |
sweep();
|
| 758 |
}
|
| 759 |
-
|
| 760 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 761 |
if (document.body) {
|
| 762 |
-
|
| 763 |
} else {
|
| 764 |
-
document.addEventListener('DOMContentLoaded',
|
| 765 |
-
obs.observe(document.body, { childList: true });
|
| 766 |
-
});
|
| 767 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 768 |
})();
|
| 769 |
</script>
|
| 770 |
"""
|
|
|
|
| 697 |
|
| 698 |
HIDE_HF_WIDGET_HEAD = """
|
| 699 |
<style>
|
| 700 |
+
/* Broad CSS targeting HF Spaces injected chrome. Class names are unstable
|
| 701 |
+
so we shotgun common patterns, and also nuke any anchor that links back
|
| 702 |
+
to huggingface.co at the top level. */
|
| 703 |
.space-header, .hf-spaces-header, .spaces-banner,
|
| 704 |
[class*="space-header"],
|
| 705 |
[class*="spaces-header"],
|
|
|
|
| 707 |
[class*="spaces-card"],
|
| 708 |
[class*="spaces-banner"],
|
| 709 |
[class*="hf-spaces"],
|
| 710 |
+
[class*="HfSpace"],
|
| 711 |
+
[class*="SpaceHeader"],
|
| 712 |
+
[class*="SpaceTag"],
|
| 713 |
+
[id*="space-header"],
|
| 714 |
+
[id*="hf-spaces"],
|
| 715 |
+
[data-testid*="space-header"],
|
| 716 |
+
[data-testid*="space-info"] {
|
| 717 |
display: none !important;
|
| 718 |
visibility: hidden !important;
|
| 719 |
pointer-events: none !important;
|
|
|
|
| 721 |
width: 0 !important;
|
| 722 |
overflow: hidden !important;
|
| 723 |
}
|
| 724 |
+
/* Body-direct anchors to HF (the floating "powered by" badge usually links there) */
|
| 725 |
+
body > a[href*="huggingface.co"],
|
| 726 |
+
body > a[href*="hf.co"] {
|
| 727 |
+
display: none !important;
|
| 728 |
+
}
|
| 729 |
</style>
|
| 730 |
<script>
|
| 731 |
(function() {
|
| 732 |
+
// HF injects a floating widget on .hf.space direct URLs. Class names
|
| 733 |
+
// change, so we use 3 detection strategies:
|
| 734 |
+
// (1) text signatures (repo path, "Built with", "Hugging Face"),
|
| 735 |
+
// (2) link signature (contains a link to huggingface.co / hf.co),
|
| 736 |
+
// (3) position heuristic (small fixed/absolute element in a corner,
|
| 737 |
+
// not inside our gradio container, not our own toast).
|
| 738 |
const SIGNATURES = [
|
| 739 |
'AE-Talk-bot/',
|
| 740 |
+
'huggingface.co/',
|
| 741 |
+
'hf.co/',
|
| 742 |
+
'Hugging Face',
|
| 743 |
'Built with',
|
| 744 |
];
|
| 745 |
+
const SAFE_IDS = new Set([
|
| 746 |
+
'root', 'gradio-app',
|
| 747 |
+
'__arg_lockdown_toast__'
|
| 748 |
+
]);
|
| 749 |
+
function isSafe(el) {
|
| 750 |
+
if (!el) return true;
|
| 751 |
+
if (SAFE_IDS.has(el.id)) return true;
|
| 752 |
+
if (el.classList && el.classList.contains('gradio-container')) return true;
|
| 753 |
+
if (el.tagName === 'SCRIPT' || el.tagName === 'STYLE' ||
|
| 754 |
+
el.tagName === 'LINK' || el.tagName === 'META' ||
|
| 755 |
+
el.tagName === 'NOSCRIPT' || el.tagName === 'IFRAME') return true;
|
| 756 |
+
// If the element CONTAINS our gradio root, it must not be hidden
|
| 757 |
+
if (el.querySelector && el.querySelector('.gradio-container, #root, #gradio-app, gradio-app')) return true;
|
| 758 |
+
return false;
|
| 759 |
+
}
|
| 760 |
function looksLikeHfWidget(el) {
|
| 761 |
if (!el || el.nodeType !== 1) return false;
|
| 762 |
+
if (isSafe(el)) return false;
|
|
|
|
|
|
|
|
|
|
| 763 |
const txt = (el.textContent || '').trim();
|
| 764 |
+
// Strategy 1: text signatures (small badge text only)
|
| 765 |
+
if (txt.length > 0 && txt.length < 400) {
|
| 766 |
+
for (const sig of SIGNATURES) {
|
| 767 |
+
if (txt.includes(sig)) return true;
|
| 768 |
+
}
|
| 769 |
+
}
|
| 770 |
+
// Strategy 2: contains a link to HF
|
| 771 |
+
if (el.querySelector && el.querySelector('a[href*="huggingface.co"], a[href*="hf.co"]')) {
|
| 772 |
+
return true;
|
| 773 |
}
|
| 774 |
+
// Strategy 3: HF-shaped class / id names
|
| 775 |
const cls = (el.className && el.className.toString) ? el.className.toString() : '';
|
| 776 |
+
if (/(^|[^a-z])(hf|huggingface)[-_]/i.test(cls)) return true;
|
| 777 |
+
if (/space[s-]?(header|tag|banner|card|info|badge|widget|overlay)/i.test(cls)) return true;
|
| 778 |
+
const idAttr = el.id || '';
|
| 779 |
+
if (/(^|[^a-z])(hf|huggingface)[-_]/i.test(idAttr)) return true;
|
| 780 |
+
// Strategy 4: position heuristic for small floating badges
|
| 781 |
+
try {
|
| 782 |
+
const style = window.getComputedStyle(el);
|
| 783 |
+
if ((style.position === 'fixed' || style.position === 'absolute') &&
|
| 784 |
+
txt.length > 0 && txt.length < 200) {
|
| 785 |
+
const rect = el.getBoundingClientRect();
|
| 786 |
+
if (rect.width > 0 && rect.width < 400 &&
|
| 787 |
+
rect.height > 0 && rect.height < 120) {
|
| 788 |
+
const inCorner =
|
| 789 |
+
(rect.top < 120 || rect.bottom > window.innerHeight - 120) &&
|
| 790 |
+
(rect.left < 120 || rect.right > window.innerWidth - 120);
|
| 791 |
+
if (inCorner) return true;
|
| 792 |
+
}
|
| 793 |
+
}
|
| 794 |
+
} catch (e) { /* ignore */ }
|
| 795 |
return false;
|
| 796 |
}
|
| 797 |
+
function nuke(el) {
|
| 798 |
+
try {
|
| 799 |
+
el.style.setProperty('display', 'none', 'important');
|
| 800 |
+
el.style.setProperty('visibility', 'hidden', 'important');
|
| 801 |
+
el.setAttribute('hidden', '');
|
| 802 |
+
console.log('[hf-widget-hide] removed', el.tagName, el.id || '', el.className || '');
|
| 803 |
+
} catch (e) { /* ignore */ }
|
| 804 |
+
}
|
| 805 |
function sweep() {
|
| 806 |
+
if (!document.body) return;
|
| 807 |
+
// Direct body children first
|
| 808 |
Array.from(document.body.children).forEach(el => {
|
| 809 |
+
if (looksLikeHfWidget(el)) nuke(el);
|
| 810 |
+
});
|
| 811 |
+
// Also check direct html children (some injection patterns put nodes there)
|
| 812 |
+
Array.from(document.documentElement.children).forEach(el => {
|
| 813 |
+
if (el.tagName === 'BODY' || el.tagName === 'HEAD') return;
|
| 814 |
+
if (looksLikeHfWidget(el)) nuke(el);
|
| 815 |
});
|
| 816 |
+
// Sweep any body-level <a> pointing to HF
|
| 817 |
+
document.querySelectorAll('body > a[href*="huggingface.co"], body > a[href*="hf.co"]').forEach(nuke);
|
| 818 |
}
|
| 819 |
if (document.readyState === 'loading') {
|
| 820 |
document.addEventListener('DOMContentLoaded', sweep);
|
| 821 |
} else {
|
| 822 |
sweep();
|
| 823 |
}
|
| 824 |
+
function attachObserver() {
|
| 825 |
+
if (!document.body) return;
|
| 826 |
+
const obs = new MutationObserver(sweep);
|
| 827 |
+
obs.observe(document.body, { childList: true, subtree: false });
|
| 828 |
+
obs.observe(document.documentElement, { childList: true, subtree: false });
|
| 829 |
+
}
|
| 830 |
if (document.body) {
|
| 831 |
+
attachObserver();
|
| 832 |
} else {
|
| 833 |
+
document.addEventListener('DOMContentLoaded', attachObserver);
|
|
|
|
|
|
|
| 834 |
}
|
| 835 |
+
// Fallback: re-sweep every 1.5s for the first 30s, in case HF injects late
|
| 836 |
+
let ticks = 0;
|
| 837 |
+
const iv = setInterval(() => {
|
| 838 |
+
sweep();
|
| 839 |
+
if (++ticks >= 20) clearInterval(iv);
|
| 840 |
+
}, 1500);
|
| 841 |
})();
|
| 842 |
</script>
|
| 843 |
"""
|