{"id":622,"date":"2005-03-22T05:20:00","date_gmt":"2005-03-22T12:20:00","guid":{"rendered":"http:\/\/kodegeek.com\/blog\/?p=622"},"modified":"2005-03-22T05:20:00","modified_gmt":"2005-03-22T12:20:00","slug":"echando-codigo-%c2%bfcomo-puedo-respaldar-mis-fotos-de-las-cuentas-gratis-de-flickr-usando-perl","status":"publish","type":"post","link":"http:\/\/kodegeek.com\/blog\/2005\/03\/22\/echando-codigo-%c2%bfcomo-puedo-respaldar-mis-fotos-de-las-cuentas-gratis-de-flickr-usando-perl\/","title":{"rendered":"Echando c\u00f3digo: \u00bfComo puedo respaldar mis fotos de las cuentas gr\u00e1tis de Flickr, usando Perl?"},"content":{"rendered":"<p>Hice <a href=\"http:\/\/www.flickr.com\/forums\/help\/5304\/\">la misma pregunta<\/a> en el foro de ayuda de <span style=\"font-style: italic;\">Flickr<\/span>; Despu\u00e9s de 3 horas uno de sus empleados me indic\u00f3 lo siguiente:       <\/p>\n<h4>                <a href=\"http:\/\/www.flickr.com\/photos\/eric\/\"><\/a><\/h4>\n<blockquote>\n<h4><a href=\"http:\/\/www.flickr.com\/photos\/eric\/\">Eric<\/a>         <img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.flickr.com\/images\/badge_staff.gif\" alt=\"Flickr Staff\" style=\"border: medium none ; vertical-align: bottom;\" height=\"16\" width=\"27\" \/>         says:<\/h4>\n<p>         Sorry for the lack of reply to your email josevnz!<\/p>\n<p>I&#8217;m afraid there is no way to do this automatically. You&#8217;ll have to download the photos from the free accounts one by one and re-upload them to your new account.<br \/><span class=\"PostDateTime\">          Posted 3 hours ago.           ( <a href=\"http:\/\/www.flickr.com\/forums\/help\/5304\/26581\/\" class=\"PostLinks\">Permalink<\/a>           )         <\/span>        <\/p>\n<\/blockquote>\n<p><span style=\"font-weight: bold; font-style: italic;\">\u00a1Que ladilla!. <\/span>As\u00ed que empec\u00e9 a echarle cabeza a la vaina, para ver si pod\u00eda evitarme esa ladilla o por lo menos minimizar el da\u00f1o.<\/p>\n<p>Despu\u00e9s de mucho pelear con uno de las personas de soporte (<span style=\"font-style: italic;\">co\u00f1o, estoy pagando, \u00bfno?<\/span>), este me di\u00f3 una idea:<\/p>\n<h4>                <a href=\"http:\/\/www.flickr.com\/photos\/eric\/\"><\/a><\/h4>\n<blockquote>\n<h4><a href=\"http:\/\/www.flickr.com\/photos\/eric\/\">Eric<\/a>         <img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.flickr.com\/images\/badge_staff.gif\" alt=\"Flickr Staff\" style=\"border: medium none ; vertical-align: bottom;\" height=\"16\" width=\"27\" \/>         says:<\/h4>\n<p><span style=\"font-style: italic;\"> Well, it is a pain I know<\/span> but you can actually pull your original sizes by hacking the url. They will end with &#8220;_o.jpg&#8221; (assuming they are jpgs), so just change the end of the url of your &#8220;resized versions&#8221; to &#8220;_o.jpg&#8221; and you&#8217;ll have your original.<\/p>\n<p>So <a href=\"http:\/\/photos6.flickr.com\/6697434_8332121f37_s.jpg\">photos6.flickr.com\/6697434_8332121f37_s.jpg<\/a> would become <a href=\"http:\/\/photos6.flickr.com\/6697434_8332121f37_o.jpg\">photos6.flickr.com\/6697434_8332121f37_o.jpg<\/a><br \/><span class=\"PostDateTime\">          Posted 3 hours ago.           ( <a href=\"http:\/\/www.flickr.com\/forums\/help\/5304\/26630\/\" class=\"PostLinks\">Permalink<\/a>           )         <\/span>        <\/p>\n<\/blockquote>\n<p>Resulta que <a href=\"http:\/\/www.flickr.com\/services\/api\/\">la documentaci\u00f3n de el API de Flickr<\/a> dice como <a href=\"http:\/\/www.flickr.com\/services\/api\/misc.urls.html\">generar el URL<\/a>. As\u00ed que me baje la clave del API y me decid\u00ed a bajar un wrapper en Perl ya que me daba una ladilla increible utilizar un protocolo de bajo nivel para obtener todos los nombres y para generar los URL:<\/p>\n<p>Al final me decid\u00ed a atacar el problema as\u00ed:<\/p>\n<ol>\n<li>Se perezoso. Busca un wrapper para el API de Flickr para evitar lidiar con detalles de bajo nivel.<\/li>\n<li>Obtener el identificador de un usuario de Flickr.<\/li>\n<li>Obtener el listado de todas fotos publicas para un identificador de usuario dado.<\/li>\n<li>Bajarse las fotos a un directorio local mientras se recorre la lista de fotos. Eso requiere que armemos el URL a mano.<\/li>\n<\/ol>\n<p> Primero instalamos el modulo de Perl para Flickr, <a href=\"http:\/\/search.cpan.org\/%7Eiamcal\/Flickr-API\/\">Flickr::API<\/a>:<\/p>\n<blockquote><p>[root@localhost root]# <span style=\"color: rgb(0, 153, 0);\">perl -MCPAN -e&#8217;install Flickr::API<\/span><\/p><\/blockquote>\n<p><span style=\"font-style: italic;\">Tiene un co\u00f1azo de dependencias<\/span>. Pero por lo menos en Fedora Core 2 se dej\u00f3 sin chistar \ud83d\ude42<\/p>\n<p>Luego a echar c\u00f3digo. Despu\u00e9s de <span style=\"font-style: italic;\">3 cervezas Corona<\/span> y dos discos completos de Metallica (<span style=\"font-style: italic;\">Reload y Saint Anger<\/span>), el programa estaba listo:<\/p>\n<style type=\"text\/css\"><!-- .syntax0 { color: #000000; } .syntax1 { color: #cc0000; } .syntax2 { color: #ff8400; } .syntax3 { color: #6600cc; } .syntax4 { color: #cc6600; } .syntax5 { color: #ff0000; } .syntax6 { color: #9966ff; } .syntax7 { background: #ffffcc; color: #ff0066; } .syntax8 { color: #006699; font-weight: bold; } .syntax9 { color: #009966; font-weight: bold; } .syntax10 { color: #0099ff; font-weight: bold; } .syntax11 { color: #66ccff; font-weight: bold; } .syntax12 { color: #02b902; } .syntax13 { color: #ff00cc; } .syntax14 { color: #cc00cc; } .syntax15 { color: #9900cc; } .syntax16 { color: #6600cc; } .syntax17 { color: #0000ff; } .syntax18 { color: #000000; font-weight: bold; } .gutter { background: #dbdbdb; color: #000000; } .gutterH { background: #dbdbdb; color: #990066; } --><br \/><\/style>\n<p><\/p>\n<pre><span class=\"gutter\">   1:<\/span>#!\/usr\/bin\/perl<br \/><span class=\"gutter\">   2:<\/span>use strict;<br \/><span class=\"gutter\">   3:<\/span>use Flickr::API;<br \/><span class=\"gutter\">   4:<\/span>use Data::Dumper;<br \/><span class=\"gutterH\">   5:<\/span>use LWP::UserAgent;<br \/><span class=\"gutter\">   6:<\/span><br \/><span class=\"gutter\">   7:<\/span><br \/><span class=\"gutter\">   8:<\/span>use constant API_KEY  =&gt; 'a8a57025bbe0f7d1889b6cb6d754ad7b';<br \/><span class=\"gutter\">   9:<\/span>use constant PER_PAGE =&gt; 500;<br \/><span class=\"gutterH\">  10:<\/span>use constant PAGE     =&gt; 1;<br \/><span class=\"gutter\">  11:<\/span>use constant DEBUG    =&gt; 0;<br \/><span class=\"gutter\">  12:<\/span><br \/><span class=\"gutter\">  13:<\/span>if (! defined $ARGV[0]) {<br \/><span class=\"gutter\">  14:<\/span>        die \"[ERROR]: Please provide the user ID!\";<br \/><span class=\"gutterH\">  15:<\/span>} else {<br \/><span class=\"gutter\">  16:<\/span>        printf \"Getting list of public pictures for '%s'\\n\", $ARGV[0];<br \/><span class=\"gutter\">  17:<\/span>}<br \/><span class=\"gutter\">  18:<\/span>my $api = new Flickr::API({<br \/><span class=\"gutter\">  19:<\/span>                'key' =&gt; API_KEY}<br \/><span class=\"gutterH\">  20:<\/span>                );<br \/><span class=\"gutter\">  21:<\/span>my $ua = LWP::UserAgent-&gt;new;<br \/><span class=\"gutter\">  22:<\/span># Get the user NSID first<br \/><span class=\"gutter\">  23:<\/span>my $response = $api-&gt;execute_method(<br \/><span class=\"gutter\">  24:<\/span>        'flickr.people.findByUsername', {<br \/><span class=\"gutterH\">  25:<\/span>                'username'  =&gt; $ARGV[0]<br \/><span class=\"gutter\">  26:<\/span>        });<br \/><span class=\"gutter\">  27:<\/span>if (! $response-&gt;{success}) {<br \/><span class=\"gutter\">  28:<\/span>        die \"[ERROR]: \" . $response-&gt;{error_message} . \" ($ARGV[0])\";<br \/><span class=\"gutter\">  29:<\/span>}<br \/><span class=\"gutterH\">  30:<\/span># Parse the tree and get the NSID<br \/><span class=\"gutter\">  31:<\/span>my %tree = %{$response-&gt;{tree}};<br \/><span class=\"gutter\">  32:<\/span># Cheat with 'print Dumper($tree);' to get the value I want right away<br \/><span class=\"gutter\">  33:<\/span>my $id = $tree{children}-&gt;[1]-&gt;{attributes}-&gt;{nsid};<br \/><span class=\"gutter\">  34:<\/span>if (DEBUG) {<br \/><span class=\"gutterH\">  35:<\/span>        printf \"%s\\n\", $id;<br \/><span class=\"gutter\">  36:<\/span>}<br \/><span class=\"gutter\">  37:<\/span># Get now the list of public photos<br \/><span class=\"gutter\">  38:<\/span>$response = $api-&gt;execute_method(<br \/><span class=\"gutter\">  39:<\/span>        'flickr.photos.search', {<br \/><span class=\"gutterH\">  40:<\/span>                'user_id'  =&gt; $id<br \/><span class=\"gutter\">  41:<\/span>        });<br \/><span class=\"gutter\">  42:<\/span>%tree = %{$response-&gt;{tree}};<br \/><span class=\"gutter\">  43:<\/span># Get the photo information. For that we get a more manageable structure<br \/><span class=\"gutter\">  44:<\/span>my @subtree = @{$tree{children}-&gt;[1]-&gt;{children}};<br \/><span class=\"gutterH\">  45:<\/span>if (DEBUG) {<br \/><span class=\"gutter\">  46:<\/span>        print Dumper(\\@subtree);<br \/><span class=\"gutter\">  47:<\/span>}<br \/><span class=\"gutter\">  48:<\/span>foreach my $ref (@subtree) {<br \/><span class=\"gutter\">  49:<\/span>        my $attributes = $$ref{attributes};<br \/><span class=\"gutterH\">  50:<\/span>        next if $attributes == undef;<br \/><span class=\"gutter\">  51:<\/span>        # Construct the URL like this:<br \/><span class=\"gutter\">  52:<\/span>        # http:\/\/photos{server-id}.flickr.com\/{id}_{secret}_o.(jpg|gif|png)<br \/><span class=\"gutter\">  53:<\/span>        my $url = \"http:\/\/photos\" .<br \/><span class=\"gutter\">  54:<\/span>                $$attributes{'server'} .<br \/><span class=\"gutterH\">  55:<\/span>                \".flickr.com\/\" .<br \/><span class=\"gutter\">  56:<\/span>                $$attributes{'id'} .<br \/><span class=\"gutter\">  57:<\/span>                \"_\" .<br \/><span class=\"gutter\">  58:<\/span>                $$attributes{'secret'} .<br \/><span class=\"gutter\">  59:<\/span>                \"_o.jpg\";<br \/><span class=\"gutterH\">  60:<\/span>        printf \"Downloading: %s -&gt; %s...\", $$attributes{'title'}, $url;<br \/><span class=\"gutter\">  61:<\/span>        $ua-&gt;mirror(<br \/><span class=\"gutter\">  62:<\/span>                $url,<br \/><span class=\"gutter\">  63:<\/span>                $$attributes{'id'} . \"_\" . $$attributes{'secret'} . \"_o.jpg\"<br \/><span class=\"gutter\">  64:<\/span>                );<br \/><span class=\"gutterH\">  65:<\/span>        if ($response-&gt;is_success) {<br \/><span class=\"gutter\">  66:<\/span>                printf \"OK\\n\";<br \/><span class=\"gutter\">  67:<\/span>        } else {<br \/><span class=\"gutter\">  68:<\/span>                printf \"ERROR\\n\";<br \/><span class=\"gutter\">  69:<\/span>        }<br \/><span class=\"gutterH\">  70:<\/span><br \/><span class=\"gutter\">  71:<\/span>}<br \/><span class=\"gutter\">  72:<\/span>__END__<br \/><\/pre>\n<p>El programa se corre as\u00ed:<\/p>\n<blockquote><p>[josevnz@localhost fotos]$ <span style=\"color: rgb(0, 153, 0);\">..\/DownloadPublicPictures.plx josevnz2<\/span><br \/>Getting list of public pictures for &#8216;josevnz2&#8217;<br \/>Downloading: I95 snow -> http:\/\/photos5.flickr.com\/4746321_036bd281f6_o.jpg&#8230;OK<br \/>Downloading: Teatro Avon Enero 2005 -> http:\/\/photos5.flickr.com\/4746319_215f0d4490_o.jpg&#8230;OK<br \/>Downloading: mudanza de servidores -> http:\/\/photos4.flickr.com\/4640875_5e09991db5_o.jpg&#8230;OK<br \/>Downloading: rack de servidores -> http:\/\/photos3.flickr.com\/4640874_8c8648dd32_o.jpg&#8230;OK<br \/>Downloading: Lanzamiento de CVEBrowser -> http:\/\/photos3.flickr.com\/4592140_5037d50d90_o.jpg&#8230;OK<br \/>Downloading: Montes East Village Manhattan New York -> http:\/\/photos4.flickr.com\/4294649_99a73efb94_o.jpg&#8230;OK<br \/>Downloading: The Olive Tree East Village Manhattan New York -> http:\/\/photos1.flickr.com\/4294648_f867326f0a_o.jpg&#8230;OK<br \/>Downloading: mazinger-flash -> http:\/\/photos3.flickr.com\/4177404_b1ba64e2f9_o.jpg&#8230;OK<br \/>Downloading: Regalos de cumplea\u00f1os: DVD -> http:\/\/photos4.flickr.com\/4145436_781e968181_o.jpg&#8230;OK<br \/>Downloading: Ipod Edici\u00f3n Especial de U2: El objeto de mi deseo -> http:\/\/photos3.flickr.com\/3573557_0d1a452590_o.jpg&#8230;OK<br \/>Downloading: Stamford Enero 2005: Frio maldito -> http:\/\/photos2.flickr.com\/3573556_1bdc308657_o.jpg&#8230;OK<br \/>Downloading: The Aviator -> http:\/\/photos3.flickr.com\/3571985_583e39b9f3_o.jpg&#8230;OK<br \/>Downloading: Blood Rayne 1 y Blood Rayne 2: Las sagas -> http:\/\/photos3.flickr.com\/3526934_7d3a658771_o.jpg&#8230;OK<br \/>Downloading: Blood Rayne 2: Yo tomando un descanzo -> http:\/\/photos3.flickr.com\/3526930_520f38ac88_o.jpg&#8230;OK<br \/>Downloading: Blood Rayne 2: Final -> http:\/\/photos3.flickr.com\/3526927_e64cb0a886_o.jpg&#8230;OK<br \/>Downloading: Battlestar Galatica site -> http:\/\/photos3.flickr.com\/3431907_6819a3c7bc_o.jpg&#8230;OK<\/p><\/blockquote>\n<p>\u00a1Chevere!. Ya con esto me baj\u00e9 todas mis fotos :D. Por cierto, para dejar varias fotos a la vez en Flickr, yo utilizo <a href=\"http:\/\/micampe.it\/things\/flickruploadr\">FlickrUploadr<\/a>, bien sencilla de usar (escrita en Python) y sobre todo, trabaja muy bien bajo Linux&#8230;<\/p>\n<p>Como siempre <a href=\"http:\/\/prdownloads.sourceforge.net\/elangelnegro\/DownloadPublicPictures.plx?download\">les dejo el c\u00f3digo fuente<\/a> para que se diviertan.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hice la misma pregunta en el foro de ayuda de Flickr; Despu\u00e9s de 3 horas uno de sus empleados me indic\u00f3 lo siguiente: Eric says: Sorry for the lack of reply to your email josevnz! I&#8217;m afraid there is no way to do this automatically. You&#8217;ll have to download the photos from the free accounts <a class=\"read-more\" href=\"http:\/\/kodegeek.com\/blog\/2005\/03\/22\/echando-codigo-%c2%bfcomo-puedo-respaldar-mis-fotos-de-las-cuentas-gratis-de-flickr-usando-perl\/\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[],"tags":[],"_links":{"self":[{"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/posts\/622"}],"collection":[{"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/comments?post=622"}],"version-history":[{"count":0,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/posts\/622\/revisions"}],"wp:attachment":[{"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/media?parent=622"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/categories?post=622"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/kodegeek.com\/blog\/wp-json\/wp\/v2\/tags?post=622"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}