One of the trickiest parts of building
dltkk.to was handling URL validation
across TikTok, YouTube and Instagram.
Each platform has completely different
URL structures and each needs different
validation logic. Here's how I solved it.
The Problem
Users paste all kinds of URLs:
\
https://www.tiktok.com/@user/video/123
https://vm.tiktok.com/abc123
https://youtube.com/watch?v=abc123
https://youtu.be/abc123
https://www.instagram.com/reel/abc123
https://instagram.com/p/abc123
\\
All valid. All need different handling.
Platform Detection
First step is detecting which platform
the URL belongs to:
\`javascript
function detectPlatform(url) {
if (!url || typeof url !== 'string') {
return null
}
if (url.includes('tiktok.com')) {
return 'tiktok'
}
if (
url.includes('youtube.com/watch') ||
url.includes('youtu.be/')
) {
return 'youtube'
}
if (url.includes('instagram.com')) {
return 'instagram'
}
return null
}
`\
Simple but effective. Returns null for
unsupported platforms which we handle
gracefully in the response.
URL Normalization
TikTok specifically has a problem with
shortened URLs (vm.tiktok.com). These
need to be expanded before processing.
YouTube has the same issue with
youtu.be short links.
\`javascript
function normalizeYouTubeUrl(url) {
const match = url.match(
/(?:youtube.com\/watch\?v=|youtu.be\/)([^&\n?#]+)/
)
if (match) {
return https://www.youtube.com/watch?v=${match[1]}
}
return url
}
`\
This extracts the video ID from any
YouTube URL format and rebuilds a
clean standardized URL.
Duration Validation (YouTube Only)
YouTube is the only platform where
we check duration before processing.
Long videos could hammer the server
so we cap at 10 minutes:
\javascriptyt-dlp --get-duration "${url}"`
function checkDuration(url) {
return new Promise((resolve, reject) => {
const command =
exec(command, { timeout: 10000 }, (error, stdout) => {
if (error) {
// Continue anyway if check fails
resolve(true)
return
}
const duration = stdout.trim()
const parts = duration.split(':').map(Number)
let totalSeconds = 0
if (parts.length === 2) {
totalSeconds = parts[0] * 60 + parts[1]
} else if (parts.length === 3) {
totalSeconds = parts[0] * 3600 +
parts[1] * 60 +
parts[2]
}
if (totalSeconds > 600) {
reject(new Error('Video exceeds 10 minute limit'))
return
}
resolve(true)
})
})
}
`\
Note: we resolve true even on error
rather than blocking the user. The
actual download will fail naturally
if something is wrong.
Error Classification
Different errors need different user
facing messages:
\`javascript
function classifyError(errorOutput) {
if (errorOutput.includes('Sign in to confirm')) {
return 'YouTube requires verification.
Try a different video.'
}
if (errorOutput.includes('Unable to extract')) {
return 'Unable to download.
Check the URL and try again.'
}
if (errorOutput.includes('HTTP Error 429')) {
return 'Too many requests.
Wait a moment and try again.'
}
if (errorOutput.includes('Private video')) {
return 'This video is private.'
}
return 'Download failed.
Check the URL and try again.'
}
`\
Generic errors are confusing for users.
Classifying them makes the experience
much better.
File Cleanup
Temporary files auto delete after
2 minutes to prevent storage issues:
\javascript
setTimeout(() => {
if (fs.existsSync(outputPath)) {
fs.unlink(outputPath, (err) => {
if (err) {
console.error('Failed to delete:', err)
}
})
}
}, 120000)
\\
Request Timeout
Long running downloads get killed
after 5 minutes:
\javascript
const timeout = setTimeout(() => {
process.kill()
res.status(500).json({
error: 'Download timeout.
Video may be too large.'
})
}, 300000)
\\
Putting It Together
\`javascript
app.post('/api/download', async (req, res) => {
const { url, format } = req.body
// Detect platform
const platform = detectPlatform(url)
if (!platform) {
return res.status(400).json({
error: 'Unsupported platform'
})
}
// Normalize URL
let videoUrl = url
if (platform === 'youtube') {
videoUrl = normalizeYouTubeUrl(url)
// Check duration
try {
await checkDuration(videoUrl)
} catch (err) {
return res.status(400).json({
error: err.message
})
}
}
// Process download
processDownload(videoUrl, format, platform, res)
})
`\
What I'd Do Differently
- Add rate limiting per IP immediately
- Use a queue system for heavy traffic
- Add Redis for caching duplicate requests
- Implement proper logging from day one
Try the Live Version
Everything above is running at dltkk.to
Free, no signup required.
Questions about any part of the
implementation? Happy to go deeper.
Top comments (0)