Скрипты Google: у приложения Urlfetchapp с API Youtube возникли проблемы с загрузкой видео с разными владельцами в общую папку на диске. Обработка заброшена

В настоящее время я пытаюсь автоматизировать загрузку видео из папки общего диска на Youtube, используя следующий код из этого поста SO:

function upload() {
  var driveurl = `https://drive.google.com/file/d/AAAAAAAAAAAAAAAAAAAAAAAAA/view?usp=share_link`
  var match = driveurl.match(/([a-z0-9_-]{25,})[$/&?]/i).pop();
  var url = `https://www.googleapis.com/drive/v3/files/`+match+`?alt=media`; 
  var title = "title";
  var description = "test";
  var topics = "TEST";
  var blob,mp4_fileId,part,requestResource,response;
  var options = {},snippet = {};

  /*
    You will need to create a GCP standard project and associate it with this Apps Script project-
    In the new code editor click the settings cog wheel and scroll down to:
    Google Cloud Platform (GCP) Project -
    You may get an error:
    In order to change your project, you will need to configure the OAuth consent screen. Configure your OAuth Consent details.
    
    And if you do not have a Google Workspace account then you wont be able to set up the GCP project as "INTERNAL"
    You will need to enable the Google Drive API and the YouTube API in the associated GCP project -
  */

  /*
    This code needs the file ID of the MP4 file in your Google Drive - 
    To get the file ID of an MP4 video file in Google Drive, right click the MP4 in your Google Drive
    and choose, "Get link"
    The link will look like this:
    https://drive.google.com/file/d/FILE_ID_IS_HERE/view?usp=sharing
    In the URL is the file ID
  */

  options = {
    "method" : "get",
    "headers" : {"Authorization": "Bearer " + ScriptApp.getOAuthToken()},
    "muteHttpExceptions":true
  }
  var video = UrlFetchApp.fetch(url,options);
 response = YouTube.Videos.insert({
            snippet:{
                title: title,
                description: description,
                tags: topics
            },
            status:{
              privacyStatus: "public",
            },
       },
       "snippet,status",
       video
   );
   Logger.log(JSON.stringify(response));    
Logger.log(response.id)
}

Код отлично работает, когда я являюсь владельцем файла. Однако, когда я пытаюсь получить файл от другого пользователя в той же папке, код больше не работает. Он пытается отправить видео на YouTube, но приводит к ошибке «Обработка прекращена», видимой на моем канале YouTube. Если я копирую файл и становлюсь владельцем копии, он работает нормально, так что это не что-то особенное с конкретным видео.

Я думал попробовать что-то вроде этого Функция Drive.File.get(ID) не выдает правильный тип объекта, т.е. это должен быть большой двоичный объект, но я не могу понять, как его туда доставить. DriveApp.getFileById(match).getBlob() - это моя мысль, но мне нужно подождать до завтра, чтобы протестировать из-за того, что сегодня я достиг предела загрузки для YouTube, и я не оптимистичен в отношении предоставленной ссылки.

Кажется, есть какая-то ошибка, связанная с разрешениями, но я не совсем уверен, как ее исправить. Мы будем очень признательны за любые мысли.

Во-первых, я прошу прощения, что мой ответ не был полезен для вашей ситуации. И я должен извиниться за мое плохое знание английского языка. К сожалению, я не могу понять вашу текущую ситуацию из However, when I try and grab a file from another user in the same folder, the code no longer works.. Могу я спросить вас о деталях этого? Во-первых, я хотел бы попытаться правильно понять ваш вопрос. Прошу прощения за это.

Tanaike 20.01.2023 01:37

@Tanaike извините за непонятный язык. Код больше не работает означает, что если файл принадлежит другому пользователю, YouTube выдает ошибку «Обработка брошена». Я успешно смог преодолеть это, заменив ``` var video = UrlFetchApp.fetch(url, options)``` на DriveApp.getFileById(match).getBlob(). Я отвечу на свой вопрос, как только пройдет нужное время, чтобы SO разрешил мне. С другой стороны, теперь я узнал, что у YouTube.Videos.insert есть ограничение на загрузку в 50 МБ, которое мне нужно выяснить, как обойти. Угу, но спасибо за комментарий

Andrewncf 20.01.2023 17:24

Спасибо за ответ. Могу я спросить вас о размере файла, который вы хотите загрузить?

Tanaike 21.01.2023 01:13

Размер файла, по-видимому, имеет ограничение более 0,05 ГБ или 50 МБ для метода DriveApp.getFileById(match).getBlob(). Метод video = UrlFetchApp.fetch(url,options) не имеет этого ограничения. Я общался со службой поддержки GAS, и они указали на проблему, связанную с типом BLOB-объекта для объекта, и это вызывало ошибку размера файла. Не совсем уверен, как решить эту проблему, поскольку для Youtube.video.insert требуется тип большого двоичного объекта, если он загружается через Driveapp. И спасибо за ответ. Здесь всегда приятно общаться с людьми

Andrewncf 21.01.2023 02:22

Спасибо за ответ. Я должен извиниться за мое плохое знание английского языка. Про ограничение в 50 мб я так понял. Итак, я спросил ожидаемый размер файла, который вы хотите загрузить. Прошу прощения за это.

Tanaike 21.01.2023 02:24

О, это моя вина, у нас есть файлы размером не более 100 МБ. Итак, <100 МБ для размера файла. Вот почему это расстраивает! Они едва превышают лимит!

Andrewncf 21.01.2023 02:40

Спасибо за ответ. Из вашего ответа я понял, что размер вашего файла меньше 100 МБ. Из этой ситуации я предложил ответ. Пожалуйста, подтвердите это.

Tanaike 21.01.2023 06:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
7
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Изменение кода: var video = UrlFetchApp.fetch(url,options); к: var video = DriveApp.getFileById(match).getBlob() решает проблему полностью. Однако я узнал, что при использовании этого процесса существует ограничение на загрузку файла размером 50 МБ, что кажется небольшим для видео. Однако, если кто-то пытается загрузить видео меньшего размера на свой канал. Я очистил код, и это работает хорошо

function upload4() {
  var driveurl = `https://drive.google.com/file/d/AAAAAAAAAAAAAAAAAAAAAAAAA?usp=share_link`
  var match = driveurl.match(/([a-z0-9_-]{25,})[$/&?]/i).pop();
  var title = "title";
  var description = "test";
  var topics = "TEST";
  var video = DriveApp.getFileById(match).getBlob();
  var response = YouTube.Videos.insert({
            snippet:{
                title: title,
                description: description,
                tags: topics
            },
            status:{
              privacyStatus: "private",
            },
       },
       "snippet,status",
       video
   );
   Logger.log(JSON.stringify(response));    
Logger.log(response.id)
}

Ответ принят как подходящий

Я считаю, что ваша цель заключается в следующем.

Из вашего следующего ответа,

у нас есть файлы размером не более 100 МБ. Итак, <100 МБ для размера файла.

Я понял, что размер файлов, которые вы хотите загрузить, меньше 100 МБ.

В этом случае требуется загрузить его на YouTube с возобновляемой загрузкой. В этом случае я уже разместил его в своем блоге. Ссылка Автор: я Но, когда я искал его в Stackoverflow, я не мог его найти. Итак, здесь я хотел бы опубликовать это как ответ.

Образец сценария.

В этом примере скрипта используются Drive API и YouTube API. Итак, включите их в расширенных сервисах Google. Скопируйте и вставьте следующий образец сценария в редактор сценариев Google Apps Script.

В вашем сценарии показа в вашем вопросе я думаю, что match - это идентификатор файла.

function myFunction() {
  // Please set the file ID of video file and the metadata for uploading it to YouTube.
  const fileId = "###";
  const metadata = {
    snippet: { description: "Upload sample.", title: "Sample uploaded video." },
    status: { privacyStatus: "private" },
  };

  // 1. Retrieve location.
  const headers = { authorization: "Bearer " + ScriptApp.getOAuthToken() };
  const url1 = encodeURI(
    "https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status"
  );
  const res1 = UrlFetchApp.fetch(url1, {
    headers,
    payload: JSON.stringify(metadata),
    contentType: "application/json",
    muteHttpExceptions: true,
  });
  if (res1.getResponseCode() != 200) {
    console.info(res1.getContentText());
    return;
  }
  const location = res1.getAllHeaders()["Location"];
  console.info("Got Location.");

  // 2. Calculate chunks.
  const chunkSize = 20971520; // 20 MB
  const { fileSize } = Drive.Files.get(fileId, {
    supportsAllDrives: true,
    fields: "fileSize",
  });
  const chunks = [...Array(Math.ceil(fileSize / chunkSize))].map((_, i, a) => [
    i * chunkSize,
    i == a.length - 1 ? fileSize - 1 : (i + 1) * chunkSize - 1,
  ]);
  console.info("Calculated chunk data.");

  // 3. Retrieve chunks from Google Drive with the partial download and uploading chunks to YouTube with the resumable upload.
  const url2 = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media&supportsAllDrives=true`;
  let res2;
  const len = chunks.length;
  let responseObject;
  chunks.forEach((e, i) => {
    console.info(`Now... ${i + 1}/${len}`);
    const params2 = {
      headers: {
        authorization: headers.authorization,
        range: `bytes=${e[0]}-${e[1]}`,
      },
    };
    res2 = UrlFetchApp.fetch(url2, params2).getContent();
    const params3 = {
      headers: { "Content-Range": `bytes ${e[0]}-${e[1]}/${fileSize}` },
      payload: res2,
      muteHttpExceptions: true,
    };
    console.info("Downloaded a chunk, and upload a chunk.");
    const res3 = UrlFetchApp.fetch(location, params3);
    const statusCode = res3.getResponseCode();
    if (statusCode == 200) {
      console.info("Done.");
      // console.info(res3.getContentText());
      responseObject = JSON.parse(res3.getContentText());
    } else if (statusCode == 308) {
      console.info("Upload the next chunk.");
      res2.splice(0, res2.length);
    } else {
      throw new Error(res3.getContentText());
    }
  });
  // console.info(responseObject); // Here, you can retrieve the response object.
  console.info(responseObject.id); // Here, you can retrieve the video ID.

  // Please don't remove the following comment line. This comment line is important for running this script.
  // YouTube.Videos.insert(); // This is used for automatically detecting the scope of "https://www.googleapis.com/auth/youtube" with the script editor.
}

Тестирование:

Когда этот скрипт запускается, вы можете увидеть следующий процесс в журнале.

Got Location.
Calculated chunk data.
Now... 1/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 2/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 3/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 4/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 5/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 6/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 7/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 8/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 9/10
Downloaded a chunk, and upload a chunk.
Upload the next chunk.
Now... 10/10
Downloaded a chunk, and upload a chunk.
Done.
{
  "kind": "youtube#video",
  "etag": "###",
  "id": "###",
  "snippet": {,,,},
  "status": {,,,}
}

ВАЖНЫЙ

  • В этом образце сценария размер фрагмента составляет 20 МБ. Вы можете изменить это. Но когда этот размер велик, может возникнуть ошибка. Пожалуйста, будьте осторожны с этим.
  • Если у вас нет канала YouTube, вы не можете загрузить видеофайл.
  • Если ваша учетная запись не подтверждена Google, видеоданные продолжительностью более 15 минут не могут быть загружены. Пожалуйста, будьте осторожны с этим.
  • На текущем этапе максимальное время выполнения скрипта Google Apps составляет 6 минут. Таким образом, если вы хотите загрузить большие видеоданные, данные могут быть не загружены полностью из-за максимального времени выполнения. Пожалуйста, будьте осторожны с этим.
    • Если вы хотите загрузить видеоданные большего размера, я думаю, вы можете добиться этого, выполнив скрипт с управляемым временем триггером. Но, в этом случае, требуется модифицировать приведенный выше скрипт. Пожалуйста, будьте осторожны с этим. В этом посте представлен простой пример сценария.
    • Я подтвердил, что при тестировании 100 МБ ошибок не возникает. Итак, что касается вашей ситуации, я подумал, что этот скрипт можно использовать.

Рекомендации

Это сработало потрясающе. Жаль, что я не нашел ваш пост в блоге, когда я работал над этим раньше. Спасибо за успешный ответ, он будет отмечен. Задам еще один вопрос. Мне интересно, можно ли вернуть id видео после завершения процесса? В исходном коде это было легко сделать с помощью var response = YouTube.Videos.insert, за которым следовал response.id, но в этом случае функция video.insert находится внутри комментария и больше не является объектом. Я вижу идентификатор в журнале выполнения, но не знаю, как его получить.

Andrewncf 21.01.2023 07:09

@Andrewncf Спасибо за ответ. Я рад, что ваша проблема была решена. Что касается вашего дополнительного вопроса I am wondering if it is possible to return the id of the video after the process is complete?, я обновил свой ответ. Пожалуйста, подтвердите это.

Tanaike 21.01.2023 07:18

Извините за задержку с принятием ответа, я исчерпал свою квоту API Youtube и не мог протестировать до сих пор. Для приложения, которое я использую, [требуется оператор возврата] (support.google.com/appsheet/answer/12309564?hl=en). Я пытался использовать простое return console.info(responseObject.id);, но не повезло. То же самое с var outputID = console.info(responseObject.id); return outputID Есть мысли? Прошу прощения, так как я привык к более декларативным форматам, поэтому я не уверен, что есть лучший способ? В любом случае, спасибо за первоначальную помощь. Это было потрясающе!!!!!!

Andrewncf 21.01.2023 17:03

@Andrewncf Спасибо за ответ. Я рад, что ваша проблема была решена. Насчет I tried to simple use return console.info(responseObject.id); but no luck there., к сожалению, когда я тестировал свой скрипт, метаданные загруженного видео и идентификатор видео можно увидеть в console.info(responseObject) и console.info(responseObject.id). Прошу прощения за это. Я думаю, что это связано с моим плохим мастерством. Прошу прощения за это. Но, я хотел бы поддержать вас. Итак, я хотел бы попытаться правильно воспроизвести вашу ситуацию. Когда я смогу правильно воспроизвести это, я хотел бы придумать решение.

Tanaike 22.01.2023 01:24

@Andrewncf Я снова должен извиниться за свои плохие навыки. Хотя я несколько раз проверял свой скрипт prosoed, я могу подтвердить возвращенные метаданные и идентификатор видео. К сожалению, я не могу повторить I tried to simple use return console.info(responseObject.id); but no luck there.. Я еще раз глубоко извиняюсь за свое слабое мастерство. Но, я хотел бы поддержать вас. Итак, я хотел бы попробовать правильно воспроизвести I tried to simple use return console.info(responseObject.id); but no luck there..

Tanaike 22.01.2023 02:47

@Andrewncf Спасибо за ответ. Я рад, что ваша проблема была решена. Что касается вашего нового вопроса I would like to assign the id to a constant (or object) to build the url youtube.com/embed{ID} so that the external application can use the youtube video that was uploaded. return responseObject.id.toString(), я хотел бы вас поддержать. Но, я должен извиниться за мое плохое знание английского языка. К сожалению, я не могу понять ваш новый вопрос. А также, я не могу понять, был ли решен ваш 2-й вопрос. Я думаю, что это связано с моим очень плохим знанием английского языка. Прошу прощения за это.

Tanaike 23.01.2023 00:31

@Andrewncf Я глубоко извиняюсь, что не могу решить ваши различные вопросы в ближайшее время. Я думаю, что мне нужно больше заниматься английским языком.

Tanaike 23.01.2023 00:32

Извините, я попытаюсь объяснить в последний раз, и если это не ясно, это нормально. Вы так помогли, и я хотел бы выразить свою признательность. Обычно мое приложение вызывает функцию следующим образом: function add(a){ var answer = a+2 return answer } Когда веб-сайт вызывает скрипт со значением a=2, он возвращает пользователя с ответом 4. Я просто не уверен, как это работает с console.info(responseObject.id) Вот почему я пытался return console.info(responseObject.id), но внешний приложение не получило возвращаемое значение.

Andrewncf 23.01.2023 00:47

Я более чем счастлив принять ваш ответ и продолжать попытки самостоятельно. Вы действительно очень помогли мне, и я так благодарен. Ваш английский был действительно хорош в общении, я очень ценю вас здесь

Andrewncf 23.01.2023 00:47

@Andrewncf Спасибо за ответ. Я хотел бы поддержать вас. Но, я должен извиниться за мое плохое знание английского, снова. К сожалению, я все еще не могу понять ваш новый вопрос. Я беспокоюсь, что могу побеспокоить вас, потому что я не могу решить ваши различные вопросы в ближайшее время. Итак, в этом случае я хотел бы порекомендовать опубликовать его как новый вопрос. Таким образом, это поможет многим пользователям найти решение. Если вы можете сотрудничать, чтобы решить ваш новый вопрос, я был бы рад. Можете ли вы сотрудничать, чтобы сделать это?

Tanaike 23.01.2023 00:50

@Andrewncf Спасибо за ответ. Когда вы разместили его как новый вопрос, я хотел бы попытаться понять его снова.

Tanaike 23.01.2023 00:52

На самом деле я смог решить свою проблему, написав отдельную функцию, которая находит идентификатор самого нового видео на моем канале и возвращает этот идентификатор обратно в исходное приложение. Вы проделали всю тяжелую работу, и еще раз спасибо за то, что так много мне помогли. Это то, что я использовал для получения идентификатора, средний вариант получения загрузок

Andrewncf 23.01.2023 19:14

@Andrewncf Спасибо за ответ. Я рад, что ваш новый вопрос был решен.

Tanaike 24.01.2023 01:51

Другие вопросы по теме