Created
September 28, 2017 10:29
-
-
Save gfldex/000b2c3e8da1c3f77837ef5f643a1ecd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! /usr/bin/env perl6 | |
use v6.c; | |
use WWW::RadioBrowser; | |
say 'start'; | |
my &GREEN = $*OUT.t ?? sub (**@s) { "\e[32m{@s.join('')}\e[0m" } !! sub (|c) { c }; | |
my &RED = $*OUT.t ?? sub (**@s) { "\e[31m{@s.join('')}\e[0m" } !! sub (|c) { c }; | |
# my @stations = internet-radio-stations-update; | |
# say +@stations; | |
say GREEN internet-radio-stations-state; | |
react { | |
whenever internet-radio-update-progress { | |
say GREEN .Str; | |
when storing { | |
say GREEN internet-radio-stations-state; | |
my $counter; | |
$counter++ for internet-radio-stations(); | |
say $counter; | |
# { | |
# for .item.kv -> $k, $v { | |
# # say $k, ‚: ‘, $v, ‚ ‘, $v.WHAT; | |
# } | |
# } | |
} | |
when ready { | |
whenever Promise.in(2) { done } | |
} | |
} | |
whenever radio-browser-debug { | |
say RED .Str; | |
} | |
} | |
sub dump-structure(\v, $level is copy = 0){ | |
say " " x $level, v.WHAT; | |
$level++; | |
v».&dump-structure($level) if v ~~ Iterable; | |
} | |
# dump-structure internet-radio-stations-deleted[0]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use v6.c; | |
use WWW; | |
use JSON::Fast; | |
# my ¬e = $*OUT.t ?? sub (**@s) { $*ERR.put: "{now.DateTime.Str} \e[1m{@s.join('')}\e[0m" } !! sub (|c) { $*ERR.say: c }; | |
constant term:<GMT> = :timezone(0); | |
my $cfg-dir = „$*HOME/.config“.IO.e ?? „$*HOME/.config/perl6-www-radiobrowser“ !! „$*HOME/.perl6-www-radiobrowser“; | |
mkdir $cfg-dir unless $cfg-dir.IO.e; | |
enum InternetRadioStationsState is export <setup fetching reading processing storing ready error>; | |
constant internet-radio-update-progress is export = Supplier.new; | |
constant radio-browser-debug is export = Supplier.new; | |
# my ¬e = sub (**@s){ radio-browser-debug.emit: DateTime.now.hh-mm-ss ~ ': ' ~ @s.join } | |
my @cache; | |
my $cache-state = setup; | |
start { | |
@cache = internet-radio-stations-update(); | |
} | |
sub internet-radio-stations() is export { | |
@cache | |
} | |
sub internet-radio-stations-state() is export { | |
$cache-state; | |
} | |
sub change-state(InternetRadioStationsState $s){ | |
$cache-state = $s; | |
internet-radio-update-progress.emit: $s | |
} | |
sub ISO8601(DateTime:D $dt) { | |
sub zPad(Str(Any) $s, int $p){'0' x $p - $s.chars ~ $s} | |
( 0 > $dt.year ?? '-'~ zPad( $dt.year.abs, 4 ) !! | |
$dt.year <= 9999 ?? zPad( $dt.year, 4 ) | |
!! '+'~ zPad( $dt.year, 5 ) ) ~'-'~ | |
zPad( $dt.month, 2 ) ~'-'~ zPad( $dt.day, 2 ) ~'T'~ | |
zPad( $dt.hour, 2 ) ~':'~ zPad( $dt.minute, 2 ) ~':'~ | |
( $dt.second.floor == $dt.second | |
?? zPad( $dt.second.Int, 2 ) | |
!! $dt.second.fmt('%09.6f') ) | |
~ | |
( $dt.timezone == 0 | |
?? 'Z' | |
!! $dt.timezone > 0 | |
?? ( '+' ~ zPad( ($dt.timezone/3600).floor, 2 ) ~':'~ | |
zPad( ($dt.timezone/60%60).floor, 2 ) ) | |
!! ( '-' ~ zPad( ($dt.timezone.abs/3600).floor, 2 ) ~':'~ | |
zPad( ($dt.timezone.abs/60%60).floor, 2 ) ) ) | |
} | |
my %type-map = | |
lastchangetime => DateTime, | |
clickcount => Int, | |
bitrate => Int, | |
clicktimestamp => DateTime, | |
votes => Int, | |
lastcheckoktime => DateTime, | |
clicktrend => Int, | |
lastcheckok => Bool, | |
negativevotes => Int, | |
tage => { .split(',') }, | |
lastchecktime => DateTime, | |
id => Int; | |
sub internet-radio-stations-update(:$schema = 'http', Int :$limit = 100000) is export { | |
my $cache-time = (try „$cfg-dir/stations.json“.IO.modified.DateTime) // now.DateTime.new(0); | |
my @stations; | |
if $cache-time < now.DateTime.earlier(:30days) { | |
change-state fetching; | |
note "fetching all unbroken stations"; | |
@stations = | jpost "$schema://www.radio-browser.info/webservice/json/stations", {User-Agent => 'https://github.com/gfldex/perl6-www-radiobrowser'}, :$limit; | |
my $stations-count = +@stations; | |
change-state processing; | |
note "processing $stations-count stations"; | |
@stations.=map: { | |
.<lastchangetime> = .<lastchangetime> ?? DateTime.new(.<lastchangetime>.subst(' ', 'T') ~ 'Z', :formatter(&ISO8601)) !! DateTime; | |
.<clickcount> = .<clickcount>.Int; | |
.<bitrate> = .<bitrate>.Int; | |
.<clicktimestamp> = .<clicktimestamp> ?? DateTime.new(.<clicktimestamp>.subst(' ', 'T') ~ 'Z', :formatter(&ISO8601)) !! DateTime; | |
.<votes> = .<votes>.Int; | |
.<lastcheckoktime> = .<lastcheckoktime> ?? DateTime.new(.<lastcheckoktime>.subst(' ', 'T') ~ 'Z', :formatter(&ISO8601)) !! DateTime; | |
.<clicktrend> = .<clicktrend>.Int; | |
.<lastcheckok> = .<lastcheckok>.Int.Bool; | |
.<negativevotes> = .<negativevotes>.Int; | |
.<tags> = .<tags>.split(','); | |
.<lastchecktime> = .<lastchecktime> ?? DateTime.new(.<lastchecktime>.subst(' ', 'T') ~ 'Z', :formatter(&ISO8601)) !! DateTime; | |
.<id> = .<id>.Int; | |
(note "$_/$stations-count processed" if $_ %% 1000) with $++; | |
.Hash | |
}; | |
@cache = @stations; | |
change-state storing; | |
{ | |
„$cfg-dir/stations.json“.IO.spurt(@stations.&to-json); | |
my $elapsed = now - ENTER now; | |
note "$stations-count stored in {$elapsed}s with {$stations-count / $elapsed} stations/s"; | |
} | |
change-state ready; | |
note ‚cache filled in: ‘ ~ (now - ENTER now) ~ ‚s‘; | |
} else { | |
change-state reading; | |
note "read cache from $cfg-dir/stations.json"; | |
my @stations = @(„$cfg-dir/stations.json“.IO.slurp.&from-json); | |
my $stations-count = @stations.elems; | |
{ | |
change-state processing; | |
note "processing $stations-count stations"; | |
@stations.=map: { | |
.AT-KEY(‚lastchangetime‘) = .AT-KEY(‚lastchangetime‘) ?? DateTime.new(.AT-KEY(‚lastchangetime‘), :formatter(&ISO8601)) !! DateTime; | |
.AT-KEY(‚clickcount‘) = .AT-KEY(‚clickcount‘).Int; | |
.AT-KEY(‚bitrate‘) = .AT-KEY(‚bitrate‘).Int; | |
.AT-KEY(‚clicktimestamp‘) = .AT-KEY(‚clicktimestamp‘) ?? DateTime.new(.AT-KEY(‚clicktimestamp‘), :formatter(&ISO8601)) !! DateTime; | |
.AT-KEY(‚votes‘) = .AT-KEY(‚votes‘).Int; | |
.AT-KEY(‚lastcheckoktime‘) = .AT-KEY(‚lastcheckoktime‘) ?? DateTime.new(.AT-KEY(‚lastcheckoktime‘), :formatter(&ISO8601)) !! DateTime; | |
.AT-KEY(‚clicktrend‘) = .AT-KEY(‚clicktrend‘).Int; | |
.AT-KEY(‚lastcheckok‘) = .AT-KEY(‚lastcheckok‘).Int.Bool; | |
.AT-KEY(‚negativevotes‘) = .AT-KEY(‚negativevotes‘).Int; | |
#.AT-KEY(‚tags‘) = .AT-KEY(‚tags‘).split(','); | |
.AT-KEY(‚lastchecktime‘) = .AT-KEY(‚lastchecktime‘) ?? DateTime.new(.AT-KEY(‚lastchecktime‘), :formatter(&ISO8601)) !! DateTime; | |
.AT-KEY(‚id‘) = .AT-KEY(‚id‘).Int; | |
(note "$_/$stations-count processed" if $_ %% 1000) with $++; | |
.Hash | |
}; | |
my $elapsed = now - ENTER now; | |
note "$stations-count processed in {$elapsed}s with {$stations-count / $elapsed} stations/s"; | |
} | |
my @deleted-stations = internet-radio-stations-deleted(since => $cache-time); | |
my @updated-stations = internet-radio-stations-changed(since => $cache-time); | |
note [ ‚total:‘, +@stations, ‚deleted:‘, +@deleted-stations, ‚changed:‘, +@updated-stations ]; | |
if +@deleted-stations | +@updated-stations { | |
my Set $d-s-ids = @deleted-stations».<id>.Set; | |
my Set $u-s-ids = @updated-stations».<id>.Set; | |
my Set $to-be-removed-stations = $d-s-ids ∩ $u-s-ids; | |
@stations = @stations.grep({ | |
my $station = .item; | |
my $ret = .<id>.Int ∉ $to-be-removed-stations; | |
CATCH { default { | |
note .^name, ': ', .Str; | |
exit 0 | |
} | |
} | |
$ret | |
}); | |
note ‚after delete: ‘, +@stations; | |
# dd @stations.grep({say .<id>; .<id>.Int ∈ $to-be-removed-stations}); | |
# dd $to-be-removed-stations; | |
@stations.append(|@updated-stations); | |
note ‚after updated: ‘, +@stations; | |
change-state storing; | |
{ | |
„$cfg-dir/stations.json“.IO.spurt(@stations.&to-json); | |
my $elapsed = now - ENTER now; | |
note "$stations-count stored in {$elapsed}s with {$stations-count / $elapsed} stations/s"; | |
} | |
} | |
change-state ready; | |
note ‚cache updated in: ‘ ~ (now - ENTER now) ~ ‚s‘; | |
} | |
@stations.Slip | |
} | |
multi sub internet-radio-stations-deleted(:$schema = 'http', DateTime :$since = now.DateTime.earlier(:30days)) is export { | |
note "fetching deleted stations"; | |
my \v = jpost "$schema://www.radio-browser.info/webservice/json/stations/deleted", {User-Agent => 'https://github.com/gfldex/perl6-www-radiobrowser'} | |
v.map: { | |
.<lastchangetime> = DateTime.new: .<lastchangetime>.subst(' ', 'T') ~ 'Z'; | |
.<changeid> = .<changeid>.Int; | |
.<id> = .<changeid>.Int; | |
.Hash | |
}; | |
v.grep: { .<lastchangetime> > $since } | |
} | |
multi sub internet-radio-stations-deleted(:$schema = 'http', :$age) is export { | |
internet-radio-stations-deleted(:$schema, since => now.DateTime.earlier(|$age)) | |
} | |
multi sub internet-radio-stations-changed(:$schema = 'http', DateTime :$since) is export { | |
note "fetching changed stations"; | |
my \v = jpost "$schema://www.radio-browser.info/webservice/json/stations/lastchange", {User-Agent => 'https://github.com/gfldex/perl6-www-radiobrowser'}; | |
v.map: { | |
.<lastchangetime> = .<lastchangetime> ?? DateTime.new: .<lastchangetime>.subst(' ', 'T') ~ 'Z' !! DateTime; | |
.<clickcount> = .<clickcount>.Int; | |
.<bitrate> = .<bitrate>.Int; | |
.<clicktimestamp> = .<clicktimestamp> ?? DateTime.new: .<clicktimestamp>.subst(' ', 'T') ~ 'Z' !! DateTime; | |
.<votes> = .<votes>.Int; | |
.<lastcheckoktime> = .<lastcheckoktime> ?? DateTime.new: .<lastcheckoktime>.subst(' ', 'T') ~ 'Z' !! DateTime; | |
.<clicktrend> = .<clicktrend>.Int; | |
.<lastcheckok> = .<lastcheckok>.Int.Bool; | |
.<negativevotes> = .<negativevotes>.Int; | |
.<tags> = .<tags>.split(','); | |
.<lastchecktime> = .<lastchangetime> ?? DateTime.new: .<lastchecktime>.subst(' ', 'T') ~ 'Z' !! DateTime; | |
.<id> = .<id>.Int; | |
.Hash | |
}; | |
v.grep: { .<lastchangetime> > $since } | |
} | |
multi sub internet-radio-stations-changed(:$schema = 'http', :$age) is export { | |
internet-radio-stations-changed(:$schema, since => now.DateTime.earlier(|$age)) | |
} | |
multi sub fetch(:$stations-changed){ | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment