Google डेटा प्रोटोकॉल में फिर से शुरू किए जा सकने वाले मीडिया अपलोड

एरिक बिडेलमैन, G Suite API टीम
फ़रवरी 2010

  1. शुरुआती जानकारी
  2. रिज़्यूमे के प्रोटोकॉल
    1. फिर से अपलोड करने की प्रोसेस शुरू करना
    2. फ़ाइल अपलोड करना
    3. अपलोड फिर से शुरू करना
    4. अपलोड रद्द करना
    5. मौजूदा संसाधन को अपडेट करना
  3. क्लाइंट लाइब्रेरी के उदाहरण

सुविधा के बारे में जानकारी

मौजूदा वेब स्टैंडर्ड ऐसी बड़ी फ़ाइल के एचटीटीपी अपलोड के लिए कोई भरोसेमंद तरीका नहीं देते. इस वजह से, Google और दूसरी साइटों पर फ़ाइल अपलोड करने का काम पारंपरिक तौर पर, सीमित साइज़ तक ही सीमित रहा है (जैसे कि 100 एमबी). YouTube और Google दस्तावेज़ सूची API जैसी सेवाओं के लिए जो बड़ी फ़ाइल अपलोड का समर्थन करती हैं, यह एक बड़ी समस्या है.

Google डेटा फिर से शुरू करने वाला प्रोटोकॉल, HTTP/1.0 में फिर से शुरू होने वाले POST/PUT एचटीटीपी अनुरोधों के साथ काम करते हुए ऊपर बताई गई समस्याओं को सीधे हल करता है. इस प्रोटोकॉल को, Google गियर्स की टीम के ResumableHttpRequestsProposal के आधार पर बनाया गया था.

इस दस्तावेज़ में बताया गया है कि आप अपने ऐप्लिकेशन में, Google डेटा को फिर से शुरू करने की सुविधा कैसे शामिल कर सकते हैं. नीचे दिए गए उदाहरण Google दस्तावेज़ सूची डेटा API का इस्तेमाल करते हैं. ध्यान दें कि इस प्रोटोकॉल को लागू करने वाले दूसरे Google API की ज़रूरतें/जवाब के कोड/वगैरह कुछ अलग हो सकते हैं. कृपया खास जानकारी के लिए सेवा के दस्तावेज़ देखें.

फिर से चालू करने वाला प्रोटोकॉल

फिर से शुरू करने लायक अपलोड अनुरोध शुरू किया जा रहा है

फिर से शुरू करने लायक अपलोड सेशन शुरू करने के लिए, फिर से शुरू करने लायक पोस्ट लिंक पर एचटीटीपी POST अनुरोध भेजें. यह लिंक, फ़ीड लेवल पर मौजूद होता है. DocList API का फिर से शुरू किया जा सकने वाला पोस्ट लिंक ऐसा दिखाई देता है:

<link rel="http://schemas.google.com/g/2005#resumable-create-media" type="application/atom+xml"
    href="https://docs.google.com/feeds/upload/create-session/default/private/full"/>

POST अनुरोध के मुख्य हिस्से में जानकारी नहीं होनी चाहिए या इसमें ऐटम एक्सएमएल एंट्री होनी चाहिए. इसमें, फ़ाइल का असल कॉन्टेंट शामिल नहीं होना चाहिए. इस उदाहरण में एक बड़ा PDF अपलोड करने के लिए, फिर से शुरू करने का अनुरोध किया गया है. साथ ही, Slug हेडर का इस्तेमाल करके, आने वाले समय के दस्तावेज़ का शीर्षक भी शामिल है.

POST /feeds/upload/create-session/default/private/full HTTP/1.1
Host: docs.google.com
GData-Version: version_number
Authorization: authorization
Content-Length: 0
Slug: MyTitle
X-Upload-Content-Type: content_type
X-Upload-Content-Length: content_length

empty body

X-Upload-Content-Type और X-Upload-Content-Length हेडर को उस फ़ाइल के mimetype और आकार पर सेट किया जाना चाहिए जिसे आप अपलोड करेंगे. अगर अपलोड सत्र के दौरान सामग्री की लंबाई के बारे में जानकारी नहीं है, तो X-Upload-Content-Length हेडर को हटाया जा सकता है.

अनुरोध का एक और उदाहरण है, जिसमें इसके बजाय कोई शब्द दस्तावेज़ अपलोड किया जाता है. इस बार, ऐटम मेटाडेटा शामिल किया जाएगा और उसे फ़ाइनल दस्तावेज़ एंट्री पर लागू किया जाएगा.

POST /feeds/upload/create-session/default/private/full?convert=false HTTP/1.1
Host: docs.google.com
GData-Version: version_number
Authorization: authorization
Content-Length: atom_metadata_content_length
Content-Type: application/atom+xml
X-Upload-Content-Type: application/msword
X-Upload-Content-Length: 7654321

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
  <category scheme="http://schemas.google.com/g/2005#kind"
      term="http://schemas.google.com/docs/2007#document"/>
  <title>MyTitle</title>
  <docs:writersCanInvite value="false"/>
</entry>

शुरुआती POST के सर्वर का रिस्पॉन्स, Location हेडर में अपलोड किया गया एक यूनीक यूआरआई और खाली रिस्पॉन्स का मुख्य हिस्सा है:

HTTP/1.1 200 OK
Location: <upload_uri>

फ़ाइलें अपलोड करने के लिए, यूनीक यूआरआई का इस्तेमाल किया जाएगा.

ध्यान दें: शुरुआती POST अनुरोध से फ़ीड में कोई नई एंट्री नहीं बनती. ऐसा तभी होता है, जब अपलोड की पूरी प्रोसेस पूरी हो जाए.

ध्यान दें: फिर से शुरू किए जा सकने वाले सेशन के यूआरआई की समयसीमा एक हफ़्ते के बाद खत्म हो जाती है.

फ़ाइल अपलोड करना

फिर से इस्तेमाल किए जा सकने वाले प्रोटोकॉल से, 'वीडियो के हिस्से' में कॉन्टेंट अपलोड करने की अनुमति मिलती है. हालांकि, ऐसा करने की ज़रूरत नहीं होती, क्योंकि एचटीटीपी पर अनुरोध के साइज़ के लिए कोई पाबंदी नहीं होती. आपके क्लाइंट के हिस्से का आकार चुन सकते हैं या पूरी फ़ाइल अपलोड कर सकते हैं. यह उदाहरण फिर से शुरू किए जा सकने वाले PUT को जारी करने के लिए यूनीक अपलोड यूआरआई का इस्तेमाल करता है. नीचे दिया गया उदाहरण 1234567 बाइट की PDF फ़ाइल का पहला 10,0000 बाइट भेजता है:

PUT upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 100000
Content-Range: bytes 0-99999/1234567

bytes 0-99999

अगर PDF फ़ाइल का साइज़ अज्ञात था, तो इस उदाहरण में Content-Range: bytes 0-99999/* का इस्तेमाल किया जाएगा. Content-Range हेडर के बारे में ज़्यादा जानकारी यहां पढ़ें.

सर्वर, सेव की गई मौजूदा बाइट रेंज के साथ रिस्पॉन्स करता है:

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-99999

जब तक पूरी फ़ाइल अपलोड नहीं हो जाती, तब तक आपके क्लाइंट को फ़ाइल के हर हिस्से की जानकारी PUT पर जारी रखनी चाहिए. जब तक अपलोड पूरा नहीं हो जाता, तब तक सर्वर 308 Resume Incomplete हेडर के साथ रिस्पॉन्स करता है. साथ ही, यह Range हेडर में बाइट की रेंज भी बताता है. क्लाइंट को यह जानने के लिए Range हेडर का इस्तेमाल करना होगा कि अगला डेटा कहां से शुरू करें. इसलिए, यह न सोचें कि सर्वर को PUT अनुरोध में भेजे गए सभी बाइट मिले हैं.

ध्यान दें: डेटा डालने के दौरान, सर्वर Location हेडर में एक नया यूनीक अपलोड यूआरआई जारी कर सकता है. आपके क्लाइंट को, अपडेट किए गए Locationकी जांच करनी चाहिए और बचे हुए हिस्से को सर्वर पर भेजने के लिए, उस यूआरआई का इस्तेमाल करना चाहिए.

डेटा अपलोड होने के बाद, उसका रिस्पॉन्स वैसा ही होगा जैसा कि एपीआई को फिर से अपलोड न करने वाले सिस्टम से किया जाता है. उदाहरण के लिए, अगर सर्वर ने बनाया है, तो <atom:entry> के साथ 201 Created दिखाया जाएगा. अपलोड किए गए यूनीक यूआरएल के बाद, PUTs से वही जवाब मिलेगा जो अपलोड पूरा होने पर मिला था. कुछ समय के बाद, जवाब 410 Gone या 404 Not Found होगा.

अपलोड फिर से शुरू करना

अगर आपका अनुरोध सर्वर से जवाब पाने से पहले खत्म हो जाता है या आपको सर्वर से एक एचटीटीपी 503 रिस्पॉन्स मिलता है, तो आप यूनीक अपलोड यूआरआई पर खाली PUT अनुरोध जारी करके, अपलोड की मौजूदा स्थिति के बारे में क्वेरी कर सकते हैं.

क्लाइंट, सर्वर पर पोल करके पता लगाता है कि उसे कौनसी बाइट मिली हैं:

PUT upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 0
Content-Range: bytes */content_length

अगर लंबाई के बारे में जानकारी नहीं है, तो * का इस्तेमाल content_length के तौर पर करें.

सर्वर, मौजूदा बाइट रेंज के साथ रिस्पॉन्स करता है:

HTTP/1.1 308 Resume Incomplete
Content-Length: 0
Range: bytes=0-42

ध्यान दें: अगर सर्वर ने सेशन के लिए कोई बाइट नहीं दिया है, तो वह Range हेडर को हटा देगा.

ध्यान दें: डेटा डालने के दौरान, सर्वर Location हेडर में एक नया यूनीक अपलोड यूआरआई जारी कर सकता है. आपके क्लाइंट को, अपडेट किए गए Locationकी जांच करनी चाहिए और बचे हुए हिस्से को सर्वर पर भेजने के लिए, उस यूआरआई का इस्तेमाल करना चाहिए.

आखिर में, क्लाइंट वहीं से शुरू करता है जहां सर्वर ने छोड़ा था:

PUT upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 57
Content-Range: 43-99/100

<bytes 43-99>

अपलोड होने की प्रोसेस रद्द करना

अगर आपको अपलोड रद्द करना है और इस पर कोई कार्रवाई नहीं करनी है, तो यूनीक अपलोड यूआरआई पर DELETE अनुरोध जारी करें.

DELETE upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 0

अगर यह सफल होता है, तो सर्वर जवाब देता है कि सेशन रद्द कर दिया गया है और आगे भी PUT या क्वेरी स्थिति के अनुरोधों के लिए उसी कोड के साथ जवाब देता है:

HTTP/1.1 499 Client Closed Request

ध्यान दें: अगर किसी वीडियो को अपलोड करने की प्रोसेस बिना रद्द किए छोड़ दी जाती है, तो यह आम तौर पर बनाए जाने के एक हफ़्ते बाद खत्म हो जाती है.

किसी मौजूदा संसाधन को अपडेट करना

फिर से शुरू किए जाने वाले अपलोड सेशन को शुरू करने की तरह ही, आप मौजूदा फ़ाइल का कॉन्टेंट बदलने के लिए फिर से अपलोड करने वाले प्रोटोकॉल का इस्तेमाल कर सकते हैं. फिर से शुरू करने लायक अपडेट करने का अनुरोध शुरू करने के लिए, RE='...#resumable-edit-media' वाले एंट्री के लिंक पर एक एचटीटीपी PUT भेजें. अगर एपीआई, संसाधन के कॉन्टेंट को अपडेट करता है, तो हर मीडिया entry में ऐसा लिंक होगा.

एक उदाहरण के रूप में, DocList API में एक दस्तावेज़ प्रविष्टि में इसके जैसा कोई लिंक होगा:

<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml"
      href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345"/>

इसलिए, पहला अनुरोध यह होगा:

PUT /feeds/upload/create-session/default/private/full/document%3A12345 HTTP/1.1
Host: docs.google.com
GData-Version: version_number
Authorization: authorization
If-Match: ETag | *
Content-Length: 0
X-Upload-Content-Length: content_length
X-Upload-Content-Type: content_type

empty body

संसाधन का मेटाडेटा और कॉन्टेंट, दोनों को एक साथ अपडेट करने के लिए, खाली बॉडी के बजाय ऐटम एक्सएमएल शामिल करें. फिर से शुरू किए जा सकने वाले अपलोड का अनुरोध शुरू करना सेक्शन में दिया गया उदाहरण देखें.

जब सर्वर यूनीक अपलोड यूआरआई के साथ जवाब दे, तो अपने पेलोड के साथ PUT भेजें. यूनीक अपलोड यूआरआई मिलने के बाद, फ़ाइल को अपडेट करने की प्रोसेस फ़ाइल अपलोड करने जैसी ही होती है.

यह खास उदाहरण, मौजूदा शॉट के कॉन्टेंट को एक बार में अपडेट कर देगा:

PUT upload_uri HTTP/1.1
Host: docs.google.com
Content-Length: 1000
Content-Range: 0-999/1000

<bytes 0-999>

वापस सबसे ऊपर जाएं

क्लाइंट लाइब्रेरी के उदाहरण

नीचे Google डेटा क्लाइंट लाइब्रेरी में Google Docs पर दोबारा अपलोड की जा सकने वाली फ़ाइल का इस्तेमाल करके, फ़िल्म फ़ाइल के नमूने अपलोड किए गए हैं. ध्यान दें कि इस समय सभी लाइब्रेरी फिर से शुरू करने की सुविधा का समर्थन नहीं करती हैं.

int MAX_CONCURRENT_UPLOADS = 10;
int PROGRESS_UPDATE_INTERVAL = 1000;
int DEFAULT_CHUNK_SIZE = 10485760;


DocsService client = new DocsService("yourCompany-yourAppName-v1");
client.setUserCredentials("user@gmail.com", "pa$$word");

// Create a listener
FileUploadProgressListener listener = new FileUploadProgressListener(); // See the sample for details on this class.

// Pool for handling concurrent upload tasks
ExecutorService executor = Executors.newFixedThreadPool(MAX_CONCURRENT_UPLOADS);

// Create {@link ResumableGDataFileUploader} for each file to upload
List uploaders = Lists.newArrayList();

File file = new File("test.mpg");
String contentType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType();
MediaFileSource mediaFile = new MediaFileSource(file, contentType);
URL createUploadUrl = new URL("https://docs.google.com/feeds/upload/create-session/default/private/full");
ResumableGDataFileUploader uploader = new ResumableGDataFileUploader(createUploadUrl, mediaFile, client, DEFAULT_CHUNK_SIZE,
                                                                     executor, listener, PROGRESS_UPDATE_INTERVAL);
uploaders.add(uploader);

listener.listenTo(uploaders); // attach the listener to list of uploaders

// Start the upload(s)
for (ResumableGDataFileUploader uploader : uploaders) {
  uploader.start();
}

// wait for uploads to complete
while(!listener.isDone()) {
  try {
    Thread.sleep(100);
  } catch (InterruptedException ie) {
    listener.printResults();
    throw ie; // rethrow
  }
// Chunk size in MB
int CHUNK_SIZE = 1;

ClientLoginAuthenticator cla = new ClientLoginAuthenticator(
    "yourCompany-yourAppName-v1", ServiceNames.Documents, "user@gmail.com", "pa$$word");

// Set up resumable uploader and notifications
ResumableUploader ru = new ResumableUploader(CHUNK_SIZE);
ru.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(this.OnDone);
ru.AsyncOperationProgress += new AsyncOperationProgressEventHandler(this.OnProgress);

// Set metadata for our upload.
Document entry = new Document()
entry.Title = "My Video";
entry.MediaSource = new MediaFileSource("c:\\test.mpg", "video/mpeg");

// Add the upload uri to document entry.
Uri createUploadUrl = new Uri("https://docs.google.com/feeds/upload/create-session/default/private/full");
AtomLink link = new AtomLink(createUploadUrl.AbsoluteUri);
link.Rel = ResumableUploader.CreateMediaRelation;
entry.DocumentEntry.Links.Add(link);

ru.InsertAsync(cla, entry.DocumentEntry, userObject);
- (void)uploadAFile {
  NSString *filePath = @"~/test.mpg";
  NSString *fileName = [filePath lastPathComponent];

  // get the file's data
  NSData *data = [NSData dataWithContentsOfMappedFile:filePath];

  // create an entry to upload
  GDataEntryDocBase *newEntry = [GDataEntryStandardDoc documentEntry];
  [newEntry setTitleWithString:fileName];

  [newEntry setUploadData:data];
  [newEntry setUploadMIMEType:@"video/mpeg"];
  [newEntry setUploadSlug:fileName];

  // to upload, we need the entry, our service object, the upload URL,
  // and the callback for when upload has finished
  GDataServiceGoogleDocs *service = [self docsService];
  NSURL *uploadURL = [GDataServiceGoogleDocs docsUploadURL];
  SEL finishedSel = @selector(uploadTicket:finishedWithEntry:error:);

  // now start the upload
  GDataServiceTicket *ticket = [service fetchEntryByInsertingEntry:newEntry
                                                        forFeedURL:uploadURL
                                                          delegate:self
                                                 didFinishSelector:finishedSel];

  // progress monitoring is done by specifying a callback, like this
  SEL progressSel = @selector(ticket:hasDeliveredByteCount:ofTotalByteCount:);
  [ticket setUploadProgressSelector:progressSel];
}

// callback for when uploading has finished
- (void)uploadTicket:(GDataServiceTicket *)ticket
   finishedWithEntry:(GDataEntryDocBase *)entry
               error:(NSError *)error {
  if (error == nil) {
    // upload succeeded
  }
}

- (void)pauseOrResumeUploadForTicket:(GDataServiceTicket *)ticket {
  if ([ticket isUploadPaused]) {
    [ticket resumeUpload];
  } else {
    [ticket pauseUpload];
  }
}
import os.path
import atom.data
import gdata.client
import gdata.docs.client
import gdata.docs.data

CHUNK_SIZE = 10485760

client = gdata.docs.client.DocsClient(source='yourCompany-yourAppName-v1')
client.ClientLogin('user@gmail.com', 'pa$$word', client.source);

f = open('test.mpg')
file_size = os.path.getsize(f.name)

uploader = gdata.client.ResumableUploader(
    client, f, 'video/mpeg', file_size, chunk_size=CHUNK_SIZE, desired_class=gdata.docs.data.DocsEntry)

# Set metadata for our upload.
entry = gdata.docs.data.DocsEntry(title=atom.data.Title(text='My Video'))
new_entry = uploader.UploadFile('/feeds/upload/create-session/default/private/full', entry=entry)
print 'Document uploaded: ' + new_entry.title.text
print 'Quota used: %s' % new_entry.quota_bytes_used.text

नमूने और स्रोत कोड के सभी उदाहरणों के लिए, नीचे दिए गए संसाधन देखें:

वापस सबसे ऊपर जाएं