diff --git a/README.md b/README.md index 3be1f38..89ff1ba 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,9 @@ Jeff downloader is a website to download from [hundreds](https://ytdl-org.github You can find a hosted version on https://namejeff.xyz/ # Credit + +SponsorBlock data is used under [CC BY-NC-SA 4.0](https://creativecommons.org/licenses/by-nc-sa/4.0/). More details: https://sponsor.ajay.app/ + [Youtube-dl](https://github.com/ytdl-org/youtube-dl/) Major Tom#6196 for AR translation @@ -13,4 +16,4 @@ Major Tom#6196 for AR translation Mastah Gengu#1596 for DE translation -МeiYali#2457 for CS translation \ No newline at end of file +МeiYali#2457 for CS translation diff --git a/app/Controllers/Http/DownloadController.js b/app/Controllers/Http/DownloadController.js index 2da8355..404a543 100644 --- a/app/Controllers/Http/DownloadController.js +++ b/app/Controllers/Http/DownloadController.js @@ -5,7 +5,8 @@ const path = require('path'); const ffmpeg = require('fluent-ffmpeg'); const { version } = require('../../../package.json'); const Antl = use('Antl'); -const proxy = require('../../../proxy/proxy.json') +const proxy = require('../../../proxy/proxy.json'); +const fetch = require('node-fetch'); let viewCounter = 0; let files = []; @@ -104,7 +105,8 @@ class DownloadController { format: request.input('format'), alt: request.input('alt'), feed: request.input('feed'), - proxy: request.input('proxy') + proxy: request.input('proxy'), + sponsorBlock : request.input('sponsorBlock') } if (!data.url) { @@ -114,6 +116,19 @@ class DownloadController { return view.render(page, viewOption); } + let videoID; + if (data.sponsorBlock) { + let regExp = /^.*((youtu.be\/)|(v\/)|(\/u\/\w\/)|(embed\/)|(watch\?))\??v?=?([^#&?]*).*/; + let match = data.url.match(regExp); + videoID = (match&&match[7].length==11)? match[7] : false; + if (!videoID) { + let viewOption = {...defaultViewOption}; + viewOption.error = true; + viewOption.errormsg = 'To use sponsorBlock you need a valid youtube link!'; + return view.render(page, viewOption); + } + } + // Youtube-dl quality settings if (data.quality == 'small') option = 'worst' @@ -177,6 +192,7 @@ class DownloadController { let title = info.title.slice(0,50); DLFile = `${title.replace(/\s/g, '')}.${ext}`; DLFile = DLFile.replace(/[()]|[/]|[\\]|[!]|[?]/g, ''); + DLFile = DLFile.replace(',', ''); // If no title use the ID if (title == '_') title = `_${info.id}`; @@ -189,9 +205,64 @@ class DownloadController { video.on('end', function() { if (data.format == 'mp4' || data.format == 'webm') { - // If user requested mp4 directly attach the file - generateThumbnail(DLFile); - return response.attachment(`./public/uploads/${DLFile}`) + if (data.sponsorBlock) { // WARNING: THIS PART SUCK + let filter = ''; + let abc = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z']; + fetch(`https://sponsor.ajay.app/api/skipSegments?videoID=${videoID}`) + .then(res => res.json()) + .then(json => { + let i = 0; + let previousEnd; + let usedLetter = []; + + json.forEach(sponsor => { + usedLetter.push(abc[i]); + if (i === 0) { + filter += `[0:v]trim=start=0:end=${sponsor.segment[0]},setpts=PTS-STARTPTS[${abc[i]}v];`; + filter += `[0:a]atrim=start=0:end=${sponsor.segment[0]},asetpts=PTS-STARTPTS[${abc[i]}a];`; + } else { + filter += `[0:v]trim=start=${previousEnd}:end=${sponsor.segment[0]},setpts=PTS-STARTPTS[${abc[i]}v];`; + filter += `[0:a]atrim=start=${previousEnd}:end=${sponsor.segment[0]},asetpts=PTS-STARTPTS[${abc[i]}a];`; + } + previousEnd = sponsor.segment[1]; + i++; + }); + usedLetter.push(abc[i]); + filter += `[0:v]trim=start=${previousEnd},setpts=PTS-STARTPTS[${abc[i]}v];`; + filter += `[0:a]atrim=start=${previousEnd},asetpts=PTS-STARTPTS[${abc[i]}a];`; + let video = ''; + let audio = ''; + usedLetter.forEach(letter => { + video += `[${letter}v]` + audio += `[${letter}a]` + }); + filter += `${video}concat=n=${i + 1}[outv];`; + filter += `${audio}concat=n=${i + 1}:v=0:a=1[outa]`; + + ffmpeg(`./public/uploads/${DLFile}`) + .inputFormat('mp4') + .complexFilter(filter) + .outputOptions('-map [outv]') + .outputOptions('-map [outa]') + .save(`./public/uploads/hidden/nosponsor${DLFile}`) + .on('error', function(err, stdout, stderr) { + console.log(stdout); + console.log(stderr); + console.log('Cannot process video: ' + err.message); + return; + }) + .on('end', () => { + console.log('end'); + fs.renameSync(`./public/uploads/hidden/nosponsor${DLFile}`, `./public/uploads/${DLFile}`) + response.attachment(`./public/uploads/${DLFile}`) + generateThumbnail(DLFile); + }); + }); + } else { + // If user requested mp4 directly attach the file + response.attachment(`./public/uploads/${DLFile}`) + generateThumbnail(DLFile); + } } else { // If user requested an audio format, convert it ffmpeg(`./public/uploads/${DLFile}`) diff --git a/resources/views/index.edge b/resources/views/index.edge index b6c6c73..3963d86 100644 --- a/resources/views/index.edge +++ b/resources/views/index.edge @@ -83,6 +83,12 @@ {{ antl.formatMessage('messages.feed') }} + + + @@ -213,6 +219,7 @@ @endif