// Name: Multi-Service GIF Search // Description: Search for GIFs across multiple services and paste them // Author: JosXa import '@johnlindquist/kit' const searchTerm = await arg({ placeholder: 'Search for GIFs', hint: 'Enter keywords to search across Giphy, Tenor, and other GIF services' }) if (!searchTerm) { await div(md('Please enter a search term')) exit() } const css = ` .focused { background: color-mix(in srgb, var(--color-secondary) calc(var(--ui-bg-opacity)* 100%), transparent); padding: 0; } .focused > img { border: 0.25rem solid var(--color-primary); } .gif-container { display: flex; justify-content: center; align-items: center; width: 100%; height: 100%; overflow: hidden; } .gif-container img { max-width: 200px; max-height: 200px; object-fit: contain; } .service-badge { position: absolute; top: 4px; right: 4px; background: rgba(0,0,0,0.7); color: white; padding: 2px 6px; border-radius: 4px; font-size: 10px; font-weight: bold; } ` const searchGiphy = async (query) => { try { const GIPHY_API_KEY = await env('GIPHY_API_KEY', { hint: 'Get a free API key from https://developers.giphy.com/dashboard/', secret: true }) const response = await get(`https://api.giphy.com/v1/gifs/search?api_key=${GIPHY_API_KEY}&q=${encodeURIComponent(query)}&limit=15&rating=g`) return response.data.data.map(gif => ({ name: gif.title.trim() || gif.slug, value: gif.images.original.url, service: 'Giphy', html: `<div class="gif-container" style="position: relative;"> <img src="${gif.images.downsized.url}" alt="${gif.title || gif.slug}"> <div class="service-badge">GIPHY</div> </div>`, focusedClassName: 'focused' })) } catch (error) { console.warn('Giphy search failed:', error.message) return [] } } const searchTenor = async (query) => { try { const TENOR_API_KEY = await env('TENOR_API_KEY', { hint: 'Get a free API key from https://tenor.com/developer/keyregistration', secret: true }) const response = await get(`https://tenor.googleapis.com/v2/search?q=${encodeURIComponent(query)}&key=${TENOR_API_KEY}&limit=15&media_filter=gif`) return response.data.results.map(gif => ({ name: gif.content_description || 'Tenor GIF', value: gif.media_formats.gif.url, service: 'Tenor', html: `<div class="gif-container" style="position: relative;"> <img src="${gif.media_formats.tinygif.url}" alt="${gif.content_description}"> <div class="service-badge">TENOR</div> </div>`, focusedClassName: 'focused' })) } catch (error) { console.warn('Tenor search failed:', error.message) return [] } } const searchGfycat = async (query) => { try { // Gfycat API (now Redgifs) - using their public search const response = await get(`https://api.gfycat.com/v1/gfycats/search?search_text=${encodeURIComponent(query)}&count=10`) return response.data.gfycats.map(gif => ({ name: gif.title || gif.gfyName, value: gif.gifUrl || gif.max5mbGif, service: 'Gfycat', html: `<div class="gif-container" style="position: relative;"> <img src="${gif.max1mbGif || gif.gifUrl}" alt="${gif.title}"> <div class="service-badge">GFYCAT</div> </div>`, focusedClassName: 'focused' })) } catch (error) { console.warn('Gfycat search failed:', error.message) return [] } } // Show loading message setPanel(md('🔍 Searching across multiple GIF services...')) // Search all services concurrently const [giphyResults, tenorResults, gfycatResults] = await Promise.all([ searchGiphy(searchTerm), searchTenor(searchTerm), searchGfycat(searchTerm) ]) // Combine and shuffle results for variety const allResults = [...giphyResults, ...tenorResults, ...gfycatResults] if (allResults.length === 0) { await div(md(`# No GIFs found for "${searchTerm}"\n\nTry a different search term or check your API keys.`)) exit() } // Shuffle the results to mix services const shuffledResults = allResults.sort(() => Math.random() - 0.5) const selectedGif = await grid({ placeholder: `Found ${allResults.length} GIFs for "${searchTerm}"`, css, columns: 4, enter: 'Paste GIF URL', shortcuts: [ { name: 'Copy URL', key: `${cmd}+c`, bar: 'right', onPress: (input, { focused }) => { copy(focused.value) toast('GIF URL copied to clipboard!') }, visible: true }, { name: 'Paste Markdown', key: `${cmd}+m`, bar: 'right', onPress: (input, { focused }) => { submit(``) }, visible: true }, { name: 'Paste HTML', key: `${cmd}+h`, bar: 'right', onPress: (input, { focused }) => { submit(`<img src="${focused.value}" alt="${searchTerm}" style="max-width: 100%;">`) }, visible: true } ] }, shuffledResults) await setSelectedText(selectedGif)