175 lines
7.5 KiB
JavaScript
175 lines
7.5 KiB
JavaScript
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(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}`
|
||
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 temporay 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')
|
||
}
|
||
})
|
||
}
|
||
}
|