p-julien / discord-bot

1 stars 0 forks source link

Afficher les vidéos v.redd.it #10

Closed MrCodeMUN closed 2 years ago

MrCodeMUN commented 3 years ago

Description

Faire en sorte que les vidéos hébergées sur le site v.redd.it puissent être jouées directement sur le client Discord.

Comportement actuel

Sans titre

Comportements possibles

Comportement n°1

image

MrCodeMUN commented 3 years ago

Recherches effectuées et avancement

Chaque vidéo d'un post Reddit est constitué d'un ficher audio (https://v.redd.it/{id_du_post}/DASH_audio.mp4) et d'un fichier vidéo (https://v.redd.it/{id_du_post}/DASH_{qualité_de_la_vidéo}.mp4).

Les qualités de vidéo disponibles sont : 240p, 360p, 480p et 720p. Certaines qualités (comme le 720p ou le 480p) peuvent être indisponibles. Il faut donc identifier la qualité de vidéo disponible la plus élevée avant de récupérer le fichier.

Pour cela, j'effectue une requête HTTP sur chaque qualité de vidéo. Si je reçois un code 200, le fichier existe et il est donc possible de le télécharger. Sinon, je teste une qualité de vidéo inférieure.

Méthode d'envoi n°1

Une fois le fichier vidéo et le fichier audio récupéré, j'utilise la librairie FFmpeg pour fusionner ces deux fichiers. Il ne reste plus qu'à envoyer le fichier en tant qu'attachment du message.

Méthode d'envoi n°2

Si le fichier audio n'existe pas (cela est possible sur les vidéos qui n'ont pas de son), j'envoie directement le fichier vidéo avec la qualité la plus élevée en tant qu'attachement du message (pas besoin de FFmpeg).

Le code (non commenté, sorry)

async function fetchRedditVideo(redditLink) {
    const redditPull = new RedditPull(client)
    const discordChannels = redditPull.getDiscordChannels()
    var https = require('https')
    const availableQualities = [720, 480, 360, 240]
    var highestQuality = 0

    for (let i = 0; i < availableQualities.length; i++) {
        const quality = availableQualities[i];
        https.get(`${redditLink}/DASH_${quality}.mp4`, function (res) {
            if (res.statusCode == 200) {
                highestQuality = quality
            }
        });
        if(highestQuality != 0) break
    }

    https.get(`${redditLink}/DASH_audio.mp4`, async function (res) {
        if (res.statusCode == 200) {
            let { createFFmpeg, fetchFile } = FFmpeg;
            let ffmpeg = createFFmpeg({
                log: true,
            });
            await ffmpeg.load();
            ffmpeg.FS('writeFile', 'video.mp4', await fetchFile(`${redditLink}/DASH_${highestQuality}.mp4`));
            ffmpeg.FS('writeFile', 'audio.mp4', await fetchFile(`${redditLink}/DASH_audio.mp4`));
            await ffmpeg.run('-i', 'video.mp4', '-i', 'audio.mp4', '-c', 'copy', 'output.mp4');
            let data = await ffmpeg.FS('readFile', 'output.mp4')
            data = new Uint8Array(data.buffer);
            fs.writeFile('C:\\Users\\codem\\Documents\\output.mp4', Buffer.from(data), (err) => {
                if(!err) console.log('Data written');
            });
            await discordChannels[3].send("**Test FFMPEG**", new MessageAttachment("C:\\Users\\codem\\Documents\\output.mp4"))
        } else {
            await discordChannels[3].send("**Test DASH**", new MessageAttachment(`${redditLink}/DASH_${highestQuality}.mp4`))
        }
    });
};

Limites

Il reste un problème : la limite d'envoi d'un fichier est de 8 Mo, et cette limite est assez simple à dépasser.

Solution possible n°1

Avec FFmpeg, il faudrait fusionner les deux fichiers, vérifier que la taille totale du fichier final n'est pas supérieure à 8 Mo. Sinon, il faut récupérer un fichier vidéo avec une qualité plus faible, re-fusionner les deux fichiers, et re-vérifier la taille du fichier... Ainsi de suite jusqu'à avoir un fichier avec une taille convenable (ce qui signifie une potentielle perte de qualité).

S'il n'y a pas de fichier audio, c'est simple : il suffit de regarder la taille du fichier vidéo grâce au header 'content-length'.

Problème, s'il n'y a aucune qualité de vidéo qui permet d'avoir un fichier avec une taille inférieure à 8 Mo, il est impossible d'envoyer la vidéo en attachment... Il faudra alors envoyer un lien sans aperçu, comme c'est déjà le cas aujourd'hui.

Solution possible n°2

Il existe un moyen de proposer un aperçu de n'importe quelle vidéo, quelle que soit sa taille, en tant que message sur Discord : il suffit d'héberger la vidéo en question sur YouTube et d'envoyer le lien YouTube en tant que message sur Discord. Cela nécessite un compte YouTube dédié au bot, et du temps de développement avec l'API de YouTube.

Cela permettrait de conserver la meilleure qualité de vidéo possible, en revanche le temps d'upload sur YouTube ne sera pas instantané et va donc ralentir l'envoi des posts Discord.

Solution possible n°3

La limite d'envoi de vidéos sur Discord est normalement de 100 Mo... Peut-être existe-t-il un moyen de faire sauter cette limite de 8 Mo pour les vidéos sous Discord.js ?

p-julien commented 2 years ago

@MrCodeMUN traité lors de la réécriture du bot en TypeScript, je clôture.