.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "MP3INFO2 1p" .TH MP3INFO2 1p "2022-12-30" "perl v5.36.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" mp3info2 \- get/set MP3 tags; uses MP3::Tag to get default values. .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& # Print the information in tags and autodeduced info \& mp3info2 *.mp3 \& \& # In addition, set the year field to 1981 \& mp3info2 \-y 1981 *.mp3 \& \& # Same without printout of info, recursively in the current directory \& mp3info2 \-R \-p "" \-y 1981 . \& \& # Do not deduce any field, print (normalized) info from the tags only \& mp3info2 \-C autoinfo=ID3v2,ID3v1 *.mp3 \& \& # As above, but without normalization/autofill, the raw information in tags \& mp3info2 \-N *.mp3 \& \& # As above, but only with ID2v1 tag read \& mp3info2 \-NC autoinfo=ID3v1 *.mp3 \& \& # Get artist from CDDB_File, autodeduce other info, write it to tags \& mp3info2 \-C artist=CDDB_File \-u *.mp3 \& \& # For title, prefer information from .inf file; autodeduce rest, update \& mp3info2 \-C title=Inf,ID3v2,ID3v1,filename \-u *.mp3 \& \& # Same, and get the artist from CDDB file \& mp3info2 \-C title=Inf,ID3v2,ID3v1,filename \-C artist=CDDB_File \-u *.mp3 \& \& # Write a script for conversion of .wav to .mp3, autodeducing tags \& mp3info2 \-p "lame \-h \-\-vbr\-new \-\-tt \*(Aq%t\*(Aq \-\-tn %n \-\-ta \*(Aq%a\*(Aq \-\-tc \*(Aq%c\*(Aq \-\-tl \*(Aq%l\*(Aq \-\-ty \*(Aq%y\*(Aq \*(Aq%f\*(Aq\en" *.wav >xxx.sh .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" The program prints a message summarizing tag info (obtained via MP3::Tag module) for specified files. .PP It may also update the information in \s-1ID3\s0 tags. This happens in three different cases. .IP "\(bu" 4 If the information supplied in command-line options \f(CW\*(C`t a l y g c n\*(C'\fR differs from the content of the corresponding \s-1ID3\s0 tags (or there is no corresponding \s-1ID3\s0 tags). .IP "\(bu" 4 If options \f(CW\*(C`\-d\*(C'\fR or \f(CW\*(C`\-F\*(C'\fR were given. .IP "\(bu" 4 if \f(CW\*(C`MP3::Tag\*(C'\fR obtains the info from other means than \s-1MP3\s0 tags, and \&\f(CW\*(C`\-u\*(C'\fR forces the update of the \s-1ID3\s0 tags. .PP (All these ways are disabled by \f(CW\*(C`\-D\*(C'\fR option.) ID3v2 tag is written if needed, or if \f(CW\*(C`\-2\*(C'\fR option is given. (Automatic fill-in of deduceable fields (via the method \fBid3v2_frames_autofill()\fR) is performed unless \f(CW\*(C`\-d\*(C'\fR or \f(CW\*(C`\-N\*(C'\fR options are given.) .PP The option \f(CW\*(C`\-u\*(C'\fR writes (\f(CW\*(C`u\*(C'\fRpdates) the fetched information to the \&\s-1MP3 ID3\s0 tags. This option is assumed if there are command-line options which explicitly set tag elements (\f(CW\*(C`\-a\*(C'\fR, \f(CW\*(C`\-t\*(C'\fR etc., and \f(CW\*(C`\-F\*(C'\fR, \f(CW\*(C`\-d\*(C'\fR). (Effects of this option may be overridden by giving \f(CW\*(C`\-D\*(C'\fR option.) If \f(CW\*(C`\-2\*(C'\fR option is also given, forces write of ID3v2 tag even if the info fits the ID3v1 tag (in addition, this option enables auto-update of \*(L"personal name\*(R" fields, and corresponding titles according to values of \f(CW\*(C`translate_person\*(C'\fR, \f(CW\*(C`person_frames\*(C'\fR etc. configuration settings; see \*(L"Normalization of fields\*(R"). This option is ignored if no change to tags is detected; however, one can force an update by repeating this option (useful if you expect the change the \&\*(L"format\*(R" of the tag, as opposed to its \*(L"content\*(R"). .PP The option \f(CW\*(C`\-p\*(C'\fR prints a message using the next argument as format (by default \f(CW\*(C`\e\e\*(C'\fR, \f(CW\*(C`\et\*(C'\fR, \f(CW\*(C`\en\*(C'\fR are replaced by backslash, tab and newline; governed by the value of \f(CW\*(C`\-E\*(C'\fR option); see \&\*(L"interpolate\*(R" in MP3::Tag for details of the format of \fBsprintf()\fR\-like escapes. If no option \f(CW\*(C`\-p\*(C'\fR is given, message in default format will be emitted. The value of option \f(CW\*(C`\-e\*(C'\fR is the encoding used for the output; if the value is a number, system-specific encoding is guessed (and used for the output if the bit 0x1 is set); if the bit 0x2 is set, then command line options are assumed to be in the guessed encoding; if the bit 0x4 is set, then command line arguments are assumed to be in the guessed encoding. If the bit 0x8 is set, the encoding/decoding configuration of file input/output of \f(CW\*(C`MP3::Tag\*(C'\fR is redone with the the detected encoding. Use the value \f(CW\*(C`binary\*(C'\fR to do binary output. .PP In presence of \f(CW\*(C`\-U\*(C'\fR option the default for \f(CW\*(C`\-e\*(C'\fR is \f(CW15\fR, and the decoding/encoding processing happens as if \s-1LANG\s0 is set for \f(CW\*(C`UTF\-8\*(C'\fR encoding. (For example, for \f(CW\*(C`\-Ue 1\*(C'\fR the \f(CW\*(C`STDOUT\*(C'\fR the output message of this script happens in \s-1UTF\-8\s0 mode, which makes it easier to detect decoding/encoding errors in tags.) .PP With option \f(CW\*(C`\-D\*(C'\fR (dry run) no update is performed, no matter what the other options are. With this option, no parsing of tags is performed unless needed. .PP Use options .PP .Vb 1 \& t a l y g c n .Ve .PP to overwrite the information (title artist album year genre comment track-number) obtained via \f(CW\*(C`MP3::Tag\*(C'\fR heuristics (\f(CW\*(C`\-u\*(C'\fR switch is implied if any one of these arguments differs from what would be found otherwise; use \f(CW\*(C`\-D\*(C'\fR switch to disable auto-update). By default, the values of these options are not \f(CW\*(C`%\*(C'\fR\-interpolated; this may be changed by \&\f(CW\*(C`\-E\*(C'\fR option. .PP The option \f(CW\*(C`\-d\*(C'\fR should contain the comma-separated list of ID3v2 frames to delete. A frame specification is the same as what might be given to \f(CW"%{...}"\fR frame interpolation command, e.g., \f(CW\*(C`TIT3\*(C'\fR, \&\f(CW\*(C`COMM03\*(C'\fR, \f(CW\*(C`COMM(fra)[short title]\*(C'\fR; the difference with modify-access is that \fB\s-1ALL\s0\fR (and not the \fBfirst\fR of) matching frames are deleted. (Option \-d may be repeated.) .PP For example, \f(CW\*(C`\-d APIC\*(C'\fR would remove all picture frames. In addition, if the list contains \f(CW\*(C`ID3v1\*(C'\fR or \f(CW\*(C`ID3v2\*(C'\fR, whole tags will be deleted. .PP Likewise, the option \f(CW\*(C`\-F\*(C'\fR allows setting of arbitrary \f(CW\*(C`ID3v2\*(C'\fR frames: if one needs to set one frame, use the directive \f(CW\*(C`FRAME_spec=VALUE\*(C'\fR: .PP .Vb 1 \& \-F TIT2=The_new_Title .Ve .PP Again, on modify, \fB\s-1ALL\s0\fR matching frames are deleted first, so be carefull with .PP .Vb 1 \& \-F COMM=MyComment .Ve .PP Option \f(CW\*(C`\-F\*(C'\fR may be repeated to set more than one frame. If configuration variable \f(CW\*(C`empty\-F\-deletes\*(C'\fR is \s-1TRUE\s0 (default), empty arguments will delete the frame. .PP One can replace \f(CW\*(C`FRAME_spec=VALUE\*(C'\fR by \f(CW\*(C`FRAME_spec < FILE\*(C'\fR; in this case the value to set is read from the file named \fI\s-1FILE\s0\fR; if the frame is text-only (meaning: at most \f(CW\*(C`[encoded]Text URL Language Description\*(C'\fR fields are present), the file is read in text mode (and with starting/trailing whitespace stripped), otherwise it is read in binary mode. (Whitespace is required about the \f(CW\*(C`<\*(C'\fR signs.) If \&\f(CW\*(C`<\*(C'\fR is replaced by \f(CW\*(C`?<\*(C'\fR, the value is set only if frame is not yet present, and if the file exists; if replaced by \f(CW\*(C`>\*(C'\fR, the value (if present) is written to \fI\s-1FILE\s0\fR (creation of intermediate directories is controlled by configuration option \f(CW\*(C`frames_write_creates_dirs\*(C'\fR, the default is \s-1FALSE\s0). .PP Additionally, \f(CW\*(C`FRAME_spec\*(C'\fR may be one of \f(CW\*(C`ID3v1\*(C'\fR or \f(CW\*(C`ID3v2\*(C'\fR or \f(CW\*(C`TAGS\*(C'\fR; in this case, whole tags are written or read. For example, for \f(CW\*(C`TAGS < FILE\*(C'\fR, \f(CW\*(C`title artist album year genre comment track\*(C'\fR info is calculated from \&\fI\s-1FILE\s0\fR, which may be raw tags, as produced with \f(CW\*(C`>\*(C'\fR, or a valid \s-1MP3\s0 file; if Image::ExifTool is present, the data may be read from arbitrary multimedia file. (Likewise, for \f(CW\*(C`ID3v1 < FILE\*(C'\fR, the same info is extracted from \&\f(CW\*(C`ID3v1\*(C'\fR tag only.) After this, in case of \f(CW\*(C`ID3v2\*(C'\fR or \f(CW\*(C`TAGS\*(C'\fR, \f(CW\*(C`ID3v2\*(C'\fR frames are copied from the \f(CW\*(C`ID3v2\*(C'\fR tag one-by-one. (With suitable modifications for \f(CW\*(C`?<\*(C'\fR.) .PP By default, the \*(L"\s-1VALUE\*(R"\s0 for \f(CW\*(C`\-F\*(C'\fR is \f(CW\*(C`%\*(C'\fR\-interpolated; this can be changed by option \f(CW\*(C`\-E\*(C'\fR. For user convenience, human-friendlier forms \&\f(CW\*(C`composer, text_by, orchestra, conductor, track, disk_n\*(C'\fR can be used instead of \&\f(CW\*(C`TCOM, TEXT, TPE2, TPE3, TRCK, TPOS\*(C'\fR. .PP The option \f(CW\*(C`\-P RECIPE\*(C'\fR is a very powerful generalization of what can be done by options \f(CW\*(C`\-F\*(C'\fR, \f(CW\*(C`\-d\*(C'\fR, and \f(CW\*(C`\-t \-a \-l \-y \-g \-c \-n\*(C'\fR. It may be repeated; the values should contain the parse recipes. They become the configuration item \f(CW\*(C`parse_data\*(C'\fR of \f(CW\*(C`MP3::Tag\*(C'\fR; eventually this information is processed by MP3::Tag::ParseData module (if the latter is present in the chain of heuristics; see option \f(CW\*(C`\-C\*(C'\fR). The \&\f(CW\*(C`RECIPE\*(C'\fR is split into \f(CW\*(C`$flags, $string, @patterns\*(C'\fR on its first non-alphanumeric character; the first of \f(CW@patterns\fR which matches \&\f(CW$string\fR is going to be executed (for side effects). (See examples: \&\*(L"\s-1EXAMPLES:\s0 parse rules\*(R".) .PP If option \f(CW\*(C`\-G\*(C'\fR is specified, the file names on the command line are considered as glob patterns. This may be useful if the maximal command-line length is too low. With the option \f(CW\*(C`\-R\*(C'\fR arguments can be directories, which are searched recursively for audio (default \&\fI*.mp3\fR) files to process; use option \f(CW\*(C`\-r\*(C'\fR to reset the regular expression to look for (the default is \f(CW\*(C`(?i:\e.mp3$)\*(C'\fR). .PP The option \f(CW\*(C`\-E\*(C'\fR controls expansion of escape characters. It should contain the letters of the command-line options where \f(CW\*(C`\e\e, \en, \et\*(C'\fR are interpolated; one can append the letters of \f(CW\*(C`t a l y g c n F\*(C'\fR options requiring \f(CW\*(C`%\*(C'\fR\-interpolation after the separator \f(CW\*(C`/i:\*(C'\fR (for \&\f(CW\*(C`\-F\*(C'\fR, only the values are interpolated). The default value is \&\f(CW\*(C`p/i:Fp\*(C'\fR: only \f(CW\*(C`\-p\*(C'\fR is \f(CW\*(C`\e\*(C'\fR\-interpolated, and only \f(CW\*(C`\-F\*(C'\fR and \f(CW\*(C`\-p\*(C'\fR are subject to \f(CW\*(C`%\*(C'\fR\-interpolation. If all one wants is to \fIadd\fR to the defaults, preceed the value of \f(CW\*(C`\-E\*(C'\fR (containing added options) by \&\f(CW"+"\fR. (Some parts of the value of option \f(CW\*(C`\-P\*(C'\fR are interpolated, but this should be governed by flags, not \f(CW\*(C`\-E\*(C'\fR; do \fI\s-1NOT\s0\fR put \f(CW\*(C`P\*(C'\fR into the \f(CW\*(C`%\*(C'\fR\-interpolated part of \f(CW\*(C`\-E\*(C'\fR.) .PP If the option \f(CW\*(C`\-@\*(C'\fR is given, all characters \f(CW\*(C`@\*(C'\fR in the options are replaced by \f(CW\*(C`%\*(C'\fR. This may be convenient if the shell treats \f(CW\*(C`%\*(C'\fR specially (e.g., \s-1DOSISH\s0 shells). .PP If option \f(CW\*(C`\-I\*(C'\fR is given, no guessworking for \fIartist\fR field is performed on typeout. .PP The option \f(CW\*(C`\-C CONFIG_OPT=VALUE1,VALUE2...\*(C'\fR sets \f(CW\*(C`MP3::Tag\*(C'\fR configuration data the same way as \f(CW\*(C`MP3::Tag\-\*(C'\fR\fBconfig()\fR> would do (recall that the value is an array; separate elements by commas if more than one). The option may be repeated to set more than one value. Note that since \f(CW\*(C`ParseData\*(C'\fR is used to process \f(CW\*(C`\-P\*(C'\fR parse recipes, it should be better be kept in the \&\f(CW\*(C`autoinfo\*(C'\fR configuration (and related fields \f(CW\*(C`author\*(C'\fR etc) in presence of \f(CW\*(C`\-P\*(C'\fR. .PP If the option \f(CW\*(C`\-x\*(C'\fR is given, the technical information about the audio file is printed (\s-1MP3\s0 level, duration, number of frames, padding, copyright, and the list of ID3v2 frame names in format suitable to \f(CW\*(C`%{...}\*(C'\fR escapes). If \f(CW\*(C`\-x\*(C'\fR is repeated, content of frames is also printed out (may output non-printable chars, if it is repeated more than twice). .PP If option \f(CW\*(C`\-N\*(C'\fR is given, all the \*(L"smarts\*(R" are disabled \- no normalization of fields happens, and (by default) no attempt to deduce the values of fields from non\-ID3 information is done. This option is (currently) equivalent to having \f(CW\*(C`\-C autoinfo=ParseData,ID3v2,ID3v1\*(C'\fR as the first directive, to having no \fINormalize::Text::Music_Fields.pm\fR present on \f(CW@INC\fR path, and not calling \fBautofill()\fR method. .SH "Normalization of fields" .IX Header "Normalization of fields" (The loading of normalization module and all subsequent operations may be disabled by the option \f(CW\*(C`\-N\*(C'\fR, or by setting the environment variable \&\f(CW\*(C`MP3TAG_NORMALIZE_FIELDS\*(C'\fR to be \s-1FALSE.\s0 If not prohibited, the module is attempted to be loaded if directory \fI~/.music_fields\fR is present, or \f(CW\*(C`MP3TAG_NORMALIZE_FIELDS\*(C'\fR is set and \s-1TRUE.\s0) .PP If loading of the module \f(CW\*(C`Normalize::Text::Music_Fields\*(C'\fR is successful, the following is applicable: .PP If the value of \f(CW\*(C`MP3TAG_NORMALIZE_FIELDS\*(C'\fR is defined and not 1, this value is broken into directories as a \s-1PATH,\s0 and load path of \&\f(CW\*(C`Normalize::Text::Music_Fields\*(C'\fR is set to be this list of directories. Then MP3::Tag is instructed (via corresponding configuration settings) to use \f(CW\*(C`normalize_artist\*(C'\fR (etc.) methods defined by this module. These methods may normalize certain tag data. The current version defines methods for \&\*(L"normalization\*(R" of personal names, and titles (based on the composer). This normalization is driven through user-editable configuration tables. .PP In addition to automatical normalization of \s-1MP3\s0 tag data, one can use \&\*(L"fake \s-1MP3\s0 files\*(R" to manually access some features of this module. For this, use an empty file name, and \f(CW\*(C`\-D\*(C'\fR option. E.g, .PP .Vb 5 \& mp3info2 \-D \-a beethoven \-p "%a\en" "" \& mp3info2 \-D \-a beethoven \-p "%{shP[%a]}\en" "" \& mp3info2 \-D \-a beethoven \-t "sonata #28" \-p "%t\en" "" \& mp3info2 \-D \-a beethoven \-t "allegretto, Bes" \-@p "@t\en" "" \& mp3info2 \-D \-a beethoven \-t "op93" \-@p "@t\en" "" .Ve .PP will print the normalized person-name for \f(CW\*(C`beethoven\*(C'\fR, the corresponding normalized short person-name, and the normalized title for \f(CW\*(C`sonata #28\*(C'\fR of composer \f(CW\*(C`beethoven\*(C'\fR. E.g., with the shipped normalization tables, it will print .PP .Vb 5 \& Ludwig van Beethoven (1770\-1827) \& L. van Beethoven \& Piano Sonata No. 28 in A major; Op. 101 (1816) \& Allegretto for Piano Trio in B flat major; WoO 39 (1812) \& Symphony No. 8 in F major; Op. 93 (comp. 1812, f.p. Vienna, 1814\-02\-27, cond. Beethoven; pubd. 1816) .Ve .SH "The order of operation" .IX Header "The order of operation" Currently, the operations are done in the following order .IP "\(bu" 2 Deletion of ID3v1 or ID3v2 as a whole via \f(CW\*(C`\-d\*(C'\fR option; .IP "\(bu" 2 Recipies of \f(CW\*(C`\-P\*(C'\fR option are set up (to be triggered by interpolation); .IP "\(bu" 2 The setting done via \f(CW\*(C`\-a/\-t/\-l/\-y/\-g/\-c/\-n\*(C'\fR options; .IP "\(bu" 2 The settings done via \f(CW\*(C`\-F\*(C'\fR option; .IP "\(bu" 2 Deletion of individual frames via \f(CW\*(C`\-d\*(C'\fR option; .IP "\(bu" 2 autofill of ID3v2 (id) frames; .IP "\(bu" 2 Emit info based on \f(CW\*(C`\-p\*(C'\fR and \f(CW\*(C`\-x\*(C'\fR options; .IP "\(bu" 2 Trigger recipies of \f(CW\*(C`\-P\*(C'\fR (if not triggered by interpolation); .IP "\(bu" 2 Update tags if needed. .SH "Usage strategy: escalation of complexity" .IX Header "Usage strategy: escalation of complexity" The purpose of this script is to to make handling of \s-1ID3\s0 tags as simple \&\fIas possible\fR. .PP On one end of the scale, one can perform arbitrarily complex manipulations with tags using \f(CW\*(C`MP3::Tag\*(C'\fR Perl module. .PP On the other end, it is much more convenient to handle simplest manipulations with tags using this script's options \f(CW\*(C`\-t \-a \-l \-y \-g \-c \-n\*(C'\fR and \f(CW\*(C`\-p \&\-F \-d\*(C'\fR. For slightly more complicated tasks, one may need to use the more elaborate method of \fIparse rules\fR, provided to this script by the option \f(CW\*(C`\-P\*(C'\fR; the rules depend heavily on \fIinterpolation\fR, see \&\*(L"interpolate\*(R" in MP3::Tag, \*(L"interpolate_with_flags\*(R" in MP3::Tag. .PP To simplify upgrade from \*(L"simplest manipulations\*(R" to \*(L"more elaborate ones\*(R", here we provide \*(L"parse rule\*(R" \fIsynonyms\fR to the simplest options. So if you start with \f(CW\*(C`\-t \-a \-l \-y \-g \-c \-n\*(C'\fR and \f(CW\*(C`\-p \-F \-d\*(C'\fR options which \*(L"almost work\*(R" for you, you have a good chance to be able to fully achieve your aim by modifying the synonyms described below. .PP (Below we assume that \f(CW\*(C`\-E\*(C'\fR option is set to its default value, so \&\f(CW\*(C`\-F \-p\*(C'\fR are \f(CW\*(C`%\*(C'\fR\-interpolated, other options are not. Note also that if your \s-1TTY\s0's encoding is recognized by Perl, it is highly recommended to set \f(CW\*(C`\-e 3\*(C'\fR option; on \s-1DOSISH\s0 shells, better use \f(CW\*(C`\-@\*(C'\fR, and replace \&\f(CW\*(C`%\*(C'\fR's by \f(CW\*(C`@\*(C'\fR's below.) .ie n .IP """\-t VALUE""" 14 .el .IP "\f(CW\-t VALUE\fR" 14 .IX Item "-t VALUE" .Vb 1 \& \-P "mz/VALUE/%t" .Ve .ie n .IP """\-a \-l \-y \-g \-c \-n""" 14 .el .IP "\f(CW\-a \-l \-y \-g \-c \-n\fR" 14 .IX Item "-a -l -y -g -c -n" Likewise. .ie n .IP """\-F"" ""TIT2=VALUE""" 14 .el .IP "\f(CW\-F\fR ``TIT2=VALUE''" 14 .IX Item "-F TIT2=VALUE" .Vb 1 \& \-P "mzi/VALUE/%{TIT2}" .Ve .ie n .IP """\-F"" ""APIC[myDescr] < \s-1FILE""\s0" 14 .el .IP "\f(CW\-F\fR ``APIC[myDescr] < \s-1FILE''\s0" 14 .IX Item "-F APIC[myDescr] < FILE" .Vb 1 \& \-F "APIC[myDescr]=%{I(fimbB)FILE}" .Ve .Sp or .Sp .Vb 1 \& \-P "mzi/%{I(fimbB)FILE}/%{APIC[myDescr]}" .Ve .Sp (remove \f(CW\*(C`bB\*(C'\fR for text-only frames). .ie n .IP """\-F"" ""APIC[myDescr] > \s-1FILE""\s0" 14 .el .IP "\f(CW\-F\fR ``APIC[myDescr] > \s-1FILE''\s0" 14 .IX Item "-F APIC[myDescr] > FILE" .Vb 1 \& \-P "bOi,%{APIC[myDescr]},FILE" .Ve .Sp (remove \f(CW\*(C`b\*(C'\fR for text-only frames); or use \f(CW\*(C`\-e binary \-p "%{APIC[myDescr]}"\*(C'\fR with redirection, see \*(L"\s-1EXAMPLES:\s0 parse rules\*(R". .ie n .IP """\-d"" \s-1TIT2\s0" 14 .el .IP "\f(CW\-d\fR \s-1TIT2\s0" 14 .IX Item "-d TIT2" .Vb 1 \& \-P "m//%{TIT2}" .Ve .ie n .IP """\-F"" ""\s-1TIT2\s0 ?< \s-1FILE""\s0" 14 .el .IP "\f(CW\-F\fR ``\s-1TIT2\s0 ?< \s-1FILE''\s0" 14 .IX Item "-F TIT2 ?< FILE" Very tricky. This won't set distinguish empty file and non-existing one: .Sp .Vb 1 \& \-P "mzi/%{TIT2:1}0%{I(fFim)FILE}/10/10%{TIT2}/0%{U1}" .Ve .Sp (add \f(CW\*(C`bB\*(C'\fR to \f(CW\*(C`fFim\*(C'\fR for non-text-only frames); the last part may be omitted if one omits the flag \f(CW\*(C`m\*(C'\fR \- it is present to catch misprints only. .PP For details on \*(L"parse rules\*(R", see \*(L"\s-1EXAMPLES:\s0 parse rules\*(R" and \&\*(L"\s-1DESCRIPTION\*(R"\s0 in MP3::Tag::ParseData. .SH "EXAMPLES: parse rules" .IX Header "EXAMPLES: parse rules" Only the \f(CW\*(C`\-P\*(C'\fR option is complicated enough to deserve comments... For full details on \fIparse rules\fR, see \&\*(L"\s-1DESCRIPTION\*(R"\s0 in MP3::Tag::ParseData; for full details on interpolation, see \*(L"interpolate\*(R" in MP3::Tag, \*(L"interpolate_with_flags\*(R" in MP3::Tag. .PP For a (silly) example, one can replace \f(CW\*(C`\-a Homer \-t Iliad\*(C'\fR by .PP .Vb 1 \& \-P mz=Homer=%a \-P mz=Iliad=%t .Ve .PP A less silly example is forcing a particular way of parsing a file name via .PP .Vb 1 \& \-P "im=%{d0}/%f=%a/%n %t.%e" .Ve .PP It is broken into .PP .Vb 2 \& flags string pattern1 \& "im" "%{d0}/%f" "%a/%n %t.%e" .Ve .PP The flag letters stand for \fIinterpolate\fR, \fImust_match\fR. This interpolates the string \f(CW"%{d0}/%f"\fR and parses the result (which is the file name with one level of the directory part preserved) using the given pattern; thus the directory name becomes the artist, the leading numeric part \- the track number, and the rest of the file name (without extension) \- the title. Note that since multiple patterns are allowed, one can similarly allow for multiple formats of the names, e.g. .PP .Vb 1 \& \-P "im=%{d0}/%f=%a/%n %t.%e=%a/%t (%y).%e" .Ve .PP allows for the file basename to be also of the form \*(L"\s-1TITLE\s0 (\s-1YEAR\s0)\*(R". An alternative way to obtain the same results is .PP .Vb 1 \& \-P "im=%{d0}=%a" \-P "im=%f=%n %t.%e=%t (%y).%e" .Ve .PP which corresponds to two recipies: .PP .Vb 3 \& flags string pattern1 pattern2 \& "im" "%{d0}" "%a" \& "im" "%f" "%n %t.%e" "%t (%y).%e" .Ve .PP Of course, one could use .PP .Vb 1 \& "im" "%B" "%n %t" "%t (%y)" .Ve .PP as a replacement for the second one. .PP Note that it may be more readable to set \fIartist\fR to \f(CW\*(C`%{d0}\*(C'\fR by an explicit asignment, with arguments similar to .PP .Vb 1 \& \-E "p/i:Fpa" \-a "%{d0}" .Ve .PP (this value of \f(CW\*(C`\-E\*(C'\fR requests \f(CW\*(C`%\*(C'\fR\-interpolation of the option \f(CW\*(C`\-a\*(C'\fR in addition to the default \f(CW\*(C`\e\*(C'\fR\-interpolation of \f(CW\*(C`\-p\*(C'\fR, and \&\f(CW\*(C`%\*(C'\fR\-interpolation of \f(CW\*(C`\-F\*(C'\fR and \f(CW\*(C`\-p\*(C'\fR; one can shortcut it with \f(CW\*(C`\-E +/i:a\*(C'\fR). .PP To give more examples, .PP .Vb 1 \& \-P "if=%D/.comment=%c" .Ve .PP will read comment from the file \fI.comment\fR in the directory of the audio file; .PP .Vb 1 \& \-P "ifn=%D/.comment=%c" .Ve .PP has similar effect if the file \fI.comment\fR has one-line comments, one per track (this assumes the the track number can be found by other means). .PP Suppose that a file \fIParts\fR in a directory of \s-1MP3\s0 files has the following format: it has a preamble, then has a short paragraph of information per audio file, preceded by the track number and dot: .PP .Vb 1 \& ... \& \& 12. Rezitativ. \& (Pizarro, Rocco) \& \& 13. Duett: jetzt, Alter, jetzt hat es Eile, (Pizarro, Rocco) \& \& ... .Ve .PP The following command puts this info into the title of the \s-1ID3\s0 tag (provided the audio file names are informative enough so that MP3::Tag can deduce the track number): .PP .Vb 1 \& mp3info2 \-u \-C parse_split=\*(Aq\en(?=\ed+\e.)\*(Aq \-P \*(Aqfl;Parts;%=n. %t\*(Aq .Ve .PP If this paragraph of information has the form \f(CW\*(C`TITLE (COMMENT)\*(C'\fR with the \&\f(CW\*(C`COMMENT\*(C'\fR part being optional, then use .PP .Vb 1 \& mp3info2 \-u \-C parse_split=\*(Aq\en(?=\ed+\e.)\*(Aq \-P \*(Aqfl;Parts;%=n. %t (%c);%=n. %t\*(Aq .Ve .PP If you want to remove a dot or a comma got into the end of the title, use .PP .Vb 2 \& mp3info2 \-u \-C parse_split=\*(Aq\en(?=\ed+\e.)\*(Aq \e \& \-P \*(Aqfl;Parts;%=n. %t (%c);%=n. %t\*(Aq \-P \*(AqiR;%t;%t[.,]$\*(Aq .Ve .PP The second pattern of this invocation is converted to .PP .Vb 1 \& [\*(AqiR\*(Aq, \*(Aq%t\*(Aq => \*(Aq%t[.,]$\*(Aq] .Ve .PP which essentially applies the substitution \f(CW\*(C`s/(.*)[.,]$/$1/s\*(C'\fR to the title. .PP Now suppose that in addition to \fIParts\fR, we have a text file \fIComment\fR with additional info; we want to put this info into the comment field \fIafter\fR what is extracted from \f(CW\*(C`TITLE (COMMENT)\*(C'\fR; separate these two parts of the comment by an empty line: .PP .Vb 3 \& mp3info2 \-E C \-C \*(Aqparse_split=\en(?=\ed+\e.)\*(Aq \-C \*(Aqparse_join=\en\en\*(Aq \e \& \-P \*(Aqf;Comment;%c\*(Aq \-P \*(Aqfl;Parts;%=n. %t\*(Aq \e \& \-P \*(Aqi;%t///%c;%t (%c)///%c\*(Aq \-P \*(AqiR;%t;%t[.,]$\*(Aq .Ve .PP This assumes that the title and the comment do not contain \f(CW\*(Aq///\*(Aq\fR as a substring. Explanation: the first pattern of \f(CW\*(C`\-P\*(C'\fR, .PP .Vb 1 \& [\*(Aqf\*(Aq, \*(AqComment\*(Aq => \*(Aq%c\*(Aq], .Ve .PP reads comment from the file \f(CW\*(C`Comment\*(C'\fR into the comment field; the second, .PP .Vb 1 \& [\*(Aqfl\*(Aq, \*(AqParts\*(Aq => \*(Aq%=n. %t\*(Aq], .Ve .PP reads a chunk of \f(CW\*(C`Parts\*(C'\fR into the title field. The third one .PP .Vb 1 \& [\*(Aqi\*(Aq, \*(Aq%t///%c\*(Aq => \*(Aq%t (%c)///%c\*(Aq] .Ve .PP rearranges the title and comment \fIprovided\fR the title is of the form \f(CW\*(C`TITLE (COMMENT)\*(C'\fR. (The configuration option \f(CW\*(C`parse_join\*(C'\fR takes care of separating two chunks of comment corresponding to two occurences of \f(CW%c\fR on the right hand side.) .PP Finally, the fourth pattern is the same as in the preceding example; it removes spurious punctuation at the end of the title. .PP More examples: removing string \*(L"with violin\*(R" from the start of the comment field (removing comment altogether if nothing remains): .PP .Vb 1 \& mp3info2 \-u \-P \*(Aqiz;%c;with violin%c\*(Aq *.mp3 .Ve .PP setting the artist field without letting auto-update feature deduce other fields from other sources; .PP .Vb 1 \& mp3info2 \-C autoinfo=ParseData \-a "A. U. Thor" *.mp3 .Ve .PP setting a comment field unless it it already present: .PP .Vb 1 \& mp3info2 \-u \-P \*(Aqi;%c///with piano;///%c\*(Aq *.mp3 .Ve .PP The last example shows how to actually write \*(L"programs\*(R" in the language of the \f(CW\*(C`\-P\*(C'\fR option: the example gives a conditional assignment. With user variables (as in \f(CW\*(C`%{U8}\*(C'\fR) for temporaries, and a possibility to use regular expressions, one could provide arbitrary programmatic logic. Of course, at some level of complexity one should better switch to direct interfacing with \&\f(CW\*(C`MP3::Tag\*(C'\fR Perl module (use the code of this Perl script as an example!). .PP Here is a typical task setting \*(L"advanced\*(R" id3v2 frames: composer (\f(CW\*(C`TCOM\*(C'\fR), orchestra (\f(CW\*(C`TPE2\*(C'\fR), conductor (\f(CW\*(C`TPE3\*(C'\fR). We assume a directory tree which contains \s-1MP3\s0 files tagged with the following conventions: \f(CW\*(C`artist\*(C'\fR is actually a composer; \f(CW\*(C`comment\*(C'\fR is of one of two forms: .PP .Vb 2 \& Performers; Orchestra; Conductor \& Orchestra; Conductor .Ve .PP To set the specific \s-1MP3\s0 frames via \f(CW\*(C`\-P\*(C'\fR rules, use .PP .Vb 2 \& mp3info2 \-@P "mi/@a/@{TCOM}" \e \& \-P "mi/@c/@{U1}; @{TPE2}; @{TPE3}/@{TPE2}; @{TPE3}" \-R . .Ve .PP With \f(CW\*(C`\-F\*(C'\fR options, this can be simplified as .PP .Vb 1 \& mp3info2 \-@F "TCOM=@a" \-P "mi/@c/@{U1}; @{TPE2}; @{TPE3}/@{TPE2}; @{TPE3}" \-R . .Ve .PP or .PP .Vb 1 \& mp3info2 \-@F "composer=@a" \-P "mi/@c/@{U1}; @{TPE2}; @{TPE3}/@{TPE2}; @{TPE3}" \-R . .Ve .PP To copy \s-1ID3\s0 tags of \s-1MP3\s0 files in the current directory to files in directory \&\fI/tmp/mp3\fR with the extension \fI.tag\fR (and print \*(L"progress report\*(R"), use .PP .Vb 1 \& mp3info2 \-p "@N@E\en" \-@P "bODi,@{ID3v2}@{ID3v1},/tmp/mp3/@N.tag" \-DNR . .Ve .PP Since we did not use \f(CW\*(C`z\*(C'\fR flag, \s-1MP3\s0 files without tags are skipped. .PP Now suppose that there are two parallel file hierarchies of audio files, and of lyrics: audio files are in \fIaudio/dir_name/audio_name.mp3\fR with corresponding lyrics file in \fItext/dir_name/audio_name.mp3\fR. To attach lyrics to \s-1MP3\s0 files (in \f(CW\*(C`COMM\*(C'\fR frame with description \f(CW\*(C`lyrics\*(C'\fR in language \&\f(CW\*(C`eng\*(C'\fR \- \fIthis is a non-standard location, see below!\fR), call .PP .Vb 1 \& mp3info2 \-@P "fim;../text/@{d0}/@B.txt;@{COMM(eng)[lyrics]}" \-Ru . .Ve .PP inside the directory \fIaudio\fR. (Change \f(CW\*(C`fim\*(C'\fR to \f(CW\*(C`Ffim\*(C'\fR to ignore the audio files for which the corresponding text file does not exist.) (Of course, to follow the specifications, one should have used the field \f(CW"%{USLT(eng)[]}"\fR instead of \f(CW"%{COMM(eng)[lyrics]}"\fR; see below for variations). .PP Finish by a very simple example: all what the pattern .PP .Vb 1 \& \-P \*(Aqi;%t;%t\*(Aq .Ve .PP does is removal of trailing and leading blanks from the title (which is deduced by other means). .SH "More examples" .IX Header "More examples" With \f(CW\*(C`\-F\*(C'\fR option, one could set the \f(CW\*(C`USLT\*(C'\fR frame as .PP .Vb 1 \& mp3info2 \-@F "USLT(eng)[] < ../text/@{d0}/@B.txt" \-Ru . .Ve .PP Print out such a frame (in any language) with .PP .Vb 1 \& mp3info2 \-@p "@{USLT[]}\en" file.mp3 .Ve .PP Similarly, to print out the \s-1APIC\s0 frame with empty description, use .PP .Vb 1 \& mp3info2 \-e binary \-@p "@{APIC[]}" file.mp3 > output_picture_file .Ve .PP or (with description \*(L"cover\*(R") .PP .Vb 1 \& mp3info2 \-@P "bOi,@{APIC[cover]},output_picture_file.jpg" audio_07.mp3 .Ve .PP To set such a frame from file \fIxxx.gif\fR (with the default \f(CW\*(C`Picture Type\*(C'\fR, \&\f(CW"Cover (front)"\fR, and empty description), do one of .PP .Vb 2 \& mp3info2 \-F "APIC < xxx.gif" file.mp3 \& mp3info2 \-@F "APIC[]=@{I(fimbB)xxx.gif}" file.mp3 .Ve .PP The difference of \f(CW\*(C`APIC\*(C'\fR and \f(CW\*(C`APIC[]\*(C'\fR is that the first removes all \&\f(CW\*(C`APIC\*(C'\fR frames first, and the second removes only all \f(CW\*(C`APIC\*(C'\fR frames with empty description \- but arbitrary image type. So it may be more suitable to use the full specification, as in \f(CW\*(C`APIC(Cover (front))[]\*(C'\fR. .PP To remove \f(CW\*(C`APIC\*(C'\fR frames with empty descriptions, arbitrary \f(CW\*(C`Picture Type\*(C'\fRs (and \f(CW\*(C`MIME type\*(C'\fRs which may be correctly calculated by \fImp3info2\fR, e.g., \&\f(CW\*(C`TIFF/JPEG/GIF/PNG\*(C'\fR), use .PP .Vb 1 \& mp3info2 \-d "APIC[]" file.mp3 .Ve .PP (note that this wouldn't free disk space, unless \*(L"shrink\*(R" is forced by configuration variables). To do the same with the \*(L"Conductor\*(R" picture type only, do .PP .Vb 1 \& mp3info2 \-d "APIC(Conductor)[]" file.mp3 .Ve .PP To scan through subdirectories, and add file \fIcover.jpg\fR from the directory of the file as a \*(L"default\*(R" \f(CW\*(C`APIC\*(C'\fR frame, but only if there is no \f(CW\*(C`APIC\*(C'\fR frame, and a file exists, do .PP .Vb 1 \& mp3info2 \-@F "APIC ?< @D/cover.jpg" \-R . .Ve .PP This deletes empty frames for date, \f(CW\*(C`TCOP, TENC, WXXX[], COMM(eng)[]\*(C'\fR, and removes the leading 0 from track number from \s-1MP3\s0 file in current directory: .PP .Vb 3 \& mp3info2 \-@ \-E +/i:y \-F "TCOP=@{TCOP}" \-F "TENC=@{TENC}" \& \-F "WXXX[]=@{WXXX[]}" \-F "COMM(eng)[]=@{COMM(eng)[]}" \& \-y "@y" \-P "mi/@n/0@n/@n" *.mp3 .Ve .SH "Examples on dealing with broken encodings" .IX Header "Examples on dealing with broken encodings" One of principal weaknesses of \s-1ID3\s0 specification was that it required that data is provided in \f(CW\*(C`latin\-1\*(C'\fR encoding. Since most languages in the world are not expressible in \f(CW\*(C`latin\-1\*(C'\fR, this lead to (majority?) of \s-1ID3\s0 tags being not standard-conforming. Newer versions of the specs fixed this shortcoming, but the damage was already done. Fortunately, this script can use abilities of \f(CW\*(C`MP3::Tag\*(C'\fR to convert from non-conforming content to a conforming one. .PP The following example converts ID3v2 tags which were written in (non-standard-conforming) encoding \f(CW\*(C`cp1251\*(C'\fR to be in standard-conforming encoding. For the purpose of this example, assume that ID3v1 tags are in the same encoding (and that one wants to leave them in the encoding \f(CW\*(C`cp1251\*(C'\fR); the files to process are found in the current directory and (recursively) in its subdirectories (\f(CW\*(C`set\*(C'\fR syntax for \s-1DOSISH\s0 shells): .PP .Vb 3 \& set MP3TAG_DECODE_V1_DEFAULT=cp1251 \& set MP3TAG_DECODE_V2_DEFAULT=cp1251 \& mp3info2 \-C id3v2_fix_encoding_on_write=1 \-u2R . .Ve .PP For more information, see \*(L"\s-1ENVIRONMENT\*(R"\s0 in MP3::Tag, \*(L"config\*(R" in MP3::Tag, and \*(L"\s-1CUSTOMIZATION\*(R"\s0 in MP3::Tag. .SH "INCOMPATIBILITIES with \fImp3info\fP" .IX Header "INCOMPATIBILITIES with mp3info" This tool is loosely modeled on the program \fImp3info\fR; it is \*(L"mostly\*(R" backward compatible (especially when in \*(L"naive\*(R" mode via \f(CW\*(C`\-N\*(C'\fR), and allows a very significant superset of functionality. Known backward incompatibilities are: .PP .Vb 1 \& \-G \-h \-r \-d \-x .Ve .PP Missing functionality: .PP .Vb 1 \& \-f \-F \-i .Ve .PP Incompatible \f(CW\*(C`%\*(C'\fR\-\fIescapes\fR: .PP .Vb 5 \& %e %E \- absolutely different semantic \& %v \- has no trailing 0s \& %q \- has fractional part \& %r \- is a number, not a word "Variable" for VBR \& %u \- is one less (in presence of descriptor frame only?) .Ve .PP Missing \f(CW\*(C`%\*(C'\fR\-\fIescapes\fR: .PP .Vb 1 \& %b %G .Ve .PP Backslash escapes: only \f(CW\*(C`\e\e\*(C'\fR, \f(CW\*(C`\en\*(C'\fR, \f(CW\*(C`\et\*(C'\fR supported. .PP \&\f(CW\*(C`\-x\*(C'\fR prints data in a different format, not all fields are present, and ID3v2 tag names are output. .SH "ENVIRONMENT" .IX Header "ENVIRONMENT" With \f(CW\*(C`\-e\*(C'\fR above 0, this script may consult environment variables \&\f(CW\*(C`LC_CTYPE, LC_ALL, LANG\*(C'\fR to deduce the current encoding. Moreover, we try to auto-detect the \f(CW\*(C`UTF\-8\*(C'\fR encoding via \f(CW\*(C`LANG\*(C'\fR environment variable (disabled if \f(CW\*(C`${^UNICODE}\*(C'\fR sets translation of the command-line arguments). (This auto-detection may be switched off by the variable \&\f(CW\*(C`MP3INFO_DECODE_ARGV_DEFAULT_RESET\*(C'\fR.) The effects of the variable \f(CW\*(C`MP3TAG_NORMALIZE_FIELDS\*(C'\fR is described in the section \*(L"Normalization of fields\*(R". No other environment variables are directly read by this script. .PP Note however, that MP3::Tag module has a rich set of defaults for encoding settings settable by environment variables; see \&\*(L"\s-1ENVIRONMENT\*(R"\s0 in MP3::Tag. So these variables affect (indirectly) how this script works. In particular, starting with v1.14, there is an autodetection of encoding of setup files (which this script uses for the \f(CW\*(C`\-P\*(C'\fR option). (However, this autodetection may be switched off.) .SH "OBSOLETE INTERFACE" .IX Header "OBSOLETE INTERFACE" If you do not understand what it is about, it is safe to ignore this announcement: .PP The old, pre\-version=\f(CW1.05\fR way (by triplication of a separator, without repetition of options) to provide multiple commands to \f(CW\*(C`\-F\*(C'\fR and <\-P> options is still supported, but is strongly discouraged. (It does not conflict with the current interface.) .SH "AUTHOR" .IX Header "AUTHOR" Ilya Zakharevich . .SH "Utilities to create CDDB file" .IX Header "Utilities to create CDDB file" Good \s-1CD\s0 reapers (e.g., \fIcdda2wav\fR with option \f(CW\*(C`cddb=0\*(C'\fR) create a \&\s-1CDDB\s0 file with fetched information \- as far as an Internet connection is present. However, if not available, other options exist. .PP The scripts (supplied with the distribution in \&\fI./examples\fR) can create a \*(L"stub\*(R" \s-1CDDB\s0 file basing on: .IP "\fIfulltoc2fake_cddb.pl\fR" 23 .IX Item "fulltoc2fake_cddb.pl" a dump of a full \s-1TOC\s0 of a \s-1CD\s0; create one, e.g., by .Sp .Vb 1 \& readcd \-fulltoc dev=0,1,0 \-f=audiocd .Ve .IP "\fIinf2fake_cddb.pl\fR" 23 .IX Item "inf2fake_cddb.pl" directory of \fI*.inf\fR files (e.g., created by \fIcdda2wav\fR without Internet connection); .IP "\fIdir_mp3_2fake_cddb.pl\fR" 23 .IX Item "dir_mp3_2fake_cddb.pl" a directory of \s-1MP3\s0 files ripped from a \s-1CD\s0 (via some guesswork). .PP Passing this stub to the script \fIcddb2cddb.pl\fR, it can be transformed to a \*(L"filled\*(R" \s-1CDDB\s0 file via a connection to some online database. Use \&\f(CW\*(C`\-r\*(C'\fR option if multiple records in the database match the \s-1CD\s0 signature. .PP .Vb 3 \& fulltoc2fake_cddb audiocd.toc | cddb2cddb > audio.cddb \& inf_2fake_cddb | cddb2cddb > audio.cddb \& dir_mp3_2fake_cddb | cddb2cddb \-r3 > audio.cddb # 3rd record .Ve .PP When such a \s-1CDDB\s0 file is present, it will be used by MP3::Tag module to deduce the information about an audio file. This information is (by default, transparently) used by this script. .SH "SEE ALSO" .IX Header "SEE ALSO" MP3::Tag, MP3::Tag::ParseData, audio_rename, typeset_audio_dir