// ==UserScript== // @name Tiktok Video Downloader🎬 // @namespace https://greasyfork.org/en/scripts/431826 // @version 1.7 // @description Download TikTok videos without watermark // @author YAD // @match *://*.tiktok.com/* // @grant GM_xmlhttpRequest // @grant GM_download // @icon https://miro.medium.com/v2/resize:fit:512/1*KX6NTUUHWlCP4sCXz28TBA.png // @downloadURL none // ==/UserScript== (function() { 'use strict'; const INTERVAL_MS = 500; // Extract video ID from the URL to name the file const getFileName = (url) => { const videoId = url.split('/').pop().split('?')[0]; return `TikTok_Video_${videoId}.mp4`; }; // Function to handle video download with error handling and feedback const downloadVideo = (url, button) => { if (!url) { console.error('No valid video URL found.'); button.textContent = '✖️'; return; } button.textContent = '⏳'; GM_xmlhttpRequest({ method: 'GET', url, responseType: 'blob', onload: ({ response, status, statusText }) => { console.log(`Response Status: ${status} ${statusText}`); if (response) { GM_download({ url: URL.createObjectURL(response), name: getFileName(url), onload: () => { button.textContent = '✔️'; setTimeout(() => button.remove(), 2000); }, onerror: () => { button.textContent = '✖️'; setTimeout(() => button.remove(), 1500); } }); } else { console.error('Failed to download the video.'); button.textContent = '✖️'; setTimeout(() => button.remove(), 1500); } }, onerror: (error) => { console.error('An error occurred during the request.', error); button.textContent = '✖️'; setTimeout(() => button.remove(), 1500); }, ontimeout: () => { console.error('Request timed out.'); button.textContent = '✖️'; setTimeout(() => button.remove(), 1500); } }); }; // Create and style the download button const createDownloadButton = (video) => { const button = document.createElement('div'); Object.assign(button.style, { position: 'absolute', right: '15px', top: '27%', transform: 'translateY(-50%)', width: '50px', height: '50px', backgroundColor: '#ff3b5c', color: '#ffffff', fontSize: '18px', textShadow: '3px 3px 0px #9C1331', textAlign: 'center', lineHeight: '50px', borderRadius: '50%', cursor: 'pointer', zIndex: '1000' }); button.textContent = '🎞️'; // On button click, initiate download and provide feedback button.onclick = (e) => { e.stopPropagation(); e.preventDefault(); button.style.backgroundColor = '#EF2950'; const videoUrl = video.src || video.querySelector('source')?.src; downloadVideo(videoUrl, button); }; // Append the button to the video container video.parentNode.style.position = 'relative'; video.parentNode.appendChild(button); return button; }; // Manage button visibility and creation on hover const manageDownloadButtons = (video) => { let button; video.addEventListener('mouseover', () => { if (!button) { button = createDownloadButton(video); } }); // Remove the button only after download is complete or fails video.addEventListener('mouseout', (e) => { if (button && !video.contains(e.relatedTarget) && !button.contains(e.relatedTarget)) { button.remove(); button = null; } }); }; // Function to periodically check for new videos const checkForNewVideos = () => { document.querySelectorAll('video:not(.processed)').forEach((video) => { video.classList.add('processed'); manageDownloadButtons(video); }); }; // Start interval to periodically check for new videos setInterval(checkForNewVideos, INTERVAL_MS); })();