insertImagesIntoDocs reads back a Google Doc to find < > placeholders, resolves image URLs (remote URLs used directly; local files are rejected), and replaces the placeholders with inline images via BatchUpdate.
(ctx context.Context, svc *docs.Service, docID string, images []markdownImage, tabID string)
| 234 | // resolves image URLs (remote URLs used directly; local files are rejected), |
| 235 | // and replaces the placeholders with inline images via BatchUpdate. |
| 236 | func insertImagesIntoDocs(ctx context.Context, svc *docs.Service, docID string, images []markdownImage, tabID string) error { |
| 237 | // Read back the document to find placeholder positions. |
| 238 | getCall := svc.Documents.Get(docID).Context(ctx) |
| 239 | if tabID != "" { |
| 240 | getCall = getCall.IncludeTabsContent(true) |
| 241 | } |
| 242 | doc, err := getCall.Do() |
| 243 | if err != nil { |
| 244 | return fmt.Errorf("read back document: %w", err) |
| 245 | } |
| 246 | if tabID != "" { |
| 247 | tab, tabErr := findTab(flattenTabs(doc.Tabs), tabID) |
| 248 | if tabErr != nil { |
| 249 | return tabErr |
| 250 | } |
| 251 | if tab.DocumentTab == nil || tab.DocumentTab.Body == nil { |
| 252 | return fmt.Errorf("tab has no document body: %s", tabID) |
| 253 | } |
| 254 | doc = &docs.Document{Body: tab.DocumentTab.Body} |
| 255 | } |
| 256 | |
| 257 | placeholders := findPlaceholderIndices(doc, images) |
| 258 | if len(placeholders) == 0 { |
| 259 | return nil |
| 260 | } |
| 261 | |
| 262 | // Resolve image URLs. The Docs API fetches InsertInlineImage URIs itself, so |
| 263 | // local files need to be hosted at a normal public HTTPS URL first. |
| 264 | imageURLs := make(map[int]string) |
| 265 | |
| 266 | for _, img := range images { |
| 267 | if _, ok := placeholders[img.placeholder()]; !ok { |
| 268 | continue |
| 269 | } |
| 270 | if img.isRemote() { |
| 271 | imageURLs[img.index] = img.originalRef |
| 272 | continue |
| 273 | } |
| 274 | return usagef("local markdown image %q cannot be inserted automatically; Google Docs image insertion requires a public HTTPS image URL, so upload the image to a public host and use that URL", img.originalRef) |
| 275 | } |
| 276 | |
| 277 | reqs := buildImageInsertRequests(placeholders, images, imageURLs, tabID) |
| 278 | if len(reqs) == 0 { |
| 279 | return nil |
| 280 | } |
| 281 | |
| 282 | return batchUpdateImageInsertRequests(ctx, svc, docID, reqs) |
| 283 | } |
| 284 | |
| 285 | var docsImageInsertRetryDelays = []time.Duration{ |
| 286 | 2 * time.Second, |