code: func (dl *downloader) foreachPhoto(ctx context.Context, sinceToken string, fn func(context.Context, *photo) error) (nextToken string, err error) {
  
  	if sinceToken != "" {
  		return dl.foreachPhotoFromChanges(ctx, sinceToken, fn)
  	}
  
  	// Get a start page token *before* we enumerate the world, so
  	// if there are changes during the import, we won't miss
  	// anything.
  	var sr *drive.StartPageToken
  	if err := dl.rateLimit(ctx, func() error {
  		var err error
  		sr, err = dl.Service.Changes.GetStartPageToken().Do()
  		return err
  	}); err != nil {
  		return "", err
  	}
  	nextToken = sr.StartPageToken
  	if nextToken == "" {
  		return "", errors.New("unexpected gdrive Changes.GetStartPageToken response with empty StartPageToken")
  	}
  
  	if err := dl.foreachPhotoFromScratch(ctx, fn); err != nil {
  		return "", err
  	}
  	return nextToken, nil
  }
docs: // foreachPhoto runs fn on each photo. If f returns an error, iteration
  // stops with that error.
  //
  // If sinceToken is provided, only photos modified or created after sinceToken are sent.
  // Typically, sinceToken is empty on the first importer run,
  // and the returned token is saved by the importer,
  // to be passed as the sinceToken in the next photos() call.
  //
  // Returns a new token to watch future changes.