diff options
author | Tom Ryder <tom@sanctum.geek.nz> | 2017-11-02 10:48:54 +1300 |
---|---|---|
committer | Tom Ryder <tom@sanctum.geek.nz> | 2017-11-02 10:48:54 +1300 |
commit | e058d3507a180a83a621f1f9b4762aac0a016664 (patch) | |
tree | b1926988dd50a5da7fa286fee6fa2efcabd7c4ac | |
parent | Merge branch 'hotfix/v0.06' (diff) | |
parent | Update tests to reflect new method names (diff) | |
download | Music-Lyrics-LRC-e058d3507a180a83a621f1f9b4762aac0a016664.tar.gz Music-Lyrics-LRC-e058d3507a180a83a621f1f9b4762aac0a016664.zip |
Merge branch 'release/v0.07'v0.07
* release/v0.07:
Update tests to reflect new method names
Regenerate README.markdown for 0.07
Update Changes for 0.07
Bump version number to 0.07
Add verbose flag to warn on malformed lines
Parse any number of fractional seconds
-rw-r--r-- | Changes | 9 | ||||
-rw-r--r-- | Makefile.PL | 2 | ||||
-rw-r--r-- | README.markdown | 27 | ||||
-rw-r--r-- | lib/Music/Lyrics/LRC.pm | 99 | ||||
-rw-r--r-- | t/basic.t | 15 |
5 files changed, 89 insertions, 63 deletions
@@ -1,5 +1,14 @@ Revision history for Music-Lyrics-LRC +0.07 2017-11-02 + + - Parse any resolution of fractional seconds in input, including no fractional + seconds at all + - Remove msec_to_ts() and ts_to_msec() functions, replaced with internals not + documented + - Add a verbose flag to the constructor to control the emission of warnings + for unparsed lines from files + 0.06 2017-11-02 - Correct syntax of output file: the format uses a period for the fractional diff --git a/Makefile.PL b/Makefile.PL index 2707497..fa6b1f2 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -25,7 +25,7 @@ WriteMakefile( 'meta-spec' => { version => 2 }, provides => { 'Music::Lyrics::LRC' => { - version => '0.06', + version => '0.07', file => 'lib/Music/Lyrics/LRC.pm', }, }, diff --git a/README.markdown b/README.markdown index 91432c9..fcaecd7 100644 --- a/README.markdown +++ b/README.markdown @@ -4,7 +4,7 @@ Music::Lyrics::LRC - Manipulate LRC karaoke timed lyrics files # VERSION -Version 0.05 +Version 0.07 # DESCRIPTION @@ -35,9 +35,16 @@ For details on the LRC file format, please see Wikipedia: # SUBROUTINES/METHODS -## `new()` +## `new(%opts)` -Constructor; no arguments. +Constructor method. Accepts a hash with one attribute `verbose`. This +specifies whether the module will `warn` explicitly when it cannot parse an +input line from a file. It defaults to 0. + + my $lrc = MRC::Lyrics::LRC->new(); + ... + my $lrc_verbose = MRC::Lyrics::LRC->new(verbose => 1); + ... ## `lyrics()` @@ -89,16 +96,6 @@ Load lyrics from the given readable filehandle. Save lyrics to the given writeable filehandle. -## `ts_to_msec(\%ts)` - -Convert the internal LRC timestamp hash structure to milliseconds. You are -probably not interested in this. - -## `msec_to_ts($msec)` - -Convert milliseconds to the internal LRC timestamp hash structure. You are -probably not interested in this, either. - # DIAGNOSTICS - `Bad lyric time` @@ -169,6 +166,10 @@ may change in future revisions. The format accepted here is very liberal, and needs to be tested with lots of different LRC files from the wild. +Fractional seconds of any length can be parsed, and preserved in the +millisecond count return by `lyrics()`, but any resolution beyond 2 decimal +places is lost on `save()`. + The test suite is skeletal, and needs a lot of fleshing out. # AUTHOR diff --git a/lib/Music/Lyrics/LRC.pm b/lib/Music/Lyrics/LRC.pm index 10204d0..f665437 100644 --- a/lib/Music/Lyrics/LRC.pm +++ b/lib/Music/Lyrics/LRC.pm @@ -13,7 +13,7 @@ use English '-no_match_vars'; use 5.006; # Declare package version -our $VERSION = '0.06'; +our $VERSION = '0.07'; # Patterns to match elements of the LRC file; these are somewhat tolerant our %RE = ( @@ -45,9 +45,13 @@ our %RE = ( \[ # Opening left bracket (\d+) # Minutes, capture : # Colon - (\d{2}) # Seconds, capture - [.] # Period - (\d{2}) # Hundredths of a second, capture + ( # Seconds group, capture + \d{2} # Whole seconds + (?: # Group for fractional seconds + [.] # Period + \d+ # At least one digit + )? # End optional fractional seconds group + ) # End seconds group \] # Closing right bracket [\t ]* # Any tabs or spaces (.*\S) # Lyric line, capture @@ -67,11 +71,10 @@ my %parsers = ( # A lyric line lyric => sub { - my ( $self, %ts, $text ); - ( $self, @ts{qw(min sec csec)}, $text ) = @_; + my ( $self, $min, $sec, $text ) = @_; # Calculate the number of milliseconds - my $msec = $self->ts_to_msec( \%ts ); + my $msec = $self->_min_sec_to_msec( $min, $sec ); # Push a lyric hashref onto our list $self->add_lyric( $msec, $text ); @@ -80,13 +83,21 @@ my %parsers = ( # Oldschool constructor sub new { - my ($class) = @_; + my ( $class, %opts ) = @_; - # Start with empty tags and lyrics + # Declare a hash to build the object around my %self; + + # Start with empty tags and lyrics $self{tags} = {}; $self{lyrics} = []; + # Read in the "verbose" flag if defined, default to zero + $self{verbose} = + exists $opts{verbose} + ? !!$opts{verbose} + : 0; + # Perlician, bless thyself return bless \%self, $class; } @@ -174,8 +185,8 @@ sub load { next LINE; } - # This line doesn't match anything we understand, complain but persist - warn "Unknown format for line $NR\n"; + # No line format match, warn if verbose + warn "Unknown format for line $NR\n" if $self->{verbose}; } # Check we got to the end of the file @@ -208,11 +219,10 @@ sub save { # Convert milliseconds to timestamp hash my $msec = $lyric->{time}; - my %ts = %{ $self->msec_to_ts($msec) }; + my ( $min, $sec ) = $self->_msec_to_min_sec($msec); # Write the line to the file, counting the lines - $lines += printf {$fh} "[%02u:%02u.%02u]%s\n", - @ts{qw(min sec csec)}, $lyric->{text} + $lines += printf {$fh} "[%02u:%05.2f]%s\n", $min, $sec, $lyric->{text} or die "Failed lyric write: $ERRNO\n"; } @@ -220,32 +230,28 @@ sub save { return $lines; } -# Factors for timestamp<->millisecond conversions -our %MSF = ( - min => 60_000, - sec => 1_000, - csec => 10, +# Named constants for the conversion functions +# This stands for "millisecond factors" +my %MSF = ( + sec => 1_000, + min => 60_000, ); -# Convert an LRC timestamp hashref to milliseconds -sub ts_to_msec { - my ( $self, $ts ) = @_; +# Convert a minutes-seconds pair to milliseconds +sub _min_sec_to_msec { + my ( $self, $min, $sec ) = @_; my $msec = 0; - for my $k ( keys %{$ts} ) { - $msec += $ts->{$k} * $MSF{$k}; - } + $msec += int $min * $MSF{min}; + $msec += $sec * $MSF{sec}; return $msec; } -# Convert milliseconds to an LRC timestamp hashref -sub msec_to_ts { +# Convert milliseconds to a minutes-seconds pair +sub _msec_to_min_sec { my ( $self, $msec ) = @_; - my %ts; - for my $k (qw(min sec csec)) { - $ts{$k} = int $msec / $MSF{$k}; - $msec %= $MSF{$k}; - } - return \%ts; + my $min = int $msec / $MSF{min}; + my $sec = ( int $msec ) % $MSF{min} / $MSF{sec}; + return ( $min, $sec ); } 1; @@ -264,7 +270,7 @@ Music::Lyrics::LRC - Manipulate LRC karaoke timed lyrics files =head1 VERSION -Version 0.06 +Version 0.07 =head1 DESCRIPTION @@ -295,9 +301,16 @@ L<https://en.wikipedia.org/wiki/LRC_(file_format)> =head1 SUBROUTINES/METHODS -=head2 C<new()> +=head2 C<new(%opts)> + +Constructor method. Accepts a hash with one attribute C<verbose>. This +specifies whether the module will C<warn> explicitly when it cannot parse an +input line from a file. It defaults to 0. -Constructor; no arguments. + my $lrc = MRC::Lyrics::LRC->new(); + ... + my $lrc_verbose = MRC::Lyrics::LRC->new(verbose => 1); + ... =head2 C<lyrics()> @@ -349,16 +362,6 @@ Load lyrics from the given readable filehandle. Save lyrics to the given writeable filehandle. -=head2 C<ts_to_msec(\%ts)> - -Convert the internal LRC timestamp hash structure to milliseconds. You are -probably not interested in this. - -=head2 C<msec_to_ts($msec)> - -Convert milliseconds to the internal LRC timestamp hash structure. You are -probably not interested in this, either. - =head1 DIAGNOSTICS =over 4 @@ -445,6 +448,10 @@ may change in future revisions. The format accepted here is very liberal, and needs to be tested with lots of different LRC files from the wild. +Fractional seconds of any length can be parsed, and preserved in the +millisecond count return by C<lyrics()>, but any resolution beyond 2 decimal +places is lost on C<save()>. + The test suite is skeletal, and needs a lot of fleshing out. =head1 AUTHOR @@ -8,7 +8,7 @@ use Test::More tests => 9; use Music::Lyrics::LRC; -our $VERSION = '0.06'; +our $VERSION = '0.07'; my $lrc = Music::Lyrics::LRC->new(); ok( defined $lrc, 'constructed' ); @@ -17,8 +17,17 @@ my $pkg = 'Music::Lyrics::LRC'; isa_ok( $lrc, $pkg ); can_ok( - $lrc, - qw(lyrics tags add_lyric set_tag unset_tag load save ts_to_msec msec_to_ts), + $lrc, qw( + lyrics + tags + add_lyric + set_tag + unset_tag + load + save + _min_sec_to_msec + _msec_to_min_sec + ), ); ok( $lrc->add_lyric( 0, 'lalala' ), 'add_lyric_0' ); |