PageSourceSearch

https://suno-wave.ru/assets/js/sw-minusa-wav-demo-download-v1.js?v=20260718_paid_safe_no_observer_1

js suno-wave.ru collected 2026-10-09 03:41:09 UTC 3,511 bytes, 117 lines download raw bytes

1(() => {
2  'use strict';
3
4  if (window.__swWavDemoDownloadV1) return;
5  window.__swWavDemoDownloadV1 = true;
6
7  const JOB_RE = /^[a-f0-9]{32}$/i;
8
9  function cleanJob(value) {
10    const job = String(value || '').trim().toLowerCase();
11    return JOB_RE.test(job) ? job : '';
12  }
13
14  function jobFromUrl(value) {
15    try {
16      const url = new URL(value, window.location.origin);
17      return cleanJob(url.searchParams.get('job'));
18    } catch (_) {
19      return '';
20    }
21  }
22
23  function resolveJob() {
24    const locationJob = cleanJob(new URLSearchParams(window.location.search).get('job'));
25    if (locationJob) return locationJob;
26
27    const candidates = document.querySelectorAll(
28      '#resultModal a[href*="job="], #resultModal [data-job], body [data-job]'
29    );
30
31    for (const node of candidates) {
32      const dataJob = cleanJob(node.getAttribute('data-job'));
33      if (dataJob) return dataJob;
34
35      const hrefJob = jobFromUrl(node.getAttribute('href') || '');
36      if (hrefJob) return hrefJob;
37    }
38
39    return '';
40  }
41
42  function wavHref(job, kind) {
43    const url = new URL('/minus_demo_wav_download.php', window.location.origin);
44    url.searchParams.set('job', job);
45    url.searchParams.set('kind', kind);
46    return url.pathname + url.search;
47  }
48
49  function isPaidState() {
50    const state = String(document.body && document.body.dataset ? document.body.dataset.pageState || '' : '').toLowerCase();
51    if (state === 'paid' || state === 'paid-processing') return true;
52    const hero = document.getElementById('paidHeroDownload');
53    if (hero && !hero.classList.contains('is-hidden') && hero.getAttribute('aria-hidden') !== 'true') return true;
54    return false;
55  }
56
57  function setButton(id, job, kind, text) {
58    const button = document.getElementById(id);
59    if (!button || !job) return;
60    if (isPaidState() || button.classList.contains('is-paid-download')) {
61      button.removeAttribute('data-sw-wav-demo');
62      return;
63    }
64
65    const expected = wavHref(job, kind);
66
67    if (button.getAttribute('href') !== expected) {
68      button.setAttribute('href', expected);
69    }
70
71    button.setAttribute('download', '');
72    button.setAttribute('rel', 'nofollow');
73    button.setAttribute('data-sw-wav-demo', '1');
74    button.setAttribute('aria-label', text);
75
76    if (button.textContent.trim() !== text) {
77      button.textContent = text;
78    }
79  }
80
81  function apply() {
82    if (isPaidState()) return;
83    const job = resolveJob();
84    if (!job) return;
85
86    /*
87     * Важно: audio.src не меняем.
88     * Плеер продолжает слушать существующий MP3 preview stream.
89     */
90    setButton('demoMinus', job, 'instrumental', 'Скачать демо WAV');
91    setButton('demoVocal', job, 'vocals', 'Скачать демо вокала WAV');
92  }
93
94  function start() {
95    apply();
96
97    document.addEventListener('sunowave:result-ready', apply);
98    document.addEventListener('sw:result-ready', apply);
99    window.addEventListener('pageshow', apply);
100
101    /*
102     * Защита от старых JS-слоёв, которые обновляют href спустя несколько секунд.
103     */
104    let ticks = 0;
105    const timer = window.setInterval(() => {
106      ticks += 1;
107      apply();
108      if (ticks >= 20 || isPaidState()) window.clearInterval(timer);
109    }, 1200);
110  }
111
112  if (document.readyState === 'loading') {
113    document.addEventListener('DOMContentLoaded', start, { once: true });
114  } else {
115    start();
116  }
117})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.