#!/usr/bin/perl use strict; use warnings; use utf8; use Encode::JP; # to import this module into an exe file which will be generated by PAR Packager use File::Spec::Functions qw(catfile); use File::Path qw(mkpath); use URI::Split qw(uri_split); use LWP::Simple; use JSON; use Getopt::Long qw(:config auto_help); use Pod::Usage qw(pod2usage); use Data::Dumper; # Gets options and analyzes them. my %options = ( outdir => 'img' ); Getopt::Long::GetOptions(\%options, qw(outdir=s proxy=s useragent=s)) or pod2usage(2); pod2usage(1) if ($options{help}); # Configures network settings. (Not checked whether it works...) if ($options{proxy}) { $LWP::Simple::ua->proxy('http', $options{proxy}); } if ($options{useragent}) { $LWP::Simple::ua->agent($options{useragent}); } # Gets the hash ID of photo contest from the homepage. (This scraping mechanism is not robust...) my $id_hash; if ($#ARGV >= 0) { $id_hash = $ARGV[0]; } else { my $homepage = get('http://hiroba.dqx.jp/sc/'); if ($homepage =~ /photoContestIdHash\s*=\s*['"](\w+)['"]/g) { $id_hash = $1; } } pod2usage(1) if (!$id_hash); my $interval_sec = 30; my $next_time = time; for (;;) { # Waits for the next time. my $cur_time = time; if ($cur_time < $next_time) { sleep 1; next; } # Makes the URL string and the download file path. # my $jsonp_url = 'http://cache.hiroba.dqx.jp/dq_resource/img/event/kbEKx/shot_h.jsonp?' . $cur_time; # my $jsonp_url = 'http://cache.hiroba.dqx.jp/dq_resource/img/event/Q8qbx/shot_h.jsonp?' . $cur_time; # my $jsonp_url = 'http://cache.hiroba.dqx.jp/dq_resource/img/event/S37gg/shot_h.jsonp?' . $cur_time; # my $jsonp_url = 'http://cache.hiroba.dqx.jp/dq_resource/img/event/DMgNz/shot_h.jsonp?' . $cur_time; my $jsonp_url = "http://cache.hiroba.dqx.jp/dq_resource/img/event/$id_hash/shot_h.jsonp?$cur_time"; # Makes a directory for images. unless (-d $options{outdir}) { mkpath($options{outdir}); } # Gets a JSONP data that contains the url of the image (and so on.) my $json = get($jsonp_url); unless ($json) { next; } $json =~ s/^[^\(]*\((.*)\)/$1/; # Adhoc way to convert JSONP to JSON. my $info = from_json($json); # Makes filename of image and text. my $image_url = $info->{liveCamValueList}->[0]->{FileNameLarge}; my (undef, undef, $image_filename, undef, undef) = uri_split($image_url); $image_filename =~ s/.*\/(.*)$/$1/; if ($image_filename eq '') { $image_filename = $cur_time; } my ($basename) = ($image_filename =~ /^([^\.]+)/); my $text_filename = $basename . '.txt'; if ($image_filename eq $basename) { $image_filename .= '.jpg'; } # Gets an image from the DQX server. my $image_outpath = catfile($options{outdir}, $image_filename); unless (-f $image_outpath) { printf "GET %s -> %s: ", $image_url, $image_outpath; my $rescode = getstore($image_url, $image_outpath); printf "%d %s\n", $rescode, is_success($rescode) ? 'OK' : 'NG'; } else { printf "Skipped %s: %s already exists\n", $image_url, $image_outpath; } # Outputs the information about the image. my $text_outpath = catfile($options{outdir}, $text_filename); unless (-f $text_outpath) { open(my $fh, '>:utf8', $text_outpath) or die "$!"; print $fh "作品タイトル: $info->{liveCamValueList}->[0]->{ZoneName}\n"; print $fh "さつえい者: $info->{liveCamValueList}->[0]->{WorldName}\n"; print $fh "URL: $image_url\n"; close $fh; } while ($next_time <= $cur_time) { $next_time += $interval_sec; } } __END__ =head1 NAME dqxsnapslide - Gets the slide images from the DRAGON QUEST web server. =head1 SYNOPSIS dqxlivecam [options] --outdir A string of output directory for image files. Default is "img". (under the current directory) --proxy A string of proxy host name. --useragent A string of user agent. --help Print this message. If photoContestIdHash is not specified, it'll be obtained from the homepage of DRAGON QUEST web server by very simple analysis mechanism. =cut