はじめに
まず、私がやろうとしていることの目標を紹介しましょう。
以前にファイルを2つの部分に分割していた
これらのファイルの両方のサイズを合わせて、50 MBを超える可能性があります(長期的な目標として)。 UrlFetchApp.fetch()
にはリクエストのサイズに関する制限があるため、個別にアップロードします。各ファイルは50 MB未満であり、結果としてそれらをマージします。今のところ(Drive APIを試すため)、小さなファイルを使用しています。
最初のファイルは _ _640000 bytes
_(_256
_の倍数)524288 bytes
_。私は以前に間違いを犯したことに気づきました。つまり、ファイルのサイズを256の倍数として使用していましたが、_256*1024
_の倍数である必要があります
2番目のファイルは _ _47626 bytes
_163339 bytes
_。
curl
を使用してファイルを分割し、ドライブにアップロードしました(通常のWebアップロード)。
_partial files
_から_Resumable Upload
_を使用して、_Google Drive API
_を使用して_Google Apps Script
_を1つずつGoogleドライブにアップロードし、それらが1つのファイルにマージされるようにする予定です。
これまでに試したことはありますか?
resumable upload
_を使用して_Drive.Files.insert
_を実行しようとしましたが、ユーザーは、以下に引用されている_Drive.Files.insert
_を使用してそれを実行することはできないと指摘しました。残念ながら、現在の段階では、再開可能なアップロードはDrive.Files.insertを使用して実行できません。これはGoogle側の現在の仕様のようです
Google Drive API
_を使用することです。以下にコードが含まれています。_function myFunction() {
var token = ScriptApp.getOAuthToken();
var f1_id = '1HkBDHV1oXXXXXXXXXXXXXXXXXXXXXXXX';
var f2_id = '1twuaKTCFTXXXXXXXXXXXXXXXXXXXX';
var putUrl = 'https://www.googleapis.com/drive/v3/files?uploadType=resumable';
var fileData = {
name : 'Merged-file-from-GAS',
file : DriveApp.getFileById(f1_id).getBlob()
}
var options = {
method : 'put',
contentType:"application/json",
headers : {
Authorization: 'Bearer ' + token,
'X-Upload-Content-Type' : 'application/octet-stream',
'Content-Type' : 'application/json; charset=UTF-8'
},
muteHttpExceptions: true,
payload : fileData
};
var response = UrlFetchApp.fetch(putUrl, options);
Logger.log(response.getResponseCode());
Logger.log(response.getAllHeaders());
}
_
また、メソッドをpatch
に変更してみました
headers
内に_Content-Length : 640000
_を追加しました。その場合、以下のようにエラーが表示されます。
例外:無効な値が指定された属性:Header:Content-Length
resource
を使用してDrive.Files.insert(resource)
でファイルを作成しようとしました。次に、変数_var patchUrl = 'https://www.googleapis.com/upload/drive/v3/files/' + fileId + '?uploadType=resumable';
_を保持しながら、UrlFetchApp(patchUrl,options)
を使用して更新しようとしました結果
[20-05-12 21:05:37:726 IST] 404.0
[20-05-12 21:05:37:736 IST] {X-Frame-Options = SAMEORIGIN、Content-Security-Policy = frame-ancestors 'self'、Transfer-Encoding = chunked、alt-svc = h3-27 = ":443"; ma = 2592000、h3-25 = ":443"; ma = 2592000、h3-Q050 = ":443"; ma = 2592000、h3-Q049 = ":443"; ma = 2592000、h3-Q048 = ":443"; ma = 2592000、h3-Q046 = ":443"; ma = 2592000、h3-Q043 = ":443"; ma = 2592000、quic = ":443"; ma = 2592000; v = "46,43"、X-Content-Type-Options = nosniff、Date = Tue、12 May 2020 15:35:37 GMT、Expires = Mon、01 Jan 1990 00:00:00 GMT、X-XSS-保護= 1; mode = block、Content-Encoding = gzip、Pragma = no-cache、Cache-Control = no-cache、no-store、max-age = 0、must-revalidate、Vary = [Origin、X-Origin]、Server = GSE、Content-Type = text/html; charset = UTF-8}
質問
_initiating a upload
_をresumable
のままにしながら、Apps ScriptからDrive APIを使用してドライブからドライブにファイルを_upload type
_する適切な方法は何ですか?
後続のリクエストはどのようにすべきですか?そのため、50 MBを超えるファイルは、その後、マージされたファイルにアップロードできますか?
編集1
修正されたファイルチャンクサイズを使用してもう一度試してみました。同じ問題が続く。
編集2
回答のコードを理解するために、Tanaikeのコードの_// 2
_のコードだけを使用して、Location
が取得される方法を理解しました。
_function understanding() {
var token = ScriptApp.getOAuthToken();
const filename = 'understanding.pdf';
const mimeType = MimeType.PDF;
const url = 'https://www.googleapis.com/drive/v3/files?uploadType=resumable';
const res1 = UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify({name: filename, mimeType: mimeType}),
headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
}});
const location = res1.getHeaders().Location;
Logger.log(location);
}
_
これにより、サイズ_understanding.pdf
_のファイル_0 bytes
_が作成されます。ただし、Logger.log(location)
はnull
をログに記録します。
なぜそうなのですか?
間違いは終点にありました。 _https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable
_に設定すると機能します。場所を取得します。
質問と回答から、以下のような状況と目標を理解できました。
このため、この答えはどうですか?
残念ながら、再開可能なアップロードを実現するためのスクリプトは不完全です。 Google Drive APIでの再開可能なアップロードの流れは以下の通りです。 参照
以上の流れで、サンプルスクリプトを用意すると以下のようになります。
この場合、ドライブAPIが使用されます。高度なGoogleサービスでDrive APIを有効にしてください。これにより、APIコンソールでDrive APIが自動的に有効になります。
サンプルスクリプトの流れは以下の通りです。
次のスクリプトをコピーして貼り付けてください。そして、ファイルIDを設定してください。この場合、マージするために設定してください。これにご注意ください。
function myFunction() {
const fileIds = ["###", "###"]; // Please set the file IDs of the file "A" and "B" in order.
const filename = "sample.pdf";
const mimeType = MimeType.PDF;
// 1. Create an object for using at the resumable upload.
const unitSize = 262144;
const fileObj = fileIds.reduce((o, id, i, a) => {
const file = DriveApp.getFileById(id);
const size = file.getSize();
if (i != a.length - 1 && (size % unitSize != 0 || size > 52428800)) {
throw new Error("Size of each file is required to be the multiples of 262,144 bytes and less than 52,428,800 bytes.");
}
o.files.Push({data: file.getBlob().getBytes(), range: `bytes ${o.size}-${o.size + size - 1}\/`, size: size.toString()});
o.size += size;
return o;
}, {size: 0, files: []});
// 2. Retrieve "location" for starting the resumable upload.
const url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
const res1 = UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify({name: filename, mimeType: mimeType}),
headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
}});
const location = res1.getHeaders().Location;
// 3. Upload each file and merge them.
fileObj.files.forEach((e, i) => {
const params = {
method: "put",
headers: {"Content-Range": e.range + fileObj.size},
payload: e.data,
muteHttpExceptions: true,
};
const res = UrlFetchApp.fetch(location, params);
const status = res.getResponseCode();
if (status != 308 && status != 200) {
throw new Error(res.getContentText());
}
if (status == 200) {
console.log(res.getContentText())
}
});
// DriveApp.createFile() // This comment line is used for automatically detecting the scope of "https://www.googleapis.com/auth/drive" by the script editor. So please don't remove this line.
}
再開可能なアップロードが完了すると、ログに次の結果が表示されます。そして、ルートフォルダでマージされたファイルを見ることができます。
{
"kind": "drive#file",
"id": "###",
"name": "sample.pdf",
"mimeType": "application/pdf"
}
田池の答えは完璧ではありません。エレガントで、array.reduce
関数について学ぶのにも役立ちました。この質問をする前は、JavaScriptに関する知識はほとんどなく、Google Drive API
の使用に関する知識はほとんどありませんでした。
私の意図は、resumable upload
のプロセス全体を言語としてGoogle Apps Script
を使用して段階的に学習することでした。 Tanaikeのコードを参照として使用生産性が高く、扱いやすく、洗練されている代わりに、(少なくとも)resumable upload
が段階的にどのように機能するかを理解できるスクリプトを作成しました。私はループもオブジェクトも配列も使用していません。
ステップ1(必要な変数を宣言する)
var fileId1 = "XXXXXXXXXXX"; //id of the first file
var fileId2 = "YYYYYYYYYYY"; //id of the second file
var filename = "merged.pdf"; //name of the final merged file
var mimeType = MimeType.PDF; //Mime type of the merged file
ステップ2(再開可能なアップロードを開始する)
//declare the end point
const url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable";
//Send the request
//Method to be used is Post during initiation
//No file is to be sent during initiation
//The file name and the mime type are sent
const res1 = UrlFetchApp.fetch(url, {
method: "post",
contentType: "application/json",
payload: JSON.stringify({name: filename, mimeType: mimeType}),
headers: {authorization: "Bearer " + ScriptApp.getOAuthToken()
}});
ステップ3(再開可能なセッションURIを保存)
const location = res1.getHeaders().Location;
ステップ4(a)(ファイル1をアップロード)
注:ステップ4の(a)および(b)は、ループを使用して実行できます。私の場合、ループなしで2回使用しました
var file = DriveApp.getFileById(fileId1); //get the first file
var data = file.getBlob().getBytes(); //get its contents in bytes array
//Method used is PUT not POST
//Content-Range will contain the range from starting byte to ending byte, then a slash
//and then file size
//bytes array of file's blob is put in data
var params = {
method : "put",
headers : {
'Content-Range' : `bytes 0-524287/687627`
},
payload : data,
muteHttpExceptions: true
};
//Request using Resumable session URI, and above params as parameter
var result = UrlFetchApp.fetch(location,params);
ステップ4(b)(2番目のファイルをアップロード)
//Almost same as Step 4 (a)
//The thing that changes is Content Range
file = DriveApp.getFileById(fileId2);
data = file.getBlob().getBytes();
params = {
method : "put",
headers : {
'Content-Range' : `bytes 524288-687626/687627`
},
payload : data,
muteHttpExceptions : true
};
result = UrlFetchApp.fetch(location, params);
ステップ4 n
の回数を実行する代わりに、ループを使用することをお勧めします。
また、このコードは、プロセス中に発生した可能性のあるエラーをチェックしません。
このコードは、自己学習の実験でしたが、誰かを助けることを願っています。 :)