linxinhua commited on
Commit
39080d8
·
verified ·
1 Parent(s): 769b091

Stronger HF-widget hide + (no_ai) clipboard lockdown

Browse files
Files changed (1) hide show
  1. app.py +101 -28
app.py CHANGED
@@ -697,7 +697,9 @@ EMOJI_SWAP_HEAD = """
697
 
698
  HIDE_HF_WIDGET_HEAD = """
699
  <style>
700
- /* CSS targeting common HF Spaces floating widget classes */
 
 
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
- [data-testid*="space-header"] {
 
 
 
 
 
 
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 Spaces floating widget signature: top-level element near top-right
720
- // that mentions the Space repo path or an HF Spaces-style breadcrumb.
721
- // We sweep on load and on every DOM mutation.
 
 
 
722
  const SIGNATURES = [
723
  'AE-Talk-bot/',
724
- 'huggingface.co/spaces/',
 
 
725
  'Built with',
726
  ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
727
  function looksLikeHfWidget(el) {
728
  if (!el || el.nodeType !== 1) return false;
729
- // Don't touch our own gradio app
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
- if (txt.length > 400) return false; // too big, not a small badge
735
- // Must match at least one signature
736
- for (const sig of SIGNATURES) {
737
- if (txt.includes(sig)) return true;
 
 
 
 
 
738
  }
739
- // Also flag obviously-HF class names
740
  const cls = (el.className && el.className.toString) ? el.className.toString() : '';
741
- if (/space[s-]?(header|tag|banner|card)/i.test(cls)) return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
742
  return false;
743
  }
 
 
 
 
 
 
 
 
744
  function sweep() {
745
- // Only check direct body children to keep this cheap
 
746
  Array.from(document.body.children).forEach(el => {
747
- if (looksLikeHfWidget(el)) {
748
- el.style.display = 'none';
749
- el.setAttribute('hidden', '');
750
- console.log('[hf-widget-hide] removed', el.tagName, el.className || '(no class)');
751
- }
 
752
  });
 
 
753
  }
754
  if (document.readyState === 'loading') {
755
  document.addEventListener('DOMContentLoaded', sweep);
756
  } else {
757
  sweep();
758
  }
759
- // Re-sweep on every mutation in case HF injects later
760
- const obs = new MutationObserver(sweep);
 
 
 
 
761
  if (document.body) {
762
- obs.observe(document.body, { childList: true });
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
  """