Inicio Informática Descargar vídeos de Youtube con esta sencilla aplicación web

Descargar vídeos de Youtube con esta sencilla aplicación web

Descarga solo vídeos que no estén afectados por licencias o derechos de autor

Publicado por entreunosyceros
Publicado el: Última actualización:

Una vez más aquí. Hoy vengo a dejar un pequeño artículo sobre una aplicación web con la que descargar vídeos de Youtube de forma rápida y sencilla. En realidad, tan solo es una forma de practicar un poco PHP, CSS y JavaScript. Evidentemente la aplicación tiene sus limitaciones, ya que la descarga de ciertos vídeos de esta plataforma es ilegal. Por este motivo, la aplicación solo va a poder descargar los vídeos que no estén sujetos a licencia alguna o a los derechos de autor.

El desarrollo de la aplicación ocupa 6 archivos, en los que se utilizan el HTML, CSS, JavaScript y PHP. Para la descarga de los vídeos se utiliza también cURL. Cuando ejecutemos la aplicación, solo tendremos que pegar la URL del vídeo que nos interese y pulsar sobre el botón buscar.

Una vez localizado el vídeo, veremos aparecer la miniatura del vídeo, junto con todas las opciones disponibles para la descarga de este desde el navegador web. Además también aparecerán dos botones. El primero de estos botones nos servirá para descargar la miniatura del vídeo (en formato jpeg) y el segundo nos llevará a ver el vídeo en cuestión en Youtube.

Aplicación web para descargar vídeos de Youtube

Además de las opciones para la descarga del vídeo, también veremos la duración de este, las visualizaciones que lleva el vídeo y un botón para dirigirnos al canal en el que se ha publicado.

cambio de color de la aplicación web

Fuera de las opciones de la descarga del vídeo, también encontraremos una paleta de colores en el lateral, la cual nos permitirá cambiar los colores según nos guste más. Y justo debajo encontraremos un botón para activar un modo oscuro.

Si utilizas esta aplicación para descargar vídeos protegidos por alguna licencia o derechos de autor, verás aparecer un mensaje como el siguiente, para indicarte que el vídeo no es descargable.

Descarga de vídeo no soportada

Descargar vídeos de Youtube

Como decía esta aplicación web se divide en ciertos archivos, que iremos viendo uno a uno en las siguientes líneas.

Archivo index.php

En la carpeta inicial, vamos a guardar el primero de estos archivos, el cual se va a llamar index.php. Dentro de este archivo guardaremos el siguiente código.

<?php

include "./scripts/GetVideoInfo.php";
$isvalid = "";
$isVideoIdValid = "";

if (isset($_POST['submit'])) {
  $video_link = $_POST['video_url'];
  if ($video_link != "") {
    $isVideoIdValid = preg_match('%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $video_link, $match);
    if ($isVideoIdValid == "1") {
      $video_id =  $match[1];

      // obtener la información del vídeo
      $video = json_decode(GetVideoInfo($video_id));
      $isvalid = $video->playabilityStatus->status;

      $formats = $video->streamingData->formats;
      $thumbnails = $video->videoDetails->thumbnail->thumbnails;
      $title = $video->videoDetails->title;
      $short_description = $video->videoDetails->shortDescription;
      $channel_id = $video->videoDetails->channelId;
      $channel_name = $video->videoDetails->author;
      $views = $video->videoDetails->viewCount;
      $video_duration_in_seconds = $video->videoDetails->lengthSeconds;
      $thumbnail = end($thumbnails)->url;

      // pasar a segundos, minutos y horas
      $hours = floor($video_duration_in_seconds / 3600);
      $minutes = floor(($video_duration_in_seconds / 60) % 60);
      $seconds = $video_duration_in_seconds % 60;
    }
  }
}

?>

<!DOCTYPE html>
<html lang="es">

<head>
  <meta charset="UTF-8" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <link href='https://unpkg.com/boxicons@2.1.1/css/boxicons.min.css' rel='stylesheet' />
  <link rel="stylesheet" href="css/style.css" />

  <!-- favicon -->
  <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
  <title>Descargador para vídeos de Youtube</title>
</head>

<body>

  <!-- Selector modo oscuro -->
  <div class="dark-mode">
    <span class="dark-mode-btn">
      <i class="bx bx-moon"></i>
    </span>
  </div>

  <!--=========== SELECTOR DE COLOR ===========-->

  <div class="color-palette">
    <span class="theme-color"></span>
    <span class="theme-color"></span>
    <span class="theme-color"></span>
    <span class="theme-color"></span>
    <span class="theme-color"></span>
    <span class="theme-color"></span>
    <span class="theme-color"></span>
    <span class="theme-color"></span>
  </div>

  <div class="downloader">
    <span id="title">
      <h1>DESCARGA DESDE <span id="youtube">YOUTUBE</span></h1>
    </span>

    <div class="main">

      <?php
      if ($isVideoIdValid == "0") { ?>
        <div class="instruction_box">
          <label><i class='bx bx-unlink'></i></label>
          <h3>La URL es inválida.</h3>
          <p>Asegurate de que la URL es válida.</p>
        </div>
      <?php } else if ($isvalid == "") { ?>
        <div class="instruction_box">
          <label><i class='bx bx-link'></i></label>
          <h3>Copia la URL del vídeo & pégala aquí.</h3>
          <p>Asegurate de que la URL es válida y no está protegida por derechos de autor.</p>
        </div>

      <?php } else if ($isvalid == "OK") { ?>

        <div class="video_detail_box">
          <div class="thumbnail_box">
            <img src="<?php echo $thumbnail; ?>" alt="thumbnail">
            <a href="./scripts/download_img.php?url=<?php echo $thumbnail; ?>&name=<?php echo $title; ?>" id="img_download_btn" title="Descargar la miniatura del vídeo"><i class='bx bxs-download'></i></a>
            <a href="<?php echo $video_link; ?>" target="_blank" id="original_video_link_btn" title="Ver en Youtube"><i class='bx bxl-youtube'></i></a>
          </div>

          <?php if (!empty($formats)) {

            if (@$formats[0]->url == "") { ?>
              <div class="instruction_box">
                <label><i class='bx bx-video-off'></i></label>
                <h3>No soportado.</h3>
                <p>Este vídeo está protegido por derechos de autor, y no se puede descargar.</p>
              </div>

            <?php } else { ?>

              <div class="text_info">
                <h4><?php echo $title; ?></h4>

                <div class="additional_info">
                  <a href="<?php echo 'https://www.youtube.com/channel/' . $channel_id ?>" target="_blank" title="Visitar el canal donde se publica el vídeo"><?php echo $channel_name ?></a>
                  <p><i class='bx bx-time-five'></i>&nbsp; <?php echo "$hours:$minutes:$seconds"; ?></p>
                  <p><i class='bx bx-show'></i>&nbsp; <?php echo $views; ?></p>
                </div>
                <table>

                  <tr>
                    <th>Calidad</th>
                    <th>Formato</th>
                    <th>Descarga</th>
                  </tr>

                  <?php foreach ($formats as $format) {

                    // obtener todos los formatos de vídeo disponibles
                    if (@$format->url == "") {
                      $signature = "https://youtube.com?" . $format->signatureCipher;
                      parse_str(parse_url($signature, PHP_URL_QUERY), $parse_signature);
                      $url = $parse_signature['url'] . "&sig=" . $parse_signature['s'];
                    } else {
                      $url = $format->url;
                    }
                  ?>

                    <tr>
                      <td> <?php if ($format->qualityLabel) echo $format->qualityLabel;
                            else echo "Desconocido"; ?>
                      </td>
                      <td><?php if ($format->mimeType) echo explode(";", explode("/", $format->mimeType)[1])[0];
                          else echo "Desconocido"; ?>
                      </td>
                      <td><a href="./scripts/download_video.php?link=<?php echo urlencode($url) ?>&title=<?php echo urlencode($title) ?>&type=<?php if ($format->mimeType) echo explode(";", explode("/", $format->mimeType)[1])[0];
                                                                                                                                              else echo "mp4"; ?>" id="download_btn"><i class='bx bxs-download'></i>&nbsp;Descargar</a></td>
                    </tr>

                  <?php } ?>

                </table>

              </div>
        </div>

    <?php }
          }
        } else { ?>
    <div class="instruction_box">
      <label><i class='bx bx-video-off'></i></label>
      <h3>No se puede obtener la información del vídeo.</h3>
      <p>Utiliza una URL válida.</p>
    </div>
  <?php } ?>
  <p>
  <form action="<?php $_SERVER['PHP_SELF'] ?>" method="POST">
    <input type="text" name="video_url" placeholder="Pega aquí la URL del vídeo..." autocomplete="off">
    <input type="submit" name="submit" value="Buscar">
  </form>
  </p>
    </div>
  </div>
  <!--=========== JS paleta colores ===========-->
  <script src="js/color_palette.js"></script>
</body>

</html>

Este archivo será el que se se ejecutará cuando iniciemos la aplicación.

Scripts PHP

Ahora vamos a crear una carpeta llamada scripts, y dentro de esta será donde guardaremos 3 archivos más. Estos serán los utilizaremos para descargar el vídeo, descargar la miniatura y para obtener la información del vídeo.

Archivo download_img

Este primer archivo será el que utilizaremos para descargar la miniatura del vídeo. Aquí será en donde indicaremos el formato de la imagen que se va a guardar en nuestro equipo. Como indica el encabezado de esta sección, este archivo se va a llamar download_img.php y lo guardaremos en la carpeta scripts. Dentro del archivo colocaremos el siguiente código.

<?php
$downloadURL = $_GET['url'];
$img_name = $_GET['name'];
$extension = "jpeg"; // extensión de la captura de pantalla
$fileName = $img_name.'.'.$extension;

if (!empty($downloadURL) && substr($downloadURL, 0, 8) === 'https://') {
    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment;filename=\"$fileName\"");
    header("Content-Transfer-Encoding: binary");

    readfile($downloadURL);
}

?>

Archivo download_video

Como en el anterior caso, este archivo se va a guardar dentro de la carpeta scripts, y se va a llamar download_video.php. Dentro solo será necesario pegar el código.

<?php
$downloadURL = urldecode($_GET['link']);
$type = urldecode($_GET['type']);
$title = urldecode($_GET['title']);
$fileName = $title.'.'.$type;


if (!empty($downloadURL) && substr($downloadURL, 0, 8) === 'https://') {
    header("Cache-Control: public");
    header("Content-Description: File Transfer");
    header("Content-Disposition: attachment;filename=\"$fileName\"");
    header("Content-Transfer-Encoding: binary");

    readfile($downloadURL);

}

?>

Archivo GetVideoinfo

Para obtener la información del vídeo que nos interese, vamos a guardar este archivo, llamado GetVideoinfo.php dentro de la carpeta scripts. Aquí será donde cURL vendrá en nuestra ayuda.

<?php

function GetVideoInfo($video_id){

    $ch = curl_init();
    
    //Configuración de las opciones para una transferencia con cUR
    curl_setopt($ch, CURLOPT_URL, 'https://www.youtube.com/youtubei/v1/player?key=AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, '{  "context": {    "client": {      "hl": "en",      "clientName": "WEB",      "clientVersion": "2.20210721.00.00",      "clientFormFactor": "UNKNOWN_FORM_FACTOR",   "clientScreen": "WATCH",      "mainAppWebInfo": {        "graftUrl": "/watch?v='.$video_id.'",           }    },    "user": {      "lockedSafetyMode": false    },    "request": {      "useSsl": true,      "internalExperimentFlags": [],      "consistencyTokenJars": []    }  },  "videoId": "'.$video_id.'",  "playbackContext": {    "contentPlaybackContext": {        "vis": 0,      "splay": false,      "autoCaptionsDefaultOn": false,      "autonavState": "STATE_NONE",      "html5Preference": "HTML5_PREF_WANTS",      "lactMilliseconds": "-1"    }  },  "racyCheckOk": false,  "contentCheckOk": false}');
    curl_setopt($ch, CURLOPT_ENCODING, 'gzip, deflate');
    
    $headers = array();
    $headers[] = 'Content-Type: application/json';
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    
    $result = curl_exec($ch);
    if (curl_errno($ch)) {
        echo 'Error:' . curl_error($ch);
    }
    curl_close($ch);
    return $result;
    
    }

?>

Archivos JavaScript

Para cambiar los colores de la aplicación, vamos a crear un archivo llamado color_palette.js, el cual vamos a guardar dentro de una carpeta llamada js que crearemos para este archivo. Dentro de este archivo, solo necesitaremos pegar el siguiente código.

//llamada a la función para obtener el tema del almacenamiento local
getTheme();

//obtener el tema del almacenamiento local
function getTheme() {
  const theme = localStorage.getItem("theme");
  if (theme) {
    changeTheme(theme);
  }
}

//guardar el tema del almacenamiento local
function saveTheme(color) {
  localStorage.setItem("theme", color);
}

//paleta de colores
const colors = [
  "hsl(245, 80%, 60%)",
  "hsl(100, 70%, 50%)",
  "hsl(200, 80%, 50%)",
  "hsl(227, 66%, 55%)",
  "hsl(26, 80%, 50%)",
  "hsl(44, 90%, 51%)",
  "hsl(280, 100%, 65%)",
  "hsl(480, 100%, 25%)",
];

const colorBtns = document.querySelectorAll(".theme-color");
const darkModeBtn = document.querySelector(".dark-mode-btn");

//cambiar a modo oscuro
var isDark = false;
darkModeBtn.addEventListener("click", () => {
  if(!isDark) {
    changeTheme("#000");
    isDark = true;
  }else{
    changeTheme(colors[3]);
    isDark = false;
  }
});

//recorre el array de colores y establece cada color en un botón
for (let i = 0; i < colorBtns.length; i++) {
  colorBtns[i].style.backgroundColor = colors[i];
}

colorBtns.forEach((btn) => {
  btn.addEventListener("click", () => {
    changeTheme(btn.style.backgroundColor);
  });
});

function changeTheme(color) {
  document.documentElement.style.setProperty("--primary-color", color);
  saveTheme(color);
}

Archivos CSS

Con todo lo anterior, ya tenemos la funcionalidad de la aplicación lista. Ahora para darle un aspecto interesante, vamos a crear una nueva carpeta llamada css. Dentro de esta carpeta, solo necesitaremos crear un archivo llamado style.css, y dentro pegar el siguiente código.

@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;800;900&display=swap");

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: "Poppins", sans-serif;
}

:root {
  --primary-color: #4193f0;
  --text-color-dark: #333;
  --text-color-light: #fff;
  --light-grey: #f5f5f5;
}

.downloader {
  height: 100vh;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  background-color: var(--primary-color);
}

.main {
  width: 426px;
  display: flex;
  flex-direction: column;
  padding: 15px;
  border-radius: 5px;
  /* background: var(--text-color-light);
    box-shadow: 0.1px 4px 8px 2px rgba(0, 0, 0, 0.05); */
  background: rgba(255, 255, 255, 0.25);
  box-shadow: 0 8px 32px 0 rgba(56, 61, 121, 0.37);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  border-radius: 10px;
  border: 1px solid rgba(6, 6, 6, 0.18);
}

.main form {
  width: 100%;
  height: 45px;
  display: flex;
  justify-content: space-between;
}

.main form input:first-child {
  width: 80%;
  height: 100%;
  padding: 10px;
  border: none;
  outline: none;
  margin-right: 4px;
  border-radius: 5px;
  font-size: 1em;
  box-shadow: 0.1px 2px 8px 4px rgba(0, 0, 0, 0.05);
}

.main form input:last-child {
  width: 20%;
  height: 100%;
  padding: 10px;
  margin-left: 4px;
  border: none;
  outline: none;
  border-radius: 5px;
  background: var(--primary-color);
  color: var(--text-color-light);
  font-size: 1em;
  cursor: pointer;
  box-shadow: 0.1px 2px 8px 4px rgba(0, 0, 0, 0.05);
}

#title > h1{
  color:#fff;
  font-family: Comic Sans, 'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif;
}

#youtube{
  color: darkred;
}

.video_detail_box {
  width: 100%;
  margin-top: 1em;
}

.video_detail_box .thumbnail_box {
  position: relative;
}

.thumbnail_box #img_download_btn {
  right: 10px;
  bottom: 10px;
  color: var(--text-color-light);
  height: 35px;
  width: 35px;
  border-radius: 50%;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--primary-color);
}

.thumbnail_box #original_video_link_btn {
  right: 55px;
  bottom: 10px;
  color: var(--text-color-light);
  height: 35px;
  width: 35px;
  border-radius: 50%;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #ec407a;
}

.thumbnail_box img {
  height: auto;
  width: 100%;
  border-radius: 5px;
  object-fit: cover;
}

.text_info {
  width: 100%;
  display: flex;
  flex-direction: column;
  margin-top: 10px;
  text-align: center;
}

.text_info table {
  border: 1px dashed #ccc;
  margin-top: 10px;
}

.text_info table th {
  padding: 10px;
}
.text_info table td {
  text-align: center;
  padding: 10px;
}

.additional_info {
  display: flex;
  align-items: center;
  margin-top: 10px;
}

.additional_info a {
  padding: 5px 10px 5px 10px;
  color: var(--text-color-light);
  font-size: 13px;
  border-radius: 5px;
  text-decoration: none;
  background: var(--primary-color);
}

.additional_info p {
  padding: 5px 10px 5px 10px;
  color: #000;
  font-size: 13px;
  border-radius: 5px;
  margin-left: 5px;
  box-shadow: 0.1px 2px 8px 4px rgba(0, 0, 0, 0.05);
}

#download_btn {
  color: var(--text-color-light);
  text-decoration: none;
  background: var(--primary-color);
  padding-left: 10px;
  padding-right: 10px;
  padding-top: 5px;
  padding-bottom: 5px;
  border-radius: 5px;
  font-size: 15px;
  display: inline-block;
}

.instruction_box {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  margin-top: 1em;
  margin-bottom: 2em;
}

.instruction_box h3 {
  margin-top: 10px;
}
.instruction_box p {
  font-size: 14px;
  margin-top: 5px;
}

.instruction_box label {
  height: 50px;
  width: 50px;
  border-radius: 50%;
  background: var(--primary-color);
  display: flex;
  align-items: center;
  justify-content: center;
}

.instruction_box label i {
  color: var(--text-color-light);
  font-size: 1.2em;
}

/* Paleta de colores */

.color-palette {
  position: absolute;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin: 12px;
  left: 0;
  background: rgba(255, 255, 255, 0.2);
  box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
  backdrop-filter: blur(1.5px);
  -webkit-backdrop-filter: blur(1.5px);
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 30px;
  padding: 8px;
  text-align: center;
  top: 50%;
  -ms-transform: translateY(-50%);
  transform: translateY(-50%);
}

.color-palette .theme-color {
  background-color: red;
  border-radius: 50%;
  width: 30px;
  height: 30px;
  cursor: pointer;
}

.color-palette .theme-color:not(:last-child) {
  margin-bottom: 10px;
}

/* Paleta de modo oscuro */

.dark-mode {
  position: absolute;
  bottom: 15px;
  left: 15px;
  background: rgba(255, 255, 255, 0.25);
  box-shadow: 0 8px 32px 0 rgba(34, 41, 126, 0.37);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(4px);
  border-radius: 50%;
  padding: 8px 13px;
  border: 1px solid rgba(255, 255, 255, 0.18);
}

.dark-mode span {
  font-size: 20px;
  cursor: pointer;
}

/*mediaquerys movil*/

@media (max-width: 800px) {
  .main {
    width: 70%;
  }
}

@media (max-width: 500px) {
  .main {
    width: 80%;
  }
}

@media (max-width: 400px) {
  .text_info table tbody tr th {
    font-size: 14px;
  }

  #download_btn {
    font-size: 8px;
  }
}

/* Media Queries */
@media only screen and (max-width: 436px) {
  .color-palette {
    max-width: 90%;
    min-width: 90%;
  }

  .color-palette .theme-color {
    width: 22px;
    height: 22px;
  }
}

@media only screen and (max-width: 636px) {
  .color-palette {
    flex-direction: row;
    justify-content: center;
    left: 50%;
    bottom: 0;
    padding: 0;
    margin: 0 auto;
    width: 400px;
    margin-bottom: 16px;
    text-align: center;
    /*to remove*/
    top: auto;
    transform: translateX(-50%);
  }

  .color-palette .theme-color {
    margin-top: 10px;
  }

  .color-palette .theme-color:not(:last-child) {
    margin-right: 10px;
  }
}

Y con esto ya tenemos nuestra aplicación web para descargar vídeos de Youtube lista para funcionar. Si quieres probar la aplicación antes de utilizarla en tu equipo, puedes verla funcionado aquí.

También te puede interesar ...

Deja un comentario

* Al utilizar este formulario, aceptas que este sitio web almacene y maneje tus datos.

Adblock Detectado!!

Ayúdanos deshabilitando la extensión AdBlocker de tu navegador para visitar esta web.
Si no sabes hacerlo en Chrome, consulta el siguiente enlace. Si utilizas Firefox, puedes consultar este otro enlace.
Esto mejorará tu experiencia en este sitio web.