picasa, picago: support video, change struct definitions, add start of more tests

This commit is contained in:
Brad Fitzpatrick 2014-07-29 11:44:44 -07:00
parent 1763efbefe
commit 29c63cc2ab
6 changed files with 361 additions and 68 deletions
pkg/importer/picasa
third_party/github.com/tgulacsi/picago

View File

@ -17,9 +17,6 @@ limitations under the License.
// Package picasa implements an importer for picasa.com accounts.
package picasa
// TODO: videos don't import correctly. it currently imports a still
// preview frame from the video, instead of the video bytes.
import (
"errors"
"fmt"
@ -55,7 +52,7 @@ const (
// complete run. Otherwise, if the importer runs to
// completion, this version number is recorded on the account
// permanode and subsequent importers can stop early.
runCompleteVersion = "1"
runCompleteVersion = "2"
)
func init() {

View File

@ -124,7 +124,7 @@ func fakeAlbum(counter int) picago.Entry {
author := picago.Author{
Name: "fakeAuthorName",
}
media := picago.Media{
media := &picago.Media{
Description: "fakeAlbumDescription",
Keywords: "fakeKeyword1,fakeKeyword2",
}
@ -186,11 +186,11 @@ func fakePhotoEntry(photoNbr int, albumNbr int) picago.Entry {
URL: "https://camlistore.org/pic/pudgy2.png",
Type: "image/png",
}
media := picago.Media{
media := &picago.Media{
Title: "fakePhotoTitle",
Description: "fakePhotoDescription",
Keywords: "fakeKeyword1,fakeKeyword2",
Content: mediaContent,
Content: []picago.MediaContent{mediaContent},
}
// to be consistent, all the pics times should be anterior to their respective albums times. whatever.
day := time.Hour * 24
@ -199,7 +199,7 @@ func fakePhotoEntry(photoNbr int, albumNbr int) picago.Entry {
published := created.Add(day)
updated := published.Add(day)
exif := picago.Exif{
exif := &picago.Exif{
FStop: 7.7,
Make: "whatisthis?", // not obvious to me, needs doc in picago
Model: "potato",

View File

@ -40,8 +40,8 @@ type Entry struct {
Location string `xml:"http://schemas.google.com/photos/2007 location"`
NumPhotos int `xml:"numphotos"`
Content EntryContent `xml:"content"`
Media Media `xml:"group"`
Exif Exif `xml:"tags"`
Media *Media `xml:"group"`
Exif *Exif `xml:"tags"`
Point string `xml:"where>Point>pos"`
}
@ -64,15 +64,19 @@ type Link struct {
}
type Media struct {
Title string `xml:"http://search.yahoo.com/mrss title"`
Description string `xml:"description"`
Keywords string `xml:"keywords"`
Content MediaContent `xml:"content"`
Title string `xml:"http://search.yahoo.com/mrss title"`
Description string `xml:"description"`
Keywords string `xml:"keywords"`
Content []MediaContent `xml:"content"`
Thumbnail []MediaContent `xml:"thumbnail"`
}
type MediaContent struct {
URL string `xml:"url,attr"`
Type string `xml:"type,attr"`
URL string `xml:"url,attr"`
Type string `xml:"type,attr"`
Width int `xml:"width,attr"`
Height int `xml:"height,attr"`
Medium string `xml:"medium,attr"` // "image" or "video" for Picasa at least
}
type EntryContent struct {

View File

@ -6,6 +6,7 @@ package picago
import (
"encoding/xml"
"os"
"testing"
)
@ -250,3 +251,39 @@ func TestAtom(t *testing.T) {
t.Logf("result: %#v", result)
}
}
func mustParseAtom(t *testing.T, file string) *Atom {
f, err := os.Open(file)
if err != nil {
t.Fatal(err)
}
defer f.Close()
a := new(Atom)
if err := xml.NewDecoder(f).Decode(a); err != nil {
t.Fatal(err)
}
return a
}
func TestVideoInGallery(t *testing.T) {
atom := mustParseAtom(t, "testdata/gallery-with-a-video.xml")
if len(atom.Entries) != 3 {
t.Fatalf("num entries = %d; want 3", len(atom.Entries))
}
p, err := atom.Entries[2].photo()
if err != nil {
t.Fatal(err)
}
if p.Type != "video/mpeg4" {
t.Errorf("type = %q; want video/mpeg4", p.Type)
}
if got, want := p.URL, "https://foo.googlevideo.com/bar.mp4"; got != want {
t.Errorf("URL = %q; want %q", got, want)
}
for i, ent := range atom.Entries {
t.Logf("%d. Media = %#v", i, ent.Media)
p, _ := ent.photo()
t.Logf("%d. %#v", i, p)
}
}

View File

@ -8,7 +8,6 @@ import (
"fmt"
"io"
"io/ioutil"
"log"
"net/http"
neturl "net/url"
"os"
@ -26,7 +25,7 @@ const (
userURL = "https://picasaweb.google.com/data/feed/api/user/{userID}/contacts?kind=user"
)
var DebugDir string
var DebugDir = os.Getenv("PICAGO_DEBUG_DIR")
type User struct {
ID, URI, Name, Thumbnail string
@ -40,13 +39,27 @@ type Album struct {
URL string
}
// A Photo is a photo (or video) in a Picasaweb (or G+) gallery.
type Photo struct {
ID, Title, Summary, Description, Location string
Keywords []string
Published, Updated time.Time
Latitude, Longitude float64
URL, Type string
Exif Exif
ID, Title, Summary, Description string
Keywords []string
Published, Updated time.Time
// Latitude and Longitude optionally contain the GPS coordinates
// of the photo.
Latitude, Longitude float64
// Location is free-form text describing the location of the
// photo.
Location string
// URL is the URL of the photo or video.
URL string
// Type is the Content-Type.
Type string
Exif *Exif
}
// Filename returns the filename of the photo (from title or ID + type).
@ -111,16 +124,22 @@ func getAlbums(albums []Album, client *http.Client, url string, startIndex int)
break
}
}
var des string
var kw []string
if entry.Media != nil {
des = entry.Media.Description
kw = strings.Split(entry.Media.Keywords, ",")
}
albums = append(albums, Album{
ID: entry.ID,
Name: entry.Name,
Summary: entry.Summary,
Title: entry.Title,
Description: entry.Media.Description,
Description: des,
Location: entry.Location,
AuthorName: entry.Author.Name,
AuthorURI: entry.Author.URI,
Keywords: strings.Split(entry.Media.Keywords, ","),
Keywords: kw,
Published: entry.Published,
Updated: entry.Updated,
URL: albumURL,
@ -162,55 +181,85 @@ func getPhotos(photos []Photo, client *http.Client, url string, startIndex int)
if len(feed.Entries) == 0 {
return nil, false, nil
}
if cap(photos)-len(photos) < len(feed.Entries) {
photos = append(photos, make([]Photo, 0, len(feed.Entries))...)
}
for _, entry := range feed.Entries {
var lat, long float64
i := strings.Index(entry.Point, " ")
if i >= 1 {
lat, err = strconv.ParseFloat(entry.Point[:i], 64)
if err != nil {
log.Printf("cannot parse %q as latitude: %v", entry.Point[:i], err)
}
long, err = strconv.ParseFloat(entry.Point[i+1:], 64)
if err != nil {
log.Printf("cannot parse %q as longitude: %v", entry.Point[i+1:], err)
}
p, err := entry.photo()
if err != nil {
return nil, false, err
}
if entry.Point != "" && lat == 0 && long == 0 {
log.Fatalf("point=%q but couldn't parse it as lat/long", entry.Point)
}
url, typ := entry.Content.URL, entry.Content.Type
if url == "" {
url, typ = entry.Media.Content.URL, entry.Media.Content.Type
}
title := entry.Title
if title == "" {
title = entry.Media.Title
}
photos = append(photos, Photo{
ID: entry.ID,
Exif: entry.Exif,
Summary: entry.Summary,
Title: title,
Description: entry.Media.Description,
Location: entry.Location,
//AuthorName: entry.Author.Name,
//AuthorURI: entry.Author.URI,
Keywords: strings.Split(entry.Media.Keywords, ","),
Published: entry.Published,
Updated: entry.Updated,
URL: url,
Type: typ,
Latitude: lat,
Longitude: long,
})
photos = append(photos, p)
}
// startIndex starts with 1, we need to compensate for it.
return photos, startIndex+len(feed.Entries) <= feed.NumPhotos, nil
}
func (e *Entry) photo() (p Photo, err error) {
var lat, long float64
i := strings.Index(e.Point, " ")
if i >= 1 {
lat, err = strconv.ParseFloat(e.Point[:i], 64)
if err != nil {
return p, fmt.Errorf("cannot parse %q as latitude: %v", e.Point[:i], err)
}
long, err = strconv.ParseFloat(e.Point[i+1:], 64)
if err != nil {
return p, fmt.Errorf("cannot parse %q as longitude: %v", e.Point[i+1:], err)
}
}
if e.Point != "" && lat == 0 && long == 0 {
return p, fmt.Errorf("point=%q but couldn't parse it as lat/long", e.Point)
}
p = Photo{
ID: e.ID,
Exif: e.Exif,
Summary: e.Summary,
Title: e.Title,
Location: e.Location,
Published: e.Published,
Updated: e.Updated,
Latitude: lat,
Longitude: long,
}
if e.Media != nil {
p.Keywords = strings.Split(e.Media.Keywords, ",")
p.Description = e.Media.Description
if mc, ok := e.Media.bestContent(); ok {
p.URL, p.Type = mc.URL, mc.Type
}
if p.Title == "" {
p.Title = e.Media.Title
}
}
return p, nil
}
func (m *Media) bestContent() (ret MediaContent, ok bool) {
// Find largest non-Flash video.
var bestPixels int64
for _, mc := range m.Content {
thisPixels := int64(mc.Width) * int64(mc.Height)
if mc.Medium == "video" && mc.Type != "application/x-shockwave-flash" && thisPixels > bestPixels {
ret = mc
ok = true
bestPixels = thisPixels
}
}
if ok {
return
}
// Else, just find largest anything.
bestPixels = 0
for _, mc := range m.Content {
thisPixels := int64(mc.Width) * int64(mc.Height)
if thisPixels > bestPixels {
ret = mc
ok = true
bestPixels = thisPixels
}
}
return
}
func downloadAndParse(client *http.Client, url string) (*Atom, error) {
resp, err := client.Get(url)
if err != nil {

View File

@ -0,0 +1,206 @@
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:exif="http://schemas.google.com/photos/exif/2007" xmlns:gphoto="http://schemas.google.com/photos/2007" xmlns:media="http://search.yahoo.com/mrss/" xmlns:openSearch="http://a9.com/-/spec/opensearchrss/1.0/" xmlns:gml="http://www.opengis.net/gml" xmlns:georss="http://www.georss.org/georss">
<id>https://picasaweb.google.com/data/feed/api/user/default/albumid/6040139514831220113</id>
<updated>2014-07-28T23:07:15.698Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#album"/>
<title type="text">Biking with Blake</title>
<subtitle type="text">Description is biking up San Bruno mountain.
And a newline.</subtitle>
<rights type="text">protected</rights>
<icon>https://lh4.googleusercontent.com/-VSf28XLm47g/U9Li4v9QrZE/AAAAAAAAAD0/Zkcd4B_xKl8/s160-c/BikingWithBlake.jpg</icon>
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="https://picasaweb.google.com/data/feed/api/user/114403741484702971746/albumid/6040139514831220113"/>
<link rel="http://schemas.google.com/g/2005#post" type="application/atom+xml" href="https://picasaweb.google.com/data/feed/api/user/114403741484702971746/albumid/6040139514831220113"/>
<link rel="http://schemas.google.com/g/2005#resumable-create-media" type="application/atom+xml" href="https://picasaweb.google.com/data/upload/resumable/media/create-session/feed/api/user/114403741484702971746/albumid/6040139514831220113"/>
<link rel="alternate" type="text/html" href="https://picasaweb.google.com/114403741484702971746/BikingWithBlake"/>
<link rel="http://schemas.google.com/photos/2007#slideshow" type="application/x-shockwave-flash" href="https://photos.gstatic.com/media/slideshow.swf?host=picasaweb.google.com&amp;RGB=0x000000&amp;feed=https://picasaweb.google.com/data/feed/api/user/114403741484702971746/albumid/6040139514831220113?alt%3Drss"/>
<link rel="http://schemas.google.com/photos/2007#report" type="text/html" href="https://picasaweb.google.com/lh/reportAbuse?uname=114403741484702971746&amp;aid=6040139514831220113"/>
<link rel="http://schemas.google.com/acl/2007#accessControlList" type="application/atom+xml" href="https://picasaweb.google.com/data/feed/api/user/114403741484702971746/albumid/6040139514831220113/acl"/>
<link rel="self" type="application/atom+xml" href="https://picasaweb.google.com/data/feed/api/user/114403741484702971746/albumid/6040139514831220113?start-index=1&amp;max-results=1000&amp;imgmax=d"/>
<author>
<name>Gast Erson</name>
<uri>https://picasaweb.google.com/114403741484702971746</uri>
</author>
<generator version="1.00" uri="http://picasaweb.google.com/">Picasaweb</generator>
<openSearch:totalResults>3</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>1000</openSearch:itemsPerPage>
<gphoto:id>6040139514831220113</gphoto:id>
<gphoto:name>BikingWithBlake</gphoto:name>
<gphoto:location>San Bruno Mt, CA</gphoto:location>
<gphoto:access>protected</gphoto:access>
<gphoto:timestamp>1406012400000</gphoto:timestamp>
<gphoto:numphotos>3</gphoto:numphotos>
<gphoto:numphotosremaining>1997</gphoto:numphotosremaining>
<gphoto:bytesUsed>4037418</gphoto:bytesUsed>
<gphoto:user>114403741484702971746</gphoto:user>
<gphoto:nickname>Gast Erson</gphoto:nickname>
<gphoto:allowPrints>true</gphoto:allowPrints>
<gphoto:allowDownloads>true</gphoto:allowDownloads>
<entry>
<id>https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040139511962430354</id>
<published>2014-07-25T23:06:10.000Z</published>
<updated>2014-07-25T23:06:14.015Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#photo"/>
<title type="text">fail.png</title>
<summary type="text"/>
<content type="image/png" src="https://lh3.googleusercontent.com/-uzJVjaTng8o/U9Li4lRSa5I/AAAAAAAAABM/qHJS4rukdqM/I/fail.png"/>
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="https://picasaweb.google.com/data/feed/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040139511962430354"/>
<link rel="alternate" type="text/html" href="https://picasaweb.google.com/114403741484702971746/BikingWithBlake#6040139511962430354"/>
<link rel="http://schemas.google.com/photos/2007#canonical" type="text/html" href="https://picasaweb.google.com/lh/photo/A_fL0dC3Fnx00P-QifpDE9MTjNZETYmyPJy0liipFm0"/>
<link rel="self" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040139511962430354"/>
<link rel="edit" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040139511962430354/3"/>
<link rel="edit-media" type="image/jpeg" href="https://picasaweb.google.com/data/media/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040139511962430354/3"/>
<link rel="media-edit" type="image/jpeg" href="https://picasaweb.google.com/data/media/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040139511962430354/3"/>
<link rel="http://schemas.google.com/photos/2007#report" type="text/html" href="https://picasaweb.google.com/lh/reportAbuse?uname=114403741484702971746&amp;aid=6040139514831220113&amp;iid=6040139511962430354"/>
<gphoto:id>6040139511962430354</gphoto:id>
<gphoto:version>3</gphoto:version>
<gphoto:position>-1.0</gphoto:position>
<gphoto:albumid>6040139514831220113</gphoto:albumid>
<gphoto:access>only_you</gphoto:access>
<gphoto:width>922</gphoto:width>
<gphoto:height>392</gphoto:height>
<gphoto:size>58730</gphoto:size>
<gphoto:client>es-upload-highlights</gphoto:client>
<gphoto:checksum/>
<gphoto:timestamp>1406329570000</gphoto:timestamp>
<gphoto:imageVersion>19</gphoto:imageVersion>
<gphoto:commentingEnabled>true</gphoto:commentingEnabled>
<gphoto:commentCount>0</gphoto:commentCount>
<gphoto:streamId>shared_group_6040139511962430354</gphoto:streamId>
<gphoto:license id="0" name="All Rights Reserved" url="">ALL_RIGHTS_RESERVED</gphoto:license>
<gphoto:shapes faces="done"/>
<exif:tags>
<exif:imageUniqueID>600da24a1bc3ddb90000000000000000</exif:imageUniqueID>
</exif:tags>
<media:group>
<media:content url="https://lh3.googleusercontent.com/-uzJVjaTng8o/U9Li4lRSa5I/AAAAAAAAABM/qHJS4rukdqM/I/fail.png" height="392" width="922" type="image/png" medium="image"/>
<media:credit>Gast Erson</media:credit>
<media:description type="plain"/>
<media:keywords/>
<media:thumbnail url="https://lh3.googleusercontent.com/-uzJVjaTng8o/U9Li4lRSa5I/AAAAAAAAABM/CmypwuJHOQo/s72/fail.png" height="31" width="72"/>
<media:thumbnail url="https://lh3.googleusercontent.com/-uzJVjaTng8o/U9Li4lRSa5I/AAAAAAAAABM/CmypwuJHOQo/s144/fail.png" height="62" width="144"/>
<media:thumbnail url="https://lh3.googleusercontent.com/-uzJVjaTng8o/U9Li4lRSa5I/AAAAAAAAABM/CmypwuJHOQo/s288/fail.png" height="123" width="288"/>
<media:title type="plain">fail.png</media:title>
</media:group>
</entry>
<entry>
<id>https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040140028386335042</id>
<published>2014-07-25T23:08:10.000Z</published>
<updated>2014-07-28T23:07:15.698Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#photo"/>
<title type="text">IMG_2034.JPG</title>
<summary type="text">This is a caption</summary>
<content type="image/jpeg" src="https://lh6.googleusercontent.com/-e8FSPDDeev8/U9LjWpGV2UI/AAAAAAAAAD0/CsA9NdVToBo/I/IMG_2034.JPG"/>
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="https://picasaweb.google.com/data/feed/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040140028386335042"/>
<link rel="alternate" type="text/html" href="https://picasaweb.google.com/114403741484702971746/BikingWithBlake#6040140028386335042"/>
<link rel="http://schemas.google.com/photos/2007#canonical" type="text/html" href="https://picasaweb.google.com/lh/photo/m-tEQgw4HKGy-gNDTkIYudMTjNZETYmyPJy0liipFm0"/>
<link rel="self" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040140028386335042"/>
<link rel="edit" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040140028386335042/16"/>
<link rel="edit-media" type="image/jpeg" href="https://picasaweb.google.com/data/media/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040140028386335042/16"/>
<link rel="media-edit" type="image/jpeg" href="https://picasaweb.google.com/data/media/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6040140028386335042/16"/>
<link rel="http://schemas.google.com/photos/2007#report" type="text/html" href="https://picasaweb.google.com/lh/reportAbuse?uname=114403741484702971746&amp;aid=6040139514831220113&amp;iid=6040140028386335042"/>
<gphoto:id>6040140028386335042</gphoto:id>
<gphoto:version>16</gphoto:version>
<gphoto:position>0.0</gphoto:position>
<gphoto:albumid>6040139514831220113</gphoto:albumid>
<gphoto:access>only_you</gphoto:access>
<gphoto:width>1183</gphoto:width>
<gphoto:height>872</gphoto:height>
<gphoto:size>689067</gphoto:size>
<gphoto:client>es-pc-add-photos</gphoto:client>
<gphoto:checksum/>
<gphoto:timestamp>1406256485000</gphoto:timestamp>
<gphoto:imageVersion>61</gphoto:imageVersion>
<gphoto:commentingEnabled>true</gphoto:commentingEnabled>
<gphoto:commentCount>1</gphoto:commentCount>
<gphoto:streamId>shared_group_6040140028386335042</gphoto:streamId>
<gphoto:license id="0" name="All Rights Reserved" url="">ALL_RIGHTS_RESERVED</gphoto:license>
<gphoto:shapes faces="done"/>
<exif:tags>
<exif:fstop>2.2</exif:fstop>
<exif:make>Apple</exif:make>
<exif:model>iPhone 5s</exif:model>
<exif:exposure>0.001242236</exif:exposure>
<exif:flash>false</exif:flash>
<exif:focallength>4.12</exif:focallength>
<exif:iso>32</exif:iso>
<exif:time>1406231285000</exif:time>
<exif:imageUniqueID>6e37fb5bf62bde9e0000000000000000</exif:imageUniqueID>
</exif:tags>
<media:group>
<media:content url="https://lh6.googleusercontent.com/-e8FSPDDeev8/U9LjWpGV2UI/AAAAAAAAAD0/CsA9NdVToBo/I/IMG_2034.JPG" height="872" width="1183" type="image/jpeg" medium="image"/>
<media:credit>Gast Erson</media:credit>
<media:description type="plain">This is a caption</media:description>
<media:keywords/>
<media:thumbnail url="https://lh6.googleusercontent.com/-e8FSPDDeev8/U9LjWpGV2UI/AAAAAAAAAD0/HsMxroJpDMw/s72/IMG_2034.JPG" height="54" width="72"/>
<media:thumbnail url="https://lh6.googleusercontent.com/-e8FSPDDeev8/U9LjWpGV2UI/AAAAAAAAAD0/HsMxroJpDMw/s144/IMG_2034.JPG" height="107" width="144"/>
<media:thumbnail url="https://lh6.googleusercontent.com/-e8FSPDDeev8/U9LjWpGV2UI/AAAAAAAAAD0/HsMxroJpDMw/s288/IMG_2034.JPG" height="213" width="288"/>
<media:title type="plain">IMG_2034.JPG</media:title>
</media:group>
<georss:where>
<gml:Point>
<gml:pos>37.6955972 -122.4339361</gml:pos>
</gml:Point>
</georss:where>
</entry>
<entry>
<id>https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6041225428268790466</id>
<published>2014-07-28T21:20:04.000Z</published>
<updated>2014-07-28T22:20:42.270Z</updated>
<category scheme="http://schemas.google.com/g/2005#kind" term="http://schemas.google.com/photos/2007#photo"/>
<title type="text">VID_20140728_141919.mp4</title>
<summary type="text"/>
<content type="image/gif" src="https://lh3.googleusercontent.com/-STi02l3-QBE/U9a-hOwEssI/AAAAAAAAAC0/ljSrrqKjShE/I/VID_20140728_141919.gif"/>
<link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="https://picasaweb.google.com/data/feed/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6041225428268790466"/>
<link rel="alternate" type="text/html" href="https://picasaweb.google.com/114403741484702971746/BikingWithBlake#6041225428268790466"/>
<link rel="http://schemas.google.com/photos/2007#canonical" type="text/html" href="https://picasaweb.google.com/lh/photo/Cf4wdphhOQS3yBMxfmeZZNMTjNZETYmyPJy0liipFm0"/>
<link rel="self" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6041225428268790466"/>
<link rel="edit" type="application/atom+xml" href="https://picasaweb.google.com/data/entry/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6041225428268790466/9"/>
<link rel="edit-media" type="image/jpeg" href="https://picasaweb.google.com/data/media/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6041225428268790466/9"/>
<link rel="media-edit" type="image/jpeg" href="https://picasaweb.google.com/data/media/api/user/114403741484702971746/albumid/6040139514831220113/photoid/6041225428268790466/9"/>
<link rel="http://schemas.google.com/photos/2007#report" type="text/html" href="https://picasaweb.google.com/lh/reportAbuse?uname=114403741484702971746&amp;aid=6040139514831220113&amp;iid=6041225428268790466"/>
<gphoto:id>6041225428268790466</gphoto:id>
<gphoto:version>9</gphoto:version>
<gphoto:position>1.0</gphoto:position>
<gphoto:albumid>6040139514831220113</gphoto:albumid>
<gphoto:access>only_you</gphoto:access>
<gphoto:videostatus>final</gphoto:videostatus>
<gphoto:originalvideo width="1920" height="1080" type="MOV" duration="1" channels="1" samplingrate="48.0" videoCodec="H264" audioCodec="AAC" fps="29.833334"/>
<gphoto:width>854</gphoto:width>
<gphoto:height>480</gphoto:height>
<gphoto:size>3289621</gphoto:size>
<gphoto:client>pwa</gphoto:client>
<gphoto:checksum/>
<gphoto:timestamp>1406607562000</gphoto:timestamp>
<gphoto:imageVersion>45</gphoto:imageVersion>
<gphoto:commentingEnabled>true</gphoto:commentingEnabled>
<gphoto:commentCount>0</gphoto:commentCount>
<gphoto:streamId>shared_group_6041225428268790466</gphoto:streamId>
<gphoto:license id="0" name="All Rights Reserved" url="">ALL_RIGHTS_RESERVED</gphoto:license>
<gphoto:shapes faces="done"/>
<exif:tags>
<exif:imageUniqueID>78d317eb33e596180000000000000000</exif:imageUniqueID>
</exif:tags>
<media:group>
<media:content url="https://lh3.googleusercontent.com/-STi02l3-QBE/U9a-hOwEssI/AAAAAAAAAC0/ljSrrqKjShE/I/VID_20140728_141919.gif" height="480" width="854" type="image/gif" medium="image"/>
<media:content url="https://redirector.googlevideo.com/videoplayback?requiressl=yes&amp;shardbypass=yes&amp;cmbypass=yes&amp;id=bd73dcba2da276ec&amp;itag=18&amp;source=picasa&amp;cmo=secure_transport%3Dyes&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=1409241526&amp;sparams=requiressl,shardbypass,cmbypass,id,itag,source,ip,ipbits,expire&amp;signature=83B789FDE8A4B67C6CF8C3734274DC5EEA7048DD.D62C52CA7E0D523E98828902D7D236F95AD6F65F&amp;key=lh1" height="360" width="640" type="video/mpeg4" medium="video"/>
<media:content url="https://redirector.googlevideo.com/videoplayback?requiressl=yes&amp;shardbypass=yes&amp;cmbypass=yes&amp;id=bd73dcba2da276ec&amp;itag=34&amp;source=picasa&amp;cmo=secure_transport%3Dyes&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=1409241526&amp;sparams=requiressl,shardbypass,cmbypass,id,itag,source,ip,ipbits,expire&amp;signature=217D84462A42D4CB88B09F75B047C68F4241A9DF.B98B88E4A5A125F4A3796C22CF494CF1154AF38C&amp;key=lh1" height="360" width="640" type="application/x-shockwave-flash" medium="video"/>
<media:content url="https://redirector.googlevideo.com/videoplayback?requiressl=yes&amp;shardbypass=yes&amp;cmbypass=yes&amp;id=bd73dcba2da276ec&amp;itag=35&amp;source=picasa&amp;cmo=secure_transport%3Dyes&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=1409241526&amp;sparams=requiressl,shardbypass,cmbypass,id,itag,source,ip,ipbits,expire&amp;signature=10070B78812CE54BCE0528FAE5453D1BF54959E5.2A1C9043CED774A59854E56556893A4891777D75&amp;key=lh1" height="480" width="854" type="application/x-shockwave-flash" medium="video"/>
<media:content url="https://redirector.googlevideo.com/videoplayback?requiressl=yes&amp;shardbypass=yes&amp;cmbypass=yes&amp;id=bd73dcba2da276ec&amp;itag=22&amp;source=picasa&amp;cmo=secure_transport%3Dyes&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=1409241526&amp;sparams=requiressl,shardbypass,cmbypass,id,itag,source,ip,ipbits,expire&amp;signature=3D7F7A631ADF6B1A8220E3571E60AF6DF77274AE.DAD9E2C950E278F57653E2AE93F36F8D6235FDBC&amp;key=lh1" height="720" width="1280" type="video/mpeg4" medium="video"/>
<media:content url="https://foo.googlevideo.com/bar.mp4" height="1080" width="1920" type="video/mpeg4" medium="video"/>
<media:credit>Gast Erson</media:credit>
<media:description type="plain"/>
<media:keywords>keyboard, stuff</media:keywords>
<media:thumbnail url="https://lh3.googleusercontent.com/-STi02l3-QBE/U9a-hOwEssI/AAAAAAAAAC0/jYJqb4T2I4E/s72/VID_20140728_141919.png" height="41" width="72"/>
<media:thumbnail url="https://lh3.googleusercontent.com/-STi02l3-QBE/U9a-hOwEssI/AAAAAAAAAC0/jYJqb4T2I4E/s144/VID_20140728_141919.png" height="81" width="144"/>
<media:thumbnail url="https://lh3.googleusercontent.com/-STi02l3-QBE/U9a-hOwEssI/AAAAAAAAAC0/jYJqb4T2I4E/s288/VID_20140728_141919.png" height="162" width="288"/>
<media:title type="plain">VID_20140728_141919.mp4</media:title>
</media:group>
<georss:where>
<gml:Point>
<gml:pos>37.7447 -122.434</gml:pos>
</gml:Point>
</georss:where>
</entry>
</feed>