Skip to main content

Overview

SoundWave provides a powerful search system that helps you find music quickly across multiple sources including YouTube and Spotify. The search feature includes real-time suggestions, smart filtering, and multi-page result aggregation.

Search Input with Debouncing

SoundWave implements debouncing to optimize search performance and reduce unnecessary API calls while you type.

How Debouncing Works

1

User Types Query

As you type in the search field, the input event is captured.
2

Debounce Timer Activates

The system waits 300ms before triggering the search to avoid excessive API calls.
3

Suggestions Display

After the delay, if you’re still typing, previous requests are cancelled and only the latest query is sent.

Implementation

The debounce function prevents API overload:
function debounce(func, wait) {
    let timeout;
    return function (...args) {
        clearTimeout(timeout);
        timeout = setTimeout(() => func.apply(this, args), wait);
    };
}

// Applied to search input with 300ms delay
document.getElementById('song-name').addEventListener('input', debounce(function () {
    const songName = this.value;
    suggestionsContainer.innerHTML = '';

    if (songName) {
        originalSearchTerm = songName.toLowerCase();
        fetchSuggestions(songName);
    } else {
        clearSuggestionsAndResults();
    }
}, 300));
The 300ms delay strikes a balance between responsiveness and performance. You can adjust this value based on your needs.

Real-Time Search Suggestions

As you type, SoundWave fetches suggestions from YouTube to help you find what you’re looking for faster.

Suggestion Sources

The system uses fallback URLs to ensure reliability:
function fetchSuggestions(songName) {
  const url1 = 'https://inv.nadeko.net/search?q=' + encodeURIComponent(songName);
  const url2 = 'https://yewtu.be/search?q=' + encodeURIComponent(songName);

  fetch('https://api.allorigins.win/raw?url=' + encodeURIComponent(url1))
    .then(response => {
        if (response.ok) return response.text();
        throw new Error('Network response was not ok.');
    })
    .then(data => {
        processSuggestionsData(data);
    })
    .catch(() => {
        // Fallback to second URL if first fails
        fetch('https://api.allorigins.win/raw?url=' + encodeURIComponent(url2))
        .then(response => response.text())
        .then(data => processSuggestionsData(data))
        .catch(error => {
            console.error('Error al obtener sugerencias:', error);
        });
    });
}
Suggestions are limited to 5 items to keep the interface clean and focused.
When you click the search button, SoundWave performs a comprehensive search across multiple pages to give you the best results.

Search Process

async function fetchSearchResults(songName) {
    const maxPages = 6; // Search across 6 pages
    let allResults = [];

    for (let page = 1; page <= maxPages; page++) {
        const url = `https://yewtu.be/search?q=${encodeURIComponent(songName)}&page=${page}`;

        try {
            const response = await fetch('https://api.allorigins.win/raw?url=' + encodeURIComponent(url));
            if (!response.ok) throw new Error('Network response was not ok.');

            const data = await response.text();
            const parser = new DOMParser();
            const doc = parser.parseFromString(data, 'text/html');
            const divs = doc.querySelectorAll('div.video-card-row');

            // Extract and filter results
            const searchResults = Array.from(divs)
                .map(div => {
                    const link = div.querySelector('a');
                    const titleElement = link ? link.querySelector('p') : null;
                    const title = titleElement ? titleElement.innerText : 'Sin título';
                    const videoId = link ? link.getAttribute('href').split('v=')[1] : null;
                    return { title, videoId };
                })
                .filter(result => {
                    // Apply filtering logic
                    const searchTerm = originalSearchTerm.toLowerCase();
                    const songTitle = result.title.toLowerCase();

                    const includesSearchTerm = (
                        songTitle.includes(searchTerm) ||
                        searchTerm.split(' ').every(term => songTitle.includes(term))
                    );

                    const excludesOfficial = !songTitle.includes('oficial') && 
                                            !songTitle.includes('official');

                    return includesSearchTerm && excludesOfficial;
                });

            allResults = allResults.concat(searchResults);
        } catch (error) {
            console.error('There was a problem with the fetch operation:', error);
        }
    }

    // Group results for pagination
    groupedResults = [];
    for (let i = 0; i < allResults.length; i += 5) {
        groupedResults.push(allResults.slice(i, i + 5));
    }

    currentGroupIndex = 0;
    showGroupedResults();
}

Result Grouping

Results are grouped in sets of 5 for easier navigation:
  • Group 1: Results 1-5
  • Group 2: Results 6-10
  • Group 3: Results 11-15
  • And so on…

Navigation Controls

Use the < and > buttons to navigate between result groups. The current group number is displayed at the bottom of the results.
SoundWave also supports Spotify search for direct access to Spotify’s catalog:
async function searchSongs() {
    const query = document.getElementById('search-query').value.trim();
    if (!query) {
        alert('Por favor, ingresa un término de búsqueda.');
        return;
    }

    const response = await fetch(
        `https://jsnode-ab0e.onrender.com/search?query=${encodeURIComponent(query)}&type=track&accessToken=${accessToken}`
    );
    const data = await response.json();

    const songList = document.getElementById('song-list');
    songList.innerHTML = '';

    data.tracks.items.forEach(track => {
        const li = document.createElement('li');
        li.textContent = `${track.name} - ${track.artists.map(artist => artist.name).join(', ')}`;
        li.dataset.embedUrl = `https://open.spotify.com/embed/track/${track.id}?utm_source=generator&theme=0`;
        li.addEventListener('click', () => playTrack(li.dataset.embedUrl));
        songList.appendChild(li);
    });
}

Search Modes

YouTube Search

Searches across multiple YouTube instances with intelligent filtering

Spotify Search

Direct access to Spotify’s official catalog with instant playback

Best Practices

Always provide specific search terms. Generic queries like “music” will return too many irrelevant results.

Search Tips

  1. Include Artist Name: Search “Song Name Artist” for better results
  2. Use Exact Titles: Exact song titles yield more accurate matches
  3. Avoid Special Characters: Keep searches simple without special symbols
  4. Be Patient: Multi-page searches may take a few seconds

Clearing Search Results

You can clear all search results and suggestions:
function clearSuggestionsAndResults() {
    suggestionsContainer.innerHTML = '';
    filteredContent.innerHTML = '';
    sourceLinksContainer.innerHTML = '';
    stopAudioPlayer();
}
This function is automatically called when you clear the search input field.

Next Steps

Filtering Results

Learn how SoundWave filters search results

Playback Controls

Discover how to control music playback

Build docs developers (and LLMs) love