#!/usr/bin/perl
use warnings;
use strict;
use ARename;

# documentation
=pod

=head1 NAME

arename - automatically rename audio files by tagging information

=head1 SYNOPSIS

arename [OPTION(s)] FILE(s)...

=head1 OPTIONS AND ARGUMENTS

=over 8

=item B<--compare-versions>

Prints the version of the arename script and the version of the Perl module,
that contains most of the code. These versions should be the same. If not,
that would indicate a possibly broken installation.

=item B<--copy> (short option: B<-c>)

Copy files instead of renaming (moving). This can be useful to copy tracks
from your audio archive to a portable device for example.

=item B<--debug> (short option: B<-D>)

Enable debugging output. This is likely to be very noisy. You probably want
to use the I<--verbose> option (setting: I<verbose>) in addition to this.

=item B<--disable-hooks> (short option: B<-H>)

Do not make use of hooks of any sort (neither global nor local ones).

=item B<--disable-profiles> (short option: B<-N>)

Do I<not> use L<configuration profiles|/Configuration profiles> (see below).
Overwrites the B<useprofiles> setting.

=item B<--dryrun> (short option: B<-d>)

Go into dryrun mode. This means, that no action will be taken. B<arename>
will print what it would do, if called without I<-d>.

=item B<--enable-hooks>

Explicitly enable hooks.

=item B<--force> (short option: B<-f>)

Overwrite files if needed.

=item B<--help> (short option: B<-h>)

Display a short help text.

=item B<--list-cfg> (short option: B<-L>)

List the current configuration in the actual configuration format.

=item B<--list-profiles> (short option: B<-S>)

Print a list of profile names defined in the active configuration.
(This is primarily used by the zsh completion for the I<--profile> option.)

=item B<--quiet> (short option: B<-q>)

Make the output way more quiet, when processing files.

This option conflicts with the verbose option.

=item B<--read-local> (short option: B<-l>)

Read a local config file (./.arename.local). Overwrites the B<uselocalrc>
configuration setting.

=item B<--stdin> (short option: B<-s>)

Read filenames from stdin after processing files given on the command line.
It reads one file name per line, which means that file names containing
newlines are not supported.

=item B<--uber-quiet> (short option: B<-Q>)

Be even more quiet (this option will suppress, if a file is skipped.
Except for files, that are skipped because they would overwrite something).

This option implies I<--quiet>.

=item B<--version> (short option: B<-V>)

Display version information.

=item B<--verbose> (short option: B<-v>)

Enable verbose output.

=item B<--rc> E<lt>fileE<gt>

Read I<file> instead of ~/.arenamerc.

=item B<--post-rc> E<lt>fileE<gt>

Read I<file> B<after> ~/.arenamerc and B<before> ./.arename.local.

=item B<--prefix> E<lt>prefixE<gt> (short option: B<-p>)

Define a prefix for destination files.

=item B<--profile> E<lt>profile(s),...E<gt> (short option: B<-P>)

Define a list of one or more profiles to use forcibly, no matter if they
would be activated normally or not.

=item B<--compilation-template> E<lt>templateE<gt> (short option: B<-T>)

Define a template, that will be used for files that contain a compilation
tag.

=item B<--template> E<lt>templateE<gt> (short option: B<-t>)

Define a generic template (for all files that do I<not> contain a
compilation tag).

=item B<--userset> E<lt>I<variable>=I<value>E<gt> (short option: B<-u>)

Set a user defined variable to a given value (see
L<User defined variables> below).

=item I<FILE(s)...>

Input files, that are subject for renaming.

=back

A word about option name stability: With I<arename version 3.0> we are now
using Getopt::Long for parsing command lines options. That change was made,
because the meaningful single letter options where used up. Every option
is available via a I<--long-option>. B<That interface will remain stable>.
So, if you want to use B<arename> in scripts, those are the options you
should use. There are currently no plans of removing or changing any further
short options, but there are no guarantees. If it is indeed better to change
a short option, we will do so.

A list of options that changed from B<arename> I<2.x> to I<3.0> can be
found in the project's CHANGES file.

=head1 DESCRIPTION

B<arename> is a tool that is able to rename audio files by looking at
a file's tagging information. It uses this information to assemble a
consistent destination file name. The user can define the format of the
destination filename by the use of template strings.

Templates can be defined in the L</Configuration files>, by the
I<template> and I<comp_template> settings (See L</SETTINGS> below).

By default, B<arename> will refuse to overwrite destination files,
if the file in question already exists. You can force overwriting by
supplying the B<--force> option.

In order to see what would happen instead of actually modifying files, you
can use the B<--dryrun> option. This way you can avoid problems, that would
occur if the situation (e.g. the information in the files or your
configuration) is not exactly as you expected it.

=head2 Supported file formats

B<arename> currently supports three widely used audio formats, namely
MPEG Layer3, ogg vorbis and flac (Free Lossless Audio Codec). The format,
that B<arename> will assume for each input file is determined by the file's
filename-extension (I<.mp3> vs. I<.ogg> vs. I<.flac>).
The extension check is case-insensitive.

I<.mp3> files may contain different types of tags, namely id3v1 and id3v2.
Id3v1 is a very limited format. Therefore B<arename> will use the id3v2 tag
when it finds it. Which means you should make sure that the id3v2 tag has
all the information you need, if you use files with both id3v1 and id3v2
tags.

=head2 Inputting a *lot* of files

B<arename> can be used to keep the file names of whole audio archives in
sync. However, that means that you will have to tell the script the
location of many files, thousands maybe.

In order to do that you will face the problem, that on most UNIX-like
systems, the length of the argument list for external programs is limited
(recent Linux versions, as an exception, do not have that limitation
anymore).

So, even if your shell can do recursive globbing like ksh or zsh, this will
most likely get you into trouble (for more than just a few files):

  % arename -d **/*.mp3

There are several ways to overcome that limitation, of course.

The first solution is to use B<find> in connection with B<arename>'s I<-s>
option:

  % find . -name "*.mp3" -print | arename -d -s

This will break for file names that contain newlines, because I<--stdin> will
read one file name per line from the standard input stream.

Another way of using B<find> to deal with this problem is to use find's
I<-exec> option:

  % find . -name "*.mp3" -exec arename -d '{}' '+'

This will work for every possible file name. No matter if it has spaces
or newlines in it. The I<+> at the end of the call causes find to call
the external program (B<arename> in this case) with as many arguments as
possible, without exceeding the limit. This requires a POSIXly correct
find. GNU find for instance, did not support the I<+> way for a long time.
If you are stuck with an old version, you can exchange the I<+> with a
I<;> (note, that a semicolon B<must> be quoted in any case), or use GNU's
xargs tool instead.

A last solution for zsh users would be zargs (which requires
'autoload zargs' in your zsh configuration):

  % zargs -- **/*.mp3 -- arename -d

=head1 GENERAL USAGE

When you are first confronted with B<arename> and you try to get started
with the documentation you might argue, that a 1000+ lines manual, that
is not filled with too many examples is hardly starter-friendly.

Therefore, this section was introduced to give you the bare minimum of
information in order to use the program without going through too much
fuzz.

If you are really afraid of documentation, you could of course just read
the output of the I<--help> option and see which options to provide in order
to get what you want. Then again, you will soon be pissed by the weird
default values B<arename> uses.

You will probably want other templates. After all, the ability to have
these expanded strings is one of the points to use B<arename> in the first
place. They are described in the TEMPLATE section; and reading that
section is the minimum effort you will want to go through.

After that, you can open the file I<~/.arenamerc> in your favourite
text editor and resemble the following text (and presumably change the
few values in there to your liking):

  # as soon as you get pissed by too much output, while arename is
  # running, uncomment the following line:
  #quiet

  # now you certainly want your own templates, so define them here
  # one for your normal files
  template &artist - &album - &tracknumber. &tracktitle

  # and another one for files that orignate from compilations
  comp_template va - &album - &tracknumber. &artist - &tracktitle

If you want more automation or more customization, you will not get
around reading the manual below. If you need to solve special
problems, the L</HOOKS> part even further below is for you.

=head1 ENVIRONMENT VARIABLES

=over 8

=item B<ARENAME_LOAD_QUIET>

When set to I<1>, B<arename> will not output any startup messages; not
while reading the configuration or hook files, nor will B<arename> emit
messages about whether it is in copy mode or on a dry-run or similar.

However, if warnings or errors are encoutered while loading the
configuration, those messages are still emitted, of course.

Any other value but I<1> - and that includes ARENAME_LOAD_QUIET being
absent from the environment - will cause B<arename> to start up in
its normal manner.

=back

=head1 FILES

B<arename>'s behaviour can be altered by a number of files it reads when
starting up.

Normal configuration tasks are done in (how convenient)
L</Configuration files>, described below.

If you need more control, or want to solve special problems you are having,
you can do so by supplying Perl code in L</Hook definition files>.

B<arename> can be configured to read configuration files as well as hook
definition files from the current working directory. This feature is
disabled by default, because they can be a security issue on multiuser
systems.

There are no such things as system wide configuration files in B<arename>.

For all setup files B<arename> tries to find (except for the local ones)
four different locations are tried. If the I<$XDG_CONFIG_HOME/arename>
directory exists, B<all> files are expected to be there. If that directory
does not exist, I<~/etc/arename/> and if that is not there I<~/.arename> are
are tried instead. If those directories could not be found either, B<arename>
will try to find the file it is looking for directly in the user's home
directory.

The default for I<$XDG_CONFIG_HOME> is I<~/.config>.

The first setup directory we find always wins. B<arename> does not consider
more than one setup directory.

If, for example, I<~/etc/arename/> exists and we are looking for the normal
L<configuration file|/Configuration files> (see below), but
I<~/etc/arename/rc> could not be found, we do B<not> try to find it in
I<~/.arename/> or the user's home directory.

=head2 Configuration files

B<arename> uses up to three configuration files. As for most programs,
the script will try to read a configuration file, that is located in the
user's I<home directory>. In addition to that, it will try to load I<local>
configuration files, if it finds appropriately named files in the
I<current directory> (and the I<uselocalrc> feature is enabled):

=over 8

=item B<$XDG_CONFIG_HOME/arename/rc>

=item B<~/etc/arename/rc>

=item B<~/.arename/rc>

=item B<~/.arenamerc>

per-user normal configuration file.

=item B<./.arename.local>

per-directory local configuration file (only read if I<uselocalrc> is set
or the I<--read-local> option is given on the command line).

=back

The per-user normal configuration file can be substituted by another file,
if specified via the I<--rc> option.

Last but not least, you can specify an intermediate configuration file,
that is read in between the normal and the per-directory file, via the
I<--post-rc> option.

=head3 File format

The format of the aforementioned files is pretty simple.
It is parsed line by line. Empty lines, lines only containing whitespace
and lines, whose first non whitespace character is a hash character (I<#>)
are ignored.

There are two different types of settings: boolean and scalar settings.

Booleans can be set like this:

  <setting> [true|false]

If the value is omitted, I<true> is assumed. I<true> and I<false> are
recognized case insensitively, and a value of I<1> is synonymous to I<true>,
as is I<0> to I<false>.

Scalar settings are done in a very similar way:

  <setting> <value>

If the value is omitted, string values will be set to an empty string and
numeric values will be set to zero.

In both cases, setting and value are separated by one or more whitespace
characters. The value will be the rest of the line (all of it, including
trailing whitespace).

If the value part starts with a backslash, that backslash is left out of the
value. That makes it possible to define templates with leading whitespace.

If a line contains only a string within square brackets, that string is the
start of a section. Section names are matches for starts of file names.
That means, the settings following such a section definition will only
applied for input file names that start with the same string as the section
name. Where file name means the string, handed over to B<arename>. The string
I<~/> at the beginning of a section name is expanded to the user's home
directory.

You may start as many sections as you would like.

A section named I</foo/bar/> supersedes a section named I</foo/> for a file
named I</foo/bar/baz.ogg>. So, the longest match wins.

Another possible configuration file entry is a user variable, which is
defined via the B<set> command. These settings are very different from the
normal settings. Therefore, they are defined in a different way. That way
is described in the L</User defined variables> subsection below.

Last but not least, you may define so called
L<profiles|/Configuration profiles>, see below.

=head3 Configuration profiles

Profiles are a very flexible and context sensitive way of using multiple
configuration files at once. With profiles, local configuration files (and
local hook definition files) can be substituted in a secure way; even on
multi-user systems.

Reading local files (configs and hook-files) is still supported for backwards
compatibility (see I<uselocalrc> and I<uselocalhooks> L<options|/SETTINGS>).
However, you are strongly encouraged to use profiles whenever you can.

As normal configuration files and global hook-files, profile-related files are
searched in one of the setup directories described above. They are using the
following naming conventions:

=over 8

=item B<$XDG_CONFIG_HOME/arename/profile.PROFILENAME>

=item B<~/etc/arename/profile.PROFILENAME>

=item B<~/.arename/profile.PROFILENAME>

=item B<~/.arename.PROFILENAME>

Profile related configuration files; read if I<PROFILENAME> is active.

They are read after a intermediate config file defined by I<--post-rc> and
a local config file (if enabled).

=item B<$XDG_CONFIG_HOME/arename/profile.PROFILENAME.hooks>

=item B<~/etc/arename/profile.PROFILENAME.hooks>

=item B<~/.arename/profile.PROFILENAME.hooks>

=item B<~/.arename.PROFILENAME.hooks>

Profile related L</Hook definition files> (see below for details); read if
I<PROFILENAME> is active.

These files are read, between global and local hook-definition files.

=back

In order to define profiles, you need to use the I<profile> keyword:

  profile <name> <pattern>

Where I<name> is a string, that is used in the place of B<PROFILENAME>
in the file location lists above. This name may contain of the following
character range: B<a-zA-Z0-9_->

I<pattern> is part of a Perl regex pattern (see I<perlreref> and I<perlretut>
manpages). The pattern will be anchored at the beginning and is open at
the end, somewhat like this pseudocode:

  if ($working_directory =~ m/^PATTERN/) { use_this_profile(); }

Example:

  profile music /mnt/audio/music/

Will cause the profile I<music> to be active when the working directory is
I</mnt/audio/music/> or below. So, do not be afraid. You can use profiles
without understanding regular expressions.

Like many other values in B<arename>'s configuration, a leading backslash of
a pattern will be ignored to allow patterns, that start in white spaces.
Furthermore, if a pattern starts in I<~/>, that string is replaced by the
user's home directory.

You may add as many patterns to a profile name, as you want:

  profile music /mnt/audio/music/
  profile music /mnt/extern/audio/music/

The above activates the I<music> profile in I</mnt/audio/music/> and
I</mnt/extern/audio/music/>, for example.

More than one profile can be activated at the same time. If that is true,
the according configuration files are read in lexical order.

=head3 Sections versus Profiles

Since B<arename> provides two context sensitive configuration facilities,
you might ask yourself when to use which, when you are confronted with both
for the first time.

First of all, I<profiles> are more powerful. They may even introduce new
hooks for B<arename> to use. But that is not the conceptual difference
between the two.

I<sections> are sets of configuration settings, that are considered for
B<each and every> input file and they are B<only> enabled for input files,
whose name matches the section name.

I<profiles> on the other hand are sets of configuration and hook-definition
files, whose inclusion in the current B<arename> run is decided at the
B<beginning> of the program's execution (not for every input file) - namely,
if the name of the current working directory matches one of the profile's
patterns.

That means, that if you need to introduce slight configuration changes based
on an B<input file's name> you want to use a I<section>.

If you need to make broader configuration changes, considering the name of
the B<current working directory>, I<profiles> are the way to go.

Of course, profile configuration files may introduce new sections, too.

=head2 Configuration file example

  # switch on verbosity
  verbose

  # canonicalize file names before working with them
  canonicalize

  # the author is crazy! use a sane template by default. :-)
  template &artist - &album (&year) - &tracknumber. &tracktitle

  # activate the 'music' profile below /mnt/audio/music/.
  profile music /mnt/audio/music/

  # force files from /foo/bar/ to stay below that directory
  [/foo/bar/]
  prefix /foo/bar

=head2 Hook definition files

=over 4

=item B<$XDG_CONFIG_HOME/arename/hooks>

=item B<~/etc/arename/hooks>

=item B<~/.arename/hooks>

=item B<~/.arename.hooks>

Defines global hooks, that are in effect in every directory if the I<usehooks>
option is set to B<true>.

=item B<./.arename.hooks.local>

This allows you to define special hooks, that will only be applied for processes
that run in the directory the local file is found (and if the I<uselocalhooks>
option is set to B<true>).

=back

For details about hooks in B<arename>, see L</HOOKS> below.

=head1 SETTINGS

The following settings are supported in all configuration files.

Not all of them are usable in I<sections>. The ones you can use in
sections are: All I<default_*> options, I<force>, I<prefix>, I<sepreplace>,
I<tnpad>, I<comp_template> and I<template>.

=over 8

=item B<canonicalize>

If set, a given file name will be transformed to its cleaned up absolute
path. You may want to set this, if you are using sections in the
configuration. If you do not use sections, all this will give you is a
performance penalty. (default value: I<false>)

=item B<checkprofilerc>

If set, B<arename> will check if there is a configuration file for a
profile as soon as it reads a profile definition in the setup and B<only>
consider the profile if it found the according config file. Profiles
without config file will cause a warning if this is set, which may cause the
I<dryrun> option to be set if the I<warningsautodryrun> option is set.

If unset, profiles without config file will not cause warnings. You will
see messages about missing configuration files, if a profile without config
file is active. (default: I<true>)

=item B<comp_template>

Defines a template to use with files that provide a compilation tag
(for 'various artist' CDs, for example). This setting can still be
overwritten by the B<--compilation-template> command line option. (default
value: I<va/&album/&tracknumber - &artist - &tracktitle>)

=item B<debug>

Enable debugging by default. This is probably only useful, if you want
debugging to be enabled as soon as possible, when you are trying to chase
bugs. Do not set this for normal execution. (default value: I<false>)

=item B<default_*>

default_artist, default_album, default_compilation, default_genre,
default_tracknumber, default_tracktitle, default_year

Defines a default value, for the given tag in files, that lack this
information. (default value: I<undefined>)

=item B<hookerrfatal>

If this is set to false, arename will continue execution even if
reading, parsing or compiling a hooks file failed. (default value:
I<false>)

=item B<prefix>

Defines a prefix for destination files. Setting this to '/foo/bar' results
in destination files named '/foo/bar/Expanded Template.ogg'

This setting can still be overwritten by the B<--profile> command line option.
(default value: I<.>)

=item B<quiet>

Switches on quietness. This makes the output a lot more compact. (default
value: I<off>)

=item B<quiet_skip>

Be quiet about skips. Even if I<quiet> is set, B<arename> will
report files it does not process, because renaming would not change their
names. With this option, these skipped files will not be reported. This
implicitly sets 'quiet'. (default value: I<off>)

=item B<sepreplace>

Tagging information strings may contain slashes, which is a pretty bad
idea on most file systems. Therefore, you can define a string, that replaces
slashes with the value of this setting. (default value: I<_>)

=item B<template>

Defines a template to use with files that do not provide a compilation tag
(or where the compilation tag and the artist tag are exactly the same).
This setting can be overwritten by the B<--compilation-template> command
line option. (default value:
I<&artist[1]/&artist/&album/&tracknumber - &tracktitle>)

=item B<tnpad>

This defines the width, to which the track number field is padded with zeros
on the left. Setting this to zero disables padding. (default value: I<2>)

=item B<usehooks>

If set to true, use hooks defined in B<~/.arename.hooks>.
(default value: I<true>)

=item B<uselocalhooks>

If set to true, use hooks defined in B<./.arename.hooks.local>.
(default value: I<false>)

=item B<uselocalrc>

If set to true, read a local configuration file (B<./.arename.local>),
if it exists. (default value: I<false>)

=item B<useprofiles>

If set to true, configuration profiles will be used. If false, they are not.
(default value: I<true>)

=item B<verbose>

Switches on verbosity by default. This makes B<arename>'s output really
noisy. This is probably only useful for debugging or if you are really
interested in what is going on. (default value: I<false>)

=item B<warningsautodryrun>

Switches on the I<dryrun> option (if not enabled already), as soon as the
configuration file parser encounters non-fatal warnings. This option was
introduced to avoid destructive behaviour due to incorrect lines in any
of the configuration files. (default value: I<true>)

=back

=head2 User defined variables

You can use the B<set> command in arenamerc files. This way the user can
define his own variables. The namespace is seperate from B<arename>'s
normal settings. (That means, you cannot, for example,  overwrite the
internal I<template> variable with this command.)

The synax is quite simple (and B<different> to normal settings on purpose!):

B<set> I<varname> = I<value>

There may be an arbitrary amount of whitespace around the equal sign
(including no whitespace at all). If you want to have a value that
starts in a whitespace character, you may start the value with a
backslash character (just like with the normal settings, a leading
backslash is always ignored).

You may also set user defined variables on the command line by using the
I<--userset> option:

  % arename --userset variable0=value
  % arename -u variable0=value

User defined variables are useful to make hooks configurable (see
L</HOOKS> below).

It is, however, not allowed to define this kind of variable within the scope
of a section. Doing so will trigger a warning, which will pull B<arename>
into I<dryrun>, depending on whether I<warningsautodryrun> is set or not.

=head1 TEMPLATE FORMAT

B<arename>'s templates are quite simple, yet powerful.

At simplest, a template is just a fixed character string. However, that would
not be exactly useful. So, the script is able to expand certain expressions
with information gathered from the file's tagging information.

The expressions can have two slightly different forms:

=over 8

=item B<&>I<identifier>

The simple form.

=item B<&>I<identifier>B<[>I<length>B<]>

The "complex" form. The I<length> argument in square brackets defines the
maximum length, to which the expression should be expanded.

That means, if the Artist of a file reveals to be 'I<Frank Zappa>', then
using 'B<&artist[1]>' will expand to 'I<F>'.

=back

=head2 Available expression identifiers

The data, that is expanded is derived from tagging information in
the audio files. For I<.ogg> and I<.flac> files, the tag checking
B<arename> does is case insensitive and the first matching tag
will be used.

=over 8

=item B<album>

Guess.

=item B<artist>

Guess again.

=item B<compilation>

For I<.ogg> and I<.flac> this is filled with information found in the
'albumartist' tag. For I<.mp3> this is filled with information from the
id3v2 TPE2 frame. If the mp3 file only provides a id3v1 tag, this is not
supported.

=item B<genre>

The genre or content type of the audio file.

=item B<tracknumber>

The number of the position of the track on the disc. Obviously. However, this
can be in the form of '12' or '12/23'. In the second form, only the part left
of the slash is used. The tracknumber is a little special, as you can define
to what width it should be padded with zeros on the left (see I<tnpad> setting
in L</SETTINGS>).

=item B<tracktitle>

Well...

=item B<year>

Year (id3v1), TYER (id3v2) or DATE tag (.ogg/.flac).

=back

=head1 EXIT STATUS

B<arename> returns zero if everything went fine; non-zero on fatal
problems. This may change in future versions.

=head1 HOOKS

Before we start, a word of warning: Hooks can solve a lot of problems.
That amount of flexibility comes at its price. All data passed to
hook functions are B<references> to the B<actual data> in the script
(except for the namespace argument, which is a copy). If you write
hooks carelessly, arename will get back at you! HOOKS ARE A BIG
HAMMER, THAT CAN CRUSH PROBLEMS AS WELL AS LIMBS!

I<You have been warned!>

=head2 Discussion

The reason for implementing hooks was to have a simple way of post
processing tags, filenames etc. without having to invent own magic in
the configuration files, when Perl has regular expressions on steriods
anyway. Hooks can do more then pure pre and post processing, because
they are called in numerous places and give broad access to the script's
data structures. Still, post processing is probably the most useful
feature they implement.

Hooks are just Perl subroutines, which are defined in one of two files
(see L</FILES>). They are run at certain events during the
execution of arename. The contents of the argument list for each hook
depends on what hook is called (see the L</List of hook events> below).
However, the first argument (argument zero aka. $_[0]) to all hooks is
the hook namespace, the subroutine is called in.

The global hooks file is read before the local one, which means, that
this local file may overwrite and extend the definitions from the global
file, as much as Perl permits. This also means, that hooks from the
local file are run I<after> the ones from the global file (unless you
are using your own method of registering hooks; but if you do so, you
know what you are doing anyway).

Subroutines must be registered to arename, to be known as hooks.
Once registered, a subroutine can be removed from the known hooks,
if requested (see L</Utility subroutines> below).

The keys in various data hashes passed to the hooks can be one of
the following: I<album>, I<artist>, I<compilation>, I<genre>,
I<tracknumber>, I<tracktitle>, I<year>.

=head2 Utility subroutines

=head3 Registration subroutines

There are two subroutines, that are used to tell arename about
subroutines, you defined that shall become hooks.

=over 4

=item B<register_hook>(I<event>, I<coderef>)

Registers a I<code reference> (read: your subroutine) for the given
I<event>. Example: register_hook('startup', \&custom_banner);

=item B<remove_hook>(I<event>, I<coderef>)

Removes B<all> entries of the I<code reference> for the given
I<event>. Example: remove_hook('startup', \&custom_banner);

If the coderef was added more than once, all entries are removed.

=back

=head3 File access and manipulation

The currently processed file name can be accessed via two subroutines:

=over 4

=item B<get_file>()

Returns the current file name as a string. This way, you can get the
name of the currently processed file in every hook.

=item B<set_file>(I<file name string>)

This gives you the opportunity of manipulating the current file name.
Be careful using this, because if you break the file name, B<arename>
cannot work properly.

=back

With these, you could even change the file name of the processed file,
while B<arename> works on it (which you really should only do, if you
know what you are doing).

=head3 User-defined-variable subroutines

Hooks can also use the data from user defined variables, via their Perl
interface:

=over 4

=item B<user_get>(I<setting>)

Returns the current value of I<setting>. This is always a scalar value.

=item B<user_set>(I<setting>, I<value>)

Change the value of I<setting> to I<value>.

=back

Here is an example for user defined settings:

  # Assume, the user set the myvar-variable to "bar" in his
  # configuration file
  my $foo = user_get('myvar');    # $foo is now "bar"
  user_set('foo', "bar, baz");
  my $foo = user_get('myvar');    # $foo is now "bar, baz"

=head3 API for accessing to arename's internal configuration

You can also access the configuration data of B<arename> itself:

=over 4

=item B<get_opt>(I<setting>)

Returns the current value of I<setting>. This is always a scalar value.

=item B<set_opt>(I<setting>, I<value>)

Change the value of I<setting> to I<value>.

=back

A list of settings B<arename> will use: canonicalize, dryrun, force,
hookerrfatal, oprefix, prefix, quiet, quiet_skip, readstdin, shutup,
sepreplace, tnpad, usehooks, uselocalhooks, uselocalrc, verbose,
comp_template and template.

If you want to actually change these settings, you should have a profound
knowledge of B<arename>'s internals. Be careful.

=head3 API for default_* settings

If you need to access the current values of the I<default_*> settings:

=over 4

=item B<get_defaults>(I<tagname>)

Returns the value of default_I<tagname>.

=item B<get_default_keys>()

Returns a lexically sorted array of tag names of currently set I<default_*>
values.

=item B<set_default>(I<tagname>, I<value>)

Sets the value of default_I<tagname> to I<value>.

=back

=head3 Output subroutines

For output, you can use the following functions, the rest of B<arename>
uses as well:

=over 4

=item B<oprint>(I<args>, ...)

Print to the standard output stream. This can be called the same way as
Perl's usual I<print> subroutine.

=item B<owarn>(I<args>, ...)

Print to the standard error stream.

=back

=head3 Miscellaneous subroutines

And finally, a few miscellaneous functions ARename.pm provides, that
might be of interest.

=over 4

=item B<choose_template>(I<data hash reference>)

Return the appropriate template (I<normal> versus I<compiliation> template)
by the data in the referenced data hash.

=item B<expand_template>(I<template string>, I<data hash reference>)

Return the expanded version of I<template string>. The information, that
is used to do the expansion is taken from the referenced data hash.

Keep in mind that this function calls hooks itself. Avoid endless loops!
See L</Hooks when expanding the template> for details.

=item B<ensure_dir>(I<directory>)

Makes sure I<directory> exists. Think: mkdir -p I<directory>

=item B<file_eq>(I<file0>, I<file1>)

Checks if the name I<file0> and the name I<file1> point to the same file.
Returns I<0>, if one of the file names does not exist or if the files do
not point to the same file, I<1> otherwise.

Dies if it cannot stat one of the given files.

=item B<tag_supported>(I<tagname>)

Returns I<1> if the tag I<tagname> is supported by arename, I<0> otherwise.

=item B<xrename>(I<src>, I<dest>)

Renames I<src> to I<dest>. Works across file systems, too. Dies
if something fails.

=back

=head2 List of hook events

This is a complete list of hooks events with descriptions.

The first argument (argument number "zero") for every hook is the
name space they are called in. To find out the name of the currently
processed file, use the I<get_file>() subroutine described above.

=head3 Hooks in the main loop

These hooks are called at the highest level of the script.

=over 4

=item B<canonicalize>

This is called in the middle of the file name canonicalization process
(but B<only> it is enabled via the I<canonicalize> setting).

Get the current file name via I<get_file()>. The canonicalized file name
is handed to you via the hook's arguments. The value from this argument
will be assigned to the processed filename after the execution of this
hook.

I<Arguments>: B<1:> canonicalized file name

=item B<next_file_early>

Called at the start of the main loop I<before> any file checks and
canonicalizations (if enabled) are done.

I<Arguments>:

=item B<next_file_late>

Called in the main loop I<after> the file checks and canonicalizations
are done.

By file checks, checks for read-access and for symlinks are meant. B<arename>
will refuse to process symlinks and files it cannot read.

I<Arguments>:

=item B<file_done>

Called in the main loop I<after> the file has been processed (unless
B<filetype_unknown> was triggered, see below).

I<Arguments>:

=item B<filetype_unknown>

Called in the main loop I<after> the file was tried to be processed but
the file type (the extension, specifically) was unknown.

I<Arguments>:

=back

=head3 Hooks in the renaming procedure

When all data has been gathered, B<arename> will go on to actually
rename the files to their new destination name (which will be generated
in the process, see L</Hooks when expanding the template> below).

=over 4

=item B<pre_apply_defaults>

This is the first action to be taken in the renaming process. It is
called even before the default values are applied.

I<Arguments>: B<1:> data hash, B<2:> file extension

=item B<pre_template>

Called I<before> template expansions have been done.

I<Arguments>: B<1:> data hash, B<2:> file extension

=item B<post_template>

Called I<after> the template has been expanded and the new file name
has been completely generated (including the destination directory
prefix).

I<Arguments>: B<1:> data hash, B<2:> file extension
B<3:> the generated new filename (including directory prefix and file
extension)

=item B<post_ensure_dir>

The destnation directory for the new file name may contain sub directories,
which currently do not exist. This hook is called I<after> it is ensured,
every directory portion exists.

I<Arguments>: B<1:> data hash, B<2:> file extension
B<3:> the generated new filename (including directory prefix and file
extension)

=item B<post_rename>

This is the final hook in the actual renaming process. The file has been
renamed at this point.

I<Arguments>: B<1:> data hash, B<2:> file extension
B<3:> the generated new filename (including directory prefix and file
extension)

=back

=head3 Hooks when expanding the template

These hooks are called when the template string is filled with the data
from tags in the audio files. All file type specific actions will have
been taken care of already. That makes these hooks probably most useful
for post processing tags, the template and file names.

=over 4

=item B<pre_expand_template>

Called before any expansions are done.

I<Arguments>: B<1:> the template string, B<2:> the data hash

=item B<expand_template_next_tag>

This hook is triggered when the next identifier in the template string
is processed. At this point it is already verified, that there is an
according tag in the data hash to fill in the identifier's space.

I<Arguments>: B<1:> the template string, B<2:> the tag's name
B<3:> the value of the length modifier in the template (zero, if
unspecified) B<4:> the data hash

=item B<expand_template_postprocess_tag>

This hooks is triggered after all internal processing of the replacement
token is done (directory seperators are replaced; tracknumbers are padded
up).

I<Arguments>: B<1:> the template string, B<2:> the text token, that will
replace the identifier in the template, B<3:> the tag's name B<4:> the
value of the length modifier, B<5:> the data hash

=item B<post_expand_template>

Called after all expansions have been done, right before the the resulting
string is returned.

I<Arguments>: B<1:> the template string (fully expanded), B<2:> the data
hash

=back

=head3 Hooks when gathering information

These hooks are triggered while the tag information is extracted from
the audio files arename is processing. Due to the differing nature
of the the involved backends, these are slightly different from file type
to file type.

Specifically, the tag for .ogg and .flac files are read one after another
(the tags in these files are pretty much the same, hence they are processed
exactly the same), whereas tags in .mp3 files are read all at the same
time.

=over 4

=item B<pre_process_flac>

I<.flac only!>

Called I<before> a flac file is processed.

I<Arguments>:

=item B<post_process_flac>

I<.flac only!>

Called I<after> a flac file is processed.

I<Arguments>:

=item B<pre_process_ogg>

I<.ogg only!>

Called I<before> an ogg file is processed.

I<Arguments>:

=item B<post_process_ogg>

I<.ogg only!>

Called I<after> an ogg file is processed.

I<Arguments>:

=item B<pre_handle_vorbistag>

I<.ogg and .flac only!>

Triggered I<before> any processing of a certain tag. It is not ensured
that the tag is even among the supported tags at this point.

I<Arguments>: B<1:> tag name, B<2:> tag value, B<3:> data hash

=item B<post_handle_vorbistag>

I<.ogg and .flac only!>

Triggered I<after> a certain tag was processed.

This hook is only reached if the currently processed tag is in fact among
the tags supported by B<arename>.

I<Arguments>: B<1:> tag name, B<2:> tag value, B<3:> the internal name for
the tag (also used as the key in the data hash), B<4:> data hash

=item B<pre_process_mp3>

I<.mp3 only!>

Called I<before> an mp3 file is processed.

I<Arguments>:

=item B<post_process_mp3>

I<.mp3 only!>

Called I<after> an mp3 file is processed.

I<Arguments>:

=item B<pre_handle_mp3tag>

I<.mp3 only!>

Called I<before> data from the mp3 object is copied to the data hash.

I<Arguments>: B<1:> the mp3 object, B<2:> data hash

=item B<post_handle_mp3tag>

I<.mp3 only!>

Called I<after> data from the mp3 object has been copied to the data hash.

I<Arguments>: B<1:> the mp3 object, B<2:> data hash

=back

=head3 Miscellaneous hooks

=over 4

=item B<apply_defaults>

This is triggered before values from the default_* settings are applied
to missing values in the audio file. This hook is I<only> run if a
default value for a tag will be used!

I<Arguments>: B<1:> data hash, B<2:> current key

=item B<pre_method>

This hook is called after a method for a file type is choosen but
I<before> the method was executed.

I<Arguments>: B<1:> method name

=item B<post_method>

Called after a method for a file type was executed.

I<Arguments>: B<1:> method name

=item B<startup>

Called directly after all the module initialisation is done, at the very
start of the script. Configuration files will have been read, as well as
hook files (obviously) and command line options will have been handled at
this point already.

This hook may be useful for postprocessing the configuration as well as
for debugging.

I<Arguments>: B<1:> program name, B<2:> its version, B<3:> configuration
hash, B<4:> hash of extensions, that point the the according method for
the file type B<5:> array of supported tags, B<6:> the program's argument
list

=item B<normal_quit>

Called at the end of the script. This is reached if nothing fatal happened.

I<Arguments>: B<1:> the program's argument list

=back

=head2 Example

This is a very simple example for a hook file, that prints a custom
banner and replaces all whitespace in the expanded template with
underscores:

  sub my_banner {
      oprint "Hello World.\n";
  }
  register_hook('startup', \&my_banner);

  sub replace_spaces_by_underscore {
      my ($templateref, $datref) = @_;
      $$templateref =~ s/\s+/_/g;
  }
  register_hook('post_expand_template',
      \&replace_spaces_by_underscore);

Further examples can be found in the B<arename.hooks> file of the
distribution.

=head1 SEE ALSO

L<Ogg::Vorbis::Header>, L<Audio::FLAC::Header> and L<MP3::Tag>.

=head1 VERSION

This manual describes B<arename> version I<3.1>.

=head1 AUTHOR

Frank Terbeck E<lt>ft@bewatermyfriend.orgE<gt>,

Please report bugs.

=head1 LICENCE

 Copyright 2007, 2008, 2009
 Frank Terbeck <ft@bewatermyfriend.org>, All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions
 are met:

   1. Redistributions of source code must retain the above
      copyright notice, this list of conditions and the following
      disclaimer.
   2. Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials
      provided with the distribution.

  THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS OF THE
  PROJECT BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

=cut

my ( $NAME, $VERSION ) = qw( arename 3.1 );

# Initialisation

ARename::set_nameversion($NAME, $VERSION);
ARename::set_default_options();
ARename::read_cmdline_options();
ARename::read_rcs();
ARename::read_cmdline_options_late();

if (ARename::cmdopts('S')) {
    ARename::dump_profiles();
    exit 0;
}

if (ARename::cmdopts('L')) {
    ARename::dump_config();
    exit 0;
}

ARename::read_hook_files();
ARename::set_default_methods();
ARename::startup_hook();

# status messages and cosmetics

sub dvr_newline {
    if (   ARename::get_opt("dryrun")
        || ARename::get_opt("readstdin")
        || ARename::get_opt("verbose")) {
        print "\n";
    }
    return 1;
}

# clear the line prefix, if we're running quietly.
ARename::set_opt("oprefix", q{}) if (ARename::get_opt("quiet"));

if (!ARename::get_opt('load_quiet')) {
    print "\n";
    print "+++ We are on a dry run!\n"  if (ARename::get_opt("dryrun"));
    print "+++ copymode enabled!\n"     if (ARename::get_opt("copymode"));
    print "+++ Running verbosely.\n"    if (ARename::get_opt("verbose"));
    print "+++ Reading stdin for filenames (after \@ARGV).\n"
                                        if (ARename::get_opt("readstdin"));
    dvr_newline();
}

foreach my $file (@ARGV) {
    ARename::process_file($file);
}

if (ARename::get_opt("readstdin")) {
    while (<STDIN>) {           ## no critic
                                # *STDIN should be the right thing to do here.
        chomp;
        ARename::process_file($_);
    }
}

ARename::run_hook('normal_quit', \@ARGV);
