DEV Community

john jewski
john jewski

Posted on

How I Handle Platform Detection and URL Validation for Multiple Video Sources in Node.js

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:

\javascript
function checkDuration(url) {
return new Promise((resolve, reject) => {
const command =
yt-dlp --get-duration "${url}"`

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)
})
Enter fullscreen mode Exit fullscreen mode

})
}
`\

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 
  })
}
Enter fullscreen mode Exit fullscreen mode

}

// Process download
processDownload(videoUrl, format, platform, res)
})
`\

What I'd Do Differently

  1. Add rate limiting per IP immediately
  2. Use a queue system for heavy traffic
  3. Add Redis for caching duplicate requests
  4. 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)