✖
✖
Picasa web の画像
Picasa web の画像って直接貼れるんだなあ。あと URL 中の s700 とかを s1920 とか s280 に変えると自由な画像サイズになる。でも恒久的なURLである根拠がないので、安心してはる感じにはならない…… と思って根拠をさがした。
<img src="/images/entry/IMG_7521-1920.jpg"/>
https://picasaweb.google.com/114431815111528304586/2011128#5683411105636128482
一通りさがして、ないなーと思ったけど、アルバムのページには「HTML を貼り付けてウェブサイトに埋め込む」というのがあって、この中の img は上記のような形式のURLになっているので、不変と思ってよさそうな気がする。
FAQ には
You can only embed images into a webpage that are 800 pixels or smaller along the largest dimension.
と書いてあって、800px までなら自由に貼れるように読める。たぶん 800px ってのは Google+ が出る前の基準な気がするので (根拠なし)、今は 2048px まで貼れるのかな…… 一応、安全にウェブサイトに貼れるのは 800px までっぽい。
画像ストレージ再考
自分のサーバーに画像を置くのは厳しい。
- 容量的
- 借りているサーバーのネットワークスピード
とかがあるので、できればウェブサービスに置いておきたいという要求があり、今のところはてなフォトライフを使っている。はてなフォトライフは無料でも30MB/月で十分だろうというのと、CDN (アカマイ) を経由していて、画像サイズに制限がないのもよい。
Picasa も昔検討したことがあって、そのときは 800px までしか無料でアップロードできず諦めたのだけれど、Google+ のリリースにより 2048px までは容量にカウントされない、すなわち実質的容量無制限になったので、候補にあがってきた。ネットワーク的にも Google の配信なので信頼がおける。
Picasa を使うとして
しかし Picasa はインターフェイス的に僕にはちょっと使いにくい感じなのと、画像を簡単に貼りつけられる方法がないのがネックになっている。前者はたぶん慣れれば大丈夫なので、後者は実装で解決してみたい。
アップロードとかは Picasa 側でやるので、最新のアップロード画像から貼りつけるインターフェイスだけ実装することを考えたが、Picasa がユーザーの最新画像のフィードを吐いていないようなので、それをなんとかして作るところからになった。
写真一覧のフィードは調べていたら普通にあった…
撮った時刻でソートするようにした
そもそも PIcasa 側で JSONP に対応していることがわかった
404 Not Found に普通に書いてあった。リファレンスの読みかたがよくわかっていなかった…
✖
✖
写真にもっとメタデータを書いておかないといけないんだろうけど、面倒くさくて無理なんだよなあ…… なんか簡単にできればいいのかな
✖
「餡の雲」で検索するといつのまにやら知らない人が出てくるようになっていて、なんか嫌な感じだし、それなりに愛着はあるけど、それほどこだわりもないしサイト名を変えたい…… 。でもいい名前が思いつかない。
✖
いろいろやって、ページのロード速度を改善してみた。
✖
サイト名を「氾濫原」に変えた。他人にとってあまり意味がない言葉で、かつ自分にとってある程度意味がある言葉、というのにしたくていろいろ悩んだ。
microdata を適当に抜き出す Perl スクリプト
あんまり仕様書読みこめてないけど書くだけ書いてみた。CPAN にあるのは依存がひどいし、別に HTML::Parser 的なもの一個の依存で JSON 返すようなのでいいじゃんと思った。やる気があればテスト書いて CPAN にあげたりしたいけど、あんまりやる気わかない。
結局 HTML::Parser ではなく HTML::TreeBuilder::LibXML にしたけど、普通に入るモジュールなのでよさそう。
レポジトリをつくってテストを書いた。
https://github.com/cho45/HTML-Microdata/blob/master/lib/HTML/Microdata.pm
use v5.12;
use LWP::Simple qw($ua);
use URI;
use JSON::XS;
my $uri = URI->new('http://www.lowreal.net/');
my $res = $ua->get($uri);
my $microdata = HTML::Microdata->parse($res->content);
say encode_json $microdata->items->{cho45}->{properties};
package HTML::Microdata;
use HTML::TreeBuilder::LibXML;
use Scalar::Util qw(refaddr);
use Hash::MultiValue;
sub new {
my ($class, $args) = @_;
bless {
items => {},
}, $class;
}
sub parse {
my ($class, $content, $opts) = @_;
my $self = $class->new($opts);
$self->_parse($content);
$self
}
sub items {
my ($self) = @_;
$self->{items};
}
sub _parse {
my ($self, $content) = @_;
my $tree = HTML::TreeBuilder::LibXML->new_from_content($content);
my $scopes = $tree->findnodes('//*[@itemscope]');
my $number = 0;
for my $scope (@$scopes) {
my $type = $scope->attr('itemtype');
my $id = $scope->attr('itemid');
unless ($scope->id) {
$scope->id($number++);
}
if (my $refs = $scope->attr('itemref')) {
my $ids = [ split /\s+/, $refs ];
for my $id (@$ids) {
my $props = $tree->findnodes('//*[\@id="' . $id . '"]//*[\@itemprop]');
for my $prop (@$props) {
my $name = $prop->attr('itemprop');
my $value = $self->extract_value($prop);
$self->{items}->{ $scope->id }->add($name => $value);
}
}
}
$self->{items}->{ $scope->id } = {
($id ? (id => $id) : ()),
type => $type,
properties => Hash::MultiValue->new,
};
}
my $props = $tree->findnodes('//*[@itemprop]');
for my $prop (@$props) {
my $name = $prop->attr('itemprop');
my $value = $self->extract_value($prop);
my $scope = $prop->findnodes('./ancestor::*[@itemscope]')->[-1];
$self->{items}->{ $scope->id }->{properties}->add($name => $value);
}
for my $key (keys %{ $self->{items} }) {
my $item = $self->{items}->{$key};
$item->{properties} = $item->{properties}->multi;
}
}
sub extract_value {
my ($self, $prop) = @_;
my $value;
if (defined $prop->attr('itemscope')) {
$value = $self->{items}->{ $prop->id };
} elsif ($prop->tag eq 'meta') {
$value = $prop->attr('content');
} elsif ($prop->tag =~ m{^audio|embed|iframe|img|source|video$}) {
$value = $prop->attr('src');
} elsif ($prop->tag =~ m{^a|area|link$}) {
$value = $prop->attr('href');
} elsif ($prop->tag eq 'object') {
$value = $prop->attr('data');
} elsif ($prop->tag eq 'time' && $prop->attr('datetime')) {
$value = $prop->attr('datetime');
} else {
$value = $prop->findvalue('normalize-space(.)');
}
$value;
}