teddit/inc/downloadAndSave.js

181 lines
7.7 KiB
JavaScript
Raw Normal View History

2020-12-21 12:52:48 +01:00
module.exports = function(tools) {
2020-12-01 20:16:51 +01:00
const config = require('../config')
2020-11-17 21:44:32 +01:00
const {spawn} = require('child_process')
const fs = require('fs')
this.downloadAndSave = (url, file_prefix = '', gifmp4, isYouTubeThumbnail) => {
2020-12-21 12:52:48 +01:00
/**
2020-11-17 21:44:32 +01:00
* This function downloads media (video or image) to disk.
* Returns a localized URL
2020-12-21 12:52:48 +01:00
*
2020-11-17 21:44:32 +01:00
* 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, '']
2020-11-17 21:44:32 +01:00
return new Promise((resolve, reject) => {
if(!invalid_urls.includes(url)) {
(async () => {
let temp_url = new URL(url)
2020-12-01 20:16:51 +01:00
if(config.valid_media_domains.includes(temp_url.hostname)) {
2020-11-17 21:44:32 +01:00
let pathname = temp_url.pathname
let file_ext
let has_extension = true
let dir = ''
2020-11-17 21:44:32 +01:00
if(gifmp4) {
file_ext = 'mp4'
} else {
2020-12-21 12:52:48 +01:00
if (file_prefix === 'flair_') {
// Flair emojis end in the name without a file extension
file_ext = 'png'
2021-02-19 20:29:39 +01:00
} else if(!pathname.includes('.')) {
/**
2020-11-17 21:44:32 +01:00
* Sometimes reddit API returns video without extension, like
* "DASH_480" and not "DASH_480.mp4".
*/
file_ext = 'mp4'
has_extension = false
2020-12-21 12:52:48 +01:00
} else {
2020-11-17 21:44:32 +01:00
file_ext = pathname.substring(pathname.lastIndexOf('.') + 1)
}
}
2020-12-21 12:52:48 +01:00
if(file_prefix === 'thumb_')
dir = 'thumbs/'
2020-12-21 12:52:48 +01:00
if(file_prefix === 'flair_')
dir = 'flairs/'
2021-03-22 19:06:57 +01:00
if(file_prefix === 'icon_')
dir = 'icons/'
2020-11-17 21:44:32 +01:00
if(valid_video_extensions.includes(file_ext) || gifmp4) {
/* Is video. */
2020-12-01 20:16:51 +01:00
if(!config.video_enabled) {
2020-11-17 21:44:32 +01:00
resolve('')
} else {
let filename = `${temp_url.pathname.substr(1).split('/')[0]}.${file_ext}`
2021-02-19 20:29:39 +01:00
if(temp_url.hostname === 'thumbs.gfycat.com')
filename = `${temp_url.pathname.substr(1).split('/')[0]}`
2020-12-25 22:14:24 +01:00
let path = `./static/vids/${dir}${filename}`
let temp_path = `./static/vids/${dir}temp_${filename}`
2020-11-17 21:44:32 +01:00
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) {
2020-12-25 22:14:24 +01:00
let audio_path = `./static/vids/${dir}temp_audio_${filename}`
2020-11-17 21:44:32 +01:00
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}`
2020-11-17 21:44:32 +01:00
let temp_files = [temp_path, audio_path]
deleteFiles(temp_files, (error) => {
if(error) {
console.log(`Error while deleting temporary files:`, error)
2020-11-17 21:44:32 +01:00
}
})
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}`
2020-11-17 21:44:32 +01:00
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}`)
2020-11-17 21:44:32 +01:00
}
}
} 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')
}
2020-12-21 12:52:48 +01:00
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)}`
}
2020-11-17 21:44:32 +01:00
}
2020-12-25 22:14:24 +01:00
path = `./static/pics/${dir}${filename}`
2020-11-17 21:44:32 +01:00
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}`
2020-11-17 21:44:32 +01:00
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}`)
2020-11-17 21:44:32 +01:00
}
}
} else {
console.log(`Invalid URL for downloading media: ${temp_url.hostname}.`)
resolve('')
}
})()
} else {
resolve('self')
}
})
}
}