aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorboblied <boblied@gmail.com>2021-03-12 09:44:27 -0600
committerboblied <boblied@gmail.com>2021-03-12 09:44:27 -0600
commit665a693f4730d44b81323270644a1a5863171400 (patch)
tree847852a20aa29bd81e8b8fc0d3c667ac5e41d703
parent9e2eb3e4ae058c514b13cd463b455238e0de6eef (diff)
downloadperlweeklychallenge-club-665a693f4730d44b81323270644a1a5863171400.tar.gz
perlweeklychallenge-club-665a693f4730d44b81323270644a1a5863171400.tar.bz2
perlweeklychallenge-club-665a693f4730d44b81323270644a1a5863171400.zip
PWC 103, Task #2 solution
-rwxr-xr-xchallenge-103/bob-lied/perl/ch-2.pl160
-rw-r--r--challenge-103/bob-lied/perl/episode.csv7
-rw-r--r--challenge-103/bob-lied/perl/lib/PlayList.pm84
3 files changed, 251 insertions, 0 deletions
diff --git a/challenge-103/bob-lied/perl/ch-2.pl b/challenge-103/bob-lied/perl/ch-2.pl
new file mode 100755
index 0000000000..3b3ce8ee66
--- /dev/null
+++ b/challenge-103/bob-lied/perl/ch-2.pl
@@ -0,0 +1,160 @@
+#!/usr/bin/env perl
+# vim:set ts=4 sw=4 sts=4 et ai wm=0 nu:
+#=============================================================================
+# ch-2.pl
+#=============================================================================
+# Copyright (c) 2021, Bob Lied
+#=============================================================================
+# Perl Weekly Challeng 103, Task #2, What's playing?
+#
+# Working from home, you decided that on occasion you wanted some background
+# noise while working. You threw together a network streamer to continuously
+# loop through the files and launched it in a tmux (or screen) session, giving
+# it a directory tree of files to play. During the day, you connected an audio
+# player to the stream, listening through the workday, closing it when done.
+#
+# For weeks you connect to the stream daily, slowly noticing a gradual drift
+# of the media. After several weeks, you take vacation. When you return, you
+# are pleasantly surprised to find the streamer still running. Before
+# connecting, however, if you consider the puzzle of determining which track
+# is playing.
+#
+# After looking at a few modules to read info regarding the media, a quick bit
+# of coding gave you a file list. The file list is in a simple CSV format,
+# each line containing two fields: the first the number of milliseconds in
+# length, the latter the media’s title
+#
+# For this script, you can assume to be provided the following information:
+# * the value of $^T ($BASETIME) of the streamer script,
+# * the value of time(), and
+# * a CSV file containing the media to play consisting of the length in
+# milliseconds and an identifier for the media (title, filename, or other).
+#
+# Write a program to output which file is currently playing. For purposes of
+# this script, you may assume gapless playback, and format the output as you
+# see fit.
+# Optional: Also display the current position in the media as a time-like value.
+#
+# Example: Input starttime currenttime filelist.csv
+# 1606134123 1614591276 episode.csv
+# Output:
+# "Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)"
+# 00:10:24
+#
+#=============================================================================
+
+use strict;
+use warnings;
+use v5.32;
+
+use experimental qw/signatures/;
+no warnings qw/experimental::signatures/;
+
+use Getopt::Long;
+my $verbose = 0;
+my $doTest = 0;
+
+use FindBin qw($Bin);
+use lib "$FindBin::Bin";
+use lib "$FindBin::Bin/lib";
+
+# Using this as an excuse to use Moo
+use PlayList;
+
+GetOptions("test" => \$doTest, "verbose" => \$verbose);
+
+exit(!runTest()) if $doTest;
+
+sub Usage() { "Usage: $0 startTS endTS file.csv" }
+
+my $startTS = shift;
+my $endTS = shift;
+my $file = shift;
+die Usage() unless defined $startTS && defined $endTS && defined $file;
+die Usage(), " start > end" if $startTS > $endTS;
+
+my $playList = PlayList->new( fileName => $file );
+use Data::Dumper;
+# say Dumper($playList);
+
+# Because the time is in seconds and track time is in millisconds, there's
+# a possibility that we could switch tracks in that second. Specifications
+# are ambiguous, so do the simplest that works -- use the start of the second.
+my $playTime = ($endTS - $startTS) * 1000; # In milliseconds
+
+my ($track, $timeIntoTrack, $timeIntoCycle) = $playList->playingAt($playTime);
+# time is in millisconds
+
+# Turn a time in milliseconds into format "HH:MM:SS", dropping fractional seconds.
+sub posFormat($pos)
+{
+ use integer;
+ my ($hours, $minutes, $seconds) = (0, 0, 0);
+ $pos /= 1000; # Now in seconds
+ $hours = $pos / 3600;
+ $pos %= 3600;
+ $minutes = $pos / 60;
+ $seconds = $pos % 60;
+
+ return sprintf("%02d:%02d:%02d", $hours, $minutes, $seconds);
+}
+
+say $track;
+say posFormat($timeIntoTrack), " in episode";
+say posFormat($timeIntoCycle), " in cycle of ", posFormat($playList->length);
+
+sub runTest()
+{
+ use Test::More;
+
+ my $pl = PlayList->new(fileName => "episode.csv");
+ is( $pl->length(), 11910604, "Total length");
+
+ my ($track, $songTime, $cycleTime) = $pl->playingAt(0);
+ is( $track, "Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)", , "track at 0 ms");
+ is( posFormat($songTime), "00:00:00", "Time at 0 ms");
+ is( posFormat($cycleTime), "00:00:00", "Cycle at 0 ms");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(1);
+ is( $track, "Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)", , "track at 1 ms");
+ is( posFormat($songTime), "00:00:00", "Time at 1 ms");
+ is( posFormat($cycleTime), "00:00:00", "Cycle at 1 ms");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(1000);
+ is( $track, "Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)", , "track at 1 sec");
+ is( posFormat($songTime), "00:00:01", "Time at 1 sec");
+ is( posFormat($cycleTime), "00:00:01", "Cycle at 1 sec");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(1709000);
+ is( $track, "Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)", , "track at 1709 sec");
+ is( posFormat($songTime), "00:28:29", "Time at 1709 sec");
+ is( posFormat($cycleTime), "00:28:29", "Cycle at 1 sec");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(1709362);
+ is( $track, "Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)", , "track at 1709.362 sec");
+ is( posFormat($songTime), "00:28:29", "Time at 1709.362 sec");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(1709363);
+ is( $track, "Les Miserables Episode 2: Javert (broadcast date: 1937-07-30)", , "track at 1709.363 sec");
+ is( posFormat($songTime), "00:00:00", "Time at 1710 sec");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(1709363);
+ is( $track, "Les Miserables Episode 2: Javert (broadcast date: 1937-07-30)", , "track at 1709.363 sec");
+ is( posFormat($songTime), "00:00:00", "Time at 1709.363 sec");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(1800000);
+ is( $track, "Les Miserables Episode 2: Javert (broadcast date: 1937-07-30)", , "track at 1800 sec");
+ is( posFormat($songTime), "00:01:30", "Time at 1800 sec");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(24*3600*1000);
+ is( $track, "Les Miserables Episode 2: Javert (broadcast date: 1937-07-30)", , "track at 1 day");
+ is( posFormat($songTime), "00:21:56", "Time at 1 day");
+ is( posFormat($cycleTime), "00:50:25", "Cycle at 1 day");
+
+ ($track, $songTime, $cycleTime) = $pl->playingAt(30*24*3600*1000);
+ is( $track, "Les Miserables Episode 5: The Grave (broadcast date: 1937-08-20)", , "track at 30 day");
+ is( posFormat($songTime), "00:09:23", "Time at 30 day");
+ is( posFormat($cycleTime), "02:03:18", "Cycle at 30 day");
+
+ done_testing;
+}
diff --git a/challenge-103/bob-lied/perl/episode.csv b/challenge-103/bob-lied/perl/episode.csv
new file mode 100644
index 0000000000..9428b93004
--- /dev/null
+++ b/challenge-103/bob-lied/perl/episode.csv
@@ -0,0 +1,7 @@
+1709363,"Les Miserables Episode 1: The Bishop (broadcast date: 1937-07-23)"
+1723781,"Les Miserables Episode 2: Javert (broadcast date: 1937-07-30)"
+1723781,"Les Miserables Episode 3: The Trial (broadcast date: 1937-08-06)"
+1678356,"Les Miserables Episode 4: Cosette (broadcast date: 1937-08-13)"
+1646043,"Les Miserables Episode 5: The Grave (broadcast date: 1937-08-20)"
+1714640,"Les Miserables Episode 6: The Barricade (broadcast date: 1937-08-27)"
+1714640,"Les Miserables Episode 7: Conclusion (broadcast date: 1937-09-03)"
diff --git a/challenge-103/bob-lied/perl/lib/PlayList.pm b/challenge-103/bob-lied/perl/lib/PlayList.pm
new file mode 100644
index 0000000000..3ee27cb770
--- /dev/null
+++ b/challenge-103/bob-lied/perl/lib/PlayList.pm
@@ -0,0 +1,84 @@
+# vim:set ts=4 sw=4 sts=4 et ai wm=0 nu:
+#=============================================================================
+# PlayList.pm
+#=============================================================================
+# Copyright (c) 2021, Bob Lied
+#=============================================================================
+
+use strict;
+use warnings;
+use v5.32;
+
+no warnings qw/experimental::signatures/;
+use feature qw/signatures/;
+
+
+package PlayList;
+{
+ use Moo;
+ use Carp qw/confess/;
+ use Data::Dumper;
+
+ has fileName => (
+ is => 'ro',
+ required => 1,
+ isa => sub { my $f = shift;
+ -r $f || confess "Can't read file $f: $!" },
+ );
+
+ has list => (
+ is => 'rw',
+ default => sub { [] },
+ );
+
+ has length => (
+ is => 'rw',
+ default => 0,
+ );
+
+no warnings qw/experimental::signatures/;
+ sub BUILD($self, $args)
+ {
+ $self->_loadFile();
+ $self->_calcLength();
+ }
+
+no warnings qw/experimental::signatures/;
+ sub _loadFile($self)
+ {
+ use Text::CSV qw/csv/;
+
+ $self->list( csv(in => $self->fileName, headers => [ qw(time title) ]) );
+
+ }
+
+ no warnings qw/experimental::signatures/;
+ sub _calcLength($self)
+ {
+ my $len = 0;
+ for my $track ( $self->list->@* )
+ {
+ $len += $track->{time};
+ }
+ $self->length($len);
+ }
+
+ sub playingAt($self, $cycleTime)
+ {
+ my $len = 0;
+ $cycleTime %= $self->length;
+ for my $track ( $self->list->@* )
+ {
+ if ( $cycleTime >= $len && $cycleTime < $len + $track->{time} )
+ {
+ my $trackTitle = $track->{title};
+ my $intoTrack = $cycleTime - $len;
+
+ return ( $trackTitle, $intoTrack, $cycleTime);
+ }
+ $len += $track->{time};
+ }
+ }
+}
+
+1;