aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/idest.texi256
-rw-r--r--examples/Makefile.am5
-rw-r--r--examples/dry-run.scm14
-rw-r--r--examples/settitle.scm11
-rw-r--r--src/cmdline.opt2
5 files changed, 230 insertions, 58 deletions
diff --git a/doc/idest.texi b/doc/idest.texi
index f88b42a..bd6bad9 100644
--- a/doc/idest.texi
+++ b/doc/idest.texi
@@ -73,6 +73,7 @@ documents IdEst @value{VERSION}.
* Frames:: ID3 Frames
* View:: Viewing Existing Tags
* Modify:: Modifying Existing Tags
+* Copy:: Copying Tags Between Files
* Delete:: Deleting Tags and Frames
* ID Versioning:: Storing Tags in Different ID3 Versions
* Structure:: Examining File Structure
@@ -190,7 +191,7 @@ which identifies a frame.
@cindex qualifiers
There are frames that can appear only once in a tag, and there are
-such that can appear multiple times. These latter have some
+ones that can appear multiple times. These latter have some
additional fields which serve to discern between them. In
@command{idest} parlance we call these fields frame @dfn{qualifiers}.
The number and semantics of qualifiers are frame-dependent. For
@@ -215,6 +216,7 @@ name can be omitted. Such an empty qualifier works as a
@samp{COMM::my-comment} select the @samp{COMM} frames with content
descriptor @samp{my-comment}, no matter what their language.
+@anchor{list-frames}
@xopindex{list-frames, introduced}
To examine the qualifiers a particular frame has, use the
@option{--list-frames} (@option{-L}) option. It lists all the supported
@@ -233,6 +235,7 @@ The output it produces consists of two columns: the first one shows
the frame ID and its qualifiers (if any). The second one contains a
short description of this frame purpose.
+@anchor{filter--list-frames}
@xopindex{filter, introduced}
To select one or several frames of interest, give their names as
argument (a comma-separated list) to the @option{--filter}
@@ -283,6 +286,7 @@ year: 1995
genre: Folk
@end example
+@anchor{filter--query}
@xopindex{filter, in query mode}
If you wish to display another frames, use the @option{--filter}
(@option{-F}) option:
@@ -317,7 +321,7 @@ Encoded by: lame
@anchor{describe}
To describe frames in a verbose manner, use the @option{--describe}
-(@option{-D}) option''
+(@option{-D}) option:
@example
$ idest --describe --filter=artist,title,year file.mp3
@@ -426,14 +430,14 @@ frames that require it:
$ idest --set comment:eng:My_comment='Noise reduction on' track01.mp3
@end example
-If a comment with this content descriptor exists, its content will be
-replaced with the new one. If not, a new comment frame will be
-created.
+In the example above, if a comment with this content descriptor
+exists, its content will be replaced with the new one. If not, a new
+comment frame will be created.
-If comment is given without a particular content descriptor, all
-existing comments will be removed and a new comment frame will be
-added. Its content descriptor field will be empty and its
-language field will be set to @samp{XXX}.
+If a frame which can appear multiple times (such as e.g. comment) is
+being set without qualifiers, all existing frames of this type will be
+removed and replaced with a new one. Its qualifiers will be set to
+default values.
@xopindex{latin1, using with --set}
Textual fields will be saved in the UTF-8 encoding. To store them
@@ -443,6 +447,40 @@ in ISO-8859-1, use the @option{--latin1} option:
$ idest --latin1 --set artist='Llu@'is Llach' *.mp3
@end example
+@node Copy
+@chapter Copying Tags Between Files
+@xopindex{copy, described}
+ To copy tags from one file to another, use the @option{--copy}
+(@option{-c}) option. Its argument supplies the @dfn{source file}.
+Non-optional arguments supply destination files:
+
+@example
+$ idest --copy sample.mp3 track1.mp3 track2.mp3
+@end example
+
+As a result of this operation all tags from @file{sample.mp3} will be
+copied to @file{track1.mp3} and @file{track2.mp3}.
+
+@anchor{filter--copy}
+@xopindex{--filter, used with @option{--copy}}.
+As with another operations, you can abridge the scope of copying to
+a certain subset of frames by using the @option{--filter} option,
+e.g.:
+
+@example
+$ idest --copy sample.mp3 --filter TPE1,TCOM track1.mp3 track2.mp3
+@end example
+
+You can also use @option{--copy} together with @option{--set} in a
+single invocation. In this case, the frames will first be copied from
+the source file and then the resulting tags will be modified according
+to the @option{--set} options. For example:
+
+@example
+$ idest --copy sample.mp3 --filter TPE1,TCOM \
+ --set year=2003 track1.mp3 track2.mp3
+@end example
+
@node Delete
@chapter Deleting Tags and Frames
@@ -458,7 +496,8 @@ $ idest --delete *.mp3
After this operation, all ID3 data are irrevocably lost, so use it
with caution.
-@xopindex{filter, used with --delete}
+@anchor{filter--delete}
+@xopindex{filter, used with @option{--delete}}
A list of frame names can be given either with the @option{--filter}
option, or (for compatibility with @command{idest} 1.x) as an argument to
@option{--delete} (similarly to @option{--query}). For example, to
@@ -483,6 +522,9 @@ form:
$ idest --delete --filter=comment::Bit_Rate track01.mp3
@end example
+The same applies to other frames that can appear multiple times
+(@pxref{Frames}).
+
@node ID Versioning
@chapter Storing Tags in Different ID3 Versions
@@ -542,7 +584,7 @@ a sequence of keyword / value pairs, as shown in the example below:
$ idest --info jt_lluny.mp3
file: jt_lluny.mp3
ntags: 2
-version: 24.0
+version: 2.4.0
offset: 0
length: 2131
version: 1.1
@@ -553,10 +595,9 @@ length: 128
The first two lines show the name of the input file and the number of
ID3 tags in it. Following are tag descriptions formatted as three
values for each tag. The @samp{version} line shows the tag version
-(major and minor numbers, separated by a dot). The major number greater
-than 1 means it is a ID3v2 tag. The @samp{offset} line shows the
-offset of this tag in the file, and the @samp{length} line contains
-size of this tag in bytes.
+(major and minor numbers, separated by dots). The @samp{offset} line
+shows the offset of this tag in the file, and the @samp{length} line
+contains size of this tag in bytes.
@node Scripting
@chapter Scripting
@@ -583,6 +624,9 @@ to this option specifies the name of the script file:
$ idest --script list.scm *.mp3
@end example
+You can omit the @samp{.scm} suffix, as @command{idest} will try it
+automatically (see below).
+
When this option is given, the following operations are performed:
@enumerate 1
@@ -621,6 +665,12 @@ The default load path is formed as follows:
@samp{$GUILE_SITE} is as described above and @var{load-path} is
the default value of @code{%load-path}.
+The script is loaded via @code{primitive-load-path} (@pxref{Loading,,
+primitive-load-path,guile,The Guile Reference Manual}), so
+@command{idest} will consult the @code{%load-extensions} list and
+try suffixes from that list as described in
+@ref{Loading,,%load-extensions,guile,The Guile Reference Manual}).
+
@item
The script is read and evaluated.
@@ -628,9 +678,10 @@ The script can access command line arguments via the usual
@code{command-line} function (@pxref{Runtime
Environment,,command-line,guile,The Guile Reference Manual}). It
can also modify the argument list (e.g. by removing its command
-line options). Any changes it does to the argument list become
-visible to @command{idest}. The only requirement is that the modified
-argument list must contain only input file names.
+line options). It must not, however, modify @samp{argv[0]}. Any
+changes it does to the argument list become visible to
+@command{idest}. The only requirement is that the modified argument
+list consist of the script name (as argv[0]) and input file names.
@item
The script's @dfn{main function} is applied to each
@@ -663,12 +714,31 @@ number/position in set}.
These are the same descriptions that are output with the
@option{--describe} option (@pxref{describe}).
+@item rawdata
+Unsupported or partially-supported frames contain only this property.
+Its value is a list of frame fields. Each field is represented by a
+triplet @samp{(@var{ord} @var{type} @var{value})}, where @var{ord} is the
+ordinal number of that field in frame, @var{type} is its type (integer) and
+@var{value} is its value. If @var{type} is one of numeric types,
+@var{value} is the numeric value converted to string (as per
+@code{number->string}). If @var{type} is a string type, @var{value}
+contains the string in the appropriate encoding. Otherwise,
+@var{value} holds the field value as a binary string. Each byte in
+such a string is represented by two hexadecimal digits. For example,
+@samp{AB\n} is represented as @samp{41420A}.
+@end table
+
+More properties are defined at a per-frame basis to represent
+frame qualifiers. They are named after corresponding qualifiers
+as listed in @code{--list-frames} output (@pxref{describe}). For
+example, for @samp{comment} (@samp{COMM}) frames:
+
+@table @asis
@item lang
A three-letter code of the language in which the text is written.
-This property is present only in comment fields.
@item condesc
-Content descriptor. This property is present only in comment fields.
+Content descriptor.
@end table
The mode in which input files are open is controlled by the
@@ -686,11 +756,14 @@ should return the new list of frames. If it returns an empty list,
all existing frames will be deleted. If the function chooses not
to modify any frames, it must return @code{#f}.
-The two following sections show how to write script files.
+The two following sections show how to write script files. The
+sample scripts they discuss can be found in subdirectory
+@file{examples} of the @command{idest} distribution.
@menu
-* list.scm:: Using Scripts to List ID3 Frames
-* title.scm:: Using Scripts to Modify ID3 Frames
+* list.scm:: Using Scripts to List ID3 Frames
+* settitle.scm:: Using Scripts to Modify ID3 Frames
+* dry-run:: Testing Scripts
@end menu
@node list.scm
@@ -703,14 +776,14 @@ listing the contents of ID3 tags.
@lisp
;; list1.scm -- lists all frames.
-(define (idest-main name tags)
+(define (idest-main name frames)
(display name)
(newline)
(for-each
- (lambda (tag)
- (display tag)
+ (lambda (frame)
+ (display frame)
(newline))
- tags))
+ frames))
@end lisp
Here is a sample output:
@@ -738,16 +811,16 @@ The main function consults this list to see whether to display a
frame:
@lisp
-(define (idest-main name tags)
+(define (idest-main name frames)
(display name)
(newline)
(for-each
- (lambda (tag)
- (if (member (car tag) frame-list)
+ (lambda (frame)
+ (if (member (car frame) frame-list)
(begin
- (display tag)
+ (display frame)
(newline))))
- tags))
+ frames))
@end lisp
Finally, the following code initializes @code{frame-list} from the
@@ -759,7 +832,7 @@ script itself, and it should not be modified.
(let ((cmd (command-line)))
(cond
((< (length cmd) 3)
- (error "usage: list2.scm FRAME-LIST FILE...")
+ (error "usage: idest -S list2 FRAME-LIST FILE...")
(exit 1))
(else
(set! frame-list (string-split (list-ref cmd 1) #\,))
@@ -772,21 +845,21 @@ The full script text is then:
;; list2.scm -- lists only requested frames.
(define frame-list '())
-(define (idest-main name tags)
+(define (idest-main name frames)
(display name)
(newline)
(for-each
- (lambda (tag)
- (if (member (car tag) frame-list)
+ (lambda (frame)
+ (if (member (car frame) frame-list)
(begin
- (display tag)
+ (display frame)
(newline))))
- tags))
+ frames))
(let ((cmd (command-line)))
(cond
((< (length cmd) 3)
- (error "usage: list2.scm FRAME-LIST FILE...")
+ (error "usage: idest -S list2 FRAME-LIST FILE...")
(exit 1))
(else
(set! frame-list (string-split (list-ref cmd 1) #\,))
@@ -796,7 +869,7 @@ The full script text is then:
Sample usage:
@example
-$ idest --script list2.scm TIT2,TENC track01.scm
+$ idest --script list2 TIT2,TENC track01.scm
(TIT2 (descr . Title/songname/content description) (text . Cor i arbre))
(TENC (descr . Encoded by) (text . Myencoder 1.0))
@end example
@@ -805,7 +878,7 @@ $ idest --script list2.scm TIT2,TENC track01.scm
followed by the title, artist name and year, as shown in this sample output:
@example
-$ idest -S shortlist.scm *.mp3
+$ idest -S shortlist *.mp3
dnr.mp3: Diamonds & Rust by Joan Baez, 1975
ams.mp3: Amsterdam, by Jacques Brel, 1968
@end example
@@ -838,7 +911,7 @@ Now, we define the main function:
(get-frame "TDRC" frames))) ; Year
@end lisp
-@node title.scm
+@node settitle.scm
@section Using Scripts to Modify ID3 Frames
This section illustrates how to write scripts that modify ID3 tags.
@@ -854,7 +927,7 @@ created using the following algorithm:
Here is the implementation:
@lisp
-;; title.scm - set title (TIT2) frame based on the file name.
+;; settitle.scm - set title (TIT2) frame based on the file name.
(use-modules (ice-9 regex)
(srfi srfi-13))
@@ -865,10 +938,13 @@ created using the following algorithm:
(lambda (match)
(cons
(cons "TIT2"
- (string-map
- (lambda (c)
- (if (char=? c #\_) #\space c))
- (match:substring match 1)))
+ (list
+ (cons
+ 'text
+ (string-map
+ (lambda (c)
+ (if (char=? c #\_) #\space c))
+ (match:substring match 1)))))
;;
(filter
(lambda (elt)
@@ -883,9 +959,74 @@ created using the following algorithm:
An example of using this script on all files in the current directory:
@example
-$ idest --script title.scm *.mp3
+$ idest --script settitle *.mp3
@end example
+@node dry-run
+@section Testing Scripts
+@cindex dry-run
+@cindex test mode
+ When writing a script which modifies tags, it is good idea to test
+it before applying it to your data. @command{Idest} provides a
+mechanism for that. To see what your script would do without actually
+modifying your data, insert the word @samp{dry-run} between the
+@option{--script} (or @option{-S}) option and the script name in the
+program invocation, e.g.:
+
+@example
+$ idest --script dry-run settitle *.mp3
+@end example
+
+ This will run your script as usual, but instead of applying the
+changes to the input files, @command{idest} will verbosely print
+results of each invocation of @samp{idest-main}. Input files will
+then be opened in read-only mode.
+
+ Here is an example of the dry-run output, obtained from the command
+above:
+
+@example
+dry-run: loading ../examples/settitle.scm ...
+dry-run: loading /usr/share/guile/1.8/ice-9/regex.scm ...
+dry-run: loading /usr/share/guile/1.8/srfi/srfi-13.scm ...
+File Tinc_un_clavell_per_a_tu.mp3
+(TIT2 (text . Tinc un clavell per a tu))
+(TALB (descr . Album/movie/show title) (text . Maremar))
+...
+@end example
+
+The first frame shown (@samp{TIT2}) was produced by
+@file{settitle.scm} (see the previous chapter). Rest of frames come
+from the input file itself.
+
+Notice the diagnostics lines which start with @samp{dry-run}. In
+dry-run mode @command{idest} verbosely reports the full file names of
+all files it loads. In this particular case, the line
+
+@example
+dry-run: loading ../examples/settitle.scm ...
+@end example
+
+@noindent
+shows the full path of the script file itself, whereas the two lines
+
+@example
+dry-run: loading /usr/share/guile/1.8/ice-9/regex.scm ...
+dry-run: loading /usr/share/guile/1.8/srfi/srfi-13.scm ...
+@end example
+
+@noindent
+reflect the @code{use-modules} clause at the beginning of
+@file{settitle.scm} (@pxref{settitle.scm}).
+
+@subheading Implementation note
+@findex dry-run.scm
+The @samp{dry-run} mode is actually implemented as a usual
+@command{idest} Guile script, named @file{dry-run.scm}. The
+script is installed to the package script directory. Its
+source can be found in the subdirectory @file{example} of the
+@command{idest} distribution.
+
@node Backups
@chapter Keeping Backup Copies
@@ -893,7 +1034,7 @@ $ idest --script title.scm *.mp3
@vindex VERSION_CONTROL
@command{Idest} offers options for making backups of files before
modifying them. Two ways of creating backup copies are supported.
-Firstly, backups may be made by copying the file to another file
+First, backups may be made by copying the file to another file
before modifying it. This backup method is enabled using the
@option{--backup} command line option. This option takes a single
optional argument, which specifies @dfn{backup method}, i.e. the
@@ -990,6 +1131,10 @@ Create tags in given @var{version}, and convert existing ones to
numbers.
@xref{ID Versioning}.
+@item -c @var{file}
+@item --copy=@var{file}
+Copy tags from @var{file} to destination files. @xref{Copy}.
+
@item -d[@var{flist}]
@itemx --delete[=@var{flist}]
Delete ID3 tags. The @var{flist} is a comma-separated list of the
@@ -1005,6 +1150,14 @@ Print verbose frame descriptions instead of short names.
@itemx --function=@var{name}
Guile function to call. @xref{Scripting}.
+@item -F @var{flist}
+@itemx --filter=@var{flist}
+Operate only on frames from @var{flist}. This option affects the
+following options: @option{--copy} (@pxref{filter--copy, filter in
+copy mode}), @option{--query} (@pxref{filter--query, filter in query
+mode}), @option{--delete} (@pxref{filter--delete, filter in delete
+mode}) and @option{--list-frames} (@pxref{filter--list-frames}).
+
@item -h
@itemx --help
Print a short help list.
@@ -1018,6 +1171,10 @@ Force latin1 output, when used in query mode (@pxref{View,latin1}).
Store strings in ISO-8859-1 encoding, when used with @option{--set}
(@pxref{Modify, latin1}).
+@item -L
+@item --list-frames
+List the supported ID3v2 frames. @xref{list-frames}.
+
@item -q[@var{flist}]
@itemx --query[=@var{flist}]
Query mode. The @var{flist} is a comma-separated list of the
@@ -1208,3 +1365,4 @@ This is a general index of all issues discussed in this manual.
@printindex cp
@bye
+
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 872a970..73b4717 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -16,11 +16,12 @@
EXTRA_DIST = \
delcomm.scm\
+ dry-run.scm\
list1.scm\
list2.scm\
shortlist.scm\
- title.scm
+ settitle.scm
sitedir = @GUILE_SITE@/$(PACKAGE)
-site_DATA=echo.scm
+site_DATA=dry-run.scm
diff --git a/examples/dry-run.scm b/examples/dry-run.scm
index d6b07ab..637ad8c 100644
--- a/examples/dry-run.scm
+++ b/examples/dry-run.scm
@@ -1,4 +1,4 @@
-;; echo.scm - test another Idest script.
+;; dry-run.scm - run a script and show the frames it produces.
;; Copyright (C) 2011 Sergey Poznyakoff
;; License GPLv3+: GNU GPL version 3 or later
;; <http://gnu.org/licenses/gpl.html>
@@ -33,7 +33,17 @@
(set! idest-main
(lambda (file frames)
(let ((result (main-func file frames)))
- (format #t "File ~A ~A~%" file result))))))
+ (format #t "File ~A~%" file)
+ (cond
+ ((not result)
+ (format #t "No modifications~%"))
+ ((null? result)
+ (format #t "Would delete all frames~%"))
+ (else
+ (for-each (lambda (frame)
+ (display frame)
+ (newline))
+ result))))))))
(else
(format (current-error-port)
"~A: idest-main is not defined in ~A~%" progname file-name)
diff --git a/examples/settitle.scm b/examples/settitle.scm
index e541b66..cd43106 100644
--- a/examples/settitle.scm
+++ b/examples/settitle.scm
@@ -14,10 +14,13 @@
(lambda (match)
(cons
(cons "TIT2"
- (string-map
- (lambda (c)
- (if (char=? c #\_) #\space c))
- (match:substring match 1)))
+ (list
+ (cons
+ 'text
+ (string-map
+ (lambda (c)
+ (if (char=? c #\_) #\space c))
+ (match:substring match 1)))))
;;
(filter
(lambda (elt)
diff --git a/src/cmdline.opt b/src/cmdline.opt
index 1400d2c..36478f0 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -112,7 +112,7 @@ END
GROUP([<Operation modifiers>])
OPTION(filter,F,FRAME-LIST,
- [<with --query, --copy and --delete: operate only on matching frames>])
+ [<operate only on matching frames>])
BEGIN
parse_filter_items(optarg);
END

Return to:

Send suggestions and report system problems to the System administrator.