aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Ryder <tom@sanctum.geek.nz>2017-10-06 13:34:17 +1300
committerTom Ryder <tom@sanctum.geek.nz>2017-10-06 13:34:17 +1300
commit9d7feb93cef5141bfef77d74a4a02fdb0de1a9a1 (patch)
tree2f9e2717a8ec029678e592f6e9f294bcb39960f3
parentSet up README (diff)
downloadMusic-Lyrics-LRC-9d7feb93cef5141bfef77d74a4a02fdb0de1a9a1.tar.gz
Music-Lyrics-LRC-9d7feb93cef5141bfef77d74a4a02fdb0de1a9a1.zip
First version for personal cgit but not CPAN yetv0.01
-rw-r--r--MANIFEST10
-rw-r--r--MANIFEST.SKIP9
-rw-r--r--Makefile.PL9
-rw-r--r--README5
-rw-r--r--README.markdown86
-rw-r--r--bin/lrcplay45
-rw-r--r--lib/Music/Lyrics/LRC.pm281
-rw-r--r--t/00-load.t13
-rw-r--r--xt/manifest.t (renamed from t/manifest.t)0
-rw-r--r--xt/pod-coverage.t (renamed from t/pod-coverage.t)0
-rw-r--r--xt/pod.t (renamed from t/pod.t)0
11 files changed, 350 insertions, 108 deletions
diff --git a/MANIFEST b/MANIFEST
index b09c3fa..5c79f14 100644
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,9 +1,9 @@
Changes
+bin/lrcplay
lib/Music/Lyrics/LRC.pm
Makefile.PL
-MANIFEST This list of files
+MANIFEST
README
-t/00-load.t
-t/manifest.t
-t/pod-coverage.t
-t/pod.t
+xt/manifest.t
+xt/pod-coverage.t
+xt/pod.t
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
new file mode 100644
index 0000000..bf1a02b
--- /dev/null
+++ b/MANIFEST.SKIP
@@ -0,0 +1,9 @@
+^\.git
+^Music-Lyrics-LRC-.*
+^MANIFEST\.SKIP$
+^MYMETA\.
+^Makefile$
+^Makefile\.old$
+^README\.markdown
+^blib
+^pm_to_blib$
diff --git a/Makefile.PL b/Makefile.PL
index 2539029..b8ab07e 100644
--- a/Makefile.PL
+++ b/Makefile.PL
@@ -18,9 +18,14 @@ WriteMakefile(
'Test::More' => '0',
},
PREREQ_PM => {
- #'ABC' => '1.6',
- #'Foo::Bar::Module' => '5.0401',
+ 'strict' => 0,
+ 'warnings' => 0,
+ 'utf8' => 0,
+ 'Carp' => 0,
+ 'English' => 0,
+ 'Time::HiRes' => 0,
},
+ EXE_FILES => ['bin/lrcplay'],
dist => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
clean => { FILES => 'Music-Lyrics-LRC-*' },
);
diff --git a/README b/README
index ec60ab3..3254d63 100644
--- a/README
+++ b/README
@@ -15,10 +15,7 @@ To install this module, run the following commands:
SUPPORT AND DOCUMENTATION
-After installing, you can find documentation for this module with the
-perldoc command.
-
- perldoc Music::Lyrics::LRC
+None yet. If you're interested, email me at <tom@sanctum.geek.nz>.
LICENSE AND COPYRIGHT
diff --git a/README.markdown b/README.markdown
new file mode 100644
index 0000000..9f35802
--- /dev/null
+++ b/README.markdown
@@ -0,0 +1,86 @@
+# NAME
+
+Music::Lyrics::LRC - Manipulate LRC karaoke lyrics files
+
+# VERSION
+
+Version 0.01
+
+# SYNOPSIS
+
+This section to be completed.
+
+# DESCRIPTION
+
+Read, write, and do simple manipulations of the LRC lyrics files used for some
+karaoke devices.
+
+# SUBROUTINES/METHODS
+
+This section to be completed.
+
+# DIAGNOSTICS
+
+This section to be completed.
+
+# CONFIGURATION AND ENVIRONMENT
+
+None to speak of.
+
+# DEPENDENCIES
+
+- Perl 5.6 or newer
+- `Carp`
+- `English`
+
+# INCOMPATIBILITIES
+
+Probably.
+
+# BUGS AND LIMITATIONS
+
+Yes.
+
+# AUTHOR
+
+Tom Ryder `<tom@sanctum.geek.nz>`
+
+# LICENSE AND COPYRIGHT
+
+Copyright (C) 2017 Tom Ryder
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the Artistic License (2.0). You may obtain a copy of the full
+license at:
+
+&lt;http://www.perlfoundation.org/artistic\_license\_2\_0>
+
+Any use, modification, and distribution of the Standard or Modified Versions is
+governed by this Artistic License. By using, modifying or distributing the
+Package, you accept this license. Do not use, modify, or distribute the
+Package, if you do not accept this license.
+
+If your Modified Version has been derived from a Modified Version made by
+someone other than you, you are nevertheless required to ensure that your
+Modified Version complies with the requirements of this license.
+
+This license does not grant you the right to use any trademark, service mark,
+tradename, or logo of the Copyright Holder.
+
+This license includes the non-exclusive, worldwide, free-of-charge patent
+license to make, have made, use, offer to sell, sell, import and otherwise
+transfer the Package with respect to any patent claims licensable by the
+Copyright Holder that are necessarily infringed by the Package. If you
+institute patent litigation (including a cross-claim or counterclaim) against
+any party alleging that the Package constitutes direct or contributory patent
+infringement, then this Artistic License to you shall terminate on the date
+that such litigation is filed.
+
+Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
+CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW.
+UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY
+OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
diff --git a/bin/lrcplay b/bin/lrcplay
new file mode 100644
index 0000000..d217098
--- /dev/null
+++ b/bin/lrcplay
@@ -0,0 +1,45 @@
+#!/usr/bin/env perl
+package main;
+
+# Force me to write this properly
+use strict;
+use warnings;
+use utf8;
+
+# Include required modules
+use Carp;
+use English '-no_match_vars';
+use Music::Lyrics::LRC;
+use Time::HiRes 'sleep';
+
+# Target reasonably old Perl
+use 5.006;
+
+# Declare package version
+# Is this the right thing to do with `main`?
+our $VERSION = '0.01';
+
+# Make a new LRC object
+my $lrc = Music::Lyrics::LRC->new();
+
+# Check we have a file to read
+@ARGV == 1
+ or croak 'Need one file argument';
+
+# Read the lyrics from the named file
+my $fn = shift;
+open my $fh, '<', $fn
+ or croak "Failed to open $fn: $ERRNO";
+$lrc->parse($fh);
+close $fh
+ or croak "Failed to close $fn: $ERRNO";
+
+# Write the timed lyric lines to standard output
+my $offset = 0;
+for my $lyric ( @{ $lrc->lyrics } ) {
+ my $delta = $lyric->{time} - $offset;
+ sleep $delta / 1_000;
+ $offset += $delta;
+ print "$lyric->{text}\n"
+ or carp "Failed stdout write: $ERRNO";
+}
diff --git a/lib/Music/Lyrics/LRC.pm b/lib/Music/Lyrics/LRC.pm
index a2d1f6e..1de55c9 100644
--- a/lib/Music/Lyrics/LRC.pm
+++ b/lib/Music/Lyrics/LRC.pm
@@ -1,141 +1,254 @@
+## no critic (RequirePODUseEncodingUTF8)
package Music::Lyrics::LRC;
-use 5.006;
+# Force me to write this properly
use strict;
use warnings;
+use utf8;
-=head1 NAME
-
-Music::Lyrics::LRC - The great new Music::Lyrics::LRC!
-
-=head1 VERSION
+# Include required modules
+use Carp;
+use English '-no_match_vars';
-Version 0.01
-
-=cut
+# Target reasonably old Perl
+use 5.006;
+# Declare package version
our $VERSION = '0.01';
+# Patterns to match elements of the LRC file; these are somewhat tolerant
+our %RE = (
+
+ # A blank line
+ blank => qr{
+ \A # Start of string
+ \s* # Any whitespace
+ \z # End of string
+ }msx,
+
+ # A meta tag line
+ tag => qr{
+ \A # Start of string
+ \s* # Any whitespace
+ \[ # Opening left bracket
+ ([[:lower:]]+) # Tag name, capture
+ : # Colon
+ (.*) # Tag value, capture
+ \] # Closing right bracket
+ \s* # Any whitespace
+ \z # End of string
+ }msx,
+
+ # A lyric line
+ line => qr {
+ \A # Start of string
+ \s* # Any whitespace
+ \[ # Opening left bracket
+ (\d+) # Minutes, capture
+ : # Colon
+ (\d{2}) # Seconds, capture
+ [.] # Period
+ (\d{2}) # Hundredths of a second, capture
+ \] # Closing right bracket
+ \h* # Any horizontal whitespace
+ (.*\S) # Lyric line, capture
+ \s* # Any whitespace
+ \z # End of string
+ }msx,
+);
+
+# Factors to get milliseconds
+our %MSF = (
+ min => 60_000,
+ sec => 1_000,
+ hsec => 10,
+);
+
+# Parser functions to consume and process captures from the above patterns
+my %parsers = (
+
+ # A meta tag line
+ tag => sub {
+ my ( $self, $tag, $value ) = @_;
+ $self->{tags}{$tag} = $value;
+ },
+
+ # A lyric line
+ line => sub {
+ my ( $self, %ts, $text );
+ ( $self, @ts{qw(min sec hsec)}, $text ) = @_;
+
+ # Calculate the number of milliseconds
+ my $msec = 0;
+ for ( keys %ts ) {
+ $msec += $ts{$_} * $MSF{$_};
+ }
+
+ # Push a lyric hashref onto our list
+ push @{ $self->{lyrics} },
+ {
+ time => $msec,
+ text => $text,
+ };
+ },
+);
+
+# Oldschool constructor
+sub new {
+ my ($class) = @_;
+
+ # Start with empty tags and lyrics
+ my %self;
+ $self{tags} = {};
+ $self{lyrics} = [];
+
+ # Perlician, bless thyself
+ return bless \%self, $class;
+}
-=head1 SYNOPSIS
-
-Quick summary of what the module does.
-
-Perhaps a little code snippet.
+# Read-only accessor for lyrics
+sub lyrics {
+ my $self = shift;
+ return $self->{lyrics};
+}
- use Music::Lyrics::LRC;
+# Read-only accessor for tags
+sub tags {
+ my $self = shift;
+ return $self->{tags};
+}
- my $foo = Music::Lyrics::LRC->new();
- ...
+# Parse an LRC file from a given filehandle
+sub parse {
+ my ( $self, $fh ) = @_;
+
+ # Iterate through lines
+ LINE: while ( my $line = <$fh> ) {
+
+ # Iterate through line types until one matches
+ TYPE: for my $type ( keys %RE ) {
+ my @vals = $line =~ $RE{$type}
+ or next TYPE;
+ exists $parsers{$type}
+ or next LINE;
+ $parsers{$type}->( $self, @vals );
+ next LINE;
+ }
+
+ # This line doesn't match anything we understand, complain but continue
+ carp "Unknown line format on line $NR";
+ }
+
+ # All done, return the number of lyrics we have now
+ return scalar @{ $self->lyrics };
+}
-=head1 EXPORT
+1;
-A list of functions that can be exported. You can delete this section
-if you don't export anything, such as for a purely object-oriented module.
+__END__
-=head1 SUBROUTINES/METHODS
+=pod
-=head2 function1
+=for stopwords
+LRC tradename licensable MERCHANTABILITY
-=cut
-
-sub function1 {
-}
-
-=head2 function2
+=head1 NAME
-=cut
+Music::Lyrics::LRC - Manipulate LRC karaoke lyrics files
-sub function2 {
-}
+=head1 VERSION
-=head1 AUTHOR
+Version 0.01
-Tom Ryder, C<< <tom at sanctum.geek.nz> >>
+=head1 SYNOPSIS
-=head1 BUGS
+This section to be completed.
-Please report any bugs or feature requests to C<bug-music-lyrics-lrc at rt.cpan.org>, or through
-the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Music-Lyrics-LRC>. I will be notified, and then you'll
-automatically be notified of progress on your bug as I make changes.
+=head1 DESCRIPTION
+Read, write, and do simple manipulations of the LRC lyrics files used for some
+karaoke devices.
+=head1 SUBROUTINES/METHODS
+This section to be completed.
-=head1 SUPPORT
+=head1 DIAGNOSTICS
-You can find documentation for this module with the perldoc command.
+This section to be completed.
- perldoc Music::Lyrics::LRC
+=head1 CONFIGURATION AND ENVIRONMENT
+None to speak of.
-You can also look for information at:
+=head1 DEPENDENCIES
=over 4
-=item * RT: CPAN's request tracker (report bugs here)
+=item *
-L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Music-Lyrics-LRC>
+Perl 5.6 or newer
-=item * AnnoCPAN: Annotated CPAN documentation
+=item *
-L<http://annocpan.org/dist/Music-Lyrics-LRC>
+C<Carp>
-=item * CPAN Ratings
+=item *
-L<http://cpanratings.perl.org/d/Music-Lyrics-LRC>
+C<English>
-=item * Search CPAN
+=back
-L<http://search.cpan.org/dist/Music-Lyrics-LRC/>
+=head1 INCOMPATIBILITIES
-=back
+Probably.
+=head1 BUGS AND LIMITATIONS
-=head1 ACKNOWLEDGEMENTS
+Yes.
+=head1 AUTHOR
-=head1 LICENSE AND COPYRIGHT
+Tom Ryder C<< <tom@sanctum.geek.nz> >>
-Copyright 2017 Tom Ryder.
+=head1 LICENSE AND COPYRIGHT
-This program is free software; you can redistribute it and/or modify it
-under the terms of the the Artistic License (2.0). You may obtain a
-copy of the full license at:
+Copyright (C) 2017 Tom Ryder
-L<http://www.perlfoundation.org/artistic_license_2_0>
+This program is free software; you can redistribute it and/or modify it under
+the terms of the Artistic License (2.0). You may obtain a copy of the full
+license at:
-Any use, modification, and distribution of the Standard or Modified
-Versions is governed by this Artistic License. By using, modifying or
-distributing the Package, you accept this license. Do not use, modify,
-or distribute the Package, if you do not accept this license.
+<http://www.perlfoundation.org/artistic_license_2_0>
-If your Modified Version has been derived from a Modified Version made
-by someone other than you, you are nevertheless required to ensure that
-your Modified Version complies with the requirements of this license.
+Any use, modification, and distribution of the Standard or Modified Versions is
+governed by this Artistic License. By using, modifying or distributing the
+Package, you accept this license. Do not use, modify, or distribute the
+Package, if you do not accept this license.
-This license does not grant you the right to use any trademark, service
-mark, tradename, or logo of the Copyright Holder.
+If your Modified Version has been derived from a Modified Version made by
+someone other than you, you are nevertheless required to ensure that your
+Modified Version complies with the requirements of this license.
-This license includes the non-exclusive, worldwide, free-of-charge
-patent license to make, have made, use, offer to sell, sell, import and
-otherwise transfer the Package with respect to any patent claims
-licensable by the Copyright Holder that are necessarily infringed by the
-Package. If you institute patent litigation (including a cross-claim or
-counterclaim) against any party alleging that the Package constitutes
-direct or contributory patent infringement, then this Artistic License
-to you shall terminate on the date that such litigation is filed.
+This license does not grant you the right to use any trademark, service mark,
+tradename, or logo of the Copyright Holder.
-Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
-AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
-THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
-YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
-CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
-CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
-EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+This license includes the non-exclusive, worldwide, free-of-charge patent
+license to make, have made, use, offer to sell, sell, import and otherwise
+transfer the Package with respect to any patent claims licensable by the
+Copyright Holder that are necessarily infringed by the Package. If you
+institute patent litigation (including a cross-claim or counterclaim) against
+any party alleging that the Package constitutes direct or contributory patent
+infringement, then this Artistic License to you shall terminate on the date
+that such litigation is filed.
+Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND
+CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
+NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW.
+UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY
+OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGE.
=cut
-
-1; # End of Music::Lyrics::LRC
diff --git a/t/00-load.t b/t/00-load.t
deleted file mode 100644
index 65a62de..0000000
--- a/t/00-load.t
+++ /dev/null
@@ -1,13 +0,0 @@
-#!perl -T
-use 5.006;
-use strict;
-use warnings;
-use Test::More;
-
-plan tests => 1;
-
-BEGIN {
- use_ok( 'Music::Lyrics::LRC' ) || print "Bail out!\n";
-}
-
-diag( "Testing Music::Lyrics::LRC $Music::Lyrics::LRC::VERSION, Perl $], $^X" );
diff --git a/t/manifest.t b/xt/manifest.t
index e0b558e..e0b558e 100644
--- a/t/manifest.t
+++ b/xt/manifest.t
diff --git a/t/pod-coverage.t b/xt/pod-coverage.t
index f5728a5..f5728a5 100644
--- a/t/pod-coverage.t
+++ b/xt/pod-coverage.t
diff --git a/t/pod.t b/xt/pod.t
index 4d3a0ce..4d3a0ce 100644
--- a/t/pod.t
+++ b/xt/pod.t