teddit/inc/downloadAndSave.js

181 lines
7.7 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

module.exports = function(tools) {
const config = require('../config')
const {spawn} = require('child_process')
const fs = require('fs')
this.downloadAndSave = (url, file_prefix = '', gifmp4, isYouTubeThumbnail) => {
/**
* This function downloads media (video or image) to disk.
* Returns a localized URL
*
* For example for images:
* https://external-preview.redd.it/DiaeK_j5fqpBqbatvo7GZzbHNJY2oxEym93B_3.jpg
* =>
* https://teddit.net/pics/DiaeK_j5fqpBqbatvo7GZzbHNJY2oxEym93B_3.jpg
*
* For videos:
* https://v.redd.it/f3lcdk4ydcl51/DASH_480.mp4?source=fallback
* =>
* https://teddit.net/vids/f3lcdk4ydcl51.mp4
*/
let valid_video_extensions = ['mp4', 'webm', 'ogg']
let invalid_urls = ['self', 'default', 'nsfw', 'image', 'spoiler', 'undefined', undefined, null, '']
return new Promise((resolve, reject) => {
if(!invalid_urls.includes(url)) {
(async () => {
let temp_url = new URL(url)
if(config.valid_media_domains.includes(temp_url.hostname)) {
let pathname = temp_url.pathname
let file_ext
let has_extension = true
let dir = ''
if(gifmp4) {
file_ext = 'mp4'
} else {
if (file_prefix === 'flair_') {
// Flair emojis end in the name without a file extension
file_ext = 'png'
} else if(!pathname.includes('.')) {
/**
* Sometimes reddit API returns video without extension, like
* "DASH_480" and not "DASH_480.mp4".
*/
file_ext = 'mp4'
has_extension = false
} else {
file_ext = pathname.substring(pathname.lastIndexOf('.') + 1)
}
}
if(file_prefix === 'thumb_')
dir = 'thumbs/'
if(file_prefix === 'flair_')
dir = 'flairs/'
if(file_prefix === 'icon_')
dir = 'icons/'
if(valid_video_extensions.includes(file_ext) || gifmp4) {
/* Is video. */
if(!config.video_enabled) {
resolve('')
} else {
let filename = `${temp_url.pathname.substr(1).split('/')[0]}.${file_ext}`
if(temp_url.hostname === 'thumbs.gfycat.com')
filename = `${temp_url.pathname.substr(1).split('/')[0]}`
let path = `./static/vids/${dir}${filename}`
let temp_path = `./static/vids/${dir}temp_${filename}`
if(!fs.existsSync(path)) {
const download = await downloadFile(cleanUrl(url))
if(download.success === true) {
const write = await writeToDisk(download.data, temp_path)
if(write.success === true) {
let audio_url
if(has_extension) {
audio_url = `${url.split('_')[0]}_audio.mp4`
} else {
let ending = `${temp_url.pathname.split('/').slice(-1)[0]}`
audio_url = url.replace(ending, 'audio')
}
const download_audio = await downloadFile(cleanUrl(audio_url))
if(download_audio.success === true) {
let audio_path = `./static/vids/${dir}temp_audio_${filename}`
const write_audio = await writeToDisk(download_audio.data, audio_path)
if(write_audio.success === true) {
let processVideo = spawn('ffmpeg', ['-y', '-i', temp_path, '-i', audio_path, '-c', 'copy', path])
processVideo.on('exit', (code) => {
if(code === 0) {
let final_url = `/vids/${dir}${filename}`
let temp_files = [temp_path, audio_path]
deleteFiles(temp_files, (error) => {
if(error) {
console.log(`Error while deleting temporary files:`, error)
}
})
resolve(final_url)
} else {
console.log(`ffmpeg error, exited with code: `, code)
resolve('')
}
})
} else {
console.log(`Error while writing temp audio file.`)
resolve('')
}
} else {
/**
* Either the video doesn't have any audio track, or we
* failed downloading it. Let's return the video only.
*/
fs.rename(temp_path, path, (error) => {
if(error) {
console.log(`Error while renaming the temp video file: ${temp_path} => ${path}.`, error)
} else {
let final_url = `/vids/${dir}${filename}`
resolve(final_url)
}
})
}
} else {
console.log(`Error while writing video file.`)
resolve('')
}
} else {
console.log(`Error while downloading video file.`)
resolve('')
}
} else {
resolve(`/vids/${dir}${filename}`)
}
}
} else {
/* Is image. */
let path, youtubeThumbUrl, filename
if(isYouTubeThumbnail) {
filename = `${file_prefix}${temp_url.pathname.split('/').slice(-2)[0]}_hqdefault.jpg`
} else {
let width = ''
if(temp_url.searchParams.get('width')) {
width = temp_url.searchParams.get('width')
}
if(file_prefix === 'flair_') {
// Flair emojis have a full path of `UUID/name`,
// so we need to incorporate the UUID to avoid duplicates
// since names alone are not unique across all of reddit
filename = `${pathname.slice(1).replace('/', '_')}.png` // Only first replacement is fine
} else {
filename = `${file_prefix}w:${temp_url.searchParams.get('width')}_${temp_url.pathname.split('/').slice(-1)}`
}
}
path = `./static/pics/${dir}${filename}`
if(!fs.existsSync(path)) {
const download = await downloadFile(cleanUrl(url))
if(download.success === true) {
const write = await writeToDisk(download.data, path)
if(write.success === true) {
let final_url = `/pics/${dir}${filename}`
resolve(final_url)
} else {
console.log(`Error while writing image file.`, write)
resolve('')
}
} else {
console.log(`Error while downloading image file.`)
resolve('')
}
} else {
resolve(`/pics/${dir}${filename}`)
}
}
} else {
console.log(`Invalid URL for downloading media: ${temp_url.hostname}.`)
resolve('')
}
})()
} else {
resolve('self')
}
})
}
}