mirror of
https://github.com/vincentmli/bpfire.git
synced 2026-04-09 10:35:53 +02:00
mpfire: removal as discussed in Conf call 7th Oct
- removal of lfs, rootfile, backup, paks, misc-progs, mpfire perl, language file content, mpfire.cgi, mpfire menu references and files, mpfire specific image, web-user-interface references and references in manualpages. Signed-off-by: Adolf Belka <adolf.belka@ipfire.org> Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
This commit is contained in:
committed by
Michael Tremer
parent
9462f634e2
commit
5fd4ca19a8
@@ -1,2 +0,0 @@
|
||||
/var/ipfire/mpfire/settings
|
||||
/var/ipfire/mpfire/webradio
|
||||
@@ -69,7 +69,6 @@ iptables.cgi=configuration/firewall/iptables
|
||||
pakfire.cgi=configuration/ipfire/pakfire
|
||||
wlanap.cgi=addons/wireless
|
||||
tor.cgi=addons/tor
|
||||
mpfire.cgi=addons/mpfire
|
||||
samba.cgi=addons/samba
|
||||
|
||||
# Logs menu
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
$subipfire->{'40.mpfire'} = {'caption' => $Lang::tr{'mpfire'},
|
||||
'uri' => '/cgi-bin/mpfire.cgi',
|
||||
'title' => $Lang::tr{'mpfire'},
|
||||
'enabled' => 1,
|
||||
};
|
||||
@@ -1,108 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
require '/var/ipfire/general-functions.pl';
|
||||
require "${General::swroot}/lang.pl";
|
||||
require "${General::swroot}/header.pl";
|
||||
|
||||
my $filename = "";
|
||||
my $debug = 0;
|
||||
|
||||
if ( `/etc/init.d/mpd status` =~/not running/ ){
|
||||
system("/etc/init.d/mpd start >/dev/null");
|
||||
}
|
||||
|
||||
if ($ARGV[0] eq 'scan') {
|
||||
if ($debug){print "Creating Database\n";}
|
||||
system("mpd --create-db >/dev/null");
|
||||
system("/etc/init.d/mpd restart >/dev/null");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'play') {
|
||||
&checkmute();
|
||||
&clearplaylist();
|
||||
if ($debug){print "Yes we are called and we will play $ARGV[1]\n";}
|
||||
system("mpc add \"$ARGV[1]\" >/dev/null && mpc play >/dev/null");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'playadd') {
|
||||
if ($debug){print "Yes we are called and we will add $ARGV[1]\n";}
|
||||
system("mpc add \"$ARGV[1]\" >/dev/null && mpc play >/dev/null");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'clearplaylist') {
|
||||
if ($debug){print "Deleting playlist\n";}
|
||||
&clearplaylist();
|
||||
}
|
||||
elsif ($ARGV[0] eq 'stop') {
|
||||
my $PID = 'cat /var/run/mpd.pid';
|
||||
if ($debug){print "Killing Process $PID\n";}
|
||||
system("mpc stop >/dev/null");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'volup') {
|
||||
if ($debug){print "Increasing Volume\n";}
|
||||
system("/usr/bin/amixer set Master $ARGV[1]%+ 2>/dev/null >/dev/null");
|
||||
system("/usr/bin/amixer set PCM $ARGV[1]%+ 2>/dev/null >/dev/null");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'voldown') {
|
||||
if ($debug){print "Decreasing Volume\n";}
|
||||
system("/usr/bin/amixer set Master $ARGV[1]%- 2>/dev/null >/dev/null");
|
||||
system("/usr/bin/amixer set PCM $ARGV[1]%- 2>/dev/null >/dev/null");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'toggle') {
|
||||
system("mpc toggle >/dev/null");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'next') {
|
||||
if ($debug){print "Next Song\n";}
|
||||
system("mpc next >/dev/null[");
|
||||
}
|
||||
elsif ( $ARGV[0] eq 'prev' ) {
|
||||
if ($debug){print "Previous Song\n";}
|
||||
system("mpc prev >/dev/null");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'song') {
|
||||
my $song = `mpc \| head -2 | grep -v volume`;
|
||||
print $song;
|
||||
}
|
||||
elsif ($ARGV[0] eq 'stats') {
|
||||
my $song = `mpc stats | grep Songs`;
|
||||
print $song;
|
||||
}
|
||||
elsif ($ARGV[0] eq 'playweb') {
|
||||
&checkmute();
|
||||
&clearplaylist();
|
||||
if ($debug){print "Playing webstream $ARGV[1] \n";}
|
||||
system("mpc add http://$ARGV[1] >/dev/null && mpc play >/dev/null && sleep 1");
|
||||
}
|
||||
elsif ($ARGV[0] eq 'volume') {
|
||||
$temp = "Master - ";
|
||||
$temp .= `amixer get Master \| tail -2 \| awk '{ print \$2" "\$5 }'`;
|
||||
$temp .= "<break>PCM -";
|
||||
$temp .= `amixer get PCM \| tail -2 \| awk '{ print \$2" "\$5 }'`;
|
||||
print $temp;
|
||||
}
|
||||
|
||||
sub clearplaylist(){
|
||||
system("mpc clear >/dev/null");
|
||||
}
|
||||
|
||||
sub shuffle(){
|
||||
system("mpc random >/dev/null");
|
||||
}
|
||||
|
||||
sub checkplaylist(){
|
||||
my $Datei = "/var/ipfire/mpd/playlist.m3u";
|
||||
my @Info = stat($Datei);
|
||||
if ( $Info[7] eq '' || $Info[7] eq '0' ){print "There is no playlist";exit(1);}
|
||||
}
|
||||
|
||||
sub checkmute(){
|
||||
$temp = `amixer get Master \| tail -2`;
|
||||
my @Master = split(/ /,$temp);
|
||||
$temp = `amixer get PCM \| tail -2`;
|
||||
my @PCM = split(/ /,$temp);
|
||||
if ( $PCM[7] =~ /off/ ){
|
||||
if ($debug){print "PCM was muted - umuting.\n";}
|
||||
system("amixer set PCM toggle >/dev/null");
|
||||
}
|
||||
if ( $Master[7] =~ /off/ ){
|
||||
if ($debug){print "Master was muted - umuting.\n";}
|
||||
system("amixer set Master toggle >/dev/null");
|
||||
}
|
||||
}
|
||||
@@ -1,675 +0,0 @@
|
||||
package Class::Accessor;
|
||||
require 5.00502;
|
||||
use strict;
|
||||
$Class::Accessor::VERSION = '0.31';
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Accessor - Automated accessor generation
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Employee;
|
||||
use base qw(Class::Accessor);
|
||||
Employee->mk_accessors(qw(name role salary));
|
||||
|
||||
# Meanwhile, in a nearby piece of code!
|
||||
# Class::Accessor provides new().
|
||||
my $mp = Foo->new({ name => "Marty", role => "JAPH" });
|
||||
|
||||
my $job = $mp->role; # gets $mp->{role}
|
||||
$mp->salary(400000); # sets $mp->{salary} = 400000 (I wish)
|
||||
|
||||
# like my @info = @{$mp}{qw(name role)}
|
||||
my @info = $mp->get(qw(name role));
|
||||
|
||||
# $mp->{salary} = 400000
|
||||
$mp->set('salary', 400000);
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This module automagically generates accessors/mutators for your class.
|
||||
|
||||
Most of the time, writing accessors is an exercise in cutting and
|
||||
pasting. You usually wind up with a series of methods like this:
|
||||
|
||||
sub name {
|
||||
my $self = shift;
|
||||
if(@_) {
|
||||
$self->{name} = $_[0];
|
||||
}
|
||||
return $self->{name};
|
||||
}
|
||||
|
||||
sub salary {
|
||||
my $self = shift;
|
||||
if(@_) {
|
||||
$self->{salary} = $_[0];
|
||||
}
|
||||
return $self->{salary};
|
||||
}
|
||||
|
||||
# etc...
|
||||
|
||||
One for each piece of data in your object. While some will be unique,
|
||||
doing value checks and special storage tricks, most will simply be
|
||||
exercises in repetition. Not only is it Bad Style to have a bunch of
|
||||
repetitious code, but its also simply not lazy, which is the real
|
||||
tragedy.
|
||||
|
||||
If you make your module a subclass of Class::Accessor and declare your
|
||||
accessor fields with mk_accessors() then you'll find yourself with a
|
||||
set of automatically generated accessors which can even be
|
||||
customized!
|
||||
|
||||
The basic set up is very simple:
|
||||
|
||||
package My::Class;
|
||||
use base qw(Class::Accessor);
|
||||
My::Class->mk_accessors( qw(foo bar car) );
|
||||
|
||||
Done. My::Class now has simple foo(), bar() and car() accessors
|
||||
defined.
|
||||
|
||||
=head2 What Makes This Different?
|
||||
|
||||
What makes this module special compared to all the other method
|
||||
generating modules (L<"SEE ALSO">)? By overriding the get() and set()
|
||||
methods you can alter the behavior of the accessors class-wide. Also,
|
||||
the accessors are implemented as closures which should cost a bit less
|
||||
memory than most other solutions which generate a new method for each
|
||||
accessor.
|
||||
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 new
|
||||
|
||||
my $obj = Class->new;
|
||||
my $obj = $other_obj->new;
|
||||
|
||||
my $obj = Class->new(\%fields);
|
||||
my $obj = $other_obj->new(\%fields);
|
||||
|
||||
Class::Accessor provides a basic constructor. It generates a
|
||||
hash-based object and can be called as either a class method or an
|
||||
object method.
|
||||
|
||||
It takes an optional %fields hash which is used to initialize the
|
||||
object (handy if you use read-only accessors). The fields of the hash
|
||||
correspond to the names of your accessors, so...
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_accessors('foo');
|
||||
|
||||
my $obj = Class->new({ foo => 42 });
|
||||
print $obj->foo; # 42
|
||||
|
||||
however %fields can contain anything, new() will shove them all into
|
||||
your object. Don't like it? Override it.
|
||||
|
||||
=cut
|
||||
|
||||
sub new {
|
||||
my($proto, $fields) = @_;
|
||||
my($class) = ref $proto || $proto;
|
||||
|
||||
$fields = {} unless defined $fields;
|
||||
|
||||
# make a copy of $fields.
|
||||
bless {%$fields}, $class;
|
||||
}
|
||||
|
||||
=head2 mk_accessors
|
||||
|
||||
Class->mk_accessors(@fields);
|
||||
|
||||
This creates accessor/mutator methods for each named field given in
|
||||
@fields. Foreach field in @fields it will generate two accessors.
|
||||
One called "field()" and the other called "_field_accessor()". For
|
||||
example:
|
||||
|
||||
# Generates foo(), _foo_accessor(), bar() and _bar_accessor().
|
||||
Class->mk_accessors(qw(foo bar));
|
||||
|
||||
See L<CAVEATS AND TRICKS/"Overriding autogenerated accessors">
|
||||
for details.
|
||||
|
||||
=cut
|
||||
|
||||
sub mk_accessors {
|
||||
my($self, @fields) = @_;
|
||||
|
||||
$self->_mk_accessors('rw', @fields);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
no strict 'refs';
|
||||
|
||||
sub _mk_accessors {
|
||||
my($self, $access, @fields) = @_;
|
||||
my $class = ref $self || $self;
|
||||
my $ra = $access eq 'rw' || $access eq 'ro';
|
||||
my $wa = $access eq 'rw' || $access eq 'wo';
|
||||
|
||||
foreach my $field (@fields) {
|
||||
my $accessor_name = $self->accessor_name_for($field);
|
||||
my $mutator_name = $self->mutator_name_for($field);
|
||||
if( $accessor_name eq 'DESTROY' or $mutator_name eq 'DESTROY' ) {
|
||||
$self->_carp("Having a data accessor named DESTROY in '$class' is unwise.");
|
||||
}
|
||||
if ($accessor_name eq $mutator_name) {
|
||||
my $accessor;
|
||||
if ($ra && $wa) {
|
||||
$accessor = $self->make_accessor($field);
|
||||
} elsif ($ra) {
|
||||
$accessor = $self->make_ro_accessor($field);
|
||||
} else {
|
||||
$accessor = $self->make_wo_accessor($field);
|
||||
}
|
||||
unless (defined &{"${class}::$accessor_name"}) {
|
||||
*{"${class}::$accessor_name"} = $accessor;
|
||||
}
|
||||
if ($accessor_name eq $field) {
|
||||
# the old behaviour
|
||||
my $alias = "_${field}_accessor";
|
||||
*{"${class}::$alias"} = $accessor unless defined &{"${class}::$alias"};
|
||||
}
|
||||
} else {
|
||||
if ($ra and not defined &{"${class}::$accessor_name"}) {
|
||||
*{"${class}::$accessor_name"} = $self->make_ro_accessor($field);
|
||||
}
|
||||
if ($wa and not defined &{"${class}::$mutator_name"}) {
|
||||
*{"${class}::$mutator_name"} = $self->make_wo_accessor($field);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub follow_best_practice {
|
||||
my($self) = @_;
|
||||
my $class = ref $self || $self;
|
||||
*{"${class}::accessor_name_for"} = \&best_practice_accessor_name_for;
|
||||
*{"${class}::mutator_name_for"} = \&best_practice_mutator_name_for;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
=head2 mk_ro_accessors
|
||||
|
||||
Class->mk_ro_accessors(@read_only_fields);
|
||||
|
||||
Same as mk_accessors() except it will generate read-only accessors
|
||||
(ie. true accessors). If you attempt to set a value with these
|
||||
accessors it will throw an exception. It only uses get() and not
|
||||
set().
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Class->mk_ro_accessors(qw(foo bar));
|
||||
|
||||
# Let's assume we have an object $foo of class Foo...
|
||||
print $foo->foo; # ok, prints whatever the value of $foo->{foo} is
|
||||
$foo->foo(42); # BOOM! Naughty you.
|
||||
|
||||
|
||||
=cut
|
||||
|
||||
sub mk_ro_accessors {
|
||||
my($self, @fields) = @_;
|
||||
|
||||
$self->_mk_accessors('ro', @fields);
|
||||
}
|
||||
|
||||
=head2 mk_wo_accessors
|
||||
|
||||
Class->mk_wo_accessors(@write_only_fields);
|
||||
|
||||
Same as mk_accessors() except it will generate write-only accessors
|
||||
(ie. mutators). If you attempt to read a value with these accessors
|
||||
it will throw an exception. It only uses set() and not get().
|
||||
|
||||
B<NOTE> I'm not entirely sure why this is useful, but I'm sure someone
|
||||
will need it. If you've found a use, let me know. Right now its here
|
||||
for orthoginality and because its easy to implement.
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Class->mk_wo_accessors(qw(foo bar));
|
||||
|
||||
# Let's assume we have an object $foo of class Foo...
|
||||
$foo->foo(42); # OK. Sets $self->{foo} = 42
|
||||
print $foo->foo; # BOOM! Can't read from this accessor.
|
||||
|
||||
=cut
|
||||
|
||||
sub mk_wo_accessors {
|
||||
my($self, @fields) = @_;
|
||||
|
||||
$self->_mk_accessors('wo', @fields);
|
||||
}
|
||||
|
||||
=head1 DETAILS
|
||||
|
||||
An accessor generated by Class::Accessor looks something like
|
||||
this:
|
||||
|
||||
# Your foo may vary.
|
||||
sub foo {
|
||||
my($self) = shift;
|
||||
if(@_) { # set
|
||||
return $self->set('foo', @_);
|
||||
}
|
||||
else {
|
||||
return $self->get('foo');
|
||||
}
|
||||
}
|
||||
|
||||
Very simple. All it does is determine if you're wanting to set a
|
||||
value or get a value and calls the appropriate method.
|
||||
Class::Accessor provides default get() and set() methods which
|
||||
your class can override. They're detailed later.
|
||||
|
||||
=head2 follow_best_practice
|
||||
|
||||
In Damian's Perl Best Practices book he recommends separate get and set methods
|
||||
with the prefix set_ and get_ to make it explicit what you intend to do. If you
|
||||
want to create those accessor methods instead of the default ones, call:
|
||||
|
||||
__PACKAGE__->follow_best_practice
|
||||
|
||||
=head2 accessor_name_for / mutator_name_for
|
||||
|
||||
You may have your own crazy ideas for the names of the accessors, so you can
|
||||
make those happen by overriding C<accessor_name_for> and C<mutator_name_for> in
|
||||
your subclass. (I copied that idea from Class::DBI.)
|
||||
|
||||
=cut
|
||||
|
||||
sub best_practice_accessor_name_for {
|
||||
my ($class, $field) = @_;
|
||||
return "get_$field";
|
||||
}
|
||||
|
||||
sub best_practice_mutator_name_for {
|
||||
my ($class, $field) = @_;
|
||||
return "set_$field";
|
||||
}
|
||||
|
||||
sub accessor_name_for {
|
||||
my ($class, $field) = @_;
|
||||
return $field;
|
||||
}
|
||||
|
||||
sub mutator_name_for {
|
||||
my ($class, $field) = @_;
|
||||
return $field;
|
||||
}
|
||||
|
||||
=head2 Modifying the behavior of the accessor
|
||||
|
||||
Rather than actually modifying the accessor itself, it is much more
|
||||
sensible to simply override the two key methods which the accessor
|
||||
calls. Namely set() and get().
|
||||
|
||||
If you -really- want to, you can override make_accessor().
|
||||
|
||||
=head2 set
|
||||
|
||||
$obj->set($key, $value);
|
||||
$obj->set($key, @values);
|
||||
|
||||
set() defines how generally one stores data in the object.
|
||||
|
||||
override this method to change how data is stored by your accessors.
|
||||
|
||||
=cut
|
||||
|
||||
sub set {
|
||||
my($self, $key) = splice(@_, 0, 2);
|
||||
|
||||
if(@_ == 1) {
|
||||
$self->{$key} = $_[0];
|
||||
}
|
||||
elsif(@_ > 1) {
|
||||
$self->{$key} = [@_];
|
||||
}
|
||||
else {
|
||||
$self->_croak("Wrong number of arguments received");
|
||||
}
|
||||
}
|
||||
|
||||
=head2 get
|
||||
|
||||
$value = $obj->get($key);
|
||||
@values = $obj->get(@keys);
|
||||
|
||||
get() defines how data is retreived from your objects.
|
||||
|
||||
override this method to change how it is retreived.
|
||||
|
||||
=cut
|
||||
|
||||
sub get {
|
||||
my $self = shift;
|
||||
|
||||
if(@_ == 1) {
|
||||
return $self->{$_[0]};
|
||||
}
|
||||
elsif( @_ > 1 ) {
|
||||
return @{$self}{@_};
|
||||
}
|
||||
else {
|
||||
$self->_croak("Wrong number of arguments received");
|
||||
}
|
||||
}
|
||||
|
||||
=head2 make_accessor
|
||||
|
||||
$accessor = Class->make_accessor($field);
|
||||
|
||||
Generates a subroutine reference which acts as an accessor for the given
|
||||
$field. It calls get() and set().
|
||||
|
||||
If you wish to change the behavior of your accessors, try overriding
|
||||
get() and set() before you start mucking with make_accessor().
|
||||
|
||||
=cut
|
||||
|
||||
sub make_accessor {
|
||||
my ($class, $field) = @_;
|
||||
|
||||
# Build a closure around $field.
|
||||
return sub {
|
||||
my $self = shift;
|
||||
|
||||
if(@_) {
|
||||
return $self->set($field, @_);
|
||||
}
|
||||
else {
|
||||
return $self->get($field);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
=head2 make_ro_accessor
|
||||
|
||||
$read_only_accessor = Class->make_ro_accessor($field);
|
||||
|
||||
Generates a subroutine refrence which acts as a read-only accessor for
|
||||
the given $field. It only calls get().
|
||||
|
||||
Override get() to change the behavior of your accessors.
|
||||
|
||||
=cut
|
||||
|
||||
sub make_ro_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
my $self = shift;
|
||||
|
||||
if (@_) {
|
||||
my $caller = caller;
|
||||
$self->_croak("'$caller' cannot alter the value of '$field' on objects of class '$class'");
|
||||
}
|
||||
else {
|
||||
return $self->get($field);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
=head2 make_wo_accessor
|
||||
|
||||
$read_only_accessor = Class->make_wo_accessor($field);
|
||||
|
||||
Generates a subroutine refrence which acts as a write-only accessor
|
||||
(mutator) for the given $field. It only calls set().
|
||||
|
||||
Override set() to change the behavior of your accessors.
|
||||
|
||||
=cut
|
||||
|
||||
sub make_wo_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
my $self = shift;
|
||||
|
||||
unless (@_) {
|
||||
my $caller = caller;
|
||||
$self->_croak("'$caller' cannot access the value of '$field' on objects of class '$class'");
|
||||
}
|
||||
else {
|
||||
return $self->set($field, @_);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
=head1 EXCEPTIONS
|
||||
|
||||
If something goes wrong Class::Accessor will warn or die by calling Carp::carp
|
||||
or Carp::croak. If you don't like this you can override _carp() and _croak() in
|
||||
your subclass and do whatever else you want.
|
||||
|
||||
=cut
|
||||
|
||||
use Carp ();
|
||||
|
||||
sub _carp {
|
||||
my ($self, $msg) = @_;
|
||||
Carp::carp($msg || $self);
|
||||
return;
|
||||
}
|
||||
|
||||
sub _croak {
|
||||
my ($self, $msg) = @_;
|
||||
Carp::croak($msg || $self);
|
||||
return;
|
||||
}
|
||||
|
||||
=head1 EFFICIENCY
|
||||
|
||||
Class::Accessor does not employ an autoloader, thus it is much faster
|
||||
than you'd think. Its generated methods incur no special penalty over
|
||||
ones you'd write yourself.
|
||||
|
||||
accessors:
|
||||
Rate Basic Average Fast Faster Direct
|
||||
Basic 189150/s -- -42% -51% -55% -89%
|
||||
Average 327679/s 73% -- -16% -22% -82%
|
||||
Fast 389212/s 106% 19% -- -8% -78%
|
||||
Faster 421646/s 123% 29% 8% -- -76%
|
||||
Direct 1771243/s 836% 441% 355% 320% --
|
||||
|
||||
mutators:
|
||||
Rate Basic Average Fast Faster Direct
|
||||
Basic 173769/s -- -34% -53% -59% -90%
|
||||
Average 263046/s 51% -- -29% -38% -85%
|
||||
Fast 371158/s 114% 41% -- -13% -78%
|
||||
Faster 425821/s 145% 62% 15% -- -75%
|
||||
Direct 1699081/s 878% 546% 358% 299% --
|
||||
|
||||
Class::Accessor::Fast is faster than methods written by an average programmer
|
||||
(where "average" is based on Schwern's example code).
|
||||
|
||||
Class::Accessor is slower than average, but more flexible.
|
||||
|
||||
Class::Accessor::Faster is even faster than Class::Accessor::Fast. It uses an
|
||||
array internally, not a hash. This could be a good or bad feature depending on
|
||||
your point of view.
|
||||
|
||||
Direct hash access is, of course, much faster than all of these, but it
|
||||
provides no encapsulation.
|
||||
|
||||
Of course, its not as simple as saying "Class::Accessor is slower than
|
||||
average". These are benchmarks for a simple accessor. If your accessors do
|
||||
any sort of complicated work (such as talking to a database or writing to a
|
||||
file) the time spent doing that work will quickly swamp the time spend just
|
||||
calling the accessor. In that case, Class::Accessor and the ones you write
|
||||
will be roughly the same speed.
|
||||
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
Here's an example of generating an accessor for every public field of
|
||||
your class.
|
||||
|
||||
package Altoids;
|
||||
|
||||
use base qw(Class::Accessor Class::Fields);
|
||||
use fields qw(curiously strong mints);
|
||||
Altoids->mk_accessors( Altoids->show_fields('Public') );
|
||||
|
||||
sub new {
|
||||
my $proto = shift;
|
||||
my $class = ref $proto || $proto;
|
||||
return fields::new($class);
|
||||
}
|
||||
|
||||
my Altoids $tin = Altoids->new;
|
||||
|
||||
$tin->curiously('Curiouser and curiouser');
|
||||
print $tin->{curiously}; # prints 'Curiouser and curiouser'
|
||||
|
||||
|
||||
# Subclassing works, too.
|
||||
package Mint::Snuff;
|
||||
use base qw(Altoids);
|
||||
|
||||
my Mint::Snuff $pouch = Mint::Snuff->new;
|
||||
$pouch->strong('Blow your head off!');
|
||||
print $pouch->{strong}; # prints 'Blow your head off!'
|
||||
|
||||
|
||||
Here's a simple example of altering the behavior of your accessors.
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_accessor(qw(this that up down));
|
||||
|
||||
sub get {
|
||||
my $self = shift;
|
||||
|
||||
# Note every time someone gets some data.
|
||||
print STDERR "Getting @_\n";
|
||||
|
||||
$self->SUPER::get(@_);
|
||||
}
|
||||
|
||||
sub set {
|
||||
my ($self, $key) = splice(@_, 0, 2);
|
||||
|
||||
# Note every time someone sets some data.
|
||||
print STDERR "Setting $key to @_\n";
|
||||
|
||||
$self->SUPER::set($key, @_);
|
||||
}
|
||||
|
||||
|
||||
=head1 CAVEATS AND TRICKS
|
||||
|
||||
Class::Accessor has to do some internal wackiness to get its
|
||||
job done quickly and efficiently. Because of this, there's a few
|
||||
tricks and traps one must know about.
|
||||
|
||||
Hey, nothing's perfect.
|
||||
|
||||
=head2 Don't make a field called DESTROY
|
||||
|
||||
This is bad. Since DESTROY is a magical method it would be bad for us
|
||||
to define an accessor using that name. Class::Accessor will
|
||||
carp if you try to use it with a field named "DESTROY".
|
||||
|
||||
=head2 Overriding autogenerated accessors
|
||||
|
||||
You may want to override the autogenerated accessor with your own, yet
|
||||
have your custom accessor call the default one. For instance, maybe
|
||||
you want to have an accessor which checks its input. Normally, one
|
||||
would expect this to work:
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Foo->mk_accessors(qw(email this that whatever));
|
||||
|
||||
# Only accept addresses which look valid.
|
||||
sub email {
|
||||
my($self) = shift;
|
||||
my($email) = @_;
|
||||
|
||||
if( @_ ) { # Setting
|
||||
require Email::Valid;
|
||||
unless( Email::Valid->address($email) ) {
|
||||
carp("$email doesn't look like a valid address.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return $self->SUPER::email(@_);
|
||||
}
|
||||
|
||||
There's a subtle problem in the last example, and its in this line:
|
||||
|
||||
return $self->SUPER::email(@_);
|
||||
|
||||
If we look at how Foo was defined, it called mk_accessors() which
|
||||
stuck email() right into Foo's namespace. There *is* no
|
||||
SUPER::email() to delegate to! Two ways around this... first is to
|
||||
make a "pure" base class for Foo. This pure class will generate the
|
||||
accessors and provide the necessary super class for Foo to use:
|
||||
|
||||
package Pure::Organic::Foo;
|
||||
use base qw(Class::Accessor);
|
||||
Pure::Organic::Foo->mk_accessors(qw(email this that whatever));
|
||||
|
||||
package Foo;
|
||||
use base qw(Pure::Organic::Foo);
|
||||
|
||||
And now Foo::email() can override the generated
|
||||
Pure::Organic::Foo::email() and use it as SUPER::email().
|
||||
|
||||
This is probably the most obvious solution to everyone but me.
|
||||
Instead, what first made sense to me was for mk_accessors() to define
|
||||
an alias of email(), _email_accessor(). Using this solution,
|
||||
Foo::email() would be written with:
|
||||
|
||||
return $self->_email_accessor(@_);
|
||||
|
||||
instead of the expected SUPER::email().
|
||||
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Copyright 2007 Marty Pauley <marty+perl@kasei.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the same terms as Perl itself. That means either (a) the GNU General Public
|
||||
License or (b) the Artistic License.
|
||||
|
||||
=head2 ORIGINAL AUTHOR
|
||||
|
||||
Michael G Schwern <schwern@pobox.com>
|
||||
|
||||
=head2 THANKS
|
||||
|
||||
Liz and RUZ for performance tweaks.
|
||||
|
||||
Tels, for his big feature request/bug report.
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Class::Accessor::Fast>
|
||||
|
||||
These are some modules which do similar things in different ways
|
||||
L<Class::Struct>, L<Class::Methodmaker>, L<Class::Generate>,
|
||||
L<Class::Class>, L<Class::Contract>
|
||||
|
||||
L<Class::DBI> for an example of this module in use.
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
||||
@@ -1,94 +0,0 @@
|
||||
package Class::Accessor::Fast;
|
||||
use base 'Class::Accessor';
|
||||
use strict;
|
||||
$Class::Accessor::Fast::VERSION = '0.31';
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Accessor::Fast - Faster, but less expandable, accessors
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor::Fast);
|
||||
|
||||
# The rest is the same as Class::Accessor but without set() and get().
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a faster but less expandable version of Class::Accessor.
|
||||
Class::Accessor's generated accessors require two method calls to accompish
|
||||
their task (one for the accessor, another for get() or set()).
|
||||
Class::Accessor::Fast eliminates calling set()/get() and does the access itself,
|
||||
resulting in a somewhat faster accessor.
|
||||
|
||||
The downside is that you can't easily alter the behavior of your
|
||||
accessors, nor can your subclasses. Of course, should you need this
|
||||
later, you can always swap out Class::Accessor::Fast for
|
||||
Class::Accessor.
|
||||
|
||||
Read the documentation for Class::Accessor for more info.
|
||||
|
||||
=cut
|
||||
|
||||
sub make_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
return $_[0]->{$field} if @_ == 1;
|
||||
return $_[0]->{$field} = $_[1] if @_ == 2;
|
||||
return (shift)->{$field} = \@_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
sub make_ro_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
return $_[0]->{$field} if @_ == 1;
|
||||
my $caller = caller;
|
||||
$_[0]->_croak("'$caller' cannot alter the value of '$field' on objects of class '$class'");
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
sub make_wo_accessor {
|
||||
my($class, $field) = @_;
|
||||
|
||||
return sub {
|
||||
if (@_ == 1) {
|
||||
my $caller = caller;
|
||||
$_[0]->_croak("'$caller' cannot access the value of '$field' on objects of class '$class'");
|
||||
}
|
||||
else {
|
||||
return $_[0]->{$field} = $_[1] if @_ == 2;
|
||||
return (shift)->{$field} = \@_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
=head1 EFFICIENCY
|
||||
|
||||
L<Class::Accessor/EFFICIENCY> for an efficiency comparison.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Copyright 2007 Marty Pauley <marty+perl@kasei.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the same terms as Perl itself. That means either (a) the GNU General Public
|
||||
License or (b) the Artistic License.
|
||||
|
||||
=head2 ORIGINAL AUTHOR
|
||||
|
||||
Michael G Schwern <schwern@pobox.com>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Class::Accessor>
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
||||
@@ -1,105 +0,0 @@
|
||||
package Class::Accessor::Faster;
|
||||
use base 'Class::Accessor';
|
||||
use strict;
|
||||
$Class::Accessor::Faster::VERSION = '0.31';
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Class::Accessor::Faster - Even faster, but less expandable, accessors
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
package Foo;
|
||||
use base qw(Class::Accessor::Faster);
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a faster but less expandable version of Class::Accessor::Fast.
|
||||
|
||||
Class::Accessor's generated accessors require two method calls to accompish
|
||||
their task (one for the accessor, another for get() or set()).
|
||||
|
||||
Class::Accessor::Fast eliminates calling set()/get() and does the access itself,
|
||||
resulting in a somewhat faster accessor.
|
||||
|
||||
Class::Accessor::Faster uses an array reference underneath to be faster.
|
||||
|
||||
Read the documentation for Class::Accessor for more info.
|
||||
|
||||
=cut
|
||||
|
||||
my %slot;
|
||||
sub _slot {
|
||||
my($class, $field) = @_;
|
||||
my $n = $slot{$class}->{$field};
|
||||
return $n if defined $n;
|
||||
$n = keys %{$slot{$class}};
|
||||
$slot{$class}->{$field} = $n;
|
||||
return $n;
|
||||
}
|
||||
|
||||
sub new {
|
||||
my($proto, $fields) = @_;
|
||||
my($class) = ref $proto || $proto;
|
||||
my $self = bless [], $class;
|
||||
|
||||
$fields = {} unless defined $fields;
|
||||
for my $k (keys %$fields) {
|
||||
my $n = $class->_slot($k);
|
||||
$self->[$n] = $fields->{$k};
|
||||
}
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub make_accessor {
|
||||
my($class, $field) = @_;
|
||||
my $n = $class->_slot($field);
|
||||
return sub {
|
||||
return $_[0]->[$n] if @_ == 1;
|
||||
return $_[0]->[$n] = $_[1] if @_ == 2;
|
||||
return (shift)->[$n] = \@_;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
sub make_ro_accessor {
|
||||
my($class, $field) = @_;
|
||||
my $n = $class->_slot($field);
|
||||
return sub {
|
||||
return $_[0]->[$n] if @_ == 1;
|
||||
my $caller = caller;
|
||||
$_[0]->_croak("'$caller' cannot alter the value of '$field' on objects of class '$class'");
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
sub make_wo_accessor {
|
||||
my($class, $field) = @_;
|
||||
my $n = $class->_slot($field);
|
||||
return sub {
|
||||
if (@_ == 1) {
|
||||
my $caller = caller;
|
||||
$_[0]->_croak("'$caller' cannot access the value of '$field' on objects of class '$class'");
|
||||
} else {
|
||||
return $_[0]->[$n] = $_[1] if @_ == 2;
|
||||
return (shift)->[$n] = \@_;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Copyright 2007 Marty Pauley <marty+perl@kasei.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the same terms as Perl itself. That means either (a) the GNU General Public
|
||||
License or (b) the Artistic License.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Class::Accessor>
|
||||
|
||||
=cut
|
||||
|
||||
1;
|
||||
@@ -1,897 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use Audio::MPD::Collection;
|
||||
use Audio::MPD::Common::Item;
|
||||
use Audio::MPD::Common::Stats;
|
||||
use Audio::MPD::Common::Status;
|
||||
use Audio::MPD::Playlist;
|
||||
use Encode;
|
||||
use IO::Socket;
|
||||
use Readonly;
|
||||
|
||||
|
||||
use base qw[ Class::Accessor::Fast Exporter ];
|
||||
__PACKAGE__->mk_accessors(
|
||||
qw[ _conntype _host _password _port _socket
|
||||
collection playlist version ] );
|
||||
|
||||
|
||||
our $VERSION = '0.19.1';
|
||||
|
||||
Readonly our $REUSE => 0;
|
||||
Readonly our $ONCE => 1;
|
||||
|
||||
our @EXPORT = qw[ $REUSE $ONCE ];
|
||||
|
||||
|
||||
#--
|
||||
# Constructor
|
||||
|
||||
#
|
||||
# my $mpd = Audio::MPD->new( [%opts] )
|
||||
#
|
||||
# This is the constructor for Audio::MPD. One can specify the following
|
||||
# options:
|
||||
# - hostname => $hostname : defaults to environment var MPD_HOST, then to 'localhost'
|
||||
# - port => $port : defaults to env var MPD_PORT, then to 6600
|
||||
# - password => $password : defaults to env var MPD_PASSWORD, then to ''
|
||||
# - conntype => $type : how the connection to mpd server is handled. it can be
|
||||
# either $REUSE: reuse the same connection
|
||||
# or $ONCE: open a new connection per command (default)
|
||||
#
|
||||
sub new {
|
||||
my ($class, %opts) = @_;
|
||||
|
||||
# use mpd defaults.
|
||||
my ($default_password, $default_host) = split( '@', $ENV{MPD_HOST} )
|
||||
if exists $ENV{MPD_HOST} && $ENV{MPD_HOST} =~ /@/;
|
||||
my $host = $opts{host} || $default_host || $ENV{MPD_HOST} || 'localhost';
|
||||
my $port = $opts{port} || $ENV{MPD_PORT} || '6600';
|
||||
my $password = $opts{password} || $ENV{MPD_PASSWORD} || $default_password || '';
|
||||
|
||||
# create & bless the object.
|
||||
my $self = {
|
||||
_host => $host,
|
||||
_port => $port,
|
||||
_password => $password,
|
||||
_conntype => exists $opts{conntype} ? $opts{conntype} : $REUSE,
|
||||
};
|
||||
bless $self, $class;
|
||||
|
||||
# create the connection if conntype is set to $REUSE
|
||||
$self->_connect_to_mpd_server if $self->_conntype == $REUSE;
|
||||
|
||||
|
||||
# create the helper objects and store them.
|
||||
$self->collection( Audio::MPD::Collection->new($self) );
|
||||
$self->playlist ( Audio::MPD::Playlist->new($self) );
|
||||
|
||||
# try to issue a ping to test connection - this can die.
|
||||
$self->ping;
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
#--
|
||||
# Private methods
|
||||
|
||||
|
||||
#
|
||||
# $mpd->_connect_to_mpd_server;
|
||||
#
|
||||
# This method connects to the mpd server. It can die on several conditions:
|
||||
# - if the server cannot be reached,
|
||||
# - if it's not an mpd server,
|
||||
# - or if the password is incorrect,
|
||||
#
|
||||
sub _connect_to_mpd_server {
|
||||
my ($self) = @_;
|
||||
|
||||
# try to connect to mpd.
|
||||
my $socket = IO::Socket::INET->new(
|
||||
PeerAddr => $self->_host,
|
||||
PeerPort => $self->_port,
|
||||
)
|
||||
or die "Could not create socket: $!\n";
|
||||
|
||||
# parse version information.
|
||||
my $line = $socket->getline;
|
||||
chomp $line;
|
||||
die "Not a mpd server - welcome string was: [$line]\n"
|
||||
if $line !~ /^OK MPD (.+)$/;
|
||||
$self->version($1);
|
||||
|
||||
# send password.
|
||||
if ( $self->_password ) {
|
||||
$socket->print( 'password ' . encode('utf-8', $self->_password) . "\n" );
|
||||
$line = $socket->getline;
|
||||
die $line if $line =~ s/^ACK //;
|
||||
}
|
||||
|
||||
# save socket
|
||||
$self->_socket($socket);
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @result = $mpd->_send_command( $command );
|
||||
#
|
||||
# This method is central to the module. It is responsible for interacting with
|
||||
# mpd by sending the $command and reading output - that will be returned as an
|
||||
# array of chomped lines (status line will not be returned).
|
||||
#
|
||||
# This method can die on several conditions:
|
||||
# - if the server cannot be reached,
|
||||
# - if it's not an mpd server,
|
||||
# - if the password is incorrect,
|
||||
# - or if the command is an invalid mpd command.
|
||||
# In the latter case, the mpd error message will be returned.
|
||||
#
|
||||
sub _send_command {
|
||||
my ($self, $command) = @_;
|
||||
|
||||
$self->_connect_to_mpd_server if $self->_conntype == $ONCE;
|
||||
my $socket = $self->_socket;
|
||||
|
||||
# ok, now we're connected - let's issue the command.
|
||||
$socket->print( encode('utf-8', $command) );
|
||||
my @output;
|
||||
while (defined ( my $line = $socket->getline ) ) {
|
||||
chomp $line;
|
||||
die $line if $line =~ s/^ACK //; # oops - error.
|
||||
last if $line =~ /^OK/; # end of output.
|
||||
push @output, decode('utf-8', $line);
|
||||
}
|
||||
|
||||
# close the socket.
|
||||
$socket->close if $self->_conntype == $ONCE;
|
||||
|
||||
return @output;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @items = $mpd->_cooked_command_as_items( $command );
|
||||
#
|
||||
# Lots of Audio::MPD methods are using _send_command() and then parse the
|
||||
# output as a collection of AMC::Item. This method is meant to factorize
|
||||
# this code, and will parse the raw output of _send_command() in a cooked
|
||||
# list of items.
|
||||
#
|
||||
sub _cooked_command_as_items {
|
||||
my ($self, $command) = @_;
|
||||
|
||||
my @lines = $self->_send_command($command);
|
||||
my (@items, %param);
|
||||
|
||||
# parse lines in reverse order since "file:" or "directory:" lines
|
||||
# come first. therefore, let's first store every other parameter,
|
||||
# and the last line will trigger the object creation.
|
||||
# of course, since we want to preserve the playlist order, this means
|
||||
# that we're going to unshift the objects instead of push.
|
||||
foreach my $line (reverse @lines) {
|
||||
my ($k,$v) = split /:\s/, $line, 2;
|
||||
$param{$k} = $v;
|
||||
next unless $k eq 'file' || $k eq 'directory' || $k eq 'playlist'; # last param of item
|
||||
unshift @items, Audio::MPD::Common::Item->new(%param);
|
||||
%param = ();
|
||||
}
|
||||
|
||||
return @items;
|
||||
}
|
||||
|
||||
|
||||
sub _cooked_command_as_filename {
|
||||
my ($self, $command) = @_;
|
||||
|
||||
my @lines = $self->_send_command($command);
|
||||
my (@items, %param);
|
||||
|
||||
# parse lines in reverse order since "file:" or "directory:" lines
|
||||
# come first. therefore, let's first store every other parameter,
|
||||
# and the last line will trigger the object creation.
|
||||
# of course, since we want to preserve the playlist order, this means
|
||||
# that we're going to unshift the objects instead of push.
|
||||
foreach my $line (@lines) {
|
||||
my ($k,$v) = split /:\s/, $line, 2;
|
||||
if ( $k eq 'file'){$param{$k} = $v;}
|
||||
unshift @items, $param{'file'};
|
||||
%param = ();
|
||||
}
|
||||
|
||||
return @items;
|
||||
}
|
||||
|
||||
#
|
||||
# my %hash = $mpd->_cooked_command_as_kv( $command );
|
||||
#
|
||||
# Lots of Audio::MPD methods are using _send_command() and then parse the
|
||||
# output to get a list of key / value (with the colon ":" acting as separator).
|
||||
# This method is meant to factorize this code, and will parse the raw output
|
||||
# of _send_command() in a cooked hash.
|
||||
#
|
||||
sub _cooked_command_as_kv {
|
||||
my ($self, $command) = @_;
|
||||
my %hash =
|
||||
map { split(/:\s/, $_, 2) }
|
||||
$self->_send_command($command);
|
||||
return %hash;
|
||||
}
|
||||
|
||||
#
|
||||
# my @list = $mpd->_cooked_command_strip_first_field( $command );
|
||||
#
|
||||
# Lots of Audio::MPD methods are using _send_command() and then parse the
|
||||
# output to remove the first field (with the colon ":" acting as separator).
|
||||
# This method is meant to factorize this code, and will parse the raw output
|
||||
# of _send_command() in a cooked list of strings.
|
||||
#
|
||||
sub _cooked_command_strip_first_field {
|
||||
my ($self, $command) = @_;
|
||||
|
||||
my @list =
|
||||
map { ( split(/:\s+/, $_, 2) )[1] }
|
||||
$self->_send_command($command);
|
||||
return @list;
|
||||
}
|
||||
|
||||
|
||||
#--
|
||||
# Public methods
|
||||
|
||||
# -- MPD interaction: general commands
|
||||
|
||||
#
|
||||
# $mpd->ping;
|
||||
#
|
||||
# Sends a ping command to the mpd server.
|
||||
#
|
||||
sub ping {
|
||||
my ($self) = @_;
|
||||
$self->_send_command( "ping\n" );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my $version = $mpd->version;
|
||||
#
|
||||
# Return version of MPD server's connected.
|
||||
#
|
||||
# sub version {} # implemented as an accessor.
|
||||
#
|
||||
|
||||
|
||||
#
|
||||
# $mpd->kill;
|
||||
#
|
||||
# Send a message to the MPD server telling it to shut down.
|
||||
#
|
||||
sub kill {
|
||||
my ($self) = @_;
|
||||
$self->_send_command("kill\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->password( [$password] )
|
||||
#
|
||||
# Change password used to communicate with MPD server to $password.
|
||||
# Empty string is assumed if $password is not supplied.
|
||||
#
|
||||
sub password {
|
||||
my ($self, $passwd) = @_;
|
||||
$passwd ||= '';
|
||||
$self->_password($passwd);
|
||||
$self->ping; # ping sends a command, and thus the password is sent
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->updatedb( [$path] );
|
||||
#
|
||||
# Force mpd to rescan its collection. If $path (relative to MPD's music
|
||||
# directory) is supplied, MPD will only scan it - otherwise, MPD will rescan
|
||||
# its whole collection.
|
||||
#
|
||||
sub updatedb {
|
||||
my ($self, $path) = @_;
|
||||
$path ||= '';
|
||||
$self->_send_command("update $path\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @handlers = $mpd->urlhandlers;
|
||||
#
|
||||
# Return an array of supported URL schemes.
|
||||
#
|
||||
sub urlhandlers {
|
||||
my ($self) = @_;
|
||||
return $self->_cooked_command_strip_first_field("urlhandlers\n");
|
||||
}
|
||||
|
||||
|
||||
# -- MPD interaction: handling volume & output
|
||||
|
||||
#
|
||||
# $mpd->volume( [+][-]$volume );
|
||||
#
|
||||
# Sets the audio output volume percentage to absolute $volume.
|
||||
# If $volume is prefixed by '+' or '-' then the volume is changed relatively
|
||||
# by that value.
|
||||
#
|
||||
sub volume {
|
||||
my ($self, $volume) = @_;
|
||||
|
||||
if ($volume =~ /^(-|\+)(\d+)/ ) {
|
||||
my $current = $self->status->volume;
|
||||
$volume = $1 eq '+' ? $current + $2 : $current - $2;
|
||||
}
|
||||
$self->_send_command("setvol $volume\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->output_enable( $output );
|
||||
#
|
||||
# Enable the specified audio output. $output is the ID of the audio output.
|
||||
#
|
||||
sub output_enable {
|
||||
my ($self, $output) = @_;
|
||||
$self->_send_command("enableoutput $output\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->output_disable( $output );
|
||||
#
|
||||
# Disable the specified audio output. $output is the ID of the audio output.
|
||||
#
|
||||
sub output_disable {
|
||||
my ($self, $output) = @_;
|
||||
$self->_send_command("disableoutput $output\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
# -- MPD interaction: retrieving info from current state
|
||||
|
||||
#
|
||||
# $mpd->stats;
|
||||
#
|
||||
# Return an AMC::Stats object with the current statistics of MPD.
|
||||
#
|
||||
sub stats {
|
||||
my ($self) = @_;
|
||||
my %kv = $self->_cooked_command_as_kv( "stats\n" );
|
||||
return Audio::MPD::Common::Stats->new(\%kv);
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my $status = $mpd->status;
|
||||
#
|
||||
# Return an AMC::Status object with various information on current
|
||||
# MPD server settings. Check the embedded pod for more information on the
|
||||
# available accessors.
|
||||
#
|
||||
sub status {
|
||||
my ($self) = @_;
|
||||
my %kv = $self->_cooked_command_as_kv( "status\n" );
|
||||
my $status = Audio::MPD::Common::Status->new( \%kv );
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my $song = $mpd->current;
|
||||
#
|
||||
# Return an AMC::Item::Song representing the song currently playing.
|
||||
#
|
||||
sub current {
|
||||
my ($self) = @_;
|
||||
my ($item) = $self->_cooked_command_as_items("currentsong\n");
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my $song = $mpd->song( [$song] )
|
||||
#
|
||||
# Return an AMC::Item::Song representing the song number $song.
|
||||
# If $song is not supplied, returns the current song.
|
||||
#
|
||||
sub song {
|
||||
my ($self, $song) = @_;
|
||||
return $self->current unless defined $song;
|
||||
my ($item) = $self->_cooked_command_as_items("playlistinfo $song\n");
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my $song = $mpd->songid( [$songid] )
|
||||
#
|
||||
# Return an AMC::Item::Song representing the song with id $songid.
|
||||
# If $songid is not supplied, returns the current song.
|
||||
#
|
||||
sub songid {
|
||||
my ($self, $songid) = @_;
|
||||
return $self->current unless defined $songid;
|
||||
my ($item) = $self->_cooked_command_as_items("playlistid $songid\n");
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
||||
# -- MPD interaction: altering settings
|
||||
|
||||
#
|
||||
# $mpd->repeat( [$repeat] );
|
||||
#
|
||||
# Set the repeat mode to $repeat (1 or 0). If $repeat is not specified then
|
||||
# the repeat mode is toggled.
|
||||
#
|
||||
sub repeat {
|
||||
my ($self, $mode) = @_;
|
||||
|
||||
$mode = not $self->status->repeat
|
||||
unless defined $mode; # toggle if no param
|
||||
$mode = $mode ? 1 : 0; # force integer
|
||||
$self->_send_command("repeat $mode\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->random( [$random] );
|
||||
#
|
||||
# Set the random mode to $random (1 or 0). If $random is not specified then
|
||||
# the random mode is toggled.
|
||||
#
|
||||
sub random {
|
||||
my ($self, $mode) = @_;
|
||||
|
||||
$mode = not $self->status->random
|
||||
unless defined $mode; # toggle if no param
|
||||
$mode = $mode ? 1 : 0; # force integer
|
||||
$self->_send_command("random $mode\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->fade( [$seconds] );
|
||||
#
|
||||
# Enable crossfading and set the duration of crossfade between songs. If
|
||||
# $seconds is not specified or $seconds is 0, then crossfading is disabled.
|
||||
#
|
||||
sub fade {
|
||||
my ($self, $value) = @_;
|
||||
$value ||= 0;
|
||||
$self->_send_command("crossfade $value\n");
|
||||
}
|
||||
|
||||
|
||||
# -- MPD interaction: controlling playback
|
||||
|
||||
#
|
||||
# $mpd->play( [$song] );
|
||||
#
|
||||
# Begin playing playlist at song number $song. If no argument supplied,
|
||||
# resume playing.
|
||||
#
|
||||
sub play {
|
||||
my ($self, $number) = @_;
|
||||
$number = '' unless defined $number;
|
||||
$self->_send_command("play $number\n");
|
||||
}
|
||||
|
||||
#
|
||||
# $mpd->playid( [$songid] );
|
||||
#
|
||||
# Begin playing playlist at song ID $songid. If no argument supplied,
|
||||
# resume playing.
|
||||
#
|
||||
sub playid {
|
||||
my ($self, $number) = @_;
|
||||
$number ||= '';
|
||||
$self->_send_command("playid $number\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->pause( [$sate] );
|
||||
#
|
||||
# Pause playback. If $state is 0 then the current track is unpaused, if
|
||||
# $state is 1 then the current track is paused.
|
||||
#
|
||||
# Note that if $state is not given, pause state will be toggled.
|
||||
#
|
||||
sub pause {
|
||||
my ($self, $state) = @_;
|
||||
$state ||= ''; # default is to toggle
|
||||
$self->_send_command("pause $state\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->stop;
|
||||
#
|
||||
# Stop playback.
|
||||
#
|
||||
sub stop {
|
||||
my ($self) = @_;
|
||||
$self->_send_command("stop\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->next;
|
||||
#
|
||||
# Play next song in playlist.
|
||||
#
|
||||
sub next {
|
||||
my ($self) = @_;
|
||||
$self->_send_command("next\n");
|
||||
}
|
||||
|
||||
#
|
||||
# $mpd->prev;
|
||||
#
|
||||
# Play previous song in playlist.
|
||||
#
|
||||
sub prev {
|
||||
my($self) = shift;
|
||||
$self->_send_command("previous\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->seek( $time, [$song] );
|
||||
#
|
||||
# Seek to $time seconds in song number $song. If $song number is not specified
|
||||
# then the perl module will try and seek to $time in the current song.
|
||||
#
|
||||
sub seek {
|
||||
my ($self, $time, $song) = @_;
|
||||
$time ||= 0; $time = int $time;
|
||||
$song = $self->status->song if not defined $song; # seek in current song
|
||||
$self->_send_command( "seek $song $time\n" );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $mpd->seekid( $time, [$songid] );
|
||||
#
|
||||
# Seek to $time seconds in song ID $songid. If $songid number is not specified
|
||||
# then the perl module will try and seek to $time in the current song.
|
||||
#
|
||||
sub seekid {
|
||||
my ($self, $time, $song) = @_;
|
||||
$time ||= 0; $time = int $time;
|
||||
$song = $self->status->songid if not defined $song; # seek in current song
|
||||
$self->_send_command( "seekid $song $time\n" );
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
||||
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD - class to talk to MPD (Music Player Daemon) servers
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Audio::MPD;
|
||||
|
||||
my $mpd = Audio::MPD->new();
|
||||
$mpd->play();
|
||||
sleep 10;
|
||||
$mpd->next();
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Audio::MPD gives a clear object-oriented interface for talking to and
|
||||
controlling MPD (Music Player Daemon) servers. A connection to the MPD
|
||||
server is established as soon as a new Audio::MPD object is created.
|
||||
|
||||
Note that the module will by default connect to mpd before sending any
|
||||
command, and will disconnect after the command has been issued. This scheme
|
||||
is far from optimal, but allows us not to care about timeout disconnections.
|
||||
|
||||
B</!\> Note that Audio::MPD is using high-level, blocking sockets. This
|
||||
means that if the mpd server is slow, or hangs for whatever reason, or
|
||||
even crash abruptly, the program will be hung forever in this sub. The
|
||||
POE::Component::Client::MPD module is way safer - you're advised to use
|
||||
it instead of Audio::MPD. Or you can try to set C<conntype> to C<$REUSE>
|
||||
(see Audio::MPD constructor for more details), but you would be then on
|
||||
your own to deal with disconnections.
|
||||
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 Constructor
|
||||
|
||||
=over 4
|
||||
|
||||
=item new( [%opts] )
|
||||
|
||||
This is the constructor for Audio::MPD. One can specify the following
|
||||
options:
|
||||
|
||||
=over 4
|
||||
|
||||
=item hostname => C<$hostname>
|
||||
|
||||
defaults to environment var MPD_HOST, then to 'localhost'. Note that
|
||||
MPD_HOST can be of the form password@host.
|
||||
|
||||
=item port => C<$port>
|
||||
|
||||
defaults to environment var MPD_PORT, then to 6600.
|
||||
|
||||
=item password => $password
|
||||
|
||||
defaults to environment var MPD_PASSWORD, then to ''.
|
||||
|
||||
=item conntype => $type
|
||||
|
||||
change how the connection to mpd server is handled. It can be either
|
||||
C<$REUSE> to reuse the same connection or C<$ONCE> to open a new
|
||||
connection per command (default)
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Controlling the server
|
||||
|
||||
=over 4
|
||||
|
||||
=item $mpd->ping()
|
||||
|
||||
Sends a ping command to the mpd server.
|
||||
|
||||
|
||||
=item $mpd->version()
|
||||
|
||||
Return the version number for the server we are connected to.
|
||||
|
||||
|
||||
=item $mpd->kill()
|
||||
|
||||
Send a message to the MPD server telling it to shut down.
|
||||
|
||||
|
||||
=item $mpd->password( [$password] )
|
||||
|
||||
Change password used to communicate with MPD server to $password.
|
||||
Empty string is assumed if $password is not supplied.
|
||||
|
||||
|
||||
=item $mpd->updatedb( [$path] )
|
||||
|
||||
Force mpd to recan its collection. If $path (relative to MPD's music directory)
|
||||
is supplied, MPD will only scan it - otherwise, MPD will rescan its whole
|
||||
collection.
|
||||
|
||||
|
||||
=item $mpd->urlhandlers()
|
||||
|
||||
Return an array of supported URL schemes.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Handling volume & output
|
||||
|
||||
=over 4
|
||||
|
||||
=item $mpd->volume( [+][-]$volume )
|
||||
|
||||
Sets the audio output volume percentage to absolute $volume.
|
||||
If $volume is prefixed by '+' or '-' then the volume is changed relatively
|
||||
by that value.
|
||||
|
||||
|
||||
=item $mpd->output_enable( $output )
|
||||
|
||||
Enable the specified audio output. $output is the ID of the audio output.
|
||||
|
||||
|
||||
=item $mpd->output_disable( $output )
|
||||
|
||||
Disable the specified audio output. $output is the ID of the audio output.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Retrieving info from current state
|
||||
|
||||
=over 4
|
||||
|
||||
=item $mpd->stats()
|
||||
|
||||
Return an C<Audio::MPD::Common::Stats> object with the current statistics
|
||||
of MPD. See the associated pod for more information.
|
||||
|
||||
|
||||
=item $mpd->status()
|
||||
|
||||
Return an C<Audio::MPD::Common::Status> object with various information on
|
||||
current MPD server settings. Check the embedded pod for more information on
|
||||
the available accessors.
|
||||
|
||||
|
||||
=item $mpd->current()
|
||||
|
||||
Return an C<Audio::MPD::Common::Item::Song> representing the song currently
|
||||
playing.
|
||||
|
||||
|
||||
=item $mpd->song( [$song] )
|
||||
|
||||
Return an C<Audio::MPD::Common::Item::Song> representing the song number
|
||||
C<$song>. If C<$song> is not supplied, returns the current song.
|
||||
|
||||
|
||||
=item $mpd->songid( [$songid] )
|
||||
|
||||
Return an C<Audio::MPD::Common::Item::Song> representing the song with id
|
||||
C<$songid>. If C<$songid> is not supplied, returns the current song.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Altering MPD settings
|
||||
|
||||
=over 4
|
||||
|
||||
=item $mpd->repeat( [$repeat] )
|
||||
|
||||
Set the repeat mode to $repeat (1 or 0). If $repeat is not specified then
|
||||
the repeat mode is toggled.
|
||||
|
||||
|
||||
=item $mpd->random( [$random] )
|
||||
|
||||
Set the random mode to $random (1 or 0). If $random is not specified then
|
||||
the random mode is toggled.
|
||||
|
||||
|
||||
=item $mpd->fade( [$seconds] )
|
||||
|
||||
Enable crossfading and set the duration of crossfade between songs.
|
||||
If $seconds is not specified or $seconds is 0, then crossfading is disabled.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Controlling playback
|
||||
|
||||
=over 4
|
||||
|
||||
=item $mpd->play( [$song] )
|
||||
|
||||
Begin playing playlist at song number $song. If no argument supplied,
|
||||
resume playing.
|
||||
|
||||
|
||||
=item $mpd->playid( [$songid] )
|
||||
|
||||
Begin playing playlist at song ID $songid. If no argument supplied,
|
||||
resume playing.
|
||||
|
||||
|
||||
=item $mpd->pause( [$state] )
|
||||
|
||||
Pause playback. If C<$state> is 0 then the current track is unpaused,
|
||||
if $state is 1 then the current track is paused.
|
||||
|
||||
Note that if C<$state> is not given, pause state will be toggled.
|
||||
|
||||
|
||||
=item $mpd->stop()
|
||||
|
||||
Stop playback.
|
||||
|
||||
|
||||
=item $mpd->next()
|
||||
|
||||
Play next song in playlist.
|
||||
|
||||
|
||||
=item $mpd->prev()
|
||||
|
||||
Play previous song in playlist.
|
||||
|
||||
|
||||
=item $mpd->seek( $time, [$song])
|
||||
|
||||
Seek to $time seconds in song number $song. If $song number is not specified
|
||||
then the perl module will try and seek to $time in the current song.
|
||||
|
||||
|
||||
=item $mpd->seekid( $time, $songid )
|
||||
|
||||
Seek to $time seconds in song ID $songid. If $song number is not specified
|
||||
then the perl module will try and seek to $time in the current song.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Searching the collection
|
||||
|
||||
To search the collection, use the C<collection()> accessor, returning the
|
||||
associated C<Audio::MPD::Collection> object. You will then be able to call:
|
||||
|
||||
$mpd->collection->random_song();
|
||||
|
||||
See C<Audio::MPD::Collection> documentation for more details on available
|
||||
methods.
|
||||
|
||||
|
||||
=head2 Handling the playlist
|
||||
|
||||
To update the playlist, use the C<playlist()> accessor, returning the
|
||||
associated C<Audio::MPD::Playlist> object. You will then be able to call:
|
||||
|
||||
$mpd->playlist->clear;
|
||||
|
||||
See C<Audio::MPD::Playlist> documentation for more details on available
|
||||
methods.
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
You can find more information on the mpd project on its homepage at
|
||||
L<http://www.musicpd.org>, or its wiki L<http://mpd.wikia.com>.
|
||||
|
||||
Regarding this Perl module, you can report bugs on CPAN via
|
||||
L<http://rt.cpan.org/Public/Bug/Report.html?Queue=Audio-MPD>.
|
||||
|
||||
Audio::MPD development takes place on <audio-mpd@googlegroups.com>: feel free
|
||||
to join us. (use L<http://groups.google.com/group/audio-mpd> to sign in). Our
|
||||
subversion repository is located at L<https://svn.musicpd.org>.
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
Original code by Tue Abrahamsen C<< <tue.abrahamsen at gmail.com> >>,
|
||||
documented by Nicholas J. Humfrey C<< <njh at aelius.com> >>.
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2005 Tue Abrahamsen, all rights reserved.
|
||||
Copyright (c) 2006 Nicolas J. Humfrey, all rights reserved.
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,594 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Collection;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Scalar::Util qw[ weaken ];
|
||||
|
||||
use base qw[ Class::Accessor::Fast ];
|
||||
__PACKAGE__->mk_accessors( qw[ _mpd ] );
|
||||
|
||||
|
||||
#our ($VERSION) = '$Rev: 5284 $' =~ /(\d+)/;
|
||||
|
||||
|
||||
#--
|
||||
# Constructor
|
||||
|
||||
#
|
||||
# my $collection = Audio::MPD::Collection->new( $mpd );
|
||||
#
|
||||
# This will create the object, holding a back-reference to the Audio::MPD
|
||||
# object itself (for communication purposes). But in order to play safe and
|
||||
# to free the memory in time, this reference is weakened.
|
||||
#
|
||||
# Note that you're not supposed to call this constructor yourself, an
|
||||
# Audio::MPD::Collection is automatically created for you during the creation
|
||||
# of an Audio::MPD object.
|
||||
#
|
||||
sub new {
|
||||
my ($pkg, $mpd) = @_;
|
||||
|
||||
my $self = { _mpd => $mpd };
|
||||
weaken( $self->{_mpd} );
|
||||
bless $self, $pkg;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
#--
|
||||
# Public methods
|
||||
|
||||
# -- Collection: retrieving songs & directories
|
||||
|
||||
#
|
||||
# my @items = $collection->all_items( [$path] );
|
||||
#
|
||||
# Return *all* AMC::Items (both songs & directories) currently known
|
||||
# by mpd.
|
||||
#
|
||||
# If $path is supplied (relative to mpd root), restrict the retrieval to
|
||||
# songs and dirs in this directory.
|
||||
#
|
||||
sub all_items {
|
||||
my ($self, $path) = @_;
|
||||
$path ||= '';
|
||||
$path =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[listallinfo "$path"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @items = $collection->all_items_simple( [$path] );
|
||||
#
|
||||
# Return *all* AMC::Items (both songs & directories) currently known
|
||||
# by mpd.
|
||||
#
|
||||
# If $path is supplied (relative to mpd root), restrict the retrieval to
|
||||
# songs and dirs in this directory.
|
||||
#
|
||||
# /!\ Warning: the AMC::Item::Song objects will only have their tag
|
||||
# file filled. Any other tag will be empty, so don't use this sub for any
|
||||
# other thing than a quick scan!
|
||||
#
|
||||
sub all_items_simple {
|
||||
my ($self, $path) = @_;
|
||||
$path ||= '';
|
||||
$path =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[listall "$path"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @items = $collection->items_in_dir( [$path] );
|
||||
#
|
||||
# Return the items in the given $path. If no $path supplied, do it on mpd's
|
||||
# root directory.
|
||||
#
|
||||
# Note that this sub does not work recusrively on all directories.
|
||||
#
|
||||
sub items_in_dir {
|
||||
my ($self, $path) = @_;
|
||||
$path ||= '';
|
||||
$path =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[lsinfo "$path"\n] );
|
||||
}
|
||||
|
||||
|
||||
|
||||
# -- Collection: retrieving the whole collection
|
||||
|
||||
#
|
||||
# my @songs = $collection->all_songs( [$path] );
|
||||
#
|
||||
# Return *all* AMC::Item::Songs currently known by mpd.
|
||||
#
|
||||
# If $path is supplied (relative to mpd root), restrict the retrieval to
|
||||
# songs and dirs in this directory.
|
||||
#
|
||||
sub all_songs {
|
||||
my ($self, $path) = @_;
|
||||
return grep { $_->isa('Audio::MPD::Common::Item::Song') } $self->all_items($path);
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @albums = $collection->all_albums;
|
||||
#
|
||||
# Return the list of all albums (strings) currently known by mpd.
|
||||
#
|
||||
sub all_albums {
|
||||
my ($self) = @_;
|
||||
return $self->_mpd->_cooked_command_strip_first_field( "list album\n" );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @artists = $collection->all_artists;
|
||||
#
|
||||
# Return the list of all artists (strings) currently known by mpd.
|
||||
#
|
||||
sub all_artists {
|
||||
my ($self) = @_;
|
||||
return $self->_mpd->_cooked_command_strip_first_field( "list artist\n" );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @titles = $collection->all_titles;
|
||||
#
|
||||
# Return the list of all titles (strings) currently known by mpd.
|
||||
#
|
||||
sub all_titles {
|
||||
my ($self) = @_;
|
||||
return $self->_mpd->_cooked_command_strip_first_field( "list title\n" );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @genre = $collection->all_genre;
|
||||
#
|
||||
# Return the list of all genres (strings) currently known by mpd.
|
||||
#
|
||||
sub all_genre {
|
||||
my ($self) = @_;
|
||||
return $self->_mpd->_cooked_command_strip_first_field( "list genre\n" );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @yers = $collection->all_years;
|
||||
#
|
||||
# Return the list of all years (strings) currently known by mpd.
|
||||
#
|
||||
sub all_years {
|
||||
my ($self) = @_;
|
||||
return $self->_mpd->_cooked_command_strip_first_field( "list date\n" );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @pathes = $collection->all_pathes;
|
||||
#
|
||||
# Return the list of all pathes (strings) currently known by mpd.
|
||||
#
|
||||
sub all_pathes {
|
||||
my ($self) = @_;
|
||||
return $self->_mpd->_cooked_command_strip_first_field( "list filename\n" );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @items = $collection->all_playlists;
|
||||
#
|
||||
# Return the list of playlists (strings) currently known by mpd.
|
||||
#
|
||||
sub all_playlists {
|
||||
my ($self) = @_;
|
||||
|
||||
return
|
||||
map { /^playlist: (.*)$/ ? ($1) : () }
|
||||
$self->_mpd->_send_command( "lsinfo\n" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
# -- Collection: picking songs
|
||||
|
||||
#
|
||||
# my $song = $collection->song( $path );
|
||||
#
|
||||
# Return the AMC::Item::Song which correspond to $path.
|
||||
#
|
||||
sub song {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
my ($item) = $self->_mpd->_cooked_command_as_items( qq[find filename "$what"\n] );
|
||||
return $item;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my $song = $collection->songs_with_filename_partial( $path );
|
||||
#
|
||||
# Return the AMC::Item::Songs containing $string in their path.
|
||||
#
|
||||
sub songs_with_filename_partial {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[search filename "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
# -- Collection: songs, albums & artists relations
|
||||
|
||||
#
|
||||
# my @albums = $collection->albums_by_artist($artist);
|
||||
#
|
||||
# Return all albums (strings) performed by $artist or where $artist
|
||||
# participated.
|
||||
#
|
||||
sub albums_by_artist {
|
||||
my ($self, $artist) = @_;
|
||||
$artist =~ s/"/\\"/g;
|
||||
return $self->_mpd->_cooked_command_strip_first_field( qq[list album "$artist"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @songs = $collection->songs_by_artist( $genre );
|
||||
#
|
||||
# Return all AMC::Item::Songs performed in $genre.
|
||||
#
|
||||
|
||||
sub songs_by_genre {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[find genre "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
sub filenames_by_artist {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_filename( qq[find artist "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
sub filenames_by_year {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_filename( qq[find date "$what"\n] );
|
||||
}
|
||||
|
||||
sub filenames_by_genre {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_filename( qq[find genre "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
sub filenames_by_album {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_filename( qq[find album "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @songs = $collection->songs_by_artist_partial( $string );
|
||||
#
|
||||
# Return all AMC::Item::Songs performed by an artist with $string
|
||||
# in her name.
|
||||
#
|
||||
sub songs_by_artist_partial {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[search artist "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @songs = $collection->songs_from_album( $album );
|
||||
#
|
||||
# Return all AMC::Item::Songs appearing in $album.
|
||||
#
|
||||
sub songs_from_album {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[find album "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @songs = $collection->songs_from_album_partial( $string );
|
||||
#
|
||||
# Return all AMC::Item::Songs appearing in album containing $string.
|
||||
#
|
||||
sub songs_from_album_partial {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[search album "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @songs = $collection->songs_with_title( $title );
|
||||
#
|
||||
# Return all AMC::Item::Songs which title is exactly $title.
|
||||
#
|
||||
sub songs_with_title {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[find title "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @songs = $collection->songs_with_title_partial( $string );
|
||||
#
|
||||
# Return all AMC::Item::Songs where $string is part of the title.
|
||||
#
|
||||
sub songs_with_title_partial {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_items( qq[search title "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
# my @songs = $collection->songs_with_title_partial_filename( $string );
|
||||
#
|
||||
# Return all AMC::Item::Songs where $string is part of the title.
|
||||
#
|
||||
sub songs_with_title_partial_filename {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
|
||||
return $self->_mpd->_cooked_command_as_filename( qq[search title "$what"\n] );
|
||||
}
|
||||
|
||||
# my @songs = $collection->songs_with_artist_partial_filename( $string );
|
||||
#
|
||||
# Return all AMC::Item::Songs where $string is part of the artist.
|
||||
#
|
||||
sub songs_with_artist_partial_filename {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_filename( qq[search artist "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
# my @songs = $collection->songs_with_album_partial_filename( $string );
|
||||
#
|
||||
# Return all AMC::Item::Songs where $string is part of the album.
|
||||
#
|
||||
sub songs_with_album_partial_filename {
|
||||
my ($self, $what) = @_;
|
||||
$what =~ s/"/\\"/g;
|
||||
|
||||
return $self->_mpd->_cooked_command_as_filename( qq[search album "$what"\n] );
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Collection - an object to query MPD's collection
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
my $song = $mpd->collection->random_song;
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<Audio::MPD::Collection> is a class meant to access & query MPD's
|
||||
collection. You will be able to use those high-level methods instead
|
||||
of using the low-level methods provided by mpd itself.
|
||||
|
||||
|
||||
=head1 PUBLIC METHODS
|
||||
|
||||
=head2 Constructor
|
||||
|
||||
=over 4
|
||||
|
||||
=item new( $mpd )
|
||||
|
||||
This will create the object, holding a back-reference to the C<Audio::MPD>
|
||||
object itself (for communication purposes). But in order to play safe and
|
||||
to free the memory in time, this reference is weakened.
|
||||
|
||||
Note that you're not supposed to call this constructor yourself, an
|
||||
C<Audio::MPD::Collection> is automatically created for you during the creation
|
||||
of an C<Audio::MPD> object.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Retrieving songs & directories
|
||||
|
||||
=over 4
|
||||
|
||||
=item $coll->all_items( [$path] )
|
||||
|
||||
Return B<all> C<Audio::MPD::Common::Item>s (both songs & directories)
|
||||
currently known by mpd.
|
||||
|
||||
If C<$path> is supplied (relative to mpd root), restrict the retrieval to
|
||||
songs and dirs in this directory.
|
||||
|
||||
|
||||
=item $coll->all_items_simple( [$path] )
|
||||
|
||||
Return B<all> C<Audio::MPD::Common::Item>s (both songs & directories)
|
||||
currently known by mpd.
|
||||
|
||||
If C<$path> is supplied (relative to mpd root), restrict the retrieval to
|
||||
songs and dirs in this directory.
|
||||
|
||||
B</!\ Warning>: the C<Audio::MPD::Common::Item::Song> objects will only have
|
||||
their tag file filled. Any other tag will be empty, so don't use this sub for
|
||||
any other thing than a quick scan!
|
||||
|
||||
|
||||
=item $coll->items_in_dir( [$path] )
|
||||
|
||||
Return the items in the given C<$path>. If no C<$path> supplied, do it on
|
||||
mpd's root directory.
|
||||
|
||||
Note that this sub does not work recusrively on all directories.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Retrieving the whole collection
|
||||
|
||||
=over 4
|
||||
|
||||
=item $coll->all_songs( [$path] )
|
||||
|
||||
Return B<all> C<Audio::MPD::Common::Item::Song>s currently known by mpd.
|
||||
|
||||
If C<$path> is supplied (relative to mpd root), restrict the retrieval to
|
||||
songs and dirs in this directory.
|
||||
|
||||
|
||||
=item $coll->all_albums()
|
||||
|
||||
Return the list of all albums (strings) currently known by mpd.
|
||||
|
||||
|
||||
=item $coll->all_artists()
|
||||
|
||||
Return the list of all artists (strings) currently known by mpd.
|
||||
|
||||
|
||||
=item $coll->all_titles()
|
||||
|
||||
Return the list of all song titles (strings) currently known by mpd.
|
||||
|
||||
|
||||
=item $coll->all_pathes()
|
||||
|
||||
Return the list of all pathes (strings) currently known by mpd.
|
||||
|
||||
|
||||
=item $coll->all_playlists()
|
||||
|
||||
Return the list of all playlists (strings) currently known by mpd.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Picking a song
|
||||
|
||||
=over 4
|
||||
|
||||
=item $coll->song( $path )
|
||||
|
||||
Return the C<Audio::MPD::Common::Item::Song> which correspond to C<$path>.
|
||||
|
||||
|
||||
=item $coll->songs_with_filename_partial( $path )
|
||||
|
||||
Return the C<Audio::MPD::Common::Item::Song>s containing $string in their path.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Songs, albums & artists relations
|
||||
|
||||
=over 4
|
||||
|
||||
=item $coll->albums_by_artist( $artist )
|
||||
|
||||
Return all albums (strings) performed by C<$artist> or where C<$artist>
|
||||
participated.
|
||||
|
||||
|
||||
=item $coll->songs_by_artist( $artist )
|
||||
|
||||
Return all C<Audio::MPD::Common::Item::Song>s performed by C<$artist>.
|
||||
|
||||
|
||||
=item $coll->songs_by_artist_partial( $string )
|
||||
|
||||
Return all C<Audio::MPD::Common::Item::Song>s performed by an artist with
|
||||
C<$string> in her name.
|
||||
|
||||
|
||||
=item $coll->songs_from_album( $album )
|
||||
|
||||
Return all C<Audio::MPD::Common::Item::Song>s appearing in C<$album>.
|
||||
|
||||
|
||||
=item $coll->songs_from_album_partial( $string )
|
||||
|
||||
Return all C<Audio::MPD::Common::Item::Song>s appearing in album containing C<$string>.
|
||||
|
||||
|
||||
=item $coll->songs_with_title( $title )
|
||||
|
||||
Return all C<Audio::MPD::Common::Item::Song>s which title is exactly C<$title>.
|
||||
|
||||
|
||||
=item $coll->songs_with_title_partial( $string )
|
||||
|
||||
Return all C<Audio::MPD::Common::Item::Song>s where C<$string> is part of the title.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Audio::MPD>
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,88 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD::Common
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Common;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
our $VERSION = '0.1.2';
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Common - a bunch of common helper classes for mpd
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Depending on whether you're using a POE-aware environment or not, people
|
||||
wanting to tinker with mpd (Music Player Daemon) will use either
|
||||
L<POE::Component::Client::MPD> or L<Audio::MPD>.
|
||||
|
||||
But even if the run-cores of those two modules differ completely, they
|
||||
are using the exact same common classes to represent the various mpd
|
||||
states and information.
|
||||
|
||||
Therefore, those common classes have been outsourced to
|
||||
L<Audio::MPD::Common>.
|
||||
|
||||
This module does not export any methods, but the dist provides the
|
||||
following classes that you can query with perldoc:
|
||||
|
||||
=over 4
|
||||
|
||||
=item o L<Audio::MPD::Common::Item>
|
||||
|
||||
=item o L<Audio::MPD::Common::Item::Directory>
|
||||
|
||||
=item o L<Audio::MPD::Common::Item::Playlist>
|
||||
|
||||
=item o L<Audio::MPD::Common::Item::Song>
|
||||
|
||||
=item o L<Audio::MPD::Common::Stats>
|
||||
|
||||
=item o L<Audio::MPD::Common::Status>
|
||||
|
||||
=item o L<Audio::MPD::Common::Time>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
Note that those modules should not be of any use outside the two mpd
|
||||
modules afore-mentioned.
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<Audio::MPD>
|
||||
|
||||
=item L<POE::Component::Client::MPD>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,100 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD::Common
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Common::Item;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Audio::MPD::Common::Item::Directory;
|
||||
use Audio::MPD::Common::Item::Playlist;
|
||||
use Audio::MPD::Common::Item::Song;
|
||||
|
||||
#our ($VERSION) = '$Rev: 5645 $' =~ /(\d+)/;
|
||||
|
||||
#
|
||||
# constructor.
|
||||
#
|
||||
sub new {
|
||||
my ($pkg, %params) = @_;
|
||||
|
||||
# transform keys in lowercase.
|
||||
my %lowcase;
|
||||
@lowcase{ keys %params } = values %params;
|
||||
|
||||
return Audio::MPD::Common::Item::Song->new(\%lowcase) if exists $params{file};
|
||||
return Audio::MPD::Common::Item::Directory->new(\%lowcase) if exists $params{directory};
|
||||
return Audio::MPD::Common::Item::Playlist->new(\%lowcase) if exists $params{playlist};
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Common::Item - a generic collection item
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
my $item = Audio::MPD::Common::Item->new( %params );
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<Audio::MPD::Common::Item> is a virtual class representing a generic
|
||||
item of mpd's collection. It can be either a song, a directory or a playlist.
|
||||
|
||||
Depending on the params given to C<new>, it will create and return an
|
||||
C<Audio::MPD::Common::Item::Song>, an C<Audio::MPD::Common::Item::Directory>
|
||||
or an C<Audio::MPD::Common::Playlist> object. Currently, the
|
||||
discrimination is done on the existence of the C<file> key of C<%params>.
|
||||
|
||||
|
||||
=head1 PUBLIC METHODS
|
||||
|
||||
Note that the only sub worth it in this class is the constructor:
|
||||
|
||||
=over 4
|
||||
|
||||
=item new( key => val [, key => val [, ...] ] )
|
||||
|
||||
Create and return either an C<Audio::MPD::Common::Item::Song>, an
|
||||
C<Audio::MPD::Common::Item::Directory> or an C<Audio::MPD::Common::Playlist>
|
||||
object, depending on the existence of a key C<file>, C<directory> or
|
||||
C<playlist> (respectively).
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<Audio::MPD>
|
||||
|
||||
=item L<POE::Component::Client::MPD>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,72 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD::Common
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Common::Item::Directory;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use base qw[ Class::Accessor::Fast Audio::MPD::Common::Item ];
|
||||
__PACKAGE__->mk_accessors( qw[ directory ] );
|
||||
|
||||
#our ($VERSION) = '$Rev: 5645 $' =~ /(\d+)/;
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Common::Item::Directory - a directory object
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
print $item->directory . "\n";
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<Audio::MPD::Common::Item::Directory> is more a placeholder for a
|
||||
hash ref with one pre-defined key, namely the directory name.
|
||||
|
||||
|
||||
=head1 PUBLIC METHODS
|
||||
|
||||
This module only has a C<new()> constructor, which should only be called by
|
||||
C<Audio::MPD::Common::Item>'s constructor.
|
||||
|
||||
The only other public method is an accessor: directory().
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<Audio::MPD>
|
||||
|
||||
=item L<POE::Component::Client::MPD>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,72 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD::Common
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Common::Item::Playlist;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use base qw[ Class::Accessor::Fast Audio::MPD::Common::Item ];
|
||||
__PACKAGE__->mk_accessors( qw[ playlist ] );
|
||||
|
||||
#our ($VERSION) = '$Rev: 5645 $' =~ /(\d+)/;
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Common::Item::Playlist - a playlist object
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
print $item->playlist . "\n";
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<Audio::MPD::Common::Item::Playlist> is more a placeholder for a hash ref
|
||||
with one pre-defined key, namely the playlist name.
|
||||
|
||||
|
||||
=head1 PUBLIC METHODS
|
||||
|
||||
This module only has a C<new()> constructor, which should only be called by
|
||||
C<Audio::MPD::Common::Item>'s constructor.
|
||||
|
||||
The only other public method is an accessor: playlist().
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<Audio::MPD>
|
||||
|
||||
=item L<POE::Component::Client::MPD>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,133 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD::Common
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Common::Item::Song;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use overload '""' => \&as_string;
|
||||
use Readonly;
|
||||
|
||||
use base qw[ Class::Accessor::Fast Audio::MPD::Common::Item ];
|
||||
__PACKAGE__->mk_accessors( qw[ Album Artist file id pos Title Track time ] );
|
||||
|
||||
#our ($VERSION) = '$Rev: 5645 $' =~ /(\d+)/;
|
||||
|
||||
Readonly my $SEP => ' = ';
|
||||
|
||||
|
||||
#
|
||||
# my $str = $song->as_string;
|
||||
#
|
||||
# Return a string representing $song. This string will be;
|
||||
# - either "Album = Track = Artist = Title"
|
||||
# - or "Artist = Title"
|
||||
# - or "Title"
|
||||
# - or "file"
|
||||
# (in this order), depending on the existing tags of the song. The last
|
||||
# possibility always exist of course, since it's a path.
|
||||
#
|
||||
sub as_string {
|
||||
my ($self) = @_;
|
||||
|
||||
return $self->file unless defined $self->Title;
|
||||
my $str = $self->Title;
|
||||
return $str unless defined $self->Artist;
|
||||
$str = $self->Artist . $SEP . $str;
|
||||
return $str unless defined $self->Album && defined $self->Track;
|
||||
return join $SEP,
|
||||
$self->Album,
|
||||
$self->Track,
|
||||
$str;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Common::Item::Song - a song object with some audio tags
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<Audio::MPD::Common::Item::Song> is more a placeholder for a
|
||||
hash ref with some pre-defined keys, namely some audio tags.
|
||||
|
||||
|
||||
=head1 PUBLIC METHODS
|
||||
|
||||
This module has a C<new()> constructor, which should only be called by
|
||||
C<Audio::MPD::Common::Item>'s constructor.
|
||||
|
||||
The only other public methods are the accessors - see below.
|
||||
|
||||
|
||||
=head2 Accessors
|
||||
|
||||
The following methods are the accessors to their respective named fields:
|
||||
C<Album()>, C<Artist()>, C<file()>, C<id>, C<pos>, C<Title()>, CTTrack()>,
|
||||
C<time()>. You can call them either with no arg to get the value, or with
|
||||
an arg to replace the current value.
|
||||
|
||||
|
||||
=head2 Methods
|
||||
|
||||
|
||||
=over 4
|
||||
|
||||
=item $song->as_string()
|
||||
|
||||
Return a string representing $song. This string will be:
|
||||
|
||||
=over 4
|
||||
|
||||
=item either "Album = Track = Artist = Title"
|
||||
|
||||
=item or "Artist = Title"
|
||||
|
||||
=item or "Title"
|
||||
|
||||
=item or "file"
|
||||
|
||||
=back
|
||||
|
||||
(in this order), depending on the existing tags of the song. The last
|
||||
possibility always exist of course, since it's a path.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<Audio::MPD>
|
||||
|
||||
=item L<POE::Component::Client::MPD>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,135 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD::Common
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Common::Stats;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use base qw[ Class::Accessor::Fast ];
|
||||
__PACKAGE__->mk_accessors
|
||||
( qw[ artists albums songs uptime playtime db_playtime db_update ] );
|
||||
|
||||
#our ($VERSION) = '$Rev$' =~ /(\d+)/;
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Common::Stats - class representing MPD stats
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
print $stats->artists;
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The MPD server maintains some general information. Those information can be
|
||||
queried with the mpd modules. Some of those information are served to you as
|
||||
an C<Audio::MPD::Common::Status> object.
|
||||
|
||||
Note that an C<Audio::MPD::Common::Stats> object does B<not> update itself
|
||||
regularly, and thus should be used immediately.
|
||||
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 Constructor
|
||||
|
||||
=over 4
|
||||
|
||||
=item new( %kv )
|
||||
|
||||
The C<new()> method is the constructor for the C<Audio::MPD::Common::Stats>
|
||||
class.
|
||||
|
||||
Note: one should B<never> ever instantiate an C<Audio::MPD::Common::Stats>
|
||||
object directly - use the mpd modules instead.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Accessors
|
||||
|
||||
Once created, one can access to the following members of the object:
|
||||
|
||||
=over 4
|
||||
|
||||
=item $stats->artists()
|
||||
|
||||
Number of artists in the music database.
|
||||
|
||||
|
||||
=item $stats->albums()
|
||||
|
||||
Number of albums in the music database.
|
||||
|
||||
|
||||
=item $stats->songs()
|
||||
|
||||
Number of songs in the music database.
|
||||
|
||||
|
||||
=item $stats->uptime()
|
||||
|
||||
Daemon uptime (time since last startup) in seconds.
|
||||
|
||||
|
||||
=item $stats->playtime()
|
||||
|
||||
Time length of music played.
|
||||
|
||||
|
||||
=item $stats->db_playtime()
|
||||
|
||||
Sum of all song times in the music database.
|
||||
|
||||
|
||||
=item $stats->db_update()
|
||||
|
||||
Last database update in UNIX time.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
Please note that those accessors are read-only: changing a value will B<not>
|
||||
change the current settings of MPD server. Use the mpd modules to alter the
|
||||
settings.
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<Audio::MPD>
|
||||
|
||||
=item L<POE::Component::Client::MPD>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,192 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD::Common
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Common::Status;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use Audio::MPD::Common::Time;
|
||||
|
||||
use base qw[ Class::Accessor::Fast ];
|
||||
__PACKAGE__->mk_accessors
|
||||
( qw[ audio bitrate error playlist playlistlength random
|
||||
repeat song songid state time volume updating_db xfade ] );
|
||||
|
||||
#our ($VERSION) = '$Rev: 5865 $' =~ /(\d+)/;
|
||||
|
||||
|
||||
#--
|
||||
# Constructor
|
||||
|
||||
#
|
||||
# my $status = Audio::MPD::Common::Status->new( \%kv )
|
||||
#
|
||||
# The constructor for the class Audio::MPD::Common::Status. %kv is
|
||||
# a cooked output of what MPD server returns to the status command.
|
||||
#
|
||||
sub new {
|
||||
my ($class, $kv) = @_;
|
||||
my %kv = %$kv;
|
||||
$kv{time} = Audio::MPD::Common::Time->new( delete $kv{time} );
|
||||
bless \%kv, $class;
|
||||
return \%kv;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Common::Status - class representing MPD status
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
print $status->bitrate;
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
The MPD server maintains some information on its current state. Those
|
||||
information can be queried with mpd modules. Some of those information
|
||||
are served to you as an C<Audio::MPD::Common::Status> object.
|
||||
|
||||
Note that an C<Audio::MPD::Common::Status> object does B<not> update
|
||||
itself regularly, and thus should be used immediately.
|
||||
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 Constructor
|
||||
|
||||
=over 4
|
||||
|
||||
=item new( \%kv )
|
||||
|
||||
The C<new()> method is the constructor for the C<Audio::MPD::Common::Status>
|
||||
class.
|
||||
|
||||
Note: one should B<never> ever instantiate an C<Audio::MPD::Common::Status>
|
||||
object directly - use the mpd modules instead.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Accessors
|
||||
|
||||
Once created, one can access to the following members of the object:
|
||||
|
||||
=over 4
|
||||
|
||||
=item $status->audio()
|
||||
|
||||
A string with the sample rate of the song currently playing, number of bits
|
||||
of the output and number of channels (2 for stereo) - separated by a colon.
|
||||
|
||||
|
||||
=item $status->bitrate()
|
||||
|
||||
The instantaneous bitrate in kbps.
|
||||
|
||||
|
||||
=item $status->error()
|
||||
|
||||
May appear in special error cases, such as when disabling output.
|
||||
|
||||
|
||||
=item $status->playlist()
|
||||
|
||||
The playlist version number, that changes every time the playlist is updated.
|
||||
|
||||
|
||||
=item $status->playlistlength()
|
||||
|
||||
The number of songs in the playlist.
|
||||
|
||||
|
||||
=item $status->random()
|
||||
|
||||
Whether the playlist is read randomly or not.
|
||||
|
||||
|
||||
=item $status->repeat()
|
||||
|
||||
Whether the song is repeated or not.
|
||||
|
||||
|
||||
=item $status->song()
|
||||
|
||||
The offset of the song currently played in the playlist.
|
||||
|
||||
|
||||
=item $status->songid()
|
||||
|
||||
The song id (MPD id) of the song currently played.
|
||||
|
||||
|
||||
=item $status->state()
|
||||
|
||||
The state of MPD server. Either C<play>, C<stop> or C<pause>.
|
||||
|
||||
|
||||
=item $status->time()
|
||||
|
||||
An C<Audio::MPD::Common::Time> object, representing the time elapsed /
|
||||
remainging and total. See the associated pod for more details.
|
||||
|
||||
|
||||
=item $status->updating_db()
|
||||
|
||||
An integer, representing the current update job.
|
||||
|
||||
|
||||
=item $status->volume()
|
||||
|
||||
The current MPD volume - an integer between 0 and 100.
|
||||
|
||||
|
||||
=item $status->xfade()
|
||||
|
||||
The crossfade in seconds.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
Please note that those accessors are read-only: changing a value will B<not>
|
||||
change the current settings of MPD server. Use the mpd modules to alter the
|
||||
settings.
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<Audio::MPD>
|
||||
|
||||
=item L<POE::Component::Client::MPD>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,186 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD::Common
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Common::Time;
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
use base qw[ Class::Accessor::Fast ];
|
||||
__PACKAGE__->mk_accessors
|
||||
( qw[ percent sofar left total
|
||||
sofar_secs sofar_mins seconds_sofar
|
||||
total_secs total_mins seconds_total
|
||||
left_secs left_mins seconds_left
|
||||
] );
|
||||
|
||||
#our ($VERSION) = '$Rev$' =~ /(\d+)/;
|
||||
|
||||
|
||||
#--
|
||||
# Constructor
|
||||
|
||||
#
|
||||
# my $status = Audio::MPD::Common::Time->new( $time )
|
||||
#
|
||||
# The constructor for the class Audio::MPD::Common::Time. $time is
|
||||
# the time value (on the "time" line) of what the output MPD server
|
||||
# returns to the status command.
|
||||
#
|
||||
sub new {
|
||||
my ($class, $time) = @_;
|
||||
$time ||= '0:0';
|
||||
my ($seconds_sofar, $seconds_total) = split /:/, $time;
|
||||
my $seconds_left = $seconds_total - $seconds_sofar;
|
||||
my $percent = $seconds_total ? 100*$seconds_sofar/$seconds_total : 0;
|
||||
|
||||
# Parse the time so far
|
||||
my $sofar_mins = int( $seconds_sofar / 60 );
|
||||
my $sofar_secs = $seconds_sofar % 60;
|
||||
my $sofar = sprintf "%d:%02d", $sofar_mins, $sofar_secs;
|
||||
|
||||
# Parse the total time
|
||||
my $total_mins = int( $seconds_total / 60 );
|
||||
my $total_secs = $seconds_total % 60;
|
||||
my $total = sprintf "%d:%02d", $total_mins, $total_secs;
|
||||
|
||||
# Parse the time left
|
||||
my $left_mins = int( $seconds_left / 60 );
|
||||
my $left_secs = $seconds_left % 60;
|
||||
my $left = sprintf "%d:%02d", $left_mins, $left_secs;
|
||||
|
||||
|
||||
# create object
|
||||
my $self = {
|
||||
# time elapsed in seconds
|
||||
seconds_sofar => $seconds_sofar,
|
||||
seconds_left => $seconds_left,
|
||||
seconds_total => $seconds_total,
|
||||
|
||||
# cooked values
|
||||
sofar => $sofar,
|
||||
left => $left,
|
||||
total => $total,
|
||||
percent => sprintf("%.1f", $percent), # 1 decimal
|
||||
|
||||
# details
|
||||
sofar_secs => $sofar_secs,
|
||||
sofar_mins => $sofar_mins,
|
||||
total_secs => $total_secs,
|
||||
total_mins => $total_mins,
|
||||
left_secs => $left_secs,
|
||||
left_mins => $left_mins,
|
||||
};
|
||||
bless $self, $class;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Common::Time - class representing time of current song
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
my $time = $status->time;
|
||||
print $time->sofar;
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<Audio::MPD::Common::Status> returns some time information with the C<time()>
|
||||
accessor. This information relates to the elapsed time of the current song,
|
||||
as well as the remaining and total time. This information is encapsulated
|
||||
in an C<Audio::MPD::Common::Time> object.
|
||||
|
||||
Note that an C<Audio::MPD::Common::Time> object does B<not> update itself
|
||||
regularly, and thus should be used immediately.
|
||||
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
=head2 Constructor
|
||||
|
||||
=over 4
|
||||
|
||||
=item new( $time )
|
||||
|
||||
The C<new()> method is the constructor for the C<Audio::MPD::Common::Time>
|
||||
class.
|
||||
|
||||
Note: one should B<never> ever instantiate an C<Audio::MPD::Common::Time>
|
||||
object directly - use the mpd modules instead.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Accessors
|
||||
|
||||
Once created, one can access the following members of the object:
|
||||
|
||||
=over 4
|
||||
|
||||
=item cooked values:
|
||||
|
||||
The C<sofar()>, C<left()> and C<total()> methods return the according values
|
||||
under the form C<minutes:seconds>. Note the existence of a C<percent()>
|
||||
method returning a percentage complete. (one decimal)
|
||||
|
||||
|
||||
=item values in seconds:
|
||||
|
||||
The C<seconds_sofar()>, C<seconds_left()> and C<seconds_total()> return the
|
||||
according values in seconds.
|
||||
|
||||
|
||||
=item detailled values:
|
||||
|
||||
If you want to cook your own value, then the following methods can help:
|
||||
C<sofar_secs()> and C<sofar_mins()> return the seconds and minutes elapsed.
|
||||
Same for C<left_secs()> and C<left_mins()> (time remaining), C<total_secs()>
|
||||
and C<total_mins()>. (total song length)
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
Please note that those accessors are read-only: changing a value will B<not>
|
||||
change the current settings of MPD server. Use the mpd modules to alter the
|
||||
settings.
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=over 4
|
||||
|
||||
=item L<Audio::MPD>
|
||||
|
||||
=item L<POE::Component::Client::MPD>
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,427 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Playlist;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Scalar::Util qw[ weaken ];
|
||||
|
||||
use base qw[ Class::Accessor::Fast ];
|
||||
__PACKAGE__->mk_accessors( qw[ _mpd ] );
|
||||
|
||||
|
||||
#our ($VERSION) = '$Rev$' =~ /(\d+)/;
|
||||
|
||||
|
||||
#--
|
||||
# Constructor
|
||||
|
||||
#
|
||||
# my $collection = Audio::MPD::Playlist->new( $mpd );
|
||||
#
|
||||
# This will create the object, holding a back-reference to the Audio::MPD
|
||||
# object itself (for communication purposes). But in order to play safe and
|
||||
# to free the memory in time, this reference is weakened.
|
||||
#
|
||||
# Note that you're not supposed to call this constructor yourself, an
|
||||
# Audio::MPD::Playlist is automatically created for you during the creation
|
||||
# of an Audio::MPD object.
|
||||
#
|
||||
sub new {
|
||||
my ($pkg, $mpd) = @_;
|
||||
|
||||
my $self = { _mpd => $mpd };
|
||||
weaken( $self->{_mpd} );
|
||||
bless $self, $pkg;
|
||||
return $self;
|
||||
}
|
||||
|
||||
|
||||
#--
|
||||
# Public methods
|
||||
|
||||
# -- Playlist: retrieving information
|
||||
|
||||
#
|
||||
# my @items = $pl->as_items;
|
||||
#
|
||||
# Return an array of AMC::Item::Songs, one for each of the
|
||||
# songs in the current playlist.
|
||||
#
|
||||
sub as_items {
|
||||
my ($self) = @_;
|
||||
|
||||
my @list = $self->_mpd->_cooked_command_as_items("playlistinfo\n");
|
||||
return @list;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# my @items = $pl->items_changed_since( $plversion );
|
||||
#
|
||||
# Return a list with all the songs (as API::Song objects) added to
|
||||
# the playlist since playlist $plversion.
|
||||
#
|
||||
sub items_changed_since {
|
||||
my ($self, $plid) = @_;
|
||||
return $self->_mpd->_cooked_command_as_items("plchanges $plid\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
# -- Playlist: adding / removing songs
|
||||
|
||||
#
|
||||
# $pl->add( $path [, $path [...] ] );
|
||||
#
|
||||
# Add the songs identified by $path (relative to MPD's music directory) to
|
||||
# the current playlist. No return value.
|
||||
#
|
||||
sub add {
|
||||
my ($self, @pathes) = @_;
|
||||
my $command =
|
||||
"command_list_begin\n"
|
||||
. join( '', map { s/"/\\"/g; qq[add "$_"\n] } @pathes )
|
||||
. "command_list_end\n";
|
||||
$self->_mpd->_send_command( $command );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->delete( $song [, $song [...] ] );
|
||||
#
|
||||
# Remove song number $song (starting from 0) from the current playlist. No
|
||||
# return value.
|
||||
#
|
||||
sub delete {
|
||||
my ($self, @songs) = @_;
|
||||
my $command =
|
||||
"command_list_begin\n"
|
||||
. join( '', map { s/"/\\"/g; "delete $_\n" } @songs )
|
||||
. "command_list_end\n";
|
||||
$self->_mpd->_send_command( $command );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->deleteid( $songid [, $songid [...] ]);
|
||||
#
|
||||
# Remove the specified $songid (as assigned by mpd when inserted in playlist)
|
||||
# from the current playlist. No return value.
|
||||
#
|
||||
sub deleteid {
|
||||
my ($self, @songs) = @_;
|
||||
my $command =
|
||||
"command_list_begin\n"
|
||||
. join( '', map { "deleteid $_\n" } @songs )
|
||||
. "command_list_end\n";
|
||||
$self->_mpd->_send_command( $command );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->clear;
|
||||
#
|
||||
# Remove all the songs from the current playlist. No return value.
|
||||
#
|
||||
sub clear {
|
||||
my ($self) = @_;
|
||||
$self->_mpd->_send_command("clear\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->crop;
|
||||
#
|
||||
# Remove all of the songs from the current playlist *except* the current one.
|
||||
#
|
||||
sub crop {
|
||||
my ($self) = @_;
|
||||
|
||||
my $status = $self->_mpd->status;
|
||||
my $cur = $status->song;
|
||||
my $len = $status->playlistlength - 1;
|
||||
|
||||
my $command =
|
||||
"command_list_begin\n"
|
||||
. join( '', map { $_ != $cur ? "delete $_\n" : '' } reverse 0..$len )
|
||||
. "command_list_end\n";
|
||||
$self->_mpd->_send_command( $command );
|
||||
}
|
||||
|
||||
|
||||
# -- Playlist: changing playlist order
|
||||
|
||||
#
|
||||
# $pl->shuffle();
|
||||
#
|
||||
# Shuffle the current playlist. No return value.
|
||||
#
|
||||
sub shuffle {
|
||||
my ($self) = @_;
|
||||
$self->_mpd->_send_command("shuffle\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->swap( $song1, $song2 );
|
||||
#
|
||||
# Swap positions of song number $song1 and $song2 in the current playlist.
|
||||
# No return value.
|
||||
#
|
||||
sub swap {
|
||||
my ($self, $from, $to) = @_;
|
||||
$self->_mpd->_send_command("swap $from $to\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->swapid( $songid1, $songid2 );
|
||||
#
|
||||
# Swap the postions of song ID $songid1 with song ID $songid2 in the
|
||||
# current playlist. No return value.
|
||||
#
|
||||
sub swapid {
|
||||
my ($self, $from, $to) = @_;
|
||||
$self->_mpd->_send_command("swapid $from $to\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->move( $song, $newpos );
|
||||
#
|
||||
# Move song number $song to the position $newpos. No return value.
|
||||
#
|
||||
sub move {
|
||||
my ($self, $song, $pos) = @_;
|
||||
$self->_mpd->_send_command("move $song $pos\n");
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->moveid( $songid, $newpos );
|
||||
#
|
||||
# Move song ID $songid to the position $newpos. No return value.
|
||||
#
|
||||
sub moveid {
|
||||
my ($self, $song, $pos) = @_;
|
||||
$self->_mpd->_send_command("moveid $song $pos\n");
|
||||
}
|
||||
|
||||
|
||||
# -- Playlist: managing playlists
|
||||
|
||||
#
|
||||
# $pl->load( $playlist );
|
||||
#
|
||||
# Load list of songs from specified $playlist file. No return value.
|
||||
#
|
||||
sub load {
|
||||
my ($self, $playlist) = @_;
|
||||
$self->_mpd->_send_command( qq[load "$playlist"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->save( $playlist );
|
||||
#
|
||||
# Save the current playlist to a file called $playlist in MPD's playlist
|
||||
# directory. No return value.
|
||||
#
|
||||
sub save {
|
||||
my ($self, $playlist) = @_;
|
||||
$self->_mpd->_send_command( qq[save "$playlist"\n] );
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# $pl->rm( $playlist )
|
||||
#
|
||||
# Delete playlist named $playlist from MPD's playlist directory. No
|
||||
# return value.
|
||||
#
|
||||
sub rm {
|
||||
my ($self, $playlist) = @_;
|
||||
$self->_mpd->_send_command( qq[rm "$playlist"\n] );
|
||||
}
|
||||
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Playlist - an object to mess MPD's playlist
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
my $song = $mpd->playlist->randomize;
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
C<Audio::MPD::Playlist> is a class meant to access & update MPD's
|
||||
playlist.
|
||||
|
||||
|
||||
=head1 PUBLIC METHODS
|
||||
|
||||
=head2 Constructor
|
||||
|
||||
=over 4
|
||||
|
||||
=item new( $mpd )
|
||||
|
||||
This will create the object, holding a back-reference to the C<Audio::MPD>
|
||||
object itself (for communication purposes). But in order to play safe and
|
||||
to free the memory in time, this reference is weakened.
|
||||
|
||||
Note that you're not supposed to call this constructor yourself, an
|
||||
C<Audio::MPD::Playlist> is automatically created for you during the creation
|
||||
of an C<Audio::MPD> object.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Retrieving information
|
||||
|
||||
=over 4
|
||||
|
||||
=item $pl->as_items()
|
||||
|
||||
Return an array of C<Audio::MPD::Common::Item::Song>s, one for each of the
|
||||
songs in the current playlist.
|
||||
|
||||
|
||||
=item $pl->items_changed_since( $plversion )
|
||||
|
||||
Return a list with all the songs (as AMC::Item::Song objects) added to
|
||||
the playlist since playlist $plversion.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Adding / removing songs
|
||||
|
||||
=over 4
|
||||
|
||||
=item $pl->add( $path [, $path [...] ] )
|
||||
|
||||
Add the songs identified by C<$path> (relative to MPD's music directory) to the
|
||||
current playlist. No return value.
|
||||
|
||||
|
||||
=item $pl->delete( $song [, $song [...] ] )
|
||||
|
||||
Remove song number C<$song>s (starting from 0) from the current playlist. No
|
||||
return value.
|
||||
|
||||
|
||||
=item $pl->deleteid( $songid [, $songid [...] ] )
|
||||
|
||||
Remove the specified C<$songid>s (as assigned by mpd when inserted in playlist)
|
||||
from the current playlist. No return value.
|
||||
|
||||
|
||||
=item $pl->clear()
|
||||
|
||||
Remove all the songs from the current playlist. No return value.
|
||||
|
||||
|
||||
=item $pl->crop()
|
||||
|
||||
Remove all of the songs from the current playlist *except* the
|
||||
song currently playing.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Changing playlist order
|
||||
|
||||
=over 4
|
||||
|
||||
=item $pl->shuffle()
|
||||
|
||||
Shuffle the current playlist. No return value.
|
||||
|
||||
|
||||
=item $pl->swap( $song1, $song2 )
|
||||
|
||||
Swap positions of song number C<$song1> and C<$song2> in the current
|
||||
playlist. No return value.
|
||||
|
||||
|
||||
=item $pl->swapid( $songid1, $songid2 )
|
||||
|
||||
Swap the postions of song ID C<$songid1> with song ID C<$songid2> in the
|
||||
current playlist. No return value.
|
||||
|
||||
|
||||
=item $pl->move( $song, $newpos )
|
||||
|
||||
Move song number C<$song> to the position C<$newpos>. No return value.
|
||||
|
||||
|
||||
=item $pl->moveid( $songid, $newpos )
|
||||
|
||||
Move song ID C<$songid> to the position C<$newpos>. No return value.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head2 Managing playlists
|
||||
|
||||
=over 4
|
||||
|
||||
=item $pl->load( $playlist )
|
||||
|
||||
Load list of songs from specified C<$playlist> file. No return value.
|
||||
|
||||
|
||||
=item $pl->save( $playlist )
|
||||
|
||||
Save the current playlist to a file called C<$playlist> in MPD's playlist
|
||||
directory. No return value.
|
||||
|
||||
|
||||
=item $pl->rm( $playlist )
|
||||
|
||||
Delete playlist named C<$playlist> from MPD's playlist directory. No
|
||||
return value.
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Audio::MPD>
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,217 +0,0 @@
|
||||
#
|
||||
# This file is part of Audio::MPD
|
||||
# Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the same terms as Perl itself.
|
||||
#
|
||||
#
|
||||
|
||||
package Audio::MPD::Test;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Exporter;
|
||||
use FindBin qw[ $Bin ];
|
||||
use Readonly;
|
||||
|
||||
|
||||
use base qw[ Exporter ];
|
||||
our @EXPORT = qw[ customize_test_mpd_configuration start_test_mpd stop_test_mpd ];
|
||||
#our ($VERSION) = '$Rev: 5284 $' =~ /(\d+)/;
|
||||
|
||||
|
||||
Readonly my $TEMPLATE => "$Bin/mpd-test/mpd.conf.template";
|
||||
Readonly my $CONFIG => "$Bin/mpd-test/mpd.conf";
|
||||
|
||||
{ # this will be run when Audio::MPD::Test will be use-d.
|
||||
my $restart = 0;
|
||||
my $stopit = 0;
|
||||
|
||||
customize_test_mpd_configuration();
|
||||
$restart = _stop_user_mpd_if_needed();
|
||||
$stopit = start_test_mpd();
|
||||
|
||||
END {
|
||||
stop_test_mpd() if $stopit;
|
||||
return unless $restart; # no need to restart
|
||||
system 'mpd 2>/dev/null'; # restart user mpd
|
||||
sleep 1; # wait 1 second to let mpd start.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#--
|
||||
# public subs
|
||||
|
||||
#
|
||||
# customize_test_mpd_configuration( [$port] )
|
||||
#
|
||||
# Create a fake mpd configuration file, based on the file mpd.conf.template
|
||||
# located in t/mpd-test. The string PWD will be replaced by the real path -
|
||||
# ie, where the tarball has been untarred. The string PORT will be replaced
|
||||
# by $port if specified, 6600 otherwise (MPD default).
|
||||
#
|
||||
sub customize_test_mpd_configuration {
|
||||
my ($port) = @_;
|
||||
$port ||= 6600;
|
||||
|
||||
# open template and config.
|
||||
open my $in, '<', $TEMPLATE or die "can't open [$TEMPLATE]: $!\n";
|
||||
open my $out, '>', $CONFIG or die "can't open [$CONFIG]: $!\n";
|
||||
|
||||
# replace string and fill in config file.
|
||||
while ( defined( my $line = <$in> ) ) {
|
||||
$line =~ s!PWD!$Bin/mpd-test!;
|
||||
$line =~ s!PORT!$port!;
|
||||
print $out $line;
|
||||
}
|
||||
|
||||
# clean up.
|
||||
close $in;
|
||||
close $out;
|
||||
|
||||
# create a fake mpd db.
|
||||
system( "mpd --create-db $CONFIG >/dev/null 2>&1" ) == 0
|
||||
or die "could not create fake mpd database: $?\n";
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# start_test_mpd()
|
||||
#
|
||||
# Start the fake mpd, and die if there were any error.
|
||||
#
|
||||
sub start_test_mpd {
|
||||
my $output = qx[mpd $CONFIG 2>&1];
|
||||
die "could not start fake mpd: $output\n" if $output;
|
||||
sleep 1; # wait 1 second to let mpd start.
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
#
|
||||
# stop_test_mpd()
|
||||
#
|
||||
# Kill the fake mpd.
|
||||
#
|
||||
sub stop_test_mpd {
|
||||
system "mpd --kill $CONFIG 2>/dev/null";
|
||||
sleep 1; # wait 1 second to free output device.
|
||||
unlink "$Bin/mpd-test/state", "$Bin/mpd-test/music.db";
|
||||
}
|
||||
|
||||
|
||||
#--
|
||||
# private subs
|
||||
|
||||
|
||||
#
|
||||
# my $was_running = _stop_user_mpd_if_needed()
|
||||
#
|
||||
# This sub will check if mpd is currently running. If it is, force it to
|
||||
# a full stop (unless MPD_TEST_OVERRIDE is not set).
|
||||
#
|
||||
# In any case, it will return a boolean stating whether mpd was running
|
||||
# before forcing stop.
|
||||
#
|
||||
sub _stop_user_mpd_if_needed {
|
||||
# check if mpd is running.
|
||||
my $is_running = grep { /mpd$/ } qx[ ps -e ];
|
||||
|
||||
return 0 unless $is_running; # mpd does not run - nothing to do.
|
||||
|
||||
# check force stop.
|
||||
die "mpd is running\n" unless $ENV{MPD_TEST_OVERRIDE};
|
||||
system( 'mpd --kill 2>/dev/null') == 0 or die "can't stop user mpd: $?\n";
|
||||
sleep 1; # wait 1 second to free output device
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Audio::MPD::Test - automate launching of fake mdp for testing purposes
|
||||
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Audio::MPD::Test; # die if error
|
||||
[...]
|
||||
stop_fake_mpd();
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
=head2 General usage
|
||||
|
||||
This module will try to launch a new mpd server for testing purposes. This
|
||||
mpd server will then be used during Audio::MPD tests.
|
||||
|
||||
In order to achieve this, the module will create a fake mpd.conf file with
|
||||
the correct pathes (ie, where you untarred the module tarball). It will then
|
||||
check if some mpd server is already running, and stop it if the
|
||||
MPD_TEST_OVERRIDE environment variable is true (die otherwise). Last it will
|
||||
run the test mpd with its newly created configuration file.
|
||||
|
||||
Everything described above is done automatically when the module is C<use>-d.
|
||||
|
||||
|
||||
Once the tests are run, the mpd server will be shut down, and the original
|
||||
one will be relaunched (if there was one).
|
||||
|
||||
Note that the test mpd will listen to C<localhost>, so you are on the safe
|
||||
side. Note also that the test suite comes with its own ogg files - and yes,
|
||||
we can redistribute them since it's only some random voice recordings :-)
|
||||
|
||||
|
||||
=head2 Advanced usage
|
||||
|
||||
In case you want more control on the test mpd server, you can use the
|
||||
following public methods:
|
||||
|
||||
=over 4
|
||||
|
||||
=item start_test_mpd()
|
||||
|
||||
Start the fake mpd, and die if there were any error.
|
||||
|
||||
=item stop_test_mpd()
|
||||
|
||||
Kill the fake mpd.
|
||||
|
||||
=item customize_test_mpd_configuration( [$port] )
|
||||
|
||||
Create a fake mpd configuration file, based on the file mpd.conf.template
|
||||
located in t/mpd-test. The string PWD will be replaced by the real path -
|
||||
ie, where the tarball has been untarred. The string PORT will be replaced
|
||||
by $port if specified, 6600 otherwise (MPD default).
|
||||
|
||||
=back
|
||||
|
||||
This might be useful when trying to test connections with mpd server.
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Audio::MPD>
|
||||
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Jerome Quelin, C<< <jquelin at cpan.org> >>
|
||||
|
||||
|
||||
=head1 COPYRIGHT & LICENSE
|
||||
|
||||
Copyright (c) 2007 Jerome Quelin, all rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself.
|
||||
|
||||
=cut
|
||||
@@ -1,803 +0,0 @@
|
||||
=for gpg
|
||||
-----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
- -----BEGIN PGP SIGNED MESSAGE-----
|
||||
Hash: SHA1
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Readonly - Facility for creating read-only scalars, arrays, hashes.
|
||||
|
||||
=head1 VERSION
|
||||
|
||||
This documentation describes version 1.03 of Readonly.pm, April 20, 2004.
|
||||
|
||||
=cut
|
||||
|
||||
# Rest of documentation is after __END__.
|
||||
|
||||
use 5.005;
|
||||
use strict;
|
||||
#use warnings;
|
||||
#no warnings 'uninitialized';
|
||||
|
||||
package Readonly;
|
||||
$Readonly::VERSION = '1.03'; # Also change in the documentation!
|
||||
|
||||
# Autocroak (Thanks, MJD)
|
||||
# Only load Carp.pm if module is croaking.
|
||||
sub croak
|
||||
{
|
||||
require Carp;
|
||||
goto &Carp::croak;
|
||||
}
|
||||
|
||||
# These functions may be overridden by Readonly::XS, if installed.
|
||||
sub is_sv_readonly ($) { 0 }
|
||||
sub make_sv_readonly ($) { die "make_sv_readonly called but not overridden" }
|
||||
use vars qw/$XSokay/; # Set to true in Readonly::XS, if available
|
||||
|
||||
# Common error messages, or portions thereof
|
||||
use vars qw/$MODIFY $REASSIGN $ODDHASH/;
|
||||
$MODIFY = 'Modification of a read-only value attempted';
|
||||
$REASSIGN = 'Attempt to reassign a readonly';
|
||||
$ODDHASH = 'May not store an odd number of values in a hash';
|
||||
|
||||
# See if we can use the XS stuff.
|
||||
$Readonly::XS::MAGIC_COOKIE = "Do NOT use or require Readonly::XS unless you're me.";
|
||||
eval 'use Readonly::XS';
|
||||
|
||||
|
||||
# ----------------
|
||||
# Read-only scalars
|
||||
# ----------------
|
||||
package Readonly::Scalar;
|
||||
|
||||
sub TIESCALAR
|
||||
{
|
||||
my $whence = (caller 2)[3]; # Check if naughty user is trying to tie directly.
|
||||
Readonly::croak "Invalid tie" unless $whence && $whence =~ /^Readonly::(?:Scalar1?|Readonly)$/;
|
||||
my $class = shift;
|
||||
Readonly::croak "No value specified for readonly scalar" unless @_;
|
||||
Readonly::croak "Too many values specified for readonly scalar" unless @_ == 1;
|
||||
|
||||
my $value = shift;
|
||||
return bless \$value, $class;
|
||||
}
|
||||
|
||||
sub FETCH
|
||||
{
|
||||
my $self = shift;
|
||||
return $$self;
|
||||
}
|
||||
|
||||
*STORE = *UNTIE =
|
||||
sub {Readonly::croak $Readonly::MODIFY};
|
||||
|
||||
|
||||
# ----------------
|
||||
# Read-only arrays
|
||||
# ----------------
|
||||
package Readonly::Array;
|
||||
|
||||
sub TIEARRAY
|
||||
{
|
||||
my $whence = (caller 1)[3]; # Check if naughty user is trying to tie directly.
|
||||
Readonly::croak "Invalid tie" unless $whence =~ /^Readonly::Array1?$/;
|
||||
my $class = shift;
|
||||
my @self = @_;
|
||||
|
||||
return bless \@self, $class;
|
||||
}
|
||||
|
||||
sub FETCH
|
||||
{
|
||||
my $self = shift;
|
||||
my $index = shift;
|
||||
return $self->[$index];
|
||||
}
|
||||
|
||||
sub FETCHSIZE
|
||||
{
|
||||
my $self = shift;
|
||||
return scalar @$self;
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
eval q{
|
||||
sub EXISTS
|
||||
{
|
||||
my $self = shift;
|
||||
my $index = shift;
|
||||
return exists $self->[$index];
|
||||
}
|
||||
} if $] >= 5.006; # couldn't do "exists" on arrays before then
|
||||
}
|
||||
|
||||
*STORE = *STORESIZE = *EXTEND = *PUSH = *POP = *UNSHIFT = *SHIFT = *SPLICE = *CLEAR = *UNTIE =
|
||||
sub {Readonly::croak $Readonly::MODIFY};
|
||||
|
||||
|
||||
# ----------------
|
||||
# Read-only hashes
|
||||
# ----------------
|
||||
package Readonly::Hash;
|
||||
|
||||
sub TIEHASH
|
||||
{
|
||||
my $whence = (caller 1)[3]; # Check if naughty user is trying to tie directly.
|
||||
Readonly::croak "Invalid tie" unless $whence =~ /^Readonly::Hash1?$/;
|
||||
|
||||
my $class = shift;
|
||||
# must have an even number of values
|
||||
Readonly::croak $Readonly::ODDHASH unless (@_ %2 == 0);
|
||||
|
||||
my %self = @_;
|
||||
return bless \%self, $class;
|
||||
}
|
||||
|
||||
sub FETCH
|
||||
{
|
||||
my $self = shift;
|
||||
my $key = shift;
|
||||
|
||||
return $self->{$key};
|
||||
}
|
||||
|
||||
sub EXISTS
|
||||
{
|
||||
my $self = shift;
|
||||
my $key = shift;
|
||||
return exists $self->{$key};
|
||||
}
|
||||
|
||||
sub FIRSTKEY
|
||||
{
|
||||
my $self = shift;
|
||||
my $dummy = keys %$self;
|
||||
return scalar each %$self;
|
||||
}
|
||||
|
||||
sub NEXTKEY
|
||||
{
|
||||
my $self = shift;
|
||||
return scalar each %$self;
|
||||
}
|
||||
|
||||
*STORE = *DELETE = *CLEAR = *UNTIE =
|
||||
sub {Readonly::croak $Readonly::MODIFY};
|
||||
|
||||
|
||||
# ----------------------------------------------------------------
|
||||
# Main package, containing convenience functions (so callers won't
|
||||
# have to explicitly tie the variables themselves).
|
||||
# ----------------------------------------------------------------
|
||||
package Readonly;
|
||||
use Exporter;
|
||||
use vars qw/@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS/;
|
||||
push @ISA, 'Exporter';
|
||||
push @EXPORT, qw/Readonly/;
|
||||
push @EXPORT_OK, qw/Scalar Array Hash Scalar1 Array1 Hash1/;
|
||||
|
||||
# Predeclare the following, so we can use them recursively
|
||||
sub Scalar ($$);
|
||||
sub Array (\@;@);
|
||||
sub Hash (\%;@);
|
||||
|
||||
# Returns true if a string begins with "Readonly::"
|
||||
# Used to prevent reassignment of Readonly variables.
|
||||
sub _is_badtype
|
||||
{
|
||||
my $type = $_[0];
|
||||
return lc $type if $type =~ s/^Readonly:://;
|
||||
return;
|
||||
}
|
||||
|
||||
# Shallow Readonly scalar
|
||||
sub Scalar1 ($$)
|
||||
{
|
||||
croak "$REASSIGN scalar" if is_sv_readonly $_[0];
|
||||
my $badtype = _is_badtype (ref tied $_[0]);
|
||||
croak "$REASSIGN $badtype" if $badtype;
|
||||
|
||||
# xs method: flag scalar as readonly
|
||||
if ($XSokay)
|
||||
{
|
||||
$_[0] = $_[1];
|
||||
make_sv_readonly $_[0];
|
||||
return;
|
||||
}
|
||||
|
||||
# pure-perl method: tied scalar
|
||||
my $tieobj = eval {tie $_[0], 'Readonly::Scalar', $_[1]};
|
||||
if ($@)
|
||||
{
|
||||
croak "$REASSIGN scalar" if substr($@,0,43) eq $MODIFY;
|
||||
die $@; # some other error?
|
||||
}
|
||||
return $tieobj;
|
||||
}
|
||||
|
||||
# Shallow Readonly array
|
||||
sub Array1 (\@;@)
|
||||
{
|
||||
my $badtype = _is_badtype (ref tied $_[0]);
|
||||
croak "$REASSIGN $badtype" if $badtype;
|
||||
|
||||
my $aref = shift;
|
||||
return tie @$aref, 'Readonly::Array', @_;
|
||||
}
|
||||
|
||||
# Shallow Readonly hash
|
||||
sub Hash1 (\%;@)
|
||||
{
|
||||
my $badtype = _is_badtype (ref tied $_[0]);
|
||||
croak "$REASSIGN $badtype" if $badtype;
|
||||
|
||||
my $href = shift;
|
||||
|
||||
# If only one value, and it's a hashref, expand it
|
||||
if (@_ == 1 && ref $_[0] eq 'HASH')
|
||||
{
|
||||
return tie %$href, 'Readonly::Hash', %{$_[0]};
|
||||
}
|
||||
|
||||
# otherwise, must have an even number of values
|
||||
croak $ODDHASH unless (@_%2 == 0);
|
||||
|
||||
return tie %$href, 'Readonly::Hash', @_;
|
||||
}
|
||||
|
||||
# Deep Readonly scalar
|
||||
sub Scalar ($$)
|
||||
{
|
||||
croak "$REASSIGN scalar" if is_sv_readonly $_[0];
|
||||
my $badtype = _is_badtype (ref tied $_[0]);
|
||||
croak "$REASSIGN $badtype" if $badtype;
|
||||
|
||||
my $value = $_[1];
|
||||
|
||||
# Recursively check passed element for references; if any, make them Readonly
|
||||
foreach ($value)
|
||||
{
|
||||
if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v}
|
||||
elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v}
|
||||
elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v}
|
||||
}
|
||||
|
||||
# xs method: flag scalar as readonly
|
||||
if ($XSokay)
|
||||
{
|
||||
$_[0] = $value;
|
||||
make_sv_readonly $_[0];
|
||||
return;
|
||||
}
|
||||
|
||||
# pure-perl method: tied scalar
|
||||
my $tieobj = eval {tie $_[0], 'Readonly::Scalar', $value};
|
||||
if ($@)
|
||||
{
|
||||
croak "$REASSIGN scalar" if substr($@,0,43) eq $MODIFY;
|
||||
die $@; # some other error?
|
||||
}
|
||||
return $tieobj;
|
||||
}
|
||||
|
||||
# Deep Readonly array
|
||||
sub Array (\@;@)
|
||||
{
|
||||
my $badtype = _is_badtype (ref tied @{$_[0]});
|
||||
croak "$REASSIGN $badtype" if $badtype;
|
||||
|
||||
my $aref = shift;
|
||||
my @values = @_;
|
||||
|
||||
# Recursively check passed elements for references; if any, make them Readonly
|
||||
foreach (@values)
|
||||
{
|
||||
if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v}
|
||||
elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v}
|
||||
elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v}
|
||||
}
|
||||
# Lastly, tie the passed reference
|
||||
return tie @$aref, 'Readonly::Array', @values;
|
||||
}
|
||||
|
||||
# Deep Readonly hash
|
||||
sub Hash (\%;@)
|
||||
{
|
||||
my $badtype = _is_badtype (ref tied %{$_[0]});
|
||||
croak "$REASSIGN $badtype" if $badtype;
|
||||
|
||||
my $href = shift;
|
||||
my @values = @_;
|
||||
|
||||
# If only one value, and it's a hashref, expand it
|
||||
if (@_ == 1 && ref $_[0] eq 'HASH')
|
||||
{
|
||||
@values = %{$_[0]};
|
||||
}
|
||||
|
||||
# otherwise, must have an even number of values
|
||||
croak $ODDHASH unless (@values %2 == 0);
|
||||
|
||||
# Recursively check passed elements for references; if any, make them Readonly
|
||||
foreach (@values)
|
||||
{
|
||||
if (ref eq 'SCALAR') {Scalar my $v => $$_; $_ = \$v}
|
||||
elsif (ref eq 'ARRAY') {Array my @v => @$_; $_ = \@v}
|
||||
elsif (ref eq 'HASH') {Hash my %v => $_; $_ = \%v}
|
||||
}
|
||||
|
||||
return tie %$href, 'Readonly::Hash', @values;
|
||||
}
|
||||
|
||||
|
||||
# Common entry-point for all supported data types
|
||||
eval q{sub Readonly} . ( $] < 5.008 ? '' : '(\[$@%]@)' ) . <<'SUB_READONLY';
|
||||
{
|
||||
if (ref $_[0] eq 'SCALAR')
|
||||
{
|
||||
croak $MODIFY if is_sv_readonly ${$_[0]};
|
||||
my $badtype = _is_badtype (ref tied ${$_[0]});
|
||||
croak "$REASSIGN $badtype" if $badtype;
|
||||
croak "Readonly scalar must have only one value" if @_ > 2;
|
||||
|
||||
my $tieobj = eval {tie ${$_[0]}, 'Readonly::Scalar', $_[1]};
|
||||
# Tie may have failed because user tried to tie a constant, or we screwed up somehow.
|
||||
if ($@)
|
||||
{
|
||||
croak $MODIFY if $@ =~ /^$MODIFY at/; # Point the finger at the user.
|
||||
die "$@\n"; # Not a modify read-only message; must be our fault.
|
||||
}
|
||||
return $tieobj;
|
||||
}
|
||||
elsif (ref $_[0] eq 'ARRAY')
|
||||
{
|
||||
my $aref = shift;
|
||||
return Array @$aref, @_;
|
||||
}
|
||||
elsif (ref $_[0] eq 'HASH')
|
||||
{
|
||||
my $href = shift;
|
||||
croak $ODDHASH if @_%2 != 0 && !(@_ == 1 && ref $_[0] eq 'HASH');
|
||||
return Hash %$href, @_;
|
||||
}
|
||||
elsif (ref $_[0])
|
||||
{
|
||||
croak "Readonly only supports scalar, array, and hash variables.";
|
||||
}
|
||||
else
|
||||
{
|
||||
croak "First argument to Readonly must be a reference.";
|
||||
}
|
||||
}
|
||||
SUB_READONLY
|
||||
|
||||
|
||||
1;
|
||||
__END__
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use Readonly;
|
||||
|
||||
# Read-only scalar
|
||||
Readonly::Scalar $sca => $initial_value;
|
||||
Readonly::Scalar my $sca => $initial_value;
|
||||
|
||||
# Read-only array
|
||||
Readonly::Array @arr => @values;
|
||||
Readonly::Array my @arr => @values;
|
||||
|
||||
# Read-only hash
|
||||
Readonly::Hash %has => (key => value, key => value, ...);
|
||||
Readonly::Hash my %has => (key => value, key => value, ...);
|
||||
# or:
|
||||
Readonly::Hash %has => {key => value, key => value, ...};
|
||||
|
||||
# You can use the read-only variables like any regular variables:
|
||||
print $sca;
|
||||
$something = $sca + $arr[2];
|
||||
next if $has{$some_key};
|
||||
|
||||
# But if you try to modify a value, your program will die:
|
||||
$sca = 7;
|
||||
push @arr, 'seven';
|
||||
delete $has{key};
|
||||
# The error message is "Modification of a read-only value
|
||||
attempted"
|
||||
|
||||
# Alternate form (Perl 5.8 and later)
|
||||
Readonly $sca => $initial_value;
|
||||
Readonly my $sca => $initial_value;
|
||||
Readonly @arr => @values;
|
||||
Readonly my @arr => @values;
|
||||
Readonly %has => (key => value, key => value, ...);
|
||||
Readonly my %has => (key => value, key => value, ...);
|
||||
# Alternate form (for Perls earlier than v5.8)
|
||||
Readonly \$sca => $initial_value;
|
||||
Readonly \my $sca => $initial_value;
|
||||
Readonly \@arr => @values;
|
||||
Readonly \my @arr => @values;
|
||||
Readonly \%has => (key => value, key => value, ...);
|
||||
Readonly \my %has => (key => value, key => value, ...);
|
||||
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
This is a facility for creating non-modifiable variables. This is
|
||||
useful for configuration files, headers, etc. It can also be useful
|
||||
as a development and debugging tool, for catching updates to variables
|
||||
that should not be changed.
|
||||
|
||||
If any of the values you pass to C<Scalar>, C<Array>, or C<Hash> are
|
||||
references, then those functions recurse over the data structures,
|
||||
marking everything as Readonly. Usually, this is what you want: the
|
||||
entire structure nonmodifiable. If you want only the top level to be
|
||||
Readonly, use the alternate C<Scalar1>, C<Array1> and C<Hash1>
|
||||
functions.
|
||||
|
||||
Please note that most users of Readonly will also want to install a
|
||||
companion module Readonly::XS. See the L</CONS> section below for more
|
||||
details.
|
||||
|
||||
=head1 COMPARISON WITH "use constant"
|
||||
|
||||
Perl provides a facility for creating constant values, via the "use
|
||||
constant" pragma. There are several problems with this pragma.
|
||||
|
||||
=over 2
|
||||
|
||||
=item *
|
||||
|
||||
The constants created have no leading $ or @ character.
|
||||
|
||||
=item *
|
||||
|
||||
These constants cannot be interpolated into strings.
|
||||
|
||||
=item *
|
||||
|
||||
Syntax can get dicey sometimes. For example:
|
||||
|
||||
use constant CARRAY => (2, 3, 5, 7, 11, 13);
|
||||
$a_prime = CARRAY[2]; # wrong!
|
||||
$a_prime = (CARRAY)[2]; # right -- MUST use parentheses
|
||||
|
||||
=item *
|
||||
|
||||
You have to be very careful in places where barewords are allowed.
|
||||
For example:
|
||||
|
||||
use constant SOME_KEY => 'key';
|
||||
%hash = (key => 'value', other_key => 'other_value');
|
||||
$some_value = $hash{SOME_KEY}; # wrong!
|
||||
$some_value = $hash{+SOME_KEY}; # right
|
||||
|
||||
(who thinks to use a unary plus when using a hash?)
|
||||
|
||||
=item *
|
||||
|
||||
C<use constant> works for scalars and arrays, not hashes.
|
||||
|
||||
=item *
|
||||
|
||||
These constants are global ot the package in which they're declared;
|
||||
cannot be lexically scoped.
|
||||
|
||||
=item *
|
||||
|
||||
Works only at compile time.
|
||||
|
||||
=item *
|
||||
|
||||
Can be overridden:
|
||||
|
||||
use constant PI => 3.14159;
|
||||
...
|
||||
use constant PI => 2.71828;
|
||||
|
||||
(this does generate a warning, however, if you have warnings enabled).
|
||||
|
||||
=item *
|
||||
|
||||
It is very difficult to make and use deep structures (complex data
|
||||
structures) with C<use constant>.
|
||||
|
||||
=back
|
||||
|
||||
=head1 COMPARISON WITH TYPEGLOB CONSTANTS
|
||||
|
||||
Another popular way to create read-only scalars is to modify the symbol
|
||||
table entry for the variable by using a typeglob:
|
||||
|
||||
*a = \'value';
|
||||
|
||||
This works fine, but it only works for global variables ("my"
|
||||
variables have no symbol table entry). Also, the following similar
|
||||
constructs do B<not> work:
|
||||
|
||||
*a = [1, 2, 3]; # Does NOT create a read-only array
|
||||
*a = { a => 'A'}; # Does NOT create a read-only hash
|
||||
|
||||
=head1 PROS
|
||||
|
||||
Readonly.pm, on the other hand, will work with global variables and
|
||||
with lexical ("my") variables. It will create scalars, arrays, or
|
||||
hashes, all of which look and work like normal, read-write Perl
|
||||
variables. You can use them in scalar context, in list context; you
|
||||
can take references to them, pass them to functions, anything.
|
||||
|
||||
Readonly.pm also works well with complex data structures, allowing you
|
||||
to tag the whole structure as nonmodifiable, or just the top level.
|
||||
|
||||
Also, Readonly variables may not be reassigned. The following code
|
||||
will die:
|
||||
|
||||
Readonly::Scalar $pi => 3.14159;
|
||||
...
|
||||
Readonly::Scalar $pi => 2.71828;
|
||||
|
||||
=head1 CONS
|
||||
|
||||
Readonly.pm does impose a performance penalty. It's pretty slow. How
|
||||
slow? Run the C<benchmark.pl> script that comes with Readonly. On my
|
||||
test system, "use constant", typeglob constants, and regular
|
||||
read/write Perl variables were all about the same speed, and
|
||||
Readonly.pm constants were about 1/20 the speed.
|
||||
|
||||
However, there is relief. There is a companion module available,
|
||||
Readonly::XS. If it is installed on your system, Readonly.pm uses it
|
||||
to make read-only scalars much faster. With Readonly::XS, Readonly
|
||||
scalars are as fast as the other types of variables. Readonly arrays
|
||||
and hashes will still be relatively slow. But it's likely that most
|
||||
of your Readonly variables will be scalars.
|
||||
|
||||
If you can't use Readonly::XS (for example, if you don't have a C
|
||||
compiler, or your perl is statically linked and you don't want to
|
||||
re-link it), you have to decide whether the benefits of Readonly
|
||||
variables outweigh the speed issue. For most configuration variables
|
||||
(and other things that Readonly is likely to be useful for), the speed
|
||||
issue is probably not really a big problem. But benchmark your
|
||||
program if it might be. If it turns out to be a problem, you may
|
||||
still want to use Readonly.pm during development, to catch changes to
|
||||
variables that should not be changed, and then remove it for
|
||||
production:
|
||||
|
||||
# For testing:
|
||||
Readonly::Scalar $Foo_Directory => '/usr/local/foo';
|
||||
Readonly::Scalar $Bar_Directory => '/usr/local/bar';
|
||||
# $Foo_Directory = '/usr/local/foo';
|
||||
# $Bar_Directory = '/usr/local/bar';
|
||||
|
||||
# For production:
|
||||
# Readonly::Scalar $Foo_Directory => '/usr/local/foo';
|
||||
# Readonly::Scalar $Bar_Directory => '/usr/local/bar';
|
||||
$Foo_Directory = '/usr/local/foo';
|
||||
$Bar_Directory = '/usr/local/bar';
|
||||
|
||||
|
||||
=head1 FUNCTIONS
|
||||
|
||||
=over 4
|
||||
|
||||
=item Readonly::Scalar $var => $value;
|
||||
|
||||
Creates a nonmodifiable scalar, C<$var>, and assigns a value of
|
||||
C<$value> to it. Thereafter, its value may not be changed. Any
|
||||
attempt to modify the value will cause your program to die.
|
||||
|
||||
A value I<must> be supplied. If you want the variable to have
|
||||
C<undef> as its value, you must specify C<undef>.
|
||||
|
||||
If C<$value> is a reference to a scalar, array, or hash, then this
|
||||
function will mark the scalar, array, or hash it points to as being
|
||||
Readonly as well, and it will recursively traverse the structure,
|
||||
marking the whole thing as Readonly. Usually, this is what you want.
|
||||
However, if you want only the C<$value> marked as Readonly, use
|
||||
C<Scalar1>.
|
||||
|
||||
If $var is already a Readonly variable, the program will die with
|
||||
an error about reassigning Readonly variables.
|
||||
|
||||
=item Readonly::Array @arr => (value, value, ...);
|
||||
|
||||
Creates a nonmodifiable array, C<@arr>, and assigns the specified list
|
||||
of values to it. Thereafter, none of its values may be changed; the
|
||||
array may not be lengthened or shortened or spliced. Any attempt to
|
||||
do so will cause your program to die.
|
||||
|
||||
If any of the values passed is a reference to a scalar, array, or hash,
|
||||
then this function will mark the scalar, array, or hash it points to as
|
||||
being Readonly as well, and it will recursively traverse the structure,
|
||||
marking the whole thing as Readonly. Usually, this is what you want.
|
||||
However, if you want only the hash C<%@arr> itself marked as Readonly,
|
||||
use C<Array1>.
|
||||
|
||||
If @arr is already a Readonly variable, the program will die with
|
||||
an error about reassigning Readonly variables.
|
||||
|
||||
=item Readonly::Hash %h => (key => value, key => value, ...);
|
||||
|
||||
=item Readonly::Hash %h => {key => value, key => value, ...};
|
||||
|
||||
Creates a nonmodifiable hash, C<%h>, and assigns the specified keys
|
||||
and values to it. Thereafter, its keys or values may not be changed.
|
||||
Any attempt to do so will cause your program to die.
|
||||
|
||||
A list of keys and values may be specified (with parentheses in the
|
||||
synopsis above), or a hash reference may be specified (curly braces in
|
||||
the synopsis above). If a list is specified, it must have an even
|
||||
number of elements, or the function will die.
|
||||
|
||||
If any of the values is a reference to a scalar, array, or hash, then
|
||||
this function will mark the scalar, array, or hash it points to as
|
||||
being Readonly as well, and it will recursively traverse the
|
||||
structure, marking the whole thing as Readonly. Usually, this is what
|
||||
you want. However, if you want only the hash C<%h> itself marked as
|
||||
Readonly, use C<Hash1>.
|
||||
|
||||
If %h is already a Readonly variable, the program will die with
|
||||
an error about reassigning Readonly variables.
|
||||
|
||||
=item Readonly $var => $value;
|
||||
|
||||
=item Readonly @arr => (value, value, ...);
|
||||
|
||||
=item Readonly %h => (key => value, ...);
|
||||
|
||||
=item Readonly %h => {key => value, ...};
|
||||
|
||||
The C<Readonly> function is an alternate to the C<Scalar>, C<Array>,
|
||||
and C<Hash> functions. It has the advantage (if you consider it an
|
||||
advantage) of being one function. That may make your program look
|
||||
neater, if you're initializing a whole bunch of constants at once.
|
||||
You may or may not prefer this uniform style.
|
||||
|
||||
It has the disadvantage of having a slightly different syntax for
|
||||
versions of Perl prior to 5.8. For earlier versions, you must supply
|
||||
a backslash, because it requires a reference as the first parameter.
|
||||
|
||||
Readonly \$var => $value;
|
||||
Readonly \@arr => (value, value, ...);
|
||||
Readonly \%h => (key => value, ...);
|
||||
Readonly \%h => {key => value, ...};
|
||||
|
||||
You may or may not consider this ugly.
|
||||
|
||||
=item Readonly::Scalar1 $var => $value;
|
||||
|
||||
=item Readonly::Array1 @arr => (value, value, ...);
|
||||
|
||||
=item Readonly::Hash1 %h => (key => value, key => value, ...);
|
||||
|
||||
=item Readonly::Hash1 %h => {key => value, key => value, ...};
|
||||
|
||||
These alternate functions create shallow Readonly variables, instead
|
||||
of deep ones. For example:
|
||||
|
||||
Readonly::Array1 @shal => (1, 2, {perl=>'Rules', java=>'Bites'}, 4, 5);
|
||||
Readonly::Array @deep => (1, 2, {perl=>'Rules', java=>'Bites'}, 4, 5);
|
||||
|
||||
$shal[1] = 7; # error
|
||||
$shal[2]{APL}='Weird'; # Allowed! since the hash isn't Readonly
|
||||
$deep[1] = 7; # error
|
||||
$deep[2]{APL}='Weird'; # error, since the hash is Readonly
|
||||
|
||||
|
||||
=back
|
||||
|
||||
|
||||
=head1 EXAMPLES
|
||||
|
||||
# SCALARS:
|
||||
|
||||
# A plain old read-only value
|
||||
Readonly::Scalar $a => "A string value";
|
||||
|
||||
# The value need not be a compile-time constant:
|
||||
Readonly::Scalar $a => $computed_value;
|
||||
|
||||
|
||||
# ARRAYS:
|
||||
|
||||
# A read-only array:
|
||||
Readonly::Array @a => (1, 2, 3, 4);
|
||||
|
||||
# The parentheses are optional:
|
||||
Readonly::Array @a => 1, 2, 3, 4;
|
||||
|
||||
# You can use Perl's built-in array quoting syntax:
|
||||
Readonly::Array @a => qw/1 2 3 4/;
|
||||
|
||||
# You can initialize a read-only array from a variable one:
|
||||
Readonly::Array @a => @computed_values;
|
||||
|
||||
# A read-only array can be empty, too:
|
||||
Readonly::Array @a => ();
|
||||
Readonly::Array @a; # equivalent
|
||||
|
||||
|
||||
# HASHES
|
||||
|
||||
# Typical usage:
|
||||
Readonly::Hash %a => (key1 => 'value1', key2 => 'value2');
|
||||
|
||||
# A read-only hash can be initialized from a variable one:
|
||||
Readonly::Hash %a => %computed_values;
|
||||
|
||||
# A read-only hash can be empty:
|
||||
Readonly::Hash %a => ();
|
||||
Readonly::Hash %a; # equivalent
|
||||
|
||||
# If you pass an odd number of values, the program will die:
|
||||
Readonly::Hash %a => (key1 => 'value1', "value2");
|
||||
--> dies with "May not store an odd number of values in a hash"
|
||||
|
||||
|
||||
=head1 EXPORTS
|
||||
|
||||
By default, this module exports the following symbol into the calling
|
||||
program's namespace:
|
||||
|
||||
Readonly
|
||||
|
||||
The following symbols are available for import into your program, if
|
||||
you like:
|
||||
|
||||
Scalar Scalar1
|
||||
Array Array1
|
||||
Hash Hash1
|
||||
|
||||
|
||||
=head1 REQUIREMENTS
|
||||
|
||||
Perl 5.000
|
||||
Carp.pm (included with Perl)
|
||||
Exporter.pm (included with Perl)
|
||||
|
||||
Readonly::XS is recommended but not required.
|
||||
|
||||
=head1 ACKNOWLEDGEMENTS
|
||||
|
||||
Thanks to Slaven Rezic for the idea of one common function
|
||||
(Readonly) for all three types of variables (13 April 2002).
|
||||
|
||||
Thanks to Ernest Lergon for the idea (and initial code) for
|
||||
deeply-Readonly data structures (21 May 2002).
|
||||
|
||||
Thanks to Damian Conway for the idea (and code) for making the
|
||||
Readonly function work a lot smoother under perl 5.8+.
|
||||
|
||||
|
||||
=head1 AUTHOR / COPYRIGHT
|
||||
|
||||
Eric J. Roode, roode@cpan.org
|
||||
|
||||
Copyright (c) 2001-2004 by Eric J. Roode. All Rights Reserved. This
|
||||
module is free software; you can redistribute it and/or modify it under
|
||||
the same terms as Perl itself.
|
||||
|
||||
If you have suggestions for improvement, please drop me a line. If
|
||||
you make improvements to this software, I ask that you please send me
|
||||
a copy of your changes. Thanks.
|
||||
|
||||
Readonly.pm is made from 100% recycled electrons. No animals were
|
||||
harmed during the development and testing of this module. Not sold
|
||||
in stores! Readonly::XS sold separately. Void where prohibited.
|
||||
|
||||
=cut
|
||||
|
||||
=begin gpg
|
||||
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v1.2.4 (MingW32)
|
||||
|
||||
iD8DBQFAhaGCY96i4h5M0egRAg++AJ0ar4ncojbOp0OOc2wo+E/1cBn5cQCg9eP9
|
||||
qTzAC87PuyKB+vrcRykrDbo=
|
||||
=39Ny
|
||||
-----END PGP SIGNATURE-----
|
||||
|
||||
=cut
|
||||
@@ -1,14 +0,0 @@
|
||||
62.75.176.45/rtl-high|89.0 RTL Hitradio|http://www.89.0rtl.de
|
||||
gffstream.ic.llnwd.net/stream/gffstream_stream_wdr_einslive_b|Einslive|http://www.einslive.de/
|
||||
213.186.41.149:8040|Deepinside Radio European|http://www.deepinside.co.uk
|
||||
62.75.176.40:80/bigfm-cbr-128|BigFM|http://www.bigfm.de
|
||||
stream.telvi.de:8000/radiobrocken|Hit-Radio Brocken|http://www.radiobrocken.de
|
||||
magic-island.eu:8000/listen.mp3|Magic Island|http://www.magic-island.eu
|
||||
dsl.blackbeats.fm:13000|BlackBeats FM|http://www.blackbeats.fm
|
||||
87.118.64.197:3100|Discofox-Radio|http://www.discofox-radio.de
|
||||
rmnradio.powerstream.de:8022|RMNradio|http://www.rmnradio.de/
|
||||
relay.radio.ethz.ch:8000/kohina.ogg|Kohina|http://www.kohina.com
|
||||
relay1.slayradio.org:8000|Slay Radio|http://www.slayradio.com/
|
||||
demovibes.de:8000/necta128.ogg|Nectarine Demoscene Radio|http://www.scenemusic.eu/
|
||||
r1.scenesat.com:8000/scenesathi|SceneSat Radio|http://www.scenesat.com
|
||||
radioparadise.steadyhost.com:8060|Radio Paradise|http://www.radioparadise.com/
|
||||
@@ -119,7 +119,6 @@ var/ipfire/menu.d/60-ipfire.menu
|
||||
var/ipfire/menu.d/70-log.menu
|
||||
#var/ipfire/menu.d/EX-apcupsd.menu
|
||||
#var/ipfire/menu.d/EX-guardian.menu
|
||||
#var/ipfire/menu.d/EX-mpfire.menu
|
||||
#var/ipfire/menu.d/EX-mympd.menu
|
||||
#var/ipfire/menu.d/EX-samba.menu
|
||||
#var/ipfire/menu.d/EX-tor.menu
|
||||
|
||||
@@ -55,7 +55,6 @@ srv/web/ipfire/cgi-bin/media.cgi
|
||||
srv/web/ipfire/cgi-bin/memory.cgi
|
||||
srv/web/ipfire/cgi-bin/modem-status.cgi
|
||||
srv/web/ipfire/cgi-bin/modem.cgi
|
||||
#srv/web/ipfire/cgi-bin/mpfire.cgi
|
||||
#srv/web/ipfire/cgi-bin/mympd.cgi
|
||||
srv/web/ipfire/cgi-bin/netexternal.cgi
|
||||
srv/web/ipfire/cgi-bin/netinternal.cgi
|
||||
@@ -218,8 +217,6 @@ srv/web/ipfire/html/images/media-resume.png
|
||||
srv/web/ipfire/html/images/media-shuffle.png
|
||||
srv/web/ipfire/html/images/media-skip-backward.png
|
||||
srv/web/ipfire/html/images/media-skip-forward.png
|
||||
srv/web/ipfire/html/images/mpfire
|
||||
srv/web/ipfire/html/images/mpfire/box.png
|
||||
srv/web/ipfire/html/images/network-error.png
|
||||
srv/web/ipfire/html/images/network-idle.png
|
||||
srv/web/ipfire/html/images/network-offline.png
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
srv/web/ipfire/cgi-bin/mpfire.cgi
|
||||
srv/web/ipfire/html/images/mpfire
|
||||
usr/lib/perl5/5.36.0/Class/Accessor
|
||||
usr/lib/perl5/5.36.0/Class/Accessor.pm
|
||||
usr/lib/perl5/5.36.0/Class/Accessor/Fast.pm
|
||||
usr/lib/perl5/5.36.0/Class/Accessor/Faster.pm
|
||||
usr/lib/perl5/5.36.0/Readonly.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Collection.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common/Item
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common/Item.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common/Item/Directory.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common/Item/Playlist.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common/Item/Song.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common/Stats.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common/Status.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Common/Time.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Playlist.pm
|
||||
usr/lib/perl5/site_perl/5.36.0/Audio/MPD/Test.pm
|
||||
usr/local/bin/mpfirectrl
|
||||
var/ipfire/backup/addons/includes/mpfire
|
||||
var/ipfire/menu.d/EX-mpfire.menu
|
||||
var/ipfire/mpfire
|
||||
var/ipfire/mpfire/bin
|
||||
var/ipfire/mpfire/bin/mpfire.pl
|
||||
var/ipfire/mpfire/settings
|
||||
var/ipfire/mpfire/webradio
|
||||
usr/local/bin/mpfirectrl
|
||||
srv/web/ipfire/cgi-bin/mpfire.cgi
|
||||
srv/web/ipfire/html/images/mpfire
|
||||
var/ipfire/menu.d/EX-mpfire.menu
|
||||
@@ -24,14 +24,19 @@ WARNING: translation string unused: ConnSched scheduler
|
||||
WARNING: translation string unused: ConnSched select profile
|
||||
WARNING: translation string unused: Daily
|
||||
WARNING: translation string unused: Disabled
|
||||
WARNING: translation string unused: Existing Files
|
||||
WARNING: translation string unused: HDD temperature
|
||||
WARNING: translation string unused: Level7 rule
|
||||
WARNING: translation string unused: Local VPN IP
|
||||
WARNING: translation string unused: Pages
|
||||
WARNING: translation string unused: Ping
|
||||
WARNING: translation string unused: Queuelenght
|
||||
WARNING: translation string unused: Remote IP
|
||||
WARNING: translation string unused: Remote VPN IP
|
||||
WARNING: translation string unused: Resolv
|
||||
WARNING: translation string unused: Scan for Files
|
||||
WARNING: translation string unused: Scan for Songs
|
||||
WARNING: translation string unused: Scan from Directory
|
||||
WARNING: translation string unused: Subclass
|
||||
WARNING: translation string unused: TOS Bits
|
||||
WARNING: translation string unused: Utilization on
|
||||
@@ -110,6 +115,7 @@ WARNING: translation string unused: age seconds
|
||||
WARNING: translation string unused: age shour
|
||||
WARNING: translation string unused: age sminute
|
||||
WARNING: translation string unused: age ssecond
|
||||
WARNING: translation string unused: album
|
||||
WARNING: translation string unused: alcatelusb help
|
||||
WARNING: translation string unused: alcatelusb upload
|
||||
WARNING: translation string unused: all interfaces
|
||||
@@ -122,6 +128,7 @@ WARNING: translation string unused: alt vpn
|
||||
WARNING: translation string unused: and
|
||||
WARNING: translation string unused: apply
|
||||
WARNING: translation string unused: archive not exist
|
||||
WARNING: translation string unused: artist
|
||||
WARNING: translation string unused: attemps
|
||||
WARNING: translation string unused: avoid dod
|
||||
WARNING: translation string unused: backup config floppy
|
||||
@@ -158,6 +165,7 @@ WARNING: translation string unused: check for net traffic update
|
||||
WARNING: translation string unused: choose config
|
||||
WARNING: translation string unused: class in use
|
||||
WARNING: translation string unused: clear cache
|
||||
WARNING: translation string unused: clear playlist
|
||||
WARNING: translation string unused: client
|
||||
WARNING: translation string unused: comment
|
||||
WARNING: translation string unused: community rules
|
||||
@@ -179,6 +187,7 @@ WARNING: translation string unused: create mask
|
||||
WARNING: translation string unused: create new backup
|
||||
WARNING: translation string unused: current media
|
||||
WARNING: translation string unused: current ovpn
|
||||
WARNING: translation string unused: current playlist
|
||||
WARNING: translation string unused: current profile
|
||||
WARNING: translation string unused: custom networks
|
||||
WARNING: translation string unused: custom services
|
||||
@@ -375,6 +384,7 @@ WARNING: translation string unused: generatekeys
|
||||
WARNING: translation string unused: generatepolicy
|
||||
WARNING: translation string unused: generatereport
|
||||
WARNING: translation string unused: genkey
|
||||
WARNING: translation string unused: genre
|
||||
WARNING: translation string unused: gpl i accept these terms and conditions
|
||||
WARNING: translation string unused: gpl license agreement
|
||||
WARNING: translation string unused: gpl please read carefully the general public license and accept it below
|
||||
@@ -540,6 +550,7 @@ WARNING: translation string unused: network traffic graphs
|
||||
WARNING: translation string unused: network updated
|
||||
WARNING: translation string unused: networks settings
|
||||
WARNING: translation string unused: new optionsfw must boot
|
||||
WARNING: translation string unused: next
|
||||
WARNING: translation string unused: no alcatelusb firmware
|
||||
WARNING: translation string unused: no cfg upload
|
||||
WARNING: translation string unused: no eciadsl synch.bin file
|
||||
@@ -632,6 +643,7 @@ WARNING: translation string unused: pdc options
|
||||
WARNING: translation string unused: phase1 group
|
||||
WARNING: translation string unused: phonebook entry
|
||||
WARNING: translation string unused: ping disabled
|
||||
WARNING: translation string unused: play
|
||||
WARNING: translation string unused: polfile
|
||||
WARNING: translation string unused: port forwarding configuration
|
||||
WARNING: translation string unused: ports
|
||||
@@ -639,6 +651,7 @@ WARNING: translation string unused: pots
|
||||
WARNING: translation string unused: pppoe
|
||||
WARNING: translation string unused: prefered master
|
||||
WARNING: translation string unused: present
|
||||
WARNING: translation string unused: prev
|
||||
WARNING: translation string unused: printcap name
|
||||
WARNING: translation string unused: printer
|
||||
WARNING: translation string unused: printername
|
||||
@@ -652,6 +665,7 @@ WARNING: translation string unused: proxy no proxy local
|
||||
WARNING: translation string unused: proxy port
|
||||
WARNING: translation string unused: psk
|
||||
WARNING: translation string unused: qos add subclass
|
||||
WARNING: translation string unused: quick playlist
|
||||
WARNING: translation string unused: read list
|
||||
WARNING: translation string unused: reboot ask
|
||||
WARNING: translation string unused: reboot question
|
||||
@@ -662,6 +676,7 @@ WARNING: translation string unused: registered user rules
|
||||
WARNING: translation string unused: released
|
||||
WARNING: translation string unused: reload
|
||||
WARNING: translation string unused: removable device advice
|
||||
WARNING: translation string unused: repeat
|
||||
WARNING: translation string unused: reportfile
|
||||
WARNING: translation string unused: reportlevel
|
||||
WARNING: translation string unused: requested data
|
||||
@@ -704,6 +719,7 @@ WARNING: translation string unused: set
|
||||
WARNING: translation string unused: shaping list options
|
||||
WARNING: translation string unused: show last x lines
|
||||
WARNING: translation string unused: show share options
|
||||
WARNING: translation string unused: shuffle
|
||||
WARNING: translation string unused: shutdown ask
|
||||
WARNING: translation string unused: shutdown sure
|
||||
WARNING: translation string unused: shutdown2
|
||||
@@ -765,9 +781,11 @@ WARNING: translation string unused: this months volume
|
||||
WARNING: translation string unused: this update is already installed
|
||||
WARNING: translation string unused: this weeks volume
|
||||
WARNING: translation string unused: time date manually reset
|
||||
WARNING: translation string unused: title
|
||||
WARNING: translation string unused: to email adr
|
||||
WARNING: translation string unused: to install an update
|
||||
WARNING: translation string unused: to warn email bad
|
||||
WARNING: translation string unused: toggle
|
||||
WARNING: translation string unused: too long 80 char max
|
||||
WARNING: translation string unused: tor 0 = disabled
|
||||
WARNING: translation string unused: tor accounting period daily
|
||||
@@ -850,6 +868,10 @@ WARNING: translation string unused: use dov
|
||||
WARNING: translation string unused: use ibod
|
||||
WARNING: translation string unused: view log
|
||||
WARNING: translation string unused: visible in browselist
|
||||
WARNING: translation string unused: voldown10
|
||||
WARNING: translation string unused: voldown5
|
||||
WARNING: translation string unused: volup10
|
||||
WARNING: translation string unused: volup5
|
||||
WARNING: translation string unused: vpn aggrmode
|
||||
WARNING: translation string unused: vpn delayed start
|
||||
WARNING: translation string unused: vpn delayed start help
|
||||
@@ -862,6 +884,7 @@ WARNING: translation string unused: vpn red name
|
||||
WARNING: translation string unused: vpn watch
|
||||
WARNING: translation string unused: warn when traffic reaches
|
||||
WARNING: translation string unused: web proxy configuration
|
||||
WARNING: translation string unused: webradio playlist
|
||||
WARNING: translation string unused: week
|
||||
WARNING: translation string unused: week-graph
|
||||
WARNING: translation string unused: weekly firewallhits
|
||||
|
||||
@@ -59,7 +59,6 @@ WARNING: untranslated string: ConnSched up = Up
|
||||
WARNING: untranslated string: ConnSched weekdays = Days of the week:
|
||||
WARNING: untranslated string: Edit an existing route = Edit an existing route
|
||||
WARNING: untranslated string: Enter TOS = Activate or deactivate TOS-bits <br /> and then press <i>Save</i>.
|
||||
WARNING: untranslated string: Existing Files = Files in database
|
||||
WARNING: untranslated string: Level7 Protocol = Level7-Protocol
|
||||
WARNING: untranslated string: Level7 Rule = Level7-Rule
|
||||
WARNING: untranslated string: MB read = MB read
|
||||
@@ -71,12 +70,8 @@ WARNING: untranslated string: Number of IPs for the pie chart = Number of IPs fo
|
||||
WARNING: untranslated string: Number of Ports for the pie chart = Number of ports for the pie chart
|
||||
WARNING: untranslated string: OVPN = OpenVPN
|
||||
WARNING: untranslated string: OpenVPN = OpenVPN
|
||||
WARNING: untranslated string: Pages = Pages
|
||||
WARNING: untranslated string: Port Rule = Port-Rule
|
||||
WARNING: untranslated string: QoS not enabled = QoS is not enabled!
|
||||
WARNING: untranslated string: Scan for Files = Scan for files
|
||||
WARNING: untranslated string: Scan for Songs = unknown string
|
||||
WARNING: untranslated string: Scan from Directory = Scan from directory
|
||||
WARNING: untranslated string: Set time on boot = Force setting the system clock on boot
|
||||
WARNING: untranslated string: TOS Rule = TOS-Rule
|
||||
WARNING: untranslated string: TOS rule = TOS rule
|
||||
@@ -307,7 +302,6 @@ WARNING: untranslated string: advproxy wpad title = Web Proxy Auto-Discovery Pro
|
||||
WARNING: untranslated string: advproxy wpad view pac = Open PAC File
|
||||
WARNING: untranslated string: age second = second
|
||||
WARNING: untranslated string: aktiv = Active
|
||||
WARNING: untranslated string: album = Album
|
||||
WARNING: untranslated string: alias ip = Alias IP
|
||||
WARNING: untranslated string: aliases = Aliases
|
||||
WARNING: untranslated string: aliases default interface = - Default Interface -
|
||||
@@ -323,7 +317,6 @@ WARNING: untranslated string: apcupsd = APC-UPS status
|
||||
WARNING: untranslated string: april = April
|
||||
WARNING: untranslated string: are you sure = Are you sure?
|
||||
WARNING: untranslated string: arp table entries = ARP Table Entries
|
||||
WARNING: untranslated string: artist = Artist
|
||||
WARNING: untranslated string: asn lookup failed = AS lookup failed
|
||||
WARNING: untranslated string: atm device = Device:
|
||||
WARNING: untranslated string: atm settings = ATM settings
|
||||
@@ -477,7 +470,6 @@ WARNING: untranslated string: check all = Check all
|
||||
WARNING: untranslated string: check vpn lr = Check
|
||||
WARNING: untranslated string: cipher = Encryption:
|
||||
WARNING: untranslated string: city = City
|
||||
WARNING: untranslated string: clear playlist = Empty playlist
|
||||
WARNING: untranslated string: clenabled = Provide time to local network
|
||||
WARNING: untranslated string: click to disable = Enabled (click to disable)
|
||||
WARNING: untranslated string: click to enable = Disabled (click to enable)
|
||||
@@ -535,7 +527,6 @@ WARNING: untranslated string: current dhcp leases on blue = Current DHCP leases
|
||||
WARNING: untranslated string: current dynamic leases = Current dynamic leases
|
||||
WARNING: untranslated string: current fixed leases = Current fixed leases
|
||||
WARNING: untranslated string: current hosts = Current hosts
|
||||
WARNING: untranslated string: current playlist = Current Playlist
|
||||
WARNING: untranslated string: current rules = Current rules:
|
||||
WARNING: untranslated string: daemon login script = Daemon login script
|
||||
WARNING: untranslated string: dangerous = Dangerous
|
||||
@@ -978,7 +969,6 @@ WARNING: untranslated string: generate iso = Generate ISO
|
||||
WARNING: untranslated string: generate ptr = Generate PTR
|
||||
WARNING: untranslated string: generate root/host certificates = Generate root/host certificates
|
||||
WARNING: untranslated string: generating the root and host certificates may take a long time. it can take up to several minutes on older hardware. please be patient = Generating the root and host certificates may take a long time. It can take up to several minutes on older hardware. Please be patient.
|
||||
WARNING: untranslated string: genre = Genre
|
||||
WARNING: untranslated string: global settings = Global Settings
|
||||
WARNING: untranslated string: graph = Graph
|
||||
WARNING: untranslated string: green = GREEN
|
||||
@@ -1338,13 +1328,6 @@ WARNING: untranslated string: month = Month
|
||||
WARNING: untranslated string: months = Months
|
||||
WARNING: untranslated string: most preferred = most preferred
|
||||
WARNING: untranslated string: mounted on = Mounted on
|
||||
WARNING: untranslated string: mpfire = Media Player for IPFire
|
||||
WARNING: untranslated string: mpfire controls = MPFire Control
|
||||
WARNING: untranslated string: mpfire playlist = MPFire Playlist
|
||||
WARNING: untranslated string: mpfire scanning = Scan for new files
|
||||
WARNING: untranslated string: mpfire search = MPFire Search
|
||||
WARNING: untranslated string: mpfire songs = MPFire songlist
|
||||
WARNING: untranslated string: mpfire webradio = MPFire Webradio
|
||||
WARNING: untranslated string: mtu = MTU
|
||||
WARNING: untranslated string: name = Name
|
||||
WARNING: untranslated string: name is invalid = Name is invalid
|
||||
@@ -1368,7 +1351,6 @@ WARNING: untranslated string: network traffic graphs others = Network (others)
|
||||
WARNING: untranslated string: never = Never
|
||||
WARNING: untranslated string: new optionsfw later = Some options need a reboot to take effect
|
||||
WARNING: untranslated string: newer = Newer
|
||||
WARNING: untranslated string: next = next
|
||||
WARNING: untranslated string: no = No
|
||||
WARNING: untranslated string: no data = unknown string
|
||||
WARNING: untranslated string: no dhcp lease = No DHCP lease has been acquired
|
||||
@@ -1505,7 +1487,6 @@ WARNING: untranslated string: percentage = Percentage
|
||||
WARNING: untranslated string: persistent = Persistent
|
||||
WARNING: untranslated string: pfs yes no = Perfect Forward Secrecy (PFS)
|
||||
WARNING: untranslated string: pkcs12 file password = PKCS12 File Password
|
||||
WARNING: untranslated string: play = Play
|
||||
WARNING: untranslated string: please reboot to apply your changes = Please reboot to apply your changes
|
||||
WARNING: untranslated string: policy = Policy
|
||||
WARNING: untranslated string: port = Port
|
||||
@@ -1517,7 +1498,6 @@ WARNING: untranslated string: pptp peer = Peer
|
||||
WARNING: untranslated string: pptp route = PPTP Route
|
||||
WARNING: untranslated string: pptp settings = Additional PPTP settings:
|
||||
WARNING: untranslated string: pre-shared key is too short = Pre-shared key is too short.
|
||||
WARNING: untranslated string: prev = previous
|
||||
WARNING: untranslated string: primary dns = Primary DNS:
|
||||
WARNING: untranslated string: primary ntp server = Primary NTP server
|
||||
WARNING: untranslated string: primary wins server address = Primary WINS server address
|
||||
@@ -1553,7 +1533,6 @@ WARNING: untranslated string: pulse dial = Pulse dial:
|
||||
WARNING: untranslated string: qos enter bandwidths = You will need to enter your downstream and upstream bandwidth!
|
||||
WARNING: untranslated string: qos graphs = Qos Graphs
|
||||
WARNING: untranslated string: qos warning = The rule <strong>must</strong> be saved, otherwise it will be discarded!
|
||||
WARNING: untranslated string: quick playlist = Quick Playlist
|
||||
WARNING: untranslated string: ram = RAM
|
||||
WARNING: untranslated string: rdns = rDNS
|
||||
WARNING: untranslated string: read bytes = Bytes Read
|
||||
@@ -1588,7 +1567,6 @@ WARNING: untranslated string: remote subnet is invalid = Remote subnet is invali
|
||||
WARNING: untranslated string: remove = Remove
|
||||
WARNING: untranslated string: remove ca certificate = Remove CA certificate
|
||||
WARNING: untranslated string: remove x509 = Remove x509
|
||||
WARNING: untranslated string: repeat = Repeat
|
||||
WARNING: untranslated string: request = Request
|
||||
WARNING: untranslated string: required = Required
|
||||
WARNING: untranslated string: required field = Required field
|
||||
@@ -1651,7 +1629,6 @@ WARNING: untranslated string: show host certificate = Show host certificate
|
||||
WARNING: untranslated string: show otp qrcode = Show OTP QRCode
|
||||
WARNING: untranslated string: show root certificate = Show root certificate
|
||||
WARNING: untranslated string: show tls-auth key = Show tls-auth key
|
||||
WARNING: untranslated string: shuffle = Shuffle
|
||||
WARNING: untranslated string: shutdown = Shutdown
|
||||
WARNING: untranslated string: shutdown control = Shutdown control
|
||||
WARNING: untranslated string: shutting down = Shutting down
|
||||
@@ -1747,9 +1724,7 @@ WARNING: untranslated string: time = Time
|
||||
WARNING: untranslated string: time server = Time Server
|
||||
WARNING: untranslated string: timeformat = %Y-%m-%d at %H:%M:%S %Z
|
||||
WARNING: untranslated string: timeout must be a number = Timeout must be a number.
|
||||
WARNING: untranslated string: title = Title
|
||||
WARNING: untranslated string: to = To
|
||||
WARNING: untranslated string: toggle = pause/resume
|
||||
WARNING: untranslated string: toggle enable disable = Enable or disable
|
||||
WARNING: untranslated string: token = Token:
|
||||
WARNING: untranslated string: token not set = No Token has been given.
|
||||
@@ -2119,10 +2094,6 @@ WARNING: untranslated string: version = Version
|
||||
WARNING: untranslated string: virtual address = Virtual Address
|
||||
WARNING: untranslated string: virtual private networking = Virtual Private Networking
|
||||
WARNING: untranslated string: visit us at = Visit us at
|
||||
WARNING: untranslated string: voldown10 = Decrease volume by 10
|
||||
WARNING: untranslated string: voldown5 = Decrease volume by 5
|
||||
WARNING: untranslated string: volup10 = Increase volume by 10
|
||||
WARNING: untranslated string: volup5 = Increase volume by 5
|
||||
WARNING: untranslated string: vpi number = VPI number:
|
||||
WARNING: untranslated string: vpn = VPN
|
||||
WARNING: untranslated string: vpn altname syntax = SubjectAltName is a comma separated list of email, dns, uri, rid and ip objects.<br />email:an email address. Syntax email:copy takes the email field from the cert to be used.<br />DNS:a valid domain name.<br />URI:any valid uri.<br />RID:registered object identifier.<br />IP:an IP address.<br />Note:charset is limited and case is significant.<br />Example:<br /><b>email:</b>ipfire@foo.org<b>,email:</b>copy<b>,DNS:</b>www.ipfire.org<b>,IP:</b>127.0.0.1<b>,URI:</b>http://url/to/something
|
||||
@@ -2157,7 +2128,6 @@ WARNING: untranslated string: was deleted = was deleted
|
||||
WARNING: untranslated string: web hits = Total number of websites matching selected criteria for
|
||||
WARNING: untranslated string: web proxy = Web Proxy
|
||||
WARNING: untranslated string: web server = Web Server
|
||||
WARNING: untranslated string: webradio playlist = Webradio Playlist
|
||||
WARNING: untranslated string: website = Website
|
||||
WARNING: untranslated string: wednesday = Wednesday
|
||||
WARNING: untranslated string: weeks = Weeks
|
||||
|
||||
@@ -26,14 +26,18 @@ WARNING: translation string unused: ConnSched scheduler
|
||||
WARNING: translation string unused: ConnSched select profile
|
||||
WARNING: translation string unused: Daily
|
||||
WARNING: translation string unused: Disabled
|
||||
WARNING: translation string unused: Existing Files
|
||||
WARNING: translation string unused: HDD temperature
|
||||
WARNING: translation string unused: Level7 rule
|
||||
WARNING: translation string unused: Local VPN IP
|
||||
WARNING: translation string unused: Pages
|
||||
WARNING: translation string unused: Ping
|
||||
WARNING: translation string unused: Queuelenght
|
||||
WARNING: translation string unused: Remote IP
|
||||
WARNING: translation string unused: Remote VPN IP
|
||||
WARNING: translation string unused: Resolv
|
||||
WARNING: translation string unused: Scan for Files
|
||||
WARNING: translation string unused: Scan from Directory
|
||||
WARNING: translation string unused: Subclass
|
||||
WARNING: translation string unused: TOS Bits
|
||||
WARNING: translation string unused: Utilization on
|
||||
@@ -112,6 +116,7 @@ WARNING: translation string unused: age seconds
|
||||
WARNING: translation string unused: age shour
|
||||
WARNING: translation string unused: age sminute
|
||||
WARNING: translation string unused: age ssecond
|
||||
WARNING: translation string unused: album
|
||||
WARNING: translation string unused: alcatelusb help
|
||||
WARNING: translation string unused: alcatelusb upload
|
||||
WARNING: translation string unused: all interfaces
|
||||
@@ -125,6 +130,7 @@ WARNING: translation string unused: and
|
||||
WARNING: translation string unused: ansi t1.483
|
||||
WARNING: translation string unused: apply
|
||||
WARNING: translation string unused: archive not exist
|
||||
WARNING: translation string unused: artist
|
||||
WARNING: translation string unused: attemps
|
||||
WARNING: translation string unused: avoid dod
|
||||
WARNING: translation string unused: backup archive
|
||||
@@ -177,6 +183,7 @@ WARNING: translation string unused: choose config
|
||||
WARNING: translation string unused: choose media
|
||||
WARNING: translation string unused: class in use
|
||||
WARNING: translation string unused: clear cache
|
||||
WARNING: translation string unused: clear playlist
|
||||
WARNING: translation string unused: client
|
||||
WARNING: translation string unused: comment
|
||||
WARNING: translation string unused: community rules
|
||||
@@ -200,6 +207,7 @@ WARNING: translation string unused: create new backup
|
||||
WARNING: translation string unused: cryptographic settings
|
||||
WARNING: translation string unused: current media
|
||||
WARNING: translation string unused: current ovpn
|
||||
WARNING: translation string unused: current playlist
|
||||
WARNING: translation string unused: current profile
|
||||
WARNING: translation string unused: custom networks
|
||||
WARNING: translation string unused: custom services
|
||||
@@ -414,6 +422,7 @@ WARNING: translation string unused: generatekeys
|
||||
WARNING: translation string unused: generatepolicy
|
||||
WARNING: translation string unused: generatereport
|
||||
WARNING: translation string unused: genkey
|
||||
WARNING: translation string unused: genre
|
||||
WARNING: translation string unused: gpl i accept these terms and conditions
|
||||
WARNING: translation string unused: gpl license agreement
|
||||
WARNING: translation string unused: gpl please read carefully the general public license and accept it below
|
||||
@@ -588,6 +597,7 @@ WARNING: translation string unused: network traffic graphs
|
||||
WARNING: translation string unused: network updated
|
||||
WARNING: translation string unused: networks settings
|
||||
WARNING: translation string unused: new optionsfw must boot
|
||||
WARNING: translation string unused: next
|
||||
WARNING: translation string unused: no alcatelusb firmware
|
||||
WARNING: translation string unused: no cfg upload
|
||||
WARNING: translation string unused: no eciadsl synch.bin file
|
||||
@@ -688,6 +698,7 @@ WARNING: translation string unused: pdc options
|
||||
WARNING: translation string unused: phase1 group
|
||||
WARNING: translation string unused: phonebook entry
|
||||
WARNING: translation string unused: ping disabled
|
||||
WARNING: translation string unused: play
|
||||
WARNING: translation string unused: polfile
|
||||
WARNING: translation string unused: port forwarding configuration
|
||||
WARNING: translation string unused: ports
|
||||
@@ -695,6 +706,7 @@ WARNING: translation string unused: pots
|
||||
WARNING: translation string unused: pppoe
|
||||
WARNING: translation string unused: prefered master
|
||||
WARNING: translation string unused: present
|
||||
WARNING: translation string unused: prev
|
||||
WARNING: translation string unused: printcap name
|
||||
WARNING: translation string unused: printer
|
||||
WARNING: translation string unused: printername
|
||||
@@ -709,6 +721,7 @@ WARNING: translation string unused: proxy port
|
||||
WARNING: translation string unused: psk
|
||||
WARNING: translation string unused: qos add subclass
|
||||
WARNING: translation string unused: quick control
|
||||
WARNING: translation string unused: quick playlist
|
||||
WARNING: translation string unused: random number generator daemon
|
||||
WARNING: translation string unused: read list
|
||||
WARNING: translation string unused: reboot ask
|
||||
@@ -720,6 +733,7 @@ WARNING: translation string unused: registered user rules
|
||||
WARNING: translation string unused: released
|
||||
WARNING: translation string unused: reload
|
||||
WARNING: translation string unused: removable device advice
|
||||
WARNING: translation string unused: repeat
|
||||
WARNING: translation string unused: reportfile
|
||||
WARNING: translation string unused: reportlevel
|
||||
WARNING: translation string unused: requested data
|
||||
@@ -765,6 +779,7 @@ WARNING: translation string unused: show areas
|
||||
WARNING: translation string unused: show last x lines
|
||||
WARNING: translation string unused: show lines
|
||||
WARNING: translation string unused: show share options
|
||||
WARNING: translation string unused: shuffle
|
||||
WARNING: translation string unused: shutdown ask
|
||||
WARNING: translation string unused: shutdown sure
|
||||
WARNING: translation string unused: shutdown2
|
||||
@@ -829,9 +844,11 @@ WARNING: translation string unused: this months volume
|
||||
WARNING: translation string unused: this update is already installed
|
||||
WARNING: translation string unused: this weeks volume
|
||||
WARNING: translation string unused: time date manually reset
|
||||
WARNING: translation string unused: title
|
||||
WARNING: translation string unused: to email adr
|
||||
WARNING: translation string unused: to install an update
|
||||
WARNING: translation string unused: to warn email bad
|
||||
WARNING: translation string unused: toggle
|
||||
WARNING: translation string unused: too long 80 char max
|
||||
WARNING: translation string unused: tor 0 = disabled
|
||||
WARNING: translation string unused: tor accounting period daily
|
||||
@@ -919,6 +936,10 @@ WARNING: translation string unused: use dov
|
||||
WARNING: translation string unused: use ibod
|
||||
WARNING: translation string unused: view log
|
||||
WARNING: translation string unused: visible in browselist
|
||||
WARNING: translation string unused: voldown10
|
||||
WARNING: translation string unused: voldown5
|
||||
WARNING: translation string unused: volup10
|
||||
WARNING: translation string unused: volup5
|
||||
WARNING: translation string unused: vpn aggrmode
|
||||
WARNING: translation string unused: vpn configuration main
|
||||
WARNING: translation string unused: vpn delayed start
|
||||
@@ -932,6 +953,7 @@ WARNING: translation string unused: vpn red name
|
||||
WARNING: translation string unused: vpn watch
|
||||
WARNING: translation string unused: warn when traffic reaches
|
||||
WARNING: translation string unused: web proxy configuration
|
||||
WARNING: translation string unused: webradio playlist
|
||||
WARNING: translation string unused: week
|
||||
WARNING: translation string unused: week-graph
|
||||
WARNING: translation string unused: weekly firewallhits
|
||||
@@ -977,7 +999,6 @@ WARNING: translation string unused: zoneconf val vlan tag range error
|
||||
WARNING: translation string unused: zoneconf val zoneslave amount error
|
||||
WARNING: untranslated string: Captive ACTIVATE = unknown string
|
||||
WARNING: untranslated string: Captive clients = unknown string
|
||||
WARNING: untranslated string: Scan for Songs = unknown string
|
||||
WARNING: untranslated string: access point name = Access Point Name
|
||||
WARNING: untranslated string: access point name is invalid = Access Point Name is invalid
|
||||
WARNING: untranslated string: access point name is required = Access Point Name is required
|
||||
|
||||
@@ -28,14 +28,19 @@ WARNING: translation string unused: ConnSched scheduler
|
||||
WARNING: translation string unused: ConnSched select profile
|
||||
WARNING: translation string unused: Daily
|
||||
WARNING: translation string unused: Disabled
|
||||
WARNING: translation string unused: Existing Files
|
||||
WARNING: translation string unused: HDD temperature
|
||||
WARNING: translation string unused: Level7 rule
|
||||
WARNING: translation string unused: Local VPN IP
|
||||
WARNING: translation string unused: Pages
|
||||
WARNING: translation string unused: Ping
|
||||
WARNING: translation string unused: Queuelenght
|
||||
WARNING: translation string unused: Remote IP
|
||||
WARNING: translation string unused: Remote VPN IP
|
||||
WARNING: translation string unused: Resolv
|
||||
WARNING: translation string unused: Scan for Files
|
||||
WARNING: translation string unused: Scan for Songs
|
||||
WARNING: translation string unused: Scan from Directory
|
||||
WARNING: translation string unused: Subclass
|
||||
WARNING: translation string unused: TOS Bits
|
||||
WARNING: translation string unused: Utilization on
|
||||
@@ -115,6 +120,7 @@ WARNING: translation string unused: age seconds
|
||||
WARNING: translation string unused: age shour
|
||||
WARNING: translation string unused: age sminute
|
||||
WARNING: translation string unused: age ssecond
|
||||
WARNING: translation string unused: album
|
||||
WARNING: translation string unused: alcatelusb help
|
||||
WARNING: translation string unused: alcatelusb upload
|
||||
WARNING: translation string unused: all interfaces
|
||||
@@ -127,6 +133,7 @@ WARNING: translation string unused: alt vpn
|
||||
WARNING: translation string unused: and
|
||||
WARNING: translation string unused: apply
|
||||
WARNING: translation string unused: archive not exist
|
||||
WARNING: translation string unused: artist
|
||||
WARNING: translation string unused: attemps
|
||||
WARNING: translation string unused: avoid dod
|
||||
WARNING: translation string unused: backup archive
|
||||
@@ -179,6 +186,7 @@ WARNING: translation string unused: choose config
|
||||
WARNING: translation string unused: choose media
|
||||
WARNING: translation string unused: class in use
|
||||
WARNING: translation string unused: clear cache
|
||||
WARNING: translation string unused: clear playlist
|
||||
WARNING: translation string unused: client
|
||||
WARNING: translation string unused: comment
|
||||
WARNING: translation string unused: community rules
|
||||
@@ -202,6 +210,7 @@ WARNING: translation string unused: create new backup
|
||||
WARNING: translation string unused: cryptographic settings
|
||||
WARNING: translation string unused: current media
|
||||
WARNING: translation string unused: current ovpn
|
||||
WARNING: translation string unused: current playlist
|
||||
WARNING: translation string unused: current profile
|
||||
WARNING: translation string unused: custom networks
|
||||
WARNING: translation string unused: custom services
|
||||
@@ -402,6 +411,7 @@ WARNING: translation string unused: generatekeys
|
||||
WARNING: translation string unused: generatepolicy
|
||||
WARNING: translation string unused: generatereport
|
||||
WARNING: translation string unused: genkey
|
||||
WARNING: translation string unused: genre
|
||||
WARNING: translation string unused: gpl i accept these terms and conditions
|
||||
WARNING: translation string unused: gpl license agreement
|
||||
WARNING: translation string unused: gpl please read carefully the general public license and accept it below
|
||||
@@ -568,6 +578,7 @@ WARNING: translation string unused: network traffic graphs
|
||||
WARNING: translation string unused: network updated
|
||||
WARNING: translation string unused: networks settings
|
||||
WARNING: translation string unused: new optionsfw must boot
|
||||
WARNING: translation string unused: next
|
||||
WARNING: translation string unused: no alcatelusb firmware
|
||||
WARNING: translation string unused: no cfg upload
|
||||
WARNING: translation string unused: no eciadsl synch.bin file
|
||||
@@ -662,6 +673,7 @@ WARNING: translation string unused: pdc options
|
||||
WARNING: translation string unused: phase1 group
|
||||
WARNING: translation string unused: phonebook entry
|
||||
WARNING: translation string unused: ping disabled
|
||||
WARNING: translation string unused: play
|
||||
WARNING: translation string unused: polfile
|
||||
WARNING: translation string unused: port forwarding configuration
|
||||
WARNING: translation string unused: ports
|
||||
@@ -669,6 +681,7 @@ WARNING: translation string unused: pots
|
||||
WARNING: translation string unused: pppoe
|
||||
WARNING: translation string unused: prefered master
|
||||
WARNING: translation string unused: present
|
||||
WARNING: translation string unused: prev
|
||||
WARNING: translation string unused: printcap name
|
||||
WARNING: translation string unused: printer
|
||||
WARNING: translation string unused: printername
|
||||
@@ -683,6 +696,7 @@ WARNING: translation string unused: proxy port
|
||||
WARNING: translation string unused: psk
|
||||
WARNING: translation string unused: qos add subclass
|
||||
WARNING: translation string unused: quick control
|
||||
WARNING: translation string unused: quick playlist
|
||||
WARNING: translation string unused: random number generator daemon
|
||||
WARNING: translation string unused: read list
|
||||
WARNING: translation string unused: reboot ask
|
||||
@@ -694,6 +708,7 @@ WARNING: translation string unused: registered user rules
|
||||
WARNING: translation string unused: released
|
||||
WARNING: translation string unused: reload
|
||||
WARNING: translation string unused: removable device advice
|
||||
WARNING: translation string unused: repeat
|
||||
WARNING: translation string unused: reportfile
|
||||
WARNING: translation string unused: reportlevel
|
||||
WARNING: translation string unused: requested data
|
||||
@@ -739,6 +754,7 @@ WARNING: translation string unused: show areas
|
||||
WARNING: translation string unused: show last x lines
|
||||
WARNING: translation string unused: show lines
|
||||
WARNING: translation string unused: show share options
|
||||
WARNING: translation string unused: shuffle
|
||||
WARNING: translation string unused: shutdown ask
|
||||
WARNING: translation string unused: shutdown sure
|
||||
WARNING: translation string unused: shutdown2
|
||||
@@ -801,9 +817,11 @@ WARNING: translation string unused: this months volume
|
||||
WARNING: translation string unused: this update is already installed
|
||||
WARNING: translation string unused: this weeks volume
|
||||
WARNING: translation string unused: time date manually reset
|
||||
WARNING: translation string unused: title
|
||||
WARNING: translation string unused: to email adr
|
||||
WARNING: translation string unused: to install an update
|
||||
WARNING: translation string unused: to warn email bad
|
||||
WARNING: translation string unused: toggle
|
||||
WARNING: translation string unused: too long 80 char max
|
||||
WARNING: translation string unused: tor 0 = disabled
|
||||
WARNING: translation string unused: tor accounting period daily
|
||||
@@ -889,6 +907,10 @@ WARNING: translation string unused: use dov
|
||||
WARNING: translation string unused: use ibod
|
||||
WARNING: translation string unused: view log
|
||||
WARNING: translation string unused: visible in browselist
|
||||
WARNING: translation string unused: voldown10
|
||||
WARNING: translation string unused: voldown5
|
||||
WARNING: translation string unused: volup10
|
||||
WARNING: translation string unused: volup5
|
||||
WARNING: translation string unused: vpn aggrmode
|
||||
WARNING: translation string unused: vpn configuration main
|
||||
WARNING: translation string unused: vpn delayed start
|
||||
@@ -902,6 +924,7 @@ WARNING: translation string unused: vpn red name
|
||||
WARNING: translation string unused: vpn watch
|
||||
WARNING: translation string unused: warn when traffic reaches
|
||||
WARNING: translation string unused: web proxy configuration
|
||||
WARNING: translation string unused: webradio playlist
|
||||
WARNING: translation string unused: week
|
||||
WARNING: translation string unused: week-graph
|
||||
WARNING: translation string unused: weekly firewallhits
|
||||
|
||||
@@ -2,14 +2,18 @@ WARNING: translation string unused: Async logging enabled
|
||||
WARNING: translation string unused: Client status and controlc
|
||||
WARNING: translation string unused: ConnSched scheduler
|
||||
WARNING: translation string unused: ConnSched select profile
|
||||
WARNING: translation string unused: Existing Files
|
||||
WARNING: translation string unused: HDD temperature
|
||||
WARNING: translation string unused: Level7 rule
|
||||
WARNING: translation string unused: Local VPN IP
|
||||
WARNING: translation string unused: Pages
|
||||
WARNING: translation string unused: Ping
|
||||
WARNING: translation string unused: Queuelenght
|
||||
WARNING: translation string unused: Remote IP
|
||||
WARNING: translation string unused: Remote VPN IP
|
||||
WARNING: translation string unused: Resolv
|
||||
WARNING: translation string unused: Scan for Files
|
||||
WARNING: translation string unused: Scan from Directory
|
||||
WARNING: translation string unused: Subclass
|
||||
WARNING: translation string unused: TOS Bits
|
||||
WARNING: translation string unused: Utilization on
|
||||
@@ -85,6 +89,7 @@ WARNING: translation string unused: age seconds
|
||||
WARNING: translation string unused: age shour
|
||||
WARNING: translation string unused: age sminute
|
||||
WARNING: translation string unused: age ssecond
|
||||
WARNING: translation string unused: album
|
||||
WARNING: translation string unused: alcatelusb help
|
||||
WARNING: translation string unused: alcatelusb upload
|
||||
WARNING: translation string unused: all interfaces
|
||||
@@ -98,6 +103,7 @@ WARNING: translation string unused: and
|
||||
WARNING: translation string unused: ansi t1.483
|
||||
WARNING: translation string unused: apply
|
||||
WARNING: translation string unused: archive not exist
|
||||
WARNING: translation string unused: artist
|
||||
WARNING: translation string unused: attemps
|
||||
WARNING: translation string unused: avoid dod
|
||||
WARNING: translation string unused: backup archive
|
||||
@@ -150,6 +156,7 @@ WARNING: translation string unused: choose config
|
||||
WARNING: translation string unused: choose media
|
||||
WARNING: translation string unused: class in use
|
||||
WARNING: translation string unused: clear cache
|
||||
WARNING: translation string unused: clear playlist
|
||||
WARNING: translation string unused: client
|
||||
WARNING: translation string unused: comment
|
||||
WARNING: translation string unused: community rules
|
||||
@@ -172,6 +179,7 @@ WARNING: translation string unused: create mask
|
||||
WARNING: translation string unused: create new backup
|
||||
WARNING: translation string unused: current media
|
||||
WARNING: translation string unused: current ovpn
|
||||
WARNING: translation string unused: current playlist
|
||||
WARNING: translation string unused: current profile
|
||||
WARNING: translation string unused: custom networks
|
||||
WARNING: translation string unused: custom services
|
||||
@@ -368,6 +376,7 @@ WARNING: translation string unused: generatekeys
|
||||
WARNING: translation string unused: generatepolicy
|
||||
WARNING: translation string unused: generatereport
|
||||
WARNING: translation string unused: genkey
|
||||
WARNING: translation string unused: genre
|
||||
WARNING: translation string unused: gpl i accept these terms and conditions
|
||||
WARNING: translation string unused: gpl license agreement
|
||||
WARNING: translation string unused: gpl please read carefully the general public license and accept it below
|
||||
@@ -524,6 +533,7 @@ WARNING: translation string unused: network traffic graphs
|
||||
WARNING: translation string unused: network updated
|
||||
WARNING: translation string unused: networks settings
|
||||
WARNING: translation string unused: new optionsfw must boot
|
||||
WARNING: translation string unused: next
|
||||
WARNING: translation string unused: no alcatelusb firmware
|
||||
WARNING: translation string unused: no cfg upload
|
||||
WARNING: translation string unused: no eciadsl synch.bin file
|
||||
@@ -616,6 +626,7 @@ WARNING: translation string unused: pdc options
|
||||
WARNING: translation string unused: phase1 group
|
||||
WARNING: translation string unused: phonebook entry
|
||||
WARNING: translation string unused: ping disabled
|
||||
WARNING: translation string unused: play
|
||||
WARNING: translation string unused: polfile
|
||||
WARNING: translation string unused: port forwarding configuration
|
||||
WARNING: translation string unused: ports
|
||||
@@ -623,6 +634,7 @@ WARNING: translation string unused: pots
|
||||
WARNING: translation string unused: pppoe
|
||||
WARNING: translation string unused: prefered master
|
||||
WARNING: translation string unused: present
|
||||
WARNING: translation string unused: prev
|
||||
WARNING: translation string unused: printcap name
|
||||
WARNING: translation string unused: printer
|
||||
WARNING: translation string unused: printername
|
||||
@@ -637,6 +649,7 @@ WARNING: translation string unused: proxy port
|
||||
WARNING: translation string unused: psk
|
||||
WARNING: translation string unused: qos add subclass
|
||||
WARNING: translation string unused: quick control
|
||||
WARNING: translation string unused: quick playlist
|
||||
WARNING: translation string unused: read list
|
||||
WARNING: translation string unused: reboot ask
|
||||
WARNING: translation string unused: reboot question
|
||||
@@ -647,6 +660,7 @@ WARNING: translation string unused: registered user rules
|
||||
WARNING: translation string unused: released
|
||||
WARNING: translation string unused: reload
|
||||
WARNING: translation string unused: removable device advice
|
||||
WARNING: translation string unused: repeat
|
||||
WARNING: translation string unused: reportfile
|
||||
WARNING: translation string unused: reportlevel
|
||||
WARNING: translation string unused: requested data
|
||||
@@ -691,6 +705,7 @@ WARNING: translation string unused: show areas
|
||||
WARNING: translation string unused: show last x lines
|
||||
WARNING: translation string unused: show lines
|
||||
WARNING: translation string unused: show share options
|
||||
WARNING: translation string unused: shuffle
|
||||
WARNING: translation string unused: shutdown ask
|
||||
WARNING: translation string unused: shutdown sure
|
||||
WARNING: translation string unused: shutdown2
|
||||
@@ -755,9 +770,11 @@ WARNING: translation string unused: this months volume
|
||||
WARNING: translation string unused: this update is already installed
|
||||
WARNING: translation string unused: this weeks volume
|
||||
WARNING: translation string unused: time date manually reset
|
||||
WARNING: translation string unused: title
|
||||
WARNING: translation string unused: to email adr
|
||||
WARNING: translation string unused: to install an update
|
||||
WARNING: translation string unused: to warn email bad
|
||||
WARNING: translation string unused: toggle
|
||||
WARNING: translation string unused: too long 80 char max
|
||||
WARNING: translation string unused: tor 0 = disabled
|
||||
WARNING: translation string unused: tor accounting period daily
|
||||
@@ -842,6 +859,10 @@ WARNING: translation string unused: use dov
|
||||
WARNING: translation string unused: use ibod
|
||||
WARNING: translation string unused: view log
|
||||
WARNING: translation string unused: visible in browselist
|
||||
WARNING: translation string unused: voldown10
|
||||
WARNING: translation string unused: voldown5
|
||||
WARNING: translation string unused: volup10
|
||||
WARNING: translation string unused: volup5
|
||||
WARNING: translation string unused: vpn aggrmode
|
||||
WARNING: translation string unused: vpn configuration main
|
||||
WARNING: translation string unused: vpn delayed start
|
||||
@@ -855,6 +876,7 @@ WARNING: translation string unused: vpn red name
|
||||
WARNING: translation string unused: vpn watch
|
||||
WARNING: translation string unused: warn when traffic reaches
|
||||
WARNING: translation string unused: web proxy configuration
|
||||
WARNING: translation string unused: webradio playlist
|
||||
WARNING: translation string unused: week
|
||||
WARNING: translation string unused: week-graph
|
||||
WARNING: translation string unused: weekly firewallhits
|
||||
@@ -917,7 +939,6 @@ WARNING: untranslated string: Captive vouchervalid = Allowed time for this coupo
|
||||
WARNING: untranslated string: Captive wrong ext = Uploaded file has wrong filetype
|
||||
WARNING: untranslated string: MTU settings = MTU settings:
|
||||
WARNING: untranslated string: Number of Countries for the pie chart = Number of Countries for the pie chart
|
||||
WARNING: untranslated string: Scan for Songs = unknown string
|
||||
WARNING: untranslated string: access point name = Access Point Name
|
||||
WARNING: untranslated string: access point name is invalid = Access Point Name is invalid
|
||||
WARNING: untranslated string: access point name is required = Access Point Name is required
|
||||
|
||||
@@ -2,14 +2,18 @@ WARNING: translation string unused: Async logging enabled
|
||||
WARNING: translation string unused: Client status and controlc
|
||||
WARNING: translation string unused: ConnSched scheduler
|
||||
WARNING: translation string unused: ConnSched select profile
|
||||
WARNING: translation string unused: Existing Files
|
||||
WARNING: translation string unused: HDD temperature
|
||||
WARNING: translation string unused: Level7 rule
|
||||
WARNING: translation string unused: Local VPN IP
|
||||
WARNING: translation string unused: Pages
|
||||
WARNING: translation string unused: Ping
|
||||
WARNING: translation string unused: Queuelenght
|
||||
WARNING: translation string unused: Remote IP
|
||||
WARNING: translation string unused: Remote VPN IP
|
||||
WARNING: translation string unused: Resolv
|
||||
WARNING: translation string unused: Scan for Files
|
||||
WARNING: translation string unused: Scan from Directory
|
||||
WARNING: translation string unused: Subclass
|
||||
WARNING: translation string unused: TOS Bits
|
||||
WARNING: translation string unused: Utilization on
|
||||
@@ -85,6 +89,7 @@ WARNING: translation string unused: age seconds
|
||||
WARNING: translation string unused: age shour
|
||||
WARNING: translation string unused: age sminute
|
||||
WARNING: translation string unused: age ssecond
|
||||
WARNING: translation string unused: album
|
||||
WARNING: translation string unused: alcatelusb help
|
||||
WARNING: translation string unused: alcatelusb upload
|
||||
WARNING: translation string unused: all interfaces
|
||||
@@ -98,6 +103,7 @@ WARNING: translation string unused: and
|
||||
WARNING: translation string unused: ansi t1.483
|
||||
WARNING: translation string unused: apply
|
||||
WARNING: translation string unused: archive not exist
|
||||
WARNING: translation string unused: artist
|
||||
WARNING: translation string unused: attemps
|
||||
WARNING: translation string unused: avoid dod
|
||||
WARNING: translation string unused: backup archive
|
||||
@@ -150,6 +156,7 @@ WARNING: translation string unused: choose config
|
||||
WARNING: translation string unused: choose media
|
||||
WARNING: translation string unused: class in use
|
||||
WARNING: translation string unused: clear cache
|
||||
WARNING: translation string unused: clear playlist
|
||||
WARNING: translation string unused: client
|
||||
WARNING: translation string unused: comment
|
||||
WARNING: translation string unused: community rules
|
||||
@@ -172,6 +179,7 @@ WARNING: translation string unused: create mask
|
||||
WARNING: translation string unused: create new backup
|
||||
WARNING: translation string unused: current media
|
||||
WARNING: translation string unused: current ovpn
|
||||
WARNING: translation string unused: current playlist
|
||||
WARNING: translation string unused: current profile
|
||||
WARNING: translation string unused: custom networks
|
||||
WARNING: translation string unused: custom services
|
||||
@@ -369,6 +377,7 @@ WARNING: translation string unused: generatekeys
|
||||
WARNING: translation string unused: generatepolicy
|
||||
WARNING: translation string unused: generatereport
|
||||
WARNING: translation string unused: genkey
|
||||
WARNING: translation string unused: genre
|
||||
WARNING: translation string unused: gpl i accept these terms and conditions
|
||||
WARNING: translation string unused: gpl license agreement
|
||||
WARNING: translation string unused: gpl please read carefully the general public license and accept it below
|
||||
@@ -526,6 +535,7 @@ WARNING: translation string unused: network traffic graphs
|
||||
WARNING: translation string unused: network updated
|
||||
WARNING: translation string unused: networks settings
|
||||
WARNING: translation string unused: new optionsfw must boot
|
||||
WARNING: translation string unused: next
|
||||
WARNING: translation string unused: no alcatelusb firmware
|
||||
WARNING: translation string unused: no cfg upload
|
||||
WARNING: translation string unused: no eciadsl synch.bin file
|
||||
@@ -616,6 +626,7 @@ WARNING: translation string unused: pdc options
|
||||
WARNING: translation string unused: phase1 group
|
||||
WARNING: translation string unused: phonebook entry
|
||||
WARNING: translation string unused: ping disabled
|
||||
WARNING: translation string unused: play
|
||||
WARNING: translation string unused: polfile
|
||||
WARNING: translation string unused: port forwarding configuration
|
||||
WARNING: translation string unused: ports
|
||||
@@ -623,6 +634,7 @@ WARNING: translation string unused: pots
|
||||
WARNING: translation string unused: pppoe
|
||||
WARNING: translation string unused: prefered master
|
||||
WARNING: translation string unused: present
|
||||
WARNING: translation string unused: prev
|
||||
WARNING: translation string unused: printcap name
|
||||
WARNING: translation string unused: printer
|
||||
WARNING: translation string unused: printername
|
||||
@@ -637,6 +649,7 @@ WARNING: translation string unused: proxy port
|
||||
WARNING: translation string unused: psk
|
||||
WARNING: translation string unused: qos add subclass
|
||||
WARNING: translation string unused: quick control
|
||||
WARNING: translation string unused: quick playlist
|
||||
WARNING: translation string unused: read list
|
||||
WARNING: translation string unused: reboot ask
|
||||
WARNING: translation string unused: reboot question
|
||||
@@ -647,6 +660,7 @@ WARNING: translation string unused: registered user rules
|
||||
WARNING: translation string unused: released
|
||||
WARNING: translation string unused: reload
|
||||
WARNING: translation string unused: removable device advice
|
||||
WARNING: translation string unused: repeat
|
||||
WARNING: translation string unused: reportfile
|
||||
WARNING: translation string unused: reportlevel
|
||||
WARNING: translation string unused: requested data
|
||||
@@ -691,6 +705,7 @@ WARNING: translation string unused: show areas
|
||||
WARNING: translation string unused: show last x lines
|
||||
WARNING: translation string unused: show lines
|
||||
WARNING: translation string unused: show share options
|
||||
WARNING: translation string unused: shuffle
|
||||
WARNING: translation string unused: shutdown ask
|
||||
WARNING: translation string unused: shutdown sure
|
||||
WARNING: translation string unused: shutdown2
|
||||
@@ -756,9 +771,11 @@ WARNING: translation string unused: this months volume
|
||||
WARNING: translation string unused: this update is already installed
|
||||
WARNING: translation string unused: this weeks volume
|
||||
WARNING: translation string unused: time date manually reset
|
||||
WARNING: translation string unused: title
|
||||
WARNING: translation string unused: to email adr
|
||||
WARNING: translation string unused: to install an update
|
||||
WARNING: translation string unused: to warn email bad
|
||||
WARNING: translation string unused: toggle
|
||||
WARNING: translation string unused: too long 80 char max
|
||||
WARNING: translation string unused: tor 0 = disabled
|
||||
WARNING: translation string unused: tor accounting period daily
|
||||
@@ -843,6 +860,10 @@ WARNING: translation string unused: use dov
|
||||
WARNING: translation string unused: use ibod
|
||||
WARNING: translation string unused: view log
|
||||
WARNING: translation string unused: visible in browselist
|
||||
WARNING: translation string unused: voldown10
|
||||
WARNING: translation string unused: voldown5
|
||||
WARNING: translation string unused: volup10
|
||||
WARNING: translation string unused: volup5
|
||||
WARNING: translation string unused: vpn aggrmode
|
||||
WARNING: translation string unused: vpn configuration main
|
||||
WARNING: translation string unused: vpn delayed start
|
||||
@@ -856,6 +877,7 @@ WARNING: translation string unused: vpn red name
|
||||
WARNING: translation string unused: vpn watch
|
||||
WARNING: translation string unused: warn when traffic reaches
|
||||
WARNING: translation string unused: web proxy configuration
|
||||
WARNING: translation string unused: webradio playlist
|
||||
WARNING: translation string unused: week
|
||||
WARNING: translation string unused: week-graph
|
||||
WARNING: translation string unused: weekly firewallhits
|
||||
@@ -918,7 +940,6 @@ WARNING: untranslated string: Captive vouchervalid = Allowed time for this coupo
|
||||
WARNING: untranslated string: Captive wrong ext = Uploaded file has wrong filetype
|
||||
WARNING: untranslated string: MTU settings = MTU settings:
|
||||
WARNING: untranslated string: Number of Countries for the pie chart = Number of Countries for the pie chart
|
||||
WARNING: untranslated string: Scan for Songs = unknown string
|
||||
WARNING: untranslated string: access point name = Access Point Name
|
||||
WARNING: untranslated string: access point name is invalid = Access Point Name is invalid
|
||||
WARNING: untranslated string: access point name is required = Access Point Name is required
|
||||
|
||||
@@ -2,14 +2,18 @@ WARNING: translation string unused: Async logging enabled
|
||||
WARNING: translation string unused: Client status and controlc
|
||||
WARNING: translation string unused: ConnSched scheduler
|
||||
WARNING: translation string unused: ConnSched select profile
|
||||
WARNING: translation string unused: Existing Files
|
||||
WARNING: translation string unused: HDD temperature
|
||||
WARNING: translation string unused: Level7 rule
|
||||
WARNING: translation string unused: Local VPN IP
|
||||
WARNING: translation string unused: Pages
|
||||
WARNING: translation string unused: Ping
|
||||
WARNING: translation string unused: Queuelenght
|
||||
WARNING: translation string unused: Remote IP
|
||||
WARNING: translation string unused: Remote VPN IP
|
||||
WARNING: translation string unused: Resolv
|
||||
WARNING: translation string unused: Scan for Files
|
||||
WARNING: translation string unused: Scan from Directory
|
||||
WARNING: translation string unused: Subclass
|
||||
WARNING: translation string unused: TOS Bits
|
||||
WARNING: translation string unused: Utilization on
|
||||
@@ -80,6 +84,7 @@ WARNING: translation string unused: advproxy update information
|
||||
WARNING: translation string unused: advproxy update notification
|
||||
WARNING: translation string unused: advproxy web browser
|
||||
WARNING: translation string unused: again
|
||||
WARNING: translation string unused: album
|
||||
WARNING: translation string unused: alcatelusb help
|
||||
WARNING: translation string unused: alcatelusb upload
|
||||
WARNING: translation string unused: all interfaces
|
||||
@@ -93,6 +98,7 @@ WARNING: translation string unused: and
|
||||
WARNING: translation string unused: ansi t1.483
|
||||
WARNING: translation string unused: apply
|
||||
WARNING: translation string unused: archive not exist
|
||||
WARNING: translation string unused: artist
|
||||
WARNING: translation string unused: attemps
|
||||
WARNING: translation string unused: avoid dod
|
||||
WARNING: translation string unused: backup archive
|
||||
@@ -143,6 +149,7 @@ WARNING: translation string unused: choose config
|
||||
WARNING: translation string unused: choose media
|
||||
WARNING: translation string unused: class in use
|
||||
WARNING: translation string unused: clear cache
|
||||
WARNING: translation string unused: clear playlist
|
||||
WARNING: translation string unused: client
|
||||
WARNING: translation string unused: comment
|
||||
WARNING: translation string unused: compression
|
||||
@@ -164,6 +171,7 @@ WARNING: translation string unused: create mask
|
||||
WARNING: translation string unused: create new backup
|
||||
WARNING: translation string unused: current media
|
||||
WARNING: translation string unused: current ovpn
|
||||
WARNING: translation string unused: current playlist
|
||||
WARNING: translation string unused: current profile
|
||||
WARNING: translation string unused: custom networks
|
||||
WARNING: translation string unused: custom services
|
||||
@@ -309,6 +317,7 @@ WARNING: translation string unused: generatekeys
|
||||
WARNING: translation string unused: generatepolicy
|
||||
WARNING: translation string unused: generatereport
|
||||
WARNING: translation string unused: genkey
|
||||
WARNING: translation string unused: genre
|
||||
WARNING: translation string unused: gpl i accept these terms and conditions
|
||||
WARNING: translation string unused: gpl license agreement
|
||||
WARNING: translation string unused: gpl please read carefully the general public license and accept it below
|
||||
@@ -463,6 +472,7 @@ WARNING: translation string unused: network traffic graphs
|
||||
WARNING: translation string unused: network updated
|
||||
WARNING: translation string unused: networks settings
|
||||
WARNING: translation string unused: new optionsfw must boot
|
||||
WARNING: translation string unused: next
|
||||
WARNING: translation string unused: no alcatelusb firmware
|
||||
WARNING: translation string unused: no cfg upload
|
||||
WARNING: translation string unused: no eciadsl synch.bin file
|
||||
@@ -541,6 +551,7 @@ WARNING: translation string unused: pdc options
|
||||
WARNING: translation string unused: phase1 group
|
||||
WARNING: translation string unused: phonebook entry
|
||||
WARNING: translation string unused: ping disabled
|
||||
WARNING: translation string unused: play
|
||||
WARNING: translation string unused: polfile
|
||||
WARNING: translation string unused: port forwarding configuration
|
||||
WARNING: translation string unused: ports
|
||||
@@ -548,6 +559,7 @@ WARNING: translation string unused: pots
|
||||
WARNING: translation string unused: pppoe
|
||||
WARNING: translation string unused: prefered master
|
||||
WARNING: translation string unused: present
|
||||
WARNING: translation string unused: prev
|
||||
WARNING: translation string unused: printcap name
|
||||
WARNING: translation string unused: printer
|
||||
WARNING: translation string unused: printername
|
||||
@@ -562,6 +574,7 @@ WARNING: translation string unused: proxy port
|
||||
WARNING: translation string unused: psk
|
||||
WARNING: translation string unused: qos add subclass
|
||||
WARNING: translation string unused: quick control
|
||||
WARNING: translation string unused: quick playlist
|
||||
WARNING: translation string unused: read list
|
||||
WARNING: translation string unused: reboot ask
|
||||
WARNING: translation string unused: reboot question
|
||||
@@ -572,6 +585,7 @@ WARNING: translation string unused: registered user rules
|
||||
WARNING: translation string unused: released
|
||||
WARNING: translation string unused: reload
|
||||
WARNING: translation string unused: removable device advice
|
||||
WARNING: translation string unused: repeat
|
||||
WARNING: translation string unused: reportfile
|
||||
WARNING: translation string unused: reportlevel
|
||||
WARNING: translation string unused: requested data
|
||||
@@ -616,6 +630,7 @@ WARNING: translation string unused: show areas
|
||||
WARNING: translation string unused: show last x lines
|
||||
WARNING: translation string unused: show lines
|
||||
WARNING: translation string unused: show share options
|
||||
WARNING: translation string unused: shuffle
|
||||
WARNING: translation string unused: shutdown ask
|
||||
WARNING: translation string unused: shutdown sure
|
||||
WARNING: translation string unused: shutdown2
|
||||
@@ -679,9 +694,11 @@ WARNING: translation string unused: this months volume
|
||||
WARNING: translation string unused: this update is already installed
|
||||
WARNING: translation string unused: this weeks volume
|
||||
WARNING: translation string unused: time date manually reset
|
||||
WARNING: translation string unused: title
|
||||
WARNING: translation string unused: to email adr
|
||||
WARNING: translation string unused: to install an update
|
||||
WARNING: translation string unused: to warn email bad
|
||||
WARNING: translation string unused: toggle
|
||||
WARNING: translation string unused: too long 80 char max
|
||||
WARNING: translation string unused: traffic back
|
||||
WARNING: translation string unused: traffic calc time
|
||||
@@ -754,6 +771,10 @@ WARNING: translation string unused: use dov
|
||||
WARNING: translation string unused: use ibod
|
||||
WARNING: translation string unused: view log
|
||||
WARNING: translation string unused: visible in browselist
|
||||
WARNING: translation string unused: voldown10
|
||||
WARNING: translation string unused: voldown5
|
||||
WARNING: translation string unused: volup10
|
||||
WARNING: translation string unused: volup5
|
||||
WARNING: translation string unused: vpn aggrmode
|
||||
WARNING: translation string unused: vpn configuration main
|
||||
WARNING: translation string unused: vpn delayed start
|
||||
@@ -767,6 +788,7 @@ WARNING: translation string unused: vpn red name
|
||||
WARNING: translation string unused: vpn watch
|
||||
WARNING: translation string unused: warn when traffic reaches
|
||||
WARNING: translation string unused: web proxy configuration
|
||||
WARNING: translation string unused: webradio playlist
|
||||
WARNING: translation string unused: week
|
||||
WARNING: translation string unused: week-graph
|
||||
WARNING: translation string unused: weekly firewallhits
|
||||
@@ -834,7 +856,6 @@ WARNING: untranslated string: MB read = MB read
|
||||
WARNING: untranslated string: MB written = MB written
|
||||
WARNING: untranslated string: MTU settings = MTU settings:
|
||||
WARNING: untranslated string: Number of Countries for the pie chart = Number of Countries for the pie chart
|
||||
WARNING: untranslated string: Scan for Songs = unknown string
|
||||
WARNING: untranslated string: access point name = Access Point Name
|
||||
WARNING: untranslated string: access point name is invalid = Access Point Name is invalid
|
||||
WARNING: untranslated string: access point name is required = Access Point Name is required
|
||||
|
||||
@@ -2,14 +2,18 @@ WARNING: translation string unused: Async logging enabled
|
||||
WARNING: translation string unused: Client status and controlc
|
||||
WARNING: translation string unused: ConnSched scheduler
|
||||
WARNING: translation string unused: ConnSched select profile
|
||||
WARNING: translation string unused: Existing Files
|
||||
WARNING: translation string unused: HDD temperature
|
||||
WARNING: translation string unused: Level7 rule
|
||||
WARNING: translation string unused: Local VPN IP
|
||||
WARNING: translation string unused: Pages
|
||||
WARNING: translation string unused: Ping
|
||||
WARNING: translation string unused: Queuelenght
|
||||
WARNING: translation string unused: Remote IP
|
||||
WARNING: translation string unused: Remote VPN IP
|
||||
WARNING: translation string unused: Resolv
|
||||
WARNING: translation string unused: Scan for Files
|
||||
WARNING: translation string unused: Scan from Directory
|
||||
WARNING: translation string unused: Subclass
|
||||
WARNING: translation string unused: TOS Bits
|
||||
WARNING: translation string unused: Utilization on
|
||||
@@ -80,6 +84,7 @@ WARNING: translation string unused: advproxy update information
|
||||
WARNING: translation string unused: advproxy update notification
|
||||
WARNING: translation string unused: advproxy web browser
|
||||
WARNING: translation string unused: again
|
||||
WARNING: translation string unused: album
|
||||
WARNING: translation string unused: alcatelusb help
|
||||
WARNING: translation string unused: alcatelusb upload
|
||||
WARNING: translation string unused: all interfaces
|
||||
@@ -93,6 +98,7 @@ WARNING: translation string unused: and
|
||||
WARNING: translation string unused: ansi t1.483
|
||||
WARNING: translation string unused: apply
|
||||
WARNING: translation string unused: archive not exist
|
||||
WARNING: translation string unused: artist
|
||||
WARNING: translation string unused: attemps
|
||||
WARNING: translation string unused: avoid dod
|
||||
WARNING: translation string unused: backup archive
|
||||
@@ -143,6 +149,7 @@ WARNING: translation string unused: choose config
|
||||
WARNING: translation string unused: choose media
|
||||
WARNING: translation string unused: class in use
|
||||
WARNING: translation string unused: clear cache
|
||||
WARNING: translation string unused: clear playlist
|
||||
WARNING: translation string unused: client
|
||||
WARNING: translation string unused: comment
|
||||
WARNING: translation string unused: compression
|
||||
@@ -164,6 +171,7 @@ WARNING: translation string unused: create mask
|
||||
WARNING: translation string unused: create new backup
|
||||
WARNING: translation string unused: current media
|
||||
WARNING: translation string unused: current ovpn
|
||||
WARNING: translation string unused: current playlist
|
||||
WARNING: translation string unused: current profile
|
||||
WARNING: translation string unused: custom networks
|
||||
WARNING: translation string unused: custom services
|
||||
@@ -306,6 +314,7 @@ WARNING: translation string unused: generatekeys
|
||||
WARNING: translation string unused: generatepolicy
|
||||
WARNING: translation string unused: generatereport
|
||||
WARNING: translation string unused: genkey
|
||||
WARNING: translation string unused: genre
|
||||
WARNING: translation string unused: gpl i accept these terms and conditions
|
||||
WARNING: translation string unused: gpl license agreement
|
||||
WARNING: translation string unused: gpl please read carefully the general public license and accept it below
|
||||
@@ -458,6 +467,7 @@ WARNING: translation string unused: network traffic graphs
|
||||
WARNING: translation string unused: network updated
|
||||
WARNING: translation string unused: networks settings
|
||||
WARNING: translation string unused: new optionsfw must boot
|
||||
WARNING: translation string unused: next
|
||||
WARNING: translation string unused: no alcatelusb firmware
|
||||
WARNING: translation string unused: no cfg upload
|
||||
WARNING: translation string unused: no eciadsl synch.bin file
|
||||
@@ -536,6 +546,7 @@ WARNING: translation string unused: pdc options
|
||||
WARNING: translation string unused: phase1 group
|
||||
WARNING: translation string unused: phonebook entry
|
||||
WARNING: translation string unused: ping disabled
|
||||
WARNING: translation string unused: play
|
||||
WARNING: translation string unused: polfile
|
||||
WARNING: translation string unused: port forwarding configuration
|
||||
WARNING: translation string unused: ports
|
||||
@@ -543,6 +554,7 @@ WARNING: translation string unused: pots
|
||||
WARNING: translation string unused: pppoe
|
||||
WARNING: translation string unused: prefered master
|
||||
WARNING: translation string unused: present
|
||||
WARNING: translation string unused: prev
|
||||
WARNING: translation string unused: printcap name
|
||||
WARNING: translation string unused: printer
|
||||
WARNING: translation string unused: printername
|
||||
@@ -557,6 +569,7 @@ WARNING: translation string unused: proxy port
|
||||
WARNING: translation string unused: psk
|
||||
WARNING: translation string unused: qos add subclass
|
||||
WARNING: translation string unused: quick control
|
||||
WARNING: translation string unused: quick playlist
|
||||
WARNING: translation string unused: read list
|
||||
WARNING: translation string unused: reboot ask
|
||||
WARNING: translation string unused: reboot question
|
||||
@@ -567,6 +580,7 @@ WARNING: translation string unused: registered user rules
|
||||
WARNING: translation string unused: released
|
||||
WARNING: translation string unused: reload
|
||||
WARNING: translation string unused: removable device advice
|
||||
WARNING: translation string unused: repeat
|
||||
WARNING: translation string unused: reportfile
|
||||
WARNING: translation string unused: reportlevel
|
||||
WARNING: translation string unused: requested data
|
||||
@@ -611,6 +625,7 @@ WARNING: translation string unused: show areas
|
||||
WARNING: translation string unused: show last x lines
|
||||
WARNING: translation string unused: show lines
|
||||
WARNING: translation string unused: show share options
|
||||
WARNING: translation string unused: shuffle
|
||||
WARNING: translation string unused: shutdown ask
|
||||
WARNING: translation string unused: shutdown sure
|
||||
WARNING: translation string unused: shutdown2
|
||||
@@ -674,9 +689,11 @@ WARNING: translation string unused: this months volume
|
||||
WARNING: translation string unused: this update is already installed
|
||||
WARNING: translation string unused: this weeks volume
|
||||
WARNING: translation string unused: time date manually reset
|
||||
WARNING: translation string unused: title
|
||||
WARNING: translation string unused: to email adr
|
||||
WARNING: translation string unused: to install an update
|
||||
WARNING: translation string unused: to warn email bad
|
||||
WARNING: translation string unused: toggle
|
||||
WARNING: translation string unused: too long 80 char max
|
||||
WARNING: translation string unused: traffic back
|
||||
WARNING: translation string unused: traffic calc time
|
||||
@@ -749,6 +766,10 @@ WARNING: translation string unused: use dov
|
||||
WARNING: translation string unused: use ibod
|
||||
WARNING: translation string unused: view log
|
||||
WARNING: translation string unused: visible in browselist
|
||||
WARNING: translation string unused: voldown10
|
||||
WARNING: translation string unused: voldown5
|
||||
WARNING: translation string unused: volup10
|
||||
WARNING: translation string unused: volup5
|
||||
WARNING: translation string unused: vpn aggrmode
|
||||
WARNING: translation string unused: vpn configuration main
|
||||
WARNING: translation string unused: vpn delayed start
|
||||
@@ -762,6 +783,7 @@ WARNING: translation string unused: vpn red name
|
||||
WARNING: translation string unused: vpn watch
|
||||
WARNING: translation string unused: warn when traffic reaches
|
||||
WARNING: translation string unused: web proxy configuration
|
||||
WARNING: translation string unused: webradio playlist
|
||||
WARNING: translation string unused: week
|
||||
WARNING: translation string unused: weekly firewallhits
|
||||
WARNING: translation string unused: wildcards
|
||||
@@ -829,7 +851,6 @@ WARNING: untranslated string: MB read = MB read
|
||||
WARNING: untranslated string: MB written = MB written
|
||||
WARNING: untranslated string: MTU settings = MTU settings:
|
||||
WARNING: untranslated string: Number of Countries for the pie chart = Number of Countries for the pie chart
|
||||
WARNING: untranslated string: Scan for Songs = unknown string
|
||||
WARNING: untranslated string: access point name = Access Point Name
|
||||
WARNING: untranslated string: access point name is invalid = Access Point Name is invalid
|
||||
WARNING: untranslated string: access point name is required = Access Point Name is required
|
||||
|
||||
@@ -23,14 +23,18 @@ WARNING: translation string unused: Captive voucher
|
||||
WARNING: translation string unused: Captive vout
|
||||
WARNING: translation string unused: ConnSched scheduler
|
||||
WARNING: translation string unused: ConnSched select profile
|
||||
WARNING: translation string unused: Existing Files
|
||||
WARNING: translation string unused: HDD temperature
|
||||
WARNING: translation string unused: Level7 rule
|
||||
WARNING: translation string unused: Local VPN IP
|
||||
WARNING: translation string unused: Pages
|
||||
WARNING: translation string unused: Ping
|
||||
WARNING: translation string unused: Queuelenght
|
||||
WARNING: translation string unused: Remote IP
|
||||
WARNING: translation string unused: Remote VPN IP
|
||||
WARNING: translation string unused: Resolv
|
||||
WARNING: translation string unused: Scan for Files
|
||||
WARNING: translation string unused: Scan from Directory
|
||||
WARNING: translation string unused: Subclass
|
||||
WARNING: translation string unused: TOS Bits
|
||||
WARNING: translation string unused: Utilization on
|
||||
@@ -107,6 +111,7 @@ WARNING: translation string unused: age seconds
|
||||
WARNING: translation string unused: age shour
|
||||
WARNING: translation string unused: age sminute
|
||||
WARNING: translation string unused: age ssecond
|
||||
WARNING: translation string unused: album
|
||||
WARNING: translation string unused: alcatelusb help
|
||||
WARNING: translation string unused: alcatelusb upload
|
||||
WARNING: translation string unused: all interfaces
|
||||
@@ -120,6 +125,7 @@ WARNING: translation string unused: and
|
||||
WARNING: translation string unused: ansi t1.483
|
||||
WARNING: translation string unused: apply
|
||||
WARNING: translation string unused: archive not exist
|
||||
WARNING: translation string unused: artist
|
||||
WARNING: translation string unused: attemps
|
||||
WARNING: translation string unused: avoid dod
|
||||
WARNING: translation string unused: backup archive
|
||||
@@ -172,6 +178,7 @@ WARNING: translation string unused: choose config
|
||||
WARNING: translation string unused: choose media
|
||||
WARNING: translation string unused: class in use
|
||||
WARNING: translation string unused: clear cache
|
||||
WARNING: translation string unused: clear playlist
|
||||
WARNING: translation string unused: client
|
||||
WARNING: translation string unused: comment
|
||||
WARNING: translation string unused: community rules
|
||||
@@ -194,6 +201,7 @@ WARNING: translation string unused: create mask
|
||||
WARNING: translation string unused: create new backup
|
||||
WARNING: translation string unused: current media
|
||||
WARNING: translation string unused: current ovpn
|
||||
WARNING: translation string unused: current playlist
|
||||
WARNING: translation string unused: current profile
|
||||
WARNING: translation string unused: custom networks
|
||||
WARNING: translation string unused: custom services
|
||||
@@ -394,6 +402,7 @@ WARNING: translation string unused: generatekeys
|
||||
WARNING: translation string unused: generatepolicy
|
||||
WARNING: translation string unused: generatereport
|
||||
WARNING: translation string unused: genkey
|
||||
WARNING: translation string unused: genre
|
||||
WARNING: translation string unused: gpl i accept these terms and conditions
|
||||
WARNING: translation string unused: gpl license agreement
|
||||
WARNING: translation string unused: gpl please read carefully the general public license and accept it below
|
||||
@@ -553,6 +562,7 @@ WARNING: translation string unused: network traffic graphs
|
||||
WARNING: translation string unused: network updated
|
||||
WARNING: translation string unused: networks settings
|
||||
WARNING: translation string unused: new optionsfw must boot
|
||||
WARNING: translation string unused: next
|
||||
WARNING: translation string unused: no alcatelusb firmware
|
||||
WARNING: translation string unused: no cfg upload
|
||||
WARNING: translation string unused: no eciadsl synch.bin file
|
||||
@@ -646,6 +656,7 @@ WARNING: translation string unused: pdc options
|
||||
WARNING: translation string unused: phase1 group
|
||||
WARNING: translation string unused: phonebook entry
|
||||
WARNING: translation string unused: ping disabled
|
||||
WARNING: translation string unused: play
|
||||
WARNING: translation string unused: polfile
|
||||
WARNING: translation string unused: port forwarding configuration
|
||||
WARNING: translation string unused: ports
|
||||
@@ -653,6 +664,7 @@ WARNING: translation string unused: pots
|
||||
WARNING: translation string unused: pppoe
|
||||
WARNING: translation string unused: prefered master
|
||||
WARNING: translation string unused: present
|
||||
WARNING: translation string unused: prev
|
||||
WARNING: translation string unused: printcap name
|
||||
WARNING: translation string unused: printer
|
||||
WARNING: translation string unused: printername
|
||||
@@ -667,6 +679,7 @@ WARNING: translation string unused: proxy port
|
||||
WARNING: translation string unused: psk
|
||||
WARNING: translation string unused: qos add subclass
|
||||
WARNING: translation string unused: quick control
|
||||
WARNING: translation string unused: quick playlist
|
||||
WARNING: translation string unused: read list
|
||||
WARNING: translation string unused: reboot ask
|
||||
WARNING: translation string unused: reboot question
|
||||
@@ -677,6 +690,7 @@ WARNING: translation string unused: registered user rules
|
||||
WARNING: translation string unused: released
|
||||
WARNING: translation string unused: reload
|
||||
WARNING: translation string unused: removable device advice
|
||||
WARNING: translation string unused: repeat
|
||||
WARNING: translation string unused: reportfile
|
||||
WARNING: translation string unused: reportlevel
|
||||
WARNING: translation string unused: requested data
|
||||
@@ -721,6 +735,7 @@ WARNING: translation string unused: show areas
|
||||
WARNING: translation string unused: show last x lines
|
||||
WARNING: translation string unused: show lines
|
||||
WARNING: translation string unused: show share options
|
||||
WARNING: translation string unused: shuffle
|
||||
WARNING: translation string unused: shutdown ask
|
||||
WARNING: translation string unused: shutdown sure
|
||||
WARNING: translation string unused: shutdown2
|
||||
@@ -785,9 +800,11 @@ WARNING: translation string unused: this months volume
|
||||
WARNING: translation string unused: this update is already installed
|
||||
WARNING: translation string unused: this weeks volume
|
||||
WARNING: translation string unused: time date manually reset
|
||||
WARNING: translation string unused: title
|
||||
WARNING: translation string unused: to email adr
|
||||
WARNING: translation string unused: to install an update
|
||||
WARNING: translation string unused: to warn email bad
|
||||
WARNING: translation string unused: toggle
|
||||
WARNING: translation string unused: too long 80 char max
|
||||
WARNING: translation string unused: tor 0 = disabled
|
||||
WARNING: translation string unused: tor accounting period daily
|
||||
@@ -872,6 +889,10 @@ WARNING: translation string unused: use dov
|
||||
WARNING: translation string unused: use ibod
|
||||
WARNING: translation string unused: view log
|
||||
WARNING: translation string unused: visible in browselist
|
||||
WARNING: translation string unused: voldown10
|
||||
WARNING: translation string unused: voldown5
|
||||
WARNING: translation string unused: volup10
|
||||
WARNING: translation string unused: volup5
|
||||
WARNING: translation string unused: vpn aggrmode
|
||||
WARNING: translation string unused: vpn configuration main
|
||||
WARNING: translation string unused: vpn delayed start
|
||||
@@ -885,6 +906,7 @@ WARNING: translation string unused: vpn red name
|
||||
WARNING: translation string unused: vpn watch
|
||||
WARNING: translation string unused: warn when traffic reaches
|
||||
WARNING: translation string unused: web proxy configuration
|
||||
WARNING: translation string unused: webradio playlist
|
||||
WARNING: translation string unused: week
|
||||
WARNING: translation string unused: week-graph
|
||||
WARNING: translation string unused: weekly firewallhits
|
||||
@@ -911,7 +933,6 @@ WARNING: translation string unused: year-graph
|
||||
WARNING: translation string unused: yearly firewallhits
|
||||
WARNING: untranslated string: Captive clients = unknown string
|
||||
WARNING: untranslated string: Captive delete logo = Delete Logo
|
||||
WARNING: untranslated string: Scan for Songs = unknown string
|
||||
WARNING: untranslated string: access point name = Access Point Name
|
||||
WARNING: untranslated string: access point name is invalid = Access Point Name is invalid
|
||||
WARNING: untranslated string: access point name is required = Access Point Name is required
|
||||
|
||||
@@ -1,673 +0,0 @@
|
||||
#!/usr/bin/perl
|
||||
###############################################################################
|
||||
# #
|
||||
# IPFire.org - A linux based firewall #
|
||||
# Copyright (C) 2007 Michael Tremer & Christian Schmidt #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
use strict;
|
||||
|
||||
# enable only the following on debugging purpose
|
||||
#use warnings;
|
||||
#use CGI::Carp 'fatalsToBrowser';
|
||||
|
||||
# use the special mpd POD and the encode POD to handle the utf8 scalars
|
||||
use Audio::MPD;
|
||||
use Encode;
|
||||
|
||||
# initiate the connector for the mpd POD, mpd must be running on locahost
|
||||
# port 6600 without authentication
|
||||
my $mpd = Audio::MPD->new('localhost',6600,'','$REUSE');
|
||||
my $work = $mpd->status()->updating_db();
|
||||
|
||||
require '/var/ipfire/general-functions.pl';
|
||||
require "${General::swroot}/lang.pl";
|
||||
require "${General::swroot}/header.pl";
|
||||
|
||||
my %color = ();
|
||||
my %mainsettings = ();
|
||||
my %mpfiresettings = ();
|
||||
my %checked = ();
|
||||
my $message = '0';
|
||||
my $errormessage = "";
|
||||
my @songs;
|
||||
|
||||
&General::readhash("${General::swroot}/main/settings", \%mainsettings);
|
||||
&General::readhash("/srv/web/ipfire/html/themes/ipfire/include/colors.txt", \%color);
|
||||
|
||||
&Header::showhttpheaders();
|
||||
|
||||
if ( $ENV{'QUERY_STRING'} =~ /title/){
|
||||
|
||||
################################################################################
|
||||
# $ENV{'QUERY_STRING'} =~ /title/ is used to handle the inline iframe used to
|
||||
# display the current song playing ( artist - title - album aso )
|
||||
# the cgi call´s itself with a parameter and the iframe refreshes itself without
|
||||
# reloading the whole page
|
||||
################################################################################
|
||||
|
||||
my $number = $mpd->status()->song()+1;
|
||||
my $volume = $mpd->status()->volume();
|
||||
my $random = $mpd->status()->random();
|
||||
|
||||
if ($random eq "0" ){
|
||||
$random="off";
|
||||
}else{
|
||||
$random="on";
|
||||
}
|
||||
|
||||
my $repeat = $mpd->status()->repeat();
|
||||
if ($repeat eq "0" ){
|
||||
$repeat="off";
|
||||
}else{
|
||||
$repeat="on";
|
||||
}
|
||||
|
||||
my $song = "";
|
||||
if ( $mpd->current() )
|
||||
{
|
||||
$song = substr("-= ".$mpd->current()->Artist()." | ".$mpd->current()->Title(),0,85)." =-<br /> ";
|
||||
if ( $song eq "-= | =-<br /> " ){
|
||||
$song = "None<br />"
|
||||
};
|
||||
$song .= $mpd->current()->Track()."# ".substr($mpd->current()->Album(),0,90)."<br />";
|
||||
}else{
|
||||
$song = "None<br /><br />";
|
||||
}
|
||||
|
||||
if ( $song eq "None<br /># <br />" ){
|
||||
$song = "None<br />".substr($mpd->current()->file(),0,90)."<br />"
|
||||
};
|
||||
$song .= "Playlist: ".$number."-".$mpd->status()->playlistlength()." Time: ".$mpd->status()->time()->sofar."/";
|
||||
$song .= $mpd->status()->time()->total." (".$mpd->status()->time()->percent()."%) Status: ";
|
||||
$song .= $mpd->status()->state()." Volume: ".$volume." % Repeat: ".$repeat." Random: ".$random;
|
||||
|
||||
print <<END
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<meta http-equiv='refresh' content='5'>
|
||||
<title></title>
|
||||
<body>
|
||||
<table width='100%' cellspacing='0' align='center' style="background-image:url(/images/mpfire/box.png);background-repeat:no-repeat">
|
||||
END
|
||||
;
|
||||
print"<tr ><td align='center'><font color='red' face='Verdana' size='2'><br />".encode('utf-8', $song)."<br /><br /></font></td></tr></table></body>";
|
||||
exit;
|
||||
}elsif ( $ENV{'QUERY_STRING'} =~ /control/){
|
||||
|
||||
################################################################################
|
||||
# $ENV{'QUERY_STRING'} =~ /control/ is used to handle the inline iframe used to
|
||||
# display the control button ( prev play skip stop toggle aso )
|
||||
# the cgi call´s itself with a parameter and only the iframe is reloaded on click
|
||||
################################################################################
|
||||
|
||||
&Header::getcgihash(\%mpfiresettings);
|
||||
if ( $mpfiresettings{'ACTION'} eq "playall" ){
|
||||
$mpd->playlist->clear();
|
||||
foreach ($mpd->collection->all_pathes){
|
||||
$mpd->playlist->add($_);
|
||||
}
|
||||
$mpd->play();
|
||||
}elsif ($mpfiresettings{'ACTION'} eq "x" ){
|
||||
$mpd->stop();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "|>" ){
|
||||
$mpd->pause();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "<<" ){
|
||||
$mpd->prev();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq ">>" ){
|
||||
$mpd->next();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "+" ){
|
||||
$mpd->volume('+5');
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "-" ){
|
||||
$mpd->volume('-5');
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "++" ){
|
||||
$mpd->volume('+10');
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "--" ){
|
||||
$mpd->volume('-10');
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq ">" ){
|
||||
$mpd->play();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "repeat" ){
|
||||
$mpd->repeat();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "shuffle" ){
|
||||
$mpd->random();
|
||||
}
|
||||
print <<END
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<title></title>
|
||||
<body>
|
||||
<table width='95%' cellspacing='0'>
|
||||
<tr>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='<<' /><input type='image' alt='$Lang::tr{'prev'}' title='$Lang::tr{'prev'}' src='/images/media-skip-backward.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='x' /><input type='image' alt='$Lang::tr{'stop'}' title='$Lang::tr{'stop'}' src='/images/media-playback-stop.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='|>' /><input type='image' alt='$Lang::tr{'toggle'}' title='$Lang::tr{'toggle'}' src='/images/media-resume.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='>' /><input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='playall' /><input type='image' alt='$Lang::tr{'play'} all' title='$Lang::tr{'play'} all' src='/images/media-playback-start-all.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='>>' /><input type='image' alt='$Lang::tr{'next'}' title='$Lang::tr{'next'}' src='/images/media-skip-forward.png' /></form></td>
|
||||
</tr>
|
||||
END
|
||||
;
|
||||
print <<END
|
||||
<tr>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='repeat' /><input type='image' alt='$Lang::tr{'repeat'}' title='$Lang::tr{'repeat'}' src='/images/media-repeat.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='--' /><input type='image' alt='$Lang::tr{'voldown10'}' title='$Lang::tr{'voldown10'}' src='/images/audio-volume-low-red.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='-' /><input type='image' alt='$Lang::tr{'voldown5'}' title='$Lang::tr{'voldown5'}' src='/images/audio-volume-low.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='+' /><input type='image' alt='$Lang::tr{'volup5'}' title='$Lang::tr{'volup5'}' src='/images/audio-volume-high.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='++' /><input type='image' alt='$Lang::tr{'volup10'}' title='$Lang::tr{'volup10'}' src='/images/audio-volume-high-red.png' /></form></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}?control'><input type='hidden' name='ACTION' value='shuffle' /><input type='image' alt='$Lang::tr{'shuffle'}' title='$Lang::tr{'shuffle'}' src='/images/media-shuffle.png' /></form></td>
|
||||
</tr>
|
||||
</table>
|
||||
</body>
|
||||
END
|
||||
;
|
||||
exit;
|
||||
}
|
||||
|
||||
# just a little subpage to handle automatic page refresh on demand ( 1 sec )
|
||||
sub refreshpage{
|
||||
&Header::openbox( 'Waiting', 1, "<meta http-equiv='refresh' content='1;' />" );
|
||||
print "<center><img src='/images/clock.gif' alt='' /><br/><font color='red'>$Lang::tr{'pagerefresh'}</font></center>";
|
||||
&Header::closebox();
|
||||
}
|
||||
|
||||
# if the mpd is updating his database because of user interaction then the cgi
|
||||
# should display that the mpd is unavailable, and refresh the status every 5 seconds
|
||||
if ($work ne ""){
|
||||
&Header::openpage($Lang::tr{'mpfire'}, 1,);
|
||||
&Header::openbigbox('100%', 'left', '', $errormessage);
|
||||
&Header::openbox( 'Waiting', 5, "<meta http-equiv='refresh' content='5;' />" );
|
||||
print "<center><img src='/images/clock.gif' alt='' /><br/><font color='red'>Database is updating, please be patient.</font></center>";
|
||||
&Header::closebox();
|
||||
&Header::closebigbox();
|
||||
&Header::closepage();
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( $mpfiresettings{'PAGE'} eq "" ){ $mpfiresettings{'PAGE'} = "1";};
|
||||
if ( $mpfiresettings{'FRAME'} eq "" ){$mpfiresettings{'FRAME'} = "webradio";};
|
||||
|
||||
&Header::getcgihash(\%mpfiresettings);
|
||||
&Header::openpage($Lang::tr{'mpfire'}, 1,);
|
||||
&Header::openbigbox('100%', 'left', '', $errormessage);
|
||||
|
||||
############################################################################################################################
|
||||
######################################## Scanne Verzeichnisse nach Mp3 Dateien #############################################
|
||||
|
||||
if ( $mpfiresettings{'ACTION'} eq "scan" ){
|
||||
|
||||
# on keypress scan the given directory and store the path to the mpd config
|
||||
&General::readhash("${General::swroot}/mpfire/settings", \%mpfiresettings);
|
||||
&Header::getcgihash(\%mpfiresettings);
|
||||
delete $mpfiresettings{'__CGI__'};delete $mpfiresettings{'x'};delete $mpfiresettings{'y'};
|
||||
delete $mpfiresettings{'PAGE'}; delete $mpfiresettings{'FRAME'};
|
||||
&General::writehash("${General::swroot}/mpfire/settings", \%mpfiresettings);
|
||||
|
||||
open(DATEI, "<${General::swroot}/mpd/mpd.conf") || die "Datei nicht gefunden";
|
||||
my @Zeilen = <DATEI>;
|
||||
close(DATEI);
|
||||
|
||||
open(DATEI, ">${General::swroot}/mpd/mpd.conf") || die "Datei nicht gefunden";
|
||||
foreach (@Zeilen){
|
||||
if ( $_ =~ /music_directory/){
|
||||
print DATEI "music_directory \"".$mpfiresettings{'MUSICDIR'}."\"\n";
|
||||
}else {
|
||||
print DATEI $_;
|
||||
}
|
||||
}
|
||||
close(DATEI);
|
||||
|
||||
$mpd->updatedb();
|
||||
refreshpage();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "playweb" ){
|
||||
$message= &General::system_output("/usr/local/bin/mpfirectrl","playweb","\"$mpfiresettings{'FILE'}\"");
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "playlist" ){
|
||||
$mpd->play();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "emptyplaylist" ){
|
||||
# on keypress clear the playlist
|
||||
$mpd->playlist->clear();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "addtoplaylist" ){
|
||||
$mpd->playlist->add($mpfiresettings{'FILE'});
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "playalbum" ){
|
||||
# on keypress play the selected albums
|
||||
my @select = split(/\|/,$mpfiresettings{'album'});
|
||||
$mpd->playlist->clear();
|
||||
foreach (@select){
|
||||
foreach ($mpd->collection->filenames_by_album($_)){
|
||||
if ( $_ ne "" ){
|
||||
$mpd->playlist->add($_);
|
||||
}
|
||||
}
|
||||
}
|
||||
$mpd->play();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "playartist" ){
|
||||
# on keypress play the selected artist
|
||||
my @select = split(/\|/,$mpfiresettings{'artist'});
|
||||
$mpd->playlist->clear();
|
||||
foreach (@select){
|
||||
foreach ($mpd->collection->filenames_by_artist($_)){
|
||||
if ( $_ ne "" ){
|
||||
$mpd->playlist->add($_);
|
||||
}
|
||||
}
|
||||
}
|
||||
$mpd->play();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "playyear" ){
|
||||
# on keypress play the selected year
|
||||
my @select = split(/\|/,$mpfiresettings{'year'});
|
||||
$mpd->playlist->clear();
|
||||
foreach (@select){
|
||||
foreach ($mpd->collection->filenames_by_year($_)){
|
||||
if ( $_ ne "" ){
|
||||
$mpd->playlist->add($_);
|
||||
}
|
||||
}
|
||||
}
|
||||
$mpd->play();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq "playgenre" ){
|
||||
# on keypress play the selected genre
|
||||
my @select = split(/\|/,$mpfiresettings{'genre'});
|
||||
$mpd->playlist->clear();
|
||||
foreach (@select){
|
||||
foreach ($mpd->collection->filenames_by_genre($_)){
|
||||
if ( $_ ne "" ){
|
||||
$mpd->playlist->add($_);
|
||||
}
|
||||
}
|
||||
}
|
||||
$mpd->play();
|
||||
}elsif ( $mpfiresettings{'ACTION'} eq ">" ){
|
||||
$mpd->playlist->clear();
|
||||
$mpd->playlist->add($mpfiresettings{'FILE'});
|
||||
$mpd->play();
|
||||
}
|
||||
|
||||
if ( $mpfiresettings{'SEARCH'} eq "artist" && $mpfiresettings{'SEARCHITEM'} ne "" ){
|
||||
foreach ($mpd->collection->songs_with_artist_partial_filename($mpfiresettings{'SEARCHITEM'})){
|
||||
if ( $_ ne "" ){
|
||||
push(@songs,$_);
|
||||
}
|
||||
}
|
||||
}elsif ( $mpfiresettings{'SEARCH'} eq "title" && $mpfiresettings{'SEARCHITEM'} ne "" ){
|
||||
foreach ($mpd->collection->songs_with_title_partial_filename($mpfiresettings{'SEARCHITEM'})){
|
||||
if ( $_ ne "" ){
|
||||
push(@songs,$_);
|
||||
}
|
||||
}
|
||||
}elsif ( $mpfiresettings{'SEARCH'} eq "album" && $mpfiresettings{'SEARCHITEM'} ne "" ){
|
||||
foreach ($mpd->collection->songs_with_album_partial_filename($mpfiresettings{'SEARCHITEM'})){
|
||||
if ( $_ ne "" ){
|
||||
push(@songs,$_);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
@songs = $mpd->collection->all_items_simple();
|
||||
shift(@songs);
|
||||
}
|
||||
|
||||
############################################################################################################################
|
||||
################################### Aufbau der HTML Seite fr globale Sambaeinstellungen ####################################
|
||||
|
||||
$mpfiresettings{'MUSICDIR'} = "/var/mp3";
|
||||
&General::readhash("${General::swroot}/mpfire/settings", \%mpfiresettings);
|
||||
|
||||
############################################################################################################################
|
||||
########################################### rekursiv nach neuen Mp3s Scannen ##############################################ä
|
||||
|
||||
if ( $message ne '0' ){
|
||||
print "<font color='red'>An Error occured while launching the command</font>";
|
||||
}elsif ( $message ne "" && $message ne '0' ){
|
||||
print "<font color='red'>$message</font>";
|
||||
}
|
||||
|
||||
&Header::openbox('100%', 'center', $Lang::tr{'mpfire scanning'});
|
||||
# box to enter the music directory and initiate the scan process
|
||||
print <<END
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
|
||||
<table width='95%' cellspacing='0'>
|
||||
<tr bgcolor='$color{'color20'}'><td colspan='2' align='left'><b>$Lang::tr{'Scan for Files'}</b></td></tr>
|
||||
<tr><td align='left' width='40%'>$Lang::tr{'Scan from Directory'}</td><td align='left'><input type='text' name='MUSICDIR' value='$mpfiresettings{'MUSICDIR'}' size="50" /></td></tr>
|
||||
<tr><td align='center' colspan='2'><input type='hidden' name='ACTION' value='scan' /><input type='image' alt='$Lang::tr{'Scan for Files'}' title='$Lang::tr{'Scan for Files'}' src='/images/edit-find.png' /></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
END
|
||||
;
|
||||
&Header::closebox();
|
||||
|
||||
&Header::openbox('100%', 'center', $Lang::tr{'mpfire controls'});
|
||||
# box for the two iframes showing the current playbar and the control buttons
|
||||
print <<END
|
||||
<iframe height='85' width='685' src='/cgi-bin/mpfire.cgi?title' scrolling='no' frameborder='no' marginheight='0'></iframe>
|
||||
<iframe height='50' width='685' src='/cgi-bin/mpfire.cgi?control' scrolling='no' frameborder='no' marginheight='0'></iframe>
|
||||
END
|
||||
;
|
||||
print "<b>Songs:".$mpd->stats()->songs()."</b><br />";
|
||||
|
||||
&Header::closebox();
|
||||
|
||||
&Header::openbox('100%', 'center', '');
|
||||
print <<END
|
||||
<tr><td align='center' colspan='4'>
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
|
||||
END
|
||||
;
|
||||
my @buttons=("webradio", "quick playlist","songs");
|
||||
foreach (@buttons){
|
||||
if ( $mpfiresettings{'FRAME'} eq $_ ) {
|
||||
print "<input type='submit' name='FRAME' value='$_' disabled />";
|
||||
} else {
|
||||
print "<input type='submit' name='FRAME' value='$_' />";
|
||||
}
|
||||
}
|
||||
|
||||
print <<END
|
||||
</form></td></tr>
|
||||
END
|
||||
;
|
||||
&Header::closebox();
|
||||
|
||||
if ( $mpfiresettings{'FRAME'} eq "quick playlist" )
|
||||
{
|
||||
&Header::openbox('100%', 'center', $Lang::tr{'quick playlist'});
|
||||
# box to quickly select artist, album, year or genre and play the selection
|
||||
print "<table width='95%' cellspacing='0'>";
|
||||
print "<tr><td align='center' bgcolor='$color{'color20'}'><b>$Lang::tr{'artist'} - ".$mpd->stats()->artists()."</b></td><td align='center' bgcolor='$color{'color20'}'><b>$Lang::tr{'album'} - ".$mpd->stats()->albums()."</b></td></tr>";
|
||||
|
||||
print <<END
|
||||
<tr><td align='center'>
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
|
||||
<select name='artist' size='8' multiple='multiple' style='width:300px;'>
|
||||
END
|
||||
;
|
||||
|
||||
foreach (sort($mpd->collection->all_artists())){
|
||||
if ( $_ ne '' ){
|
||||
print "<option>".encode('utf-8', $_)."</option>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print <<END
|
||||
</select><br/>
|
||||
<input type='hidden' name='ACTION' value='playartist' />
|
||||
<input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form></td>
|
||||
<td align='center'>
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
|
||||
<select name='album' size='8' multiple='multiple' style='width:300px;'>
|
||||
END
|
||||
;
|
||||
|
||||
foreach (sort($mpd->collection->all_albums())){
|
||||
if ( $_ ne '' ){
|
||||
print "<option>".encode('utf-8', $_)."</option>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print <<END
|
||||
</select><br/>
|
||||
<input type='hidden' name='ACTION' value='playalbum' />
|
||||
<input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form></td>
|
||||
</tr>
|
||||
<tr><td align='center' bgcolor='$color{'color20'}'><b>$Lang::tr{'year'}</b></td><td align='center' bgcolor='$color{'color20'}'><b>$Lang::tr{'genre'}</b></td></tr>
|
||||
<tr><td align='center'>
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
|
||||
<select name='year' size='8' multiple='multiple' style='width:300px;'>
|
||||
END
|
||||
;
|
||||
|
||||
foreach (sort($mpd->collection->all_years())){
|
||||
if ( $_ ne '' ){
|
||||
print "<option>$_</option>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print <<END
|
||||
</select><br/>
|
||||
<input type='hidden' name='ACTION' value='playyear' />
|
||||
<input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form></td>
|
||||
<td align='center'>
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
|
||||
<select name='genre' size='8' multiple='multiple' style='width:300px;'>
|
||||
END
|
||||
;
|
||||
|
||||
foreach (sort($mpd->collection->all_genre())){
|
||||
if ( $_ ne '' ){
|
||||
print "<option>$_</option>\n";
|
||||
}
|
||||
}
|
||||
|
||||
print <<END
|
||||
</select><br/>
|
||||
<input type='hidden' name='ACTION' value='playgenre' />
|
||||
<input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form></td>
|
||||
</tr></table>
|
||||
END
|
||||
;
|
||||
|
||||
&Header::closebox();
|
||||
}
|
||||
|
||||
if ( $mpfiresettings{'FRAME'} eq "songs" )
|
||||
{
|
||||
&Header::openbox('100%', 'center', $Lang::tr{'mpfire search'});
|
||||
# box to quickly search artist, album or title
|
||||
print <<END
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}#$Lang::tr{'mpfire songs'}'>
|
||||
<table width='95%' cellspacing='0'>
|
||||
<tr>
|
||||
<td align='right' width='33%'>$Lang::tr{'artist'}</td>
|
||||
<td align='center' width='33%'>$Lang::tr{'title'}</td>
|
||||
<td align='left' width='33%'>$Lang::tr{'album'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align='right' width='33%'><input type='radio' name='SEARCH' value='artist' /></td>
|
||||
<td align='center' width='33%'><input type='radio' name='SEARCH' value='title' checked='checked' /></td>
|
||||
<td align='left' width='33%'><input type='radio' name='SEARCH' value='album' /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align='center' colspan='3'><input type='text' name='SEARCHITEM' value='$mpfiresettings{'SEARCHITEM'}' size="50" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align='center' colspan='3'><input type='hidden' name='ACTION' value='search' /><input type='image' alt='$Lang::tr{'Scan for Songs'}' title='$Lang::tr{'Scan for Songs'}' src='/images/edit-find.png' /></td>
|
||||
</tr>
|
||||
</table>
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form>
|
||||
END
|
||||
;
|
||||
&Header::closebox();
|
||||
|
||||
&Header::openbox('100%', 'center', $Lang::tr{'mpfire songs'});
|
||||
print <<END
|
||||
<a id='$Lang::tr{'mpfire songs'}' name='$Lang::tr{'mpfire songs'}'></a>
|
||||
<table width='95%' cellspacing='3'>
|
||||
<tr bgcolor='$color{'color20'}'><td colspan='4' align='left'><b>$Lang::tr{'Existing Files'}</b></td></tr>
|
||||
END
|
||||
;
|
||||
if ( $#songs > 100 ){
|
||||
print "<tr><td align='center' colspan='4'><br/>$Lang::tr{'Pages'}<br/><form method='post' action='$ENV{'SCRIPT_NAME'}'><input type='submit' name='PAGE' value='all' /><br/>";
|
||||
my $pages =(int($#songs/100)+1);
|
||||
for(my $i = 1; $i <= $pages; $i++){
|
||||
print "<input type='submit' name='PAGE' value='$i' />";
|
||||
if (!($i % 205)){
|
||||
print"<br/>";
|
||||
}
|
||||
}
|
||||
print "<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />";
|
||||
print "</form></td></tr>";
|
||||
}
|
||||
print <<END
|
||||
<tr><td align='center'></td>
|
||||
<td align='center'><b>$Lang::tr{'artist'}<br/>$Lang::tr{'title'}</b></td>
|
||||
<td align='center'><b>$Lang::tr{'number'}</b></td>
|
||||
<td align='center'><b>$Lang::tr{'album'}</b></td>
|
||||
END
|
||||
;
|
||||
|
||||
my $lines=0;my $i=0;my $begin;my $end;
|
||||
if ( $mpfiresettings{'PAGE'} eq 'all' ){
|
||||
$begin=0;
|
||||
$end=$#songs;
|
||||
}else{
|
||||
$begin=(($mpfiresettings{'PAGE'}-1) * 100);
|
||||
$end=(($mpfiresettings{'PAGE'} * 100)-1);
|
||||
}
|
||||
foreach (@songs){
|
||||
if (!($i >= $begin && $i <= $end)){
|
||||
#print $begin."->".$i."<-".$end."\n";
|
||||
$i++;next;
|
||||
}
|
||||
my @song = split(/\=/,$mpd->collection->song($_));
|
||||
@song = reverse @song;
|
||||
|
||||
if ($lines % 2) {
|
||||
print "<tr bgcolor='$color{'color20'}'>";
|
||||
}else{
|
||||
print "<tr bgcolor='$color{'color22'}'>";
|
||||
}
|
||||
print <<END
|
||||
<td align='center' style="white-space:nowrap;">
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}#$Lang::tr{'mpfire songs'}'>
|
||||
<input type='hidden' name='ACTION' value='addtoplaylist' />
|
||||
<input type='hidden' name='FILE' value="$_" />
|
||||
<input type='hidden' name='PAGE' value='$mpfiresettings{'PAGE'}' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
<input type='hidden' name='SEARCH' value='$mpfiresettings{'SEARCH'}' />
|
||||
<input type='hidden' name='SEARCHITEM' value='$mpfiresettings{'SEARCHITEM'}' />
|
||||
<input type='image' alt='$Lang::tr{'add'}' title='$Lang::tr{'add'}' src='/images/list-add.png' />
|
||||
</form>
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}#$Lang::tr{'mpfire songs'}'>
|
||||
<input type='hidden' name='ACTION' value='>' />
|
||||
<input type='hidden' name='FILE' value="$_" />
|
||||
<input type='hidden' name='PAGE' value='$mpfiresettings{'PAGE'}' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
<input type='hidden' name='SEARCH' value='$mpfiresettings{'SEARCH'}' />
|
||||
<input type='hidden' name='SEARCHITEM' value='$mpfiresettings{'SEARCHITEM'}' />
|
||||
<input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' />
|
||||
</form>
|
||||
</td>
|
||||
END
|
||||
;
|
||||
print "<td align='center'>".encode('utf-8', $song[0])."<br/>".encode('utf-8', $song[1])."</td>";
|
||||
print "<td align='center'>".encode('utf-8', $song[2])."</td>";
|
||||
print "<td align='center'>".encode('utf-8', $song[3])."</td>";
|
||||
$lines++;
|
||||
$i++;
|
||||
}
|
||||
|
||||
print "</table>";
|
||||
&Header::closebox();
|
||||
}
|
||||
|
||||
if ( $mpfiresettings{'FRAME'} eq "webradio" )
|
||||
{
|
||||
&Header::openbox('100%', 'center', $Lang::tr{'mpfire webradio'});
|
||||
# box to select some webradio´s to be played by one click
|
||||
open(DATEI, "<${General::swroot}/mpfire/webradio") || die "Could not open playlist";
|
||||
my @webradio = <DATEI>;
|
||||
close(DATEI);
|
||||
|
||||
print <<END
|
||||
<table width='95%' cellspacing='0'>
|
||||
<tr bgcolor='$color{'color20'}'><td colspan='9' align='left'><b>$Lang::tr{'webradio playlist'}</b></td></tr>
|
||||
<tr><td align='left'>Stream</td><td colspan='2'></td></tr>
|
||||
END
|
||||
;
|
||||
|
||||
my $lines=0;
|
||||
foreach (@webradio){
|
||||
my @stream = split(/\|/,$_);
|
||||
$lines++;
|
||||
chomp($stream[2]);
|
||||
if ($lines % 2) {
|
||||
print "<tr bgcolor='$color{'color22'}'>";
|
||||
}else{
|
||||
print "<tr>";
|
||||
}
|
||||
chomp $stream[1];chomp $stream[2];
|
||||
print <<END
|
||||
<td align='left'><a href='$stream[2]' target='_blank'>$stream[1]</a></td>
|
||||
<td align='center'><form method='post' action='$ENV{'SCRIPT_NAME'}'><input type='hidden' name='FILE' value='$stream[0]' /><input type='hidden' name='ACTION' value='playweb' /><input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' align='middle' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form></td>
|
||||
</tr>
|
||||
END
|
||||
;
|
||||
}
|
||||
|
||||
$lines++;
|
||||
if ($lines % 2){
|
||||
print "<tr bgcolor='$color{'color22'}'>";
|
||||
}else{
|
||||
print "<tr>";
|
||||
}
|
||||
|
||||
print <<END
|
||||
<td align='center' colspan='2'><form method='post' action='$ENV{'SCRIPT_NAME'}'><br />http://<input type=text name='FILE' value='www.meineradiourl:1234' size='75' />
|
||||
<input type='hidden' name='ACTION' value='playweb' /><input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' align='top' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form></td>
|
||||
</tr>
|
||||
END
|
||||
;
|
||||
print "</table>";
|
||||
&Header::closebox();
|
||||
}
|
||||
|
||||
&Header::openbox('100%', 'center', $Lang::tr{'mpfire playlist'});
|
||||
# box to show the current playlist given from mpc system command
|
||||
my @playlist = `mpc playlist 2>/dev/null`;
|
||||
|
||||
print <<END
|
||||
<table width='95%' cellspacing='0'>
|
||||
<tr bgcolor='$color{'color20'}'><td colspan='2' align='left'><b>$Lang::tr{'current playlist'}</b></td></tr>
|
||||
<tr><td align='center' colspan='2' ><textarea cols='100' rows='10' name='playlist' style='font-size:11px;width:650px;' readonly='readonly'>
|
||||
END
|
||||
;
|
||||
|
||||
foreach (@playlist){
|
||||
$_=~s/&/&\;/g;;print $_;
|
||||
}
|
||||
|
||||
print <<END
|
||||
</textarea></td></tr><tr>
|
||||
<td align='right'>
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
|
||||
<input type='hidden' name='ACTION' value='emptyplaylist' />
|
||||
<input type='image' alt='$Lang::tr{'clear playlist'}' title='$Lang::tr{'clear playlist'}' src='/images/user-trash.png' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form>
|
||||
</td>
|
||||
<td align='left'>
|
||||
<form method='post' action='$ENV{'SCRIPT_NAME'}'>
|
||||
<input type='hidden' name='ACTION' value='playlist' />
|
||||
<input type='image' alt='$Lang::tr{'play'}' title='$Lang::tr{'play'}' src='/images/media-playback-start.png' />
|
||||
<input type='hidden' name='FRAME' value='$mpfiresettings{'FRAME'}' />
|
||||
</form>
|
||||
</td></tr>
|
||||
</table>
|
||||
END
|
||||
;
|
||||
|
||||
&Header::closebox();
|
||||
&Header::closebigbox();
|
||||
&Header::closepage();
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 KiB |
@@ -1793,13 +1793,6 @@
|
||||
'most preferred' => 'präferiert',
|
||||
'mount' => 'Einbinden',
|
||||
'mounted on' => 'Mounted auf',
|
||||
'mpfire' => 'Media Player für IPFire',
|
||||
'mpfire controls' => 'MPFire Steuerung',
|
||||
'mpfire playlist' => 'MPFire Playlist',
|
||||
'mpfire scanning' => 'Nach neuen Dateien suchen',
|
||||
'mpfire search' => 'MPFire Suche',
|
||||
'mpfire songs' => 'MPFire Songliste',
|
||||
'mpfire webradio' => 'MPFire Webradio',
|
||||
'mtu' => 'MTU',
|
||||
'mtu QoS' => 'Diese Einstellung ändert die MTU nicht global sondern nur für das QoS.',
|
||||
'my new share' => 'Meine neue Freigabe',
|
||||
|
||||
@@ -1853,13 +1853,6 @@
|
||||
'most preferred' => 'most preferred',
|
||||
'mount' => 'Mount',
|
||||
'mounted on' => 'Mounted on',
|
||||
'mpfire' => 'Media Player for IPFire',
|
||||
'mpfire controls' => 'MPFire Control',
|
||||
'mpfire playlist' => 'MPFire Playlist',
|
||||
'mpfire scanning' => 'Scan for new files',
|
||||
'mpfire search' => 'MPFire Search',
|
||||
'mpfire songs' => 'MPFire songlist',
|
||||
'mpfire webradio' => 'MPFire Webradio',
|
||||
'mtu' => 'MTU',
|
||||
'mtu QoS' => 'This does not change the global MTU, it only sets MTU for QoS.',
|
||||
'my new share' => 'My new share',
|
||||
|
||||
@@ -1848,13 +1848,6 @@
|
||||
'most preferred' => 'Más preferido',
|
||||
'mount' => 'Montar',
|
||||
'mounted on' => 'Montado en',
|
||||
'mpfire' => 'Media Player para IPFire',
|
||||
'mpfire controls' => 'Control de MPFire',
|
||||
'mpfire playlist' => 'Lista de reproducción de MPFire',
|
||||
'mpfire scanning' => 'Analiza en busca de nuevos archivos',
|
||||
'mpfire search' => 'Búsqueda MPFire',
|
||||
'mpfire songs' => 'Lista de canciones de MPFire',
|
||||
'mpfire webradio' => 'Webradio de MPFire',
|
||||
'mtu' => 'MTU',
|
||||
'mtu QoS' => 'Esto no cambia el MTU global, solo establece MTU para QoS',
|
||||
'my new share' => 'Mi nuevo recurso compartido',
|
||||
|
||||
@@ -1849,13 +1849,6 @@
|
||||
'most preferred' => 'le préféré',
|
||||
'mount' => 'Monter',
|
||||
'mounted on' => 'Monté en tant que',
|
||||
'mpfire' => 'Lecteur de médias pour IPFire',
|
||||
'mpfire controls' => 'Contrôle MPFire',
|
||||
'mpfire playlist' => 'Liste de lecture MPFire',
|
||||
'mpfire scanning' => 'Chercher de nouveaux fichiers',
|
||||
'mpfire search' => 'Recherche MPFire',
|
||||
'mpfire songs' => 'Liste des chansons MPFire',
|
||||
'mpfire webradio' => 'Radio web MPFire',
|
||||
'mtu' => 'MTU',
|
||||
'mtu QoS' => 'Ceci ne change pas le MTU global, cela règle uniquement le MTU pour la QoS.',
|
||||
'my new share' => 'Mon nouveau partage',
|
||||
|
||||
@@ -1516,13 +1516,6 @@
|
||||
'most preferred' => 'most preferred',
|
||||
'mount' => 'Mount',
|
||||
'mounted on' => 'Montato su',
|
||||
'mpfire' => 'Media Player for IPFire',
|
||||
'mpfire controls' => 'MPFire Control',
|
||||
'mpfire playlist' => 'MPFire Playlist',
|
||||
'mpfire scanning' => 'Scan for new files',
|
||||
'mpfire search' => 'MPFire Search',
|
||||
'mpfire songs' => 'MPFire songlist',
|
||||
'mpfire webradio' => 'MPFire Webradio',
|
||||
'mtu QoS' => 'This does not change the global MTU, it only sets MTU for QoS.',
|
||||
'my new share' => 'My new share',
|
||||
'name' => 'Nome',
|
||||
|
||||
@@ -1497,13 +1497,6 @@
|
||||
'most preferred' => 'Meeste voorkeur',
|
||||
'mount' => 'Koppelen',
|
||||
'mounted on' => 'Gekoppeld op',
|
||||
'mpfire' => 'Mediaspeler voor IPFire',
|
||||
'mpfire controls' => 'MPFire Controle',
|
||||
'mpfire playlist' => 'MPFire afspeellijst',
|
||||
'mpfire scanning' => 'Zoeken naar nieuwe bestanden',
|
||||
'mpfire search' => 'MPFire Zoeken',
|
||||
'mpfire songs' => 'MPFire lijst met nummers',
|
||||
'mpfire webradio' => 'MPFire Webradio',
|
||||
'mtu QoS' => 'Dit verandert niet de globale MTU, het zet alleen de MTU voor QoS.',
|
||||
'my new share' => 'Mijn nieuwe share',
|
||||
'name' => 'Naam',
|
||||
|
||||
@@ -1193,13 +1193,6 @@
|
||||
'more' => 'więcej',
|
||||
'mount' => 'Montuj',
|
||||
'mounted on' => 'Zamontowany w',
|
||||
'mpfire' => 'Odtwarzać mediów dla IPFire',
|
||||
'mpfire controls' => 'Zarządzanie MPFire',
|
||||
'mpfire playlist' => 'Playlist\'a MPFire ',
|
||||
'mpfire scanning' => 'Skanuj w poszukiwaniu nowych plików',
|
||||
'mpfire search' => 'MPFire Szukaj',
|
||||
'mpfire songs' => 'MPFire lista utworów',
|
||||
'mpfire webradio' => 'MPFire Webradio',
|
||||
'mtu QoS' => 'Ta opcja nie zmienia globalnego MTU, a jedynie MTU dla QoS.',
|
||||
'my new share' => 'Mój nowy zasób',
|
||||
'name' => 'Nazwa',
|
||||
|
||||
@@ -1185,13 +1185,6 @@
|
||||
'more' => 'Больше',
|
||||
'mount' => 'Монтировать',
|
||||
'mounted on' => 'Смонтирован на',
|
||||
'mpfire' => 'Media Player for IPFire',
|
||||
'mpfire controls' => 'MPFire Control',
|
||||
'mpfire playlist' => 'MPFire Playlist',
|
||||
'mpfire scanning' => 'Искать новые файлы',
|
||||
'mpfire search' => 'MPFire Search',
|
||||
'mpfire songs' => 'MPFire songlist',
|
||||
'mpfire webradio' => 'MPFire Webradio',
|
||||
'mtu QoS' => 'Это нре изменит глобальные настройки MTU, а только задаёт MTU для QoS.',
|
||||
'my new share' => 'Моя новая шара',
|
||||
'name' => 'Имя',
|
||||
|
||||
@@ -1652,13 +1652,6 @@
|
||||
'most preferred' => 'En çok tercih edilen',
|
||||
'mount' => 'Bağla',
|
||||
'mounted on' => 'Bağlı',
|
||||
'mpfire' => 'IPFire için Media Player',
|
||||
'mpfire controls' => 'MPFire Kontrol',
|
||||
'mpfire playlist' => 'MPFire Çalma Listesi',
|
||||
'mpfire scanning' => 'Yeni dosyalar için tara',
|
||||
'mpfire search' => 'MPFire Ara',
|
||||
'mpfire songs' => 'MPFire şarkı listesi',
|
||||
'mpfire webradio' => 'MPFire Webradyo',
|
||||
'mtu QoS' => 'Bu genel MTU değiştirilemez. Sadece QoS için MTU ayarı yapılır.',
|
||||
'my new share' => 'Yeni paylaşımlarım',
|
||||
'name' => 'Ad',
|
||||
|
||||
75
lfs/mpfire
75
lfs/mpfire
@@ -1,75 +0,0 @@
|
||||
###############################################################################
|
||||
# #
|
||||
# IPFire.org - A linux based firewall #
|
||||
# Copyright (C) 2007-2024 IPFire Team <info@ipfire.org> #
|
||||
# #
|
||||
# This program is free software: you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation, either version 3 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# This program is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>. #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
###############################################################################
|
||||
# Definitions
|
||||
###############################################################################
|
||||
|
||||
include Config
|
||||
|
||||
SUMMARY = IPFire integration for the Music Player Daemon
|
||||
|
||||
VER = ipfire
|
||||
|
||||
THISAPP = mpfire-$(VER)
|
||||
DIR_APP = $(DIR_SRC)/$(THISAPP)
|
||||
TARGET = $(DIR_INFO)/$(THISAPP)
|
||||
PROG = mpfire
|
||||
PAK_VER = 17
|
||||
|
||||
DEPS = mpd mpc
|
||||
|
||||
SERVICES =
|
||||
|
||||
###############################################################################
|
||||
# Top-level Rules
|
||||
###############################################################################
|
||||
|
||||
objects =
|
||||
|
||||
install : $(TARGET)
|
||||
|
||||
check :
|
||||
|
||||
download :
|
||||
|
||||
b2 :
|
||||
|
||||
dist:
|
||||
@$(PAK)
|
||||
|
||||
###############################################################################
|
||||
# Installation Details
|
||||
###############################################################################
|
||||
|
||||
$(TARGET) : $(patsubst %,$(DIR_DL)/%,$(objects))
|
||||
@$(PREBUILD)
|
||||
-mkdir -p /var/ipfire/mpfire/bin
|
||||
touch /var/ipfire/mpfire/settings
|
||||
install -v -m 755 $(DIR_SRC)/config/mpfire/mpfire.pl /var/ipfire/mpfire/bin
|
||||
install -v -m 644 $(DIR_SRC)/config/mpfire/webradio /var/ipfire/mpfire/
|
||||
chown nobody.nobody /var/ipfire/mpfire/{settings,webradio}
|
||||
chmod 755 /srv/web/ipfire/html/images/mpfire
|
||||
install -v -m 644 $(DIR_SRC)/config/backup/includes/mpfire /var/ipfire/backup/addons/includes/mpfire
|
||||
-mkdir -p /usr/lib/perl5/site_perl/5.36.0/Audio/
|
||||
cp -vrf $(DIR_SRC)/config/mpfire/perl/Audio/MPD* /usr/lib/perl5/site_perl/5.36.0/Audio/
|
||||
cp -vrf $(DIR_SRC)/config/mpfire/perl/Accessor* /usr/lib/perl5/5.36.0/Class/
|
||||
cp -vrf $(DIR_SRC)/config/mpfire/perl/Readonly.pm /usr/lib/perl5/5.36.0/Readonly.pm
|
||||
@$(POSTBUILD)
|
||||
1
make.sh
1
make.sh
@@ -1819,7 +1819,6 @@ build_system() {
|
||||
lfsmake2 perl-NetAddr-IP
|
||||
lfsmake2 dma
|
||||
lfsmake2 alsa
|
||||
lfsmake2 mpfire
|
||||
lfsmake2 guardian
|
||||
lfsmake2 libid3tag
|
||||
lfsmake2 libmad
|
||||
|
||||
@@ -29,7 +29,7 @@ SUID_PROGS = squidctrl sshctrl ipfirereboot \
|
||||
logwatch wioscan wiohelper openvpnctrl firewallctrl \
|
||||
wirelessctrl getipstat qosctrl \
|
||||
redctrl syslogdctrl extrahdctrl sambactrl \
|
||||
smartctrl clamavctrl addonctrl pakfire mpfirectrl wlanapctrl \
|
||||
smartctrl clamavctrl addonctrl pakfire wlanapctrl \
|
||||
setaliases urlfilterctrl updxlratorctrl fireinfoctrl rebuildroutes \
|
||||
getconntracktable wirelessclient torctrl ddnsctrl unboundctrl \
|
||||
captivectrl
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/* This file is part of the IPFire Firewall.
|
||||
*
|
||||
* This program is distributed under the terms of the GNU General Public
|
||||
* Licence. See the file COPYING for details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "setuid.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (!initsetuid())
|
||||
exit(1);
|
||||
|
||||
return run("/var/ipfire/mpfire/bin/mpfire.pl", argv + 1);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# #
|
||||
# This file is part of the IPFire Firewall. #
|
||||
# #
|
||||
# IPFire is free software; you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation; either version 2 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IPFire is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with IPFire; if not, write to the Free Software #
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
# #
|
||||
# Copyright (C) 2007-2024 IPFire-Team <info@ipfire.org>. #
|
||||
# #
|
||||
############################################################################
|
||||
#
|
||||
. /opt/pakfire/lib/functions.sh
|
||||
extract_files
|
||||
chmod 755 /srv/web/ipfire/html/images/mpfire
|
||||
restore_backup ${NAME}
|
||||
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# #
|
||||
# This file is part of the IPFire Firewall. #
|
||||
# #
|
||||
# IPFire is free software; you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation; either version 2 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IPFire is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with IPFire; if not, write to the Free Software #
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
# #
|
||||
# Copyright (C) 2007-2024 IPFire-Team <info@ipfire.org>. #
|
||||
# #
|
||||
############################################################################
|
||||
#
|
||||
. /opt/pakfire/lib/functions.sh
|
||||
make_backup ${NAME}
|
||||
remove_files
|
||||
@@ -1,27 +0,0 @@
|
||||
#!/bin/bash
|
||||
############################################################################
|
||||
# #
|
||||
# This file is part of the IPFire Firewall. #
|
||||
# #
|
||||
# IPFire is free software; you can redistribute it and/or modify #
|
||||
# it under the terms of the GNU General Public License as published by #
|
||||
# the Free Software Foundation; either version 2 of the License, or #
|
||||
# (at your option) any later version. #
|
||||
# #
|
||||
# IPFire is distributed in the hope that it will be useful, #
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
|
||||
# GNU General Public License for more details. #
|
||||
# #
|
||||
# You should have received a copy of the GNU General Public License #
|
||||
# along with IPFire; if not, write to the Free Software #
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
# #
|
||||
# Copyright (C) 2007-2024 IPFire-Team <info@ipfire.org>. #
|
||||
# #
|
||||
############################################################################
|
||||
#
|
||||
. /opt/pakfire/lib/functions.sh
|
||||
extract_backup_includes
|
||||
./uninstall.sh
|
||||
./install.sh
|
||||
Reference in New Issue
Block a user