Ejemplo n.º 1
0
// See https://developers.google.com/accounts/docs/OAuth2InstalledApp .
func main() {
	flagID := flag.String("id", os.Getenv("CLIENT_ID"), "application client ID")
	flagSecret := flag.String("secret", os.Getenv("CLIENT_SECRET"), "application client secret")
	flagCode := flag.String("code", os.Getenv("AUTH_CODE"), "authorization code")
	flagTokenCache := flag.String("cache", "token-cache.json", "token cache filename")
	flagDir := flag.String("dir", "", "directory to download images to")
	flagDebugDir := flag.String("debug", "", "set to a valid path to save the response XMLs there")

	flag.Parse()
	picago.DebugDir = *flagDebugDir
	userid := flag.Arg(0)

	client, err := picago.NewClient(*flagID, *flagSecret, *flagCode, *flagTokenCache)
	if err != nil {
		log.Fatalf("error with authorization: %v", err)
	}
	user, err := picago.GetUser(client, "")
	log.Printf("user=%#v err=%v", user, err)

	albums, err := picago.GetAlbums(client, userid)
	if err != nil {
		log.Fatalf("error listing albums: %v", err)
	}
	log.Printf("user %s has %d albums.", userid, len(albums))

	download := *flagDir != ""
	dir, fn := "", ""
	for _, album := range albums {
		albumJ, err := json.Marshal(album)
		if err != nil {
			log.Fatalf("error marshaling %#v: %v", album, err)
		}
		if download {
			dir = filepath.Join(*flagDir, album.Name)
			if err = os.MkdirAll(dir, 0750); err != nil {
				log.Fatalf("cannot create directory %s: %v", dir, err)
			}
			fn = filepath.Join(dir, "album-"+album.Name+".json")
			if err = ioutil.WriteFile(fn, albumJ, 0750); err != nil {
				log.Fatalf("error writing %s: %v", fn, err)
			}
		}
		log.Printf("downloading album %s.", albumJ)
		photos, err := picago.GetPhotos(client, userid, album.ID)
		if err != nil {
			log.Printf("error listing photos of %s: %v", album.ID, err)
			continue
		}
		log.Printf("album %s contains %d photos.", album.ID, len(photos))
		for _, photo := range photos {
			photoJ, err := json.Marshal(photo)
			if err != nil {
				log.Fatalf("error marshaling %#v: %v", photo, err)
			}
			log.Printf("Photo: %s", photoJ)

			if !download {
				continue
			}
			fn = filepath.Join(dir, photo.Filename)
			if err = ioutil.WriteFile(fn+".json", photoJ, 0750); err != nil {
				log.Fatalf("error writing %s.json: %v", fn, err)
			}
			if err = downloadTo(fn, client, photo.URL); err != nil {
				log.Fatalf("downloading %s: %v", photo.URL, err)
			}
		}
	}
}
Ejemplo n.º 2
0
func (r *run) importAlbum(ctx context.Context, albumsNode *importer.Object, album picago.Album) (ret error) {
	if album.ID == "" {
		return errors.New("album has no ID")
	}
	albumNode, err := albumsNode.ChildPathObject(album.ID)
	if err != nil {
		return fmt.Errorf("importAlbum: error listing album: %v", err)
	}

	dateMod := schema.RFC3339FromTime(album.Updated)

	// Data reference: https://developers.google.com/picasa-web/docs/2.0/reference
	// TODO(tgulacsi): add more album info
	changes, err := albumNode.SetAttrs2(
		attrPicasaId, album.ID,
		nodeattr.Type, "picasaweb.google.com:album",
		nodeattr.Title, album.Title,
		nodeattr.DatePublished, schema.RFC3339FromTime(album.Published),
		nodeattr.LocationText, album.Location,
		nodeattr.Description, album.Description,
		nodeattr.URL, album.URL,
	)
	if err != nil {
		return fmt.Errorf("error setting album attributes: %v", err)
	}
	if !changes && r.incremental && albumNode.Attr(nodeattr.DateModified) == dateMod {
		return nil
	}
	defer func() {
		// Don't update DateModified on the album node until
		// we've successfully imported all the photos.
		if ret == nil {
			ret = albumNode.SetAttr(nodeattr.DateModified, dateMod)
		}
	}()

	log.Printf("Importing album %v: %v/%v (published %v, updated %v)", album.ID, album.Name, album.Title, album.Published, album.Updated)

	// TODO(bradfitz): GetPhotos does multiple HTTP requests to
	// return a slice of all photos. My "InstantUpload/Auto
	// Backup" album has 6678 photos (and growing) and this
	// currently takes like 40 seconds. Fix.
	photos, err := picago.GetPhotos(ctxutil.Client(ctx), "default", album.ID)
	if err != nil {
		return err
	}

	log.Printf("Importing %d photos from album %q (%s)", len(photos), albumNode.Attr(nodeattr.Title),
		albumNode.PermanodeRef())

	var grp syncutil.Group
	for i := range photos {
		select {
		case <-ctx.Done():
			return ctx.Err()
		default:
		}
		photo := photos[i]
		r.photoGate.Start()
		grp.Go(func() error {
			defer r.photoGate.Done()
			return r.updatePhotoInAlbum(ctx, albumNode, photo)
		})
	}
	return grp.Err()
}