From a3e24dd68adfa73d246c7268a46d630fcf7fbd64 Mon Sep 17 00:00:00 2001
From: loicbersier <loic.bersier1@gmail.com>
Date: Mon, 31 Aug 2020 03:13:33 +0200
Subject: [PATCH] Added SponsorBlock!

---
 README.md                                  |  5 +-
 app/Controllers/Http/DownloadController.js | 81 ++++++++++++++++++++--
 resources/views/index.edge                 |  7 ++
 3 files changed, 87 insertions(+), 6 deletions(-)

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 @@
                                         <input class="checkbox" type="checkbox" name="feed" id="feed" title="Use this if you don't want the video you are downloading to be public">
                                         {{ antl.formatMessage('messages.feed') }}
                                     </label>
+
+                                    <label class="checkbox" for="sponsorBlock">
+                                        <input class="checkbox" type="checkbox" name="sponsorBlock" id="sponsorBlock" title="(Using sponsor.ajay.app)">
+                                        (W.I.P) Remove sponsors of video using <a href="https://sponsor.ajay.app/">SponsorBlock</a>
+                                    </label>
+
                                 </div>
                             </div>
                         </div>
@@ -213,6 +219,7 @@
     </section>
     @endif
     <footer class="footer has-background-grey-dark has-text-light has-text-centered">
+        <p>Uses SponsorBlock API from <a href="https://sponsor.ajay.app/">https://sponsor.ajay.app/</a></p>
         <p>{{ antl.formatMessage('messages.footer') }}</p>
         @if(antl._locale == 'ar')
         <bdi><p>{{ antl.formatMessage('messages.footer2p1') }} <a href="https://github.com/rg3/youtube-dl/">youtube-dl</a> - {{ antl.formatMessage('messages.footer2p2') }} <a href="https://discordapp.com/oauth2/authorize?client_id=377563711927484418&scope=bot&permissions=0">Haha yes</a> & <a href="https://twitter.com/ExplosmR">ExplosmRCG twitter bot</a> - {{ antl.formatMessage('messages.footer2p3') }}: {{ viewCounter }} - {{ antl.formatMessage('messages.footer2p4') }} <a href="https://discord.gg/cNRh5JQ">Supositware#1616</a> {{ antl.formatMessage('messages.footer2p5') }} </bdi></p>