aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS20
-rw-r--r--doc/idest.texi234
-rw-r--r--examples/echo.scm18
-rw-r--r--src/idop.c46
-rw-r--r--src/main.c30
5 files changed, 227 insertions, 121 deletions
diff --git a/NEWS b/NEWS
index 6d93da5..601118e 100644
--- a/NEWS
+++ b/NEWS
@@ -31,7 +31,7 @@ The --copy option can be used together with --set and --script.
The --filter=FRAME-LIST option can be used in conjunction with
--query, --copy and --delete. It abridges the scope of operation
-to the fields from FRAME-LIST. The `--delete --filter=FRAME-LIST'
+to fields from FRAME-LIST. The `--delete --filter=FRAME-LIST'
is equivalent to `--delete=FRAME-LIST'.
* New option --list-frames (-L)
@@ -90,9 +90,8 @@ The full syntax is:
NAME:QUAL
Where NAME is a frame name or ID and QUAL stands for a list of
-qualifiers separated by colons. Empty
-qualifiers and '*' act as wildcards, matching any actual field value.
-For example:
+qualifiers separated by colons. Empty qualifiers and '*' act as
+wildcards, matching any actual field value. For example:
--query title,comment::my-comment
--delete=comment:eng:my-comment
@@ -129,6 +128,17 @@ frame qualifiers. For example, for "comment" (COMM) frames:
the text is written
condesc content descriptor
+Unsupported or partially-supported frames contain a single property:
+rawdata. The value of this property is a list of frame fields. Each
+field is represented by a triplet (ORD TYPE VALUE), where ORD is the
+ordinal number of that field in frame, TYPE is its type (integer) and
+VALUE is its value. If TYPE is one of numeric types, VALUE is the
+numeric value converted to string (string->number will bring it back
+to number). If TYPE is a string type, VALUE contains the string in
+the appropriate encoding. Otherwise, VALUE holds the field value as
+a binary string. Each byte in such a string is represented by two
+hexagesimal digits. For example, "AB\n" is represented as 41420A.
+
* Guile startup files.
When run with the --script option, idest searches for files .idest.scm,
@@ -145,7 +155,7 @@ This feature is disabled if the argument contains directory separators
* Test script `echo.scm'
-The test script `echo.scm' is installed into the program script
+The test script `echo.scm' is installed in the program script
directory. It allows you to check whether your scripts work in
the expected way and correctly modify the frames. For example,
to test the script `modify.scm' run
diff --git a/doc/idest.texi b/doc/idest.texi
index 37bdfec..f88b42a 100644
--- a/doc/idest.texi
+++ b/doc/idest.texi
@@ -37,13 +37,9 @@ Copyright @copyright{} 2009-2011 Sergey Poznyakoff
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3 or
any later version published by the Free Software Foundation; with no
-Invariant Sections, with the Front-Cover texts being ``IdEst -- an
-ID3 Edit and Scripting Tool'' and with the Back-Cover Texts as in (a)
-below. A copy of the license is included in the section entitled
-``GNU Free Documentation License''.
-
-(a) The Back-Cover Text is: ``You have freedom to copy and modify
-this manual, like GNU software.''
+Invariant Sections, and without restrictions as to the Front and
+Back-Cover texts. A copy of the license is included in the section
+entitled ``GNU Free Documentation License''.
@end copying
@titlepage
@@ -74,9 +70,10 @@ documents IdEst @value{VERSION}.
@menu
* Intro:: Introduction to ID3 Tags and @samp{IdEst}
* Tag Versions:: ID3 Tag Versions
+* Frames:: ID3 Frames
* View:: Viewing Existing Tags
* Modify:: Modifying Existing Tags
-* Delete:: Deleting Tags
+* Delete:: Deleting Tags and Frames
* ID Versioning:: Storing Tags in Different ID3 Versions
* Structure:: Examining File Structure
* Scripting:: Scripting
@@ -139,7 +136,7 @@ creating version 1 tags or converting version 2 to version 1.
Properly speaking, the pure version 1 tag is seldom used. It is its
modified version, called 1.1 which is used most often.
- The version 1.1 tag contains the following fields:
+ The version 1.1 tag contains the following frames:
@float Table, ID3v1
@caption{ID3v1.1 tag}
@@ -156,11 +153,11 @@ modified version, called 1.1 which is used most often.
@end float
The last field, @samp{genre}, merits special notice. It is an ordinal
-number of the genre in a predefined table of genres (@pxref{Genre
+number of genre in a predefined table of genres (@pxref{Genre
Codes}). When modifying or setting this tag, you should supply one
of the values listed in that table (case-insensitive). If the value
you supply is not found in that table, the value @samp{Other} will be
-set.
+used.
@cindex ID3v2
@cindex ID3 version 2
@@ -183,6 +180,73 @@ corresponding to the ID3v1 fields, are:
@end multitable
@end float
+@node Frames
+@chapter ID3 Frames
+@cindex frames
+Each ID3 tag consists of frames. As described above, IDv1 tags
+contain a fixed set of frames, whereas IDv2 tags can contain
+any number of this. The frame @dfn{ID} is a four-character name
+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
+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
+example, the @samp{COMM} (comment) frame contains two qualifiers:
+@dfn{language}, which holds a three-letter code of the language the
+comment is written in, and @dfn{content descriptor}, which holds
+arbitrary string describing the comment.
+
+@anchor{fully-qualified name}
+@cindex fully-qualified frame name
+There are two ways to address a frame: by its ID, and by its
+fully-qualified name. Addressing the frame by its ID retrieves all
+instances of that frame. A @dfn{fully-qualified name}, on the other
+hand, provides a way to retrieve a particular instance of the frame.
+A fully-qualified name consists of frame ID, followed by a colon and
+a list of qualifier values, delimited with colons. For example, the
+name @samp{COMM:eng:my-comment} will select the @samp{COMM} frame
+which has @samp{eng} in its language field and @samp{my-comment} in
+its content descriptor field. Any of qualifiers in a fully-qualified
+name can be omitted. Such an empty qualifier works as a
+@dfn{wildcard}, matching any value in the actual field. Thus,
+@samp{COMM::my-comment} select the @samp{COMM} frames with content
+descriptor @samp{my-comment}, no matter what their language.
+
+@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
+frames:
+
+@example
+$ idest --list-frames
+COMM:lang:condesc Comments
+TALB Album/movie/show title
+TBPM BPM (beats per minute)
+TCOM Composer
+...
+@end example
+
+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.
+
+@xopindex{filter, introduced}
+To select one or several frames of interest, give their names as
+argument (a comma-separated list) to the @option{--filter}
+(@option{-F}) argument, e.g.:
+
+@example
+$ idest --list --filter=COMM,TXXX
+COMM:lang:condesc Comments
+TXXX:descr User defined text information frame
+@end example
+
+The @option{--filter} option is a standard way to abridge
+@command{idest} operation to a subset of frames.
+
@node View
@chapter Viewing Existing Tags
@@ -203,42 +267,78 @@ genre: Folk
@cindex query mode
@xopindex{query, introduced}
This operation mode is called @dfn{query mode}. By default,
-@command{idest} shows all these fields in this order. If you wish to
-display only a subset of them, use the @option{--query} option
-(or @option{-q}, for short). It takes a comma-separated list of the
-frame names to query. For example:
+@command{idest} shows all these fields in this order. If there are
+several comment fields, they will be shown in the fully-qualified
+form, e.g.:
@example
-$ idest --query=artist,title,year file.mp3
+$ idest track01.mp3
+title: Plou i fa sol
+album: Camins de Tarda
+track: 3
+comment:eng:my: Comment text
+comment:eng:encoder: lame
+artist: Josep Tero
+year: 1995
+genre: Folk
+@end example
+
+@xopindex{filter, in query mode}
+If you wish to display another frames, use the @option{--filter}
+(@option{-F}) option:
+
+@example
+$ idest --filter=artist,title,year file.mp3
artist: Joan Baez
title: Diamonds & Rust
year: 1975
@end example
-If the long option form is used, as in the example above, then the
-frame list must be separated from it by an equal sign, with no
-surrounding white space. If the short option form is used, the list
-must follow the option letter, with no white space in between, e.g.:
+The names given in the filter list can be either IDv1 or IDv2 names,
+@command{idest} will convert the to IDv2 automatically.
+
+Frames can also be given in a fully-qualified form, for example:
@example
-$ idest -qartist,title,year file.mp3
+$ idest --filter=title,comment::encoder track01.mp3
+title: Plou i fa sol
+comment:eng:encoder: lame
@end example
-The frame list may contain either field names (@pxref{ID3v1}) or
-the corresponding standard frame names (@pxref{ID3v2}).
+You can also define a string which will be printed instead of the
+frame name in the output. This string is given as a prefix to the
+frame name. The two parts are delimited by a percent sign, e.g.:
+
+@example
+$ idest --filter=Title%title,'Encoded by'%comment::encoder track01.mp3
+Title: Plou i fa sol
+Encoded by: lame
+@end example
@anchor{describe}
-@xopindex{describe, introduced}
To describe frames in a verbose manner, use the @option{--describe}
(@option{-D}) option''
@example
-$ idest --describe -qartist,title,year file.mp3
+$ idest --describe --filter=artist,title,year file.mp3
Lead performer(s)/soloist(s): Joan Baez
Title/songname/content description: Diamonds & Rust
Recording time: 1975
@end example
+@xopindex{query, introduced}
+For compatibility with previous versions, the @option{--query} option
+(or @option{-q}, for short) is supported. When used without argument
+it forces the query mode. If argument is supplied, it must be in the
+same format as for the @option{--filter} option and has the same
+effect (e.g. @code{idest -qartist,title,year file.mp3}).
+
+If the long option form (@option{--query}) is used, then the frame
+list must be separated from the option by an equal sign, with no
+surrounding white space. If the short option form (@option{-q}) is
+used, the list must follow the option letter, with no white space in
+between.
+
@xopindex{latin1, introduced}
@cindex UTF-8
@cindex ISO-8859-1
@@ -257,11 +357,11 @@ year: 1991
genre:
@end example
-Of course, @option{--latin1} and @option{--query} can be used
-together:
+Of course, @option{--latin1} and @option{--filter} (or
+@option{--query}) can be used together:
@example
-$ idest --latin1 --query=title,artist,album track06.mp3
+$ idest --latin1 --filter=title,artist,album track06.mp3
title: D@'ona'm sa m@`a
artist: Llu@'is Llach
album: Torna aviat
@@ -270,45 +370,12 @@ album: Torna aviat
Future versions of @command{idest} will provide more sophisticated
recoding facilities.
-@anchor{comment frames}
-@cindex comment frames, in query mode
-@cindex content descriptor, in comment frames
-@cindex language, in comment frames
-If several frames match a queried frame name, @command{idest}
-concatenates their values and displays them on a single line. Comment
-frames are treated specially. Each comment frame has a @dfn{language
-field}, which holds a three-letter code of the language the comment is
-written in, and a @dfn{content descriptor} field, which is supposed to
-help discern multiple comment entries. In the concatenated string,
-each frame value is prefixed by the corresponding content
-descriptor enclosed in square brackets. For example:
-
-@example
-$ idest track01.mp3
-title: Cor i arbre
-album: Fronteres
-track: 1
-comment: [Bit_Rate]: 320 [Sample_Rate]: 44100
-artist: Josep Tero
-year: 2009
-genre:
-@end example
-
@anchor{all-frames query}
@anchor{fully qualified comment}
@xopindex{all, introduced}
@cindex comment, fully qualified form
There is a special option which instructs @command{idest} to output
-all frames: the @option{--all} (@option{-a}) option. When it is used,
-comment headers are output in @dfn{fully qualified} form, i.e.:
-
-@example
-comment:@var{lang}:@var{descr}
-@end example
-
-@noindent
-where @var{lang} is the three-letter language code and @var{descr} is
-the content descriptor. For example:
+all frames: the @option{--all} (@option{-a}) option:
@example
$ idest --all track01.mp3
@@ -323,16 +390,6 @@ year: 2009
genre:
@end example
-You can also use fully qualified comment form in frame lists given
-with the @option{--query} option, e.g.:
-
-@example
-$ idest --all title,track,comment::Sample_Rate track01.mp3
-title: Cor i arbre
-track: 1
-comment: [Sample_Rate]: track01.mp3
-@end example
-
@node Modify
@chapter Modifying Existing Tags
@@ -344,16 +401,26 @@ option. For example:
$ idest --set artist='Jacques Brel' track01.mp3
@end example
-Several @option{--set} options may be used together to set several
-fields at once:
+Several frames can be set at once. To do so you can either supply
+a distinct @option{--set} option for each frame, or to give a
+single @option{--set} option followed by as many frame assignments as
+you need, for example:
@example
$ idest --set artist='Jacques Brel' \
--set title='Ne me quitte pas' track01.mp3
@end example
-When setting comment frames, you can use fully qualified form
-(@pxref{fully qualified comment}), e.g.:
+@noindent
+or
+
+@example
+$ idest --set artist='Jacques Brel' \
+ title='Ne me quitte pas' track01.mp3
+@end example
+
+You can use fully qualified form (@pxref{fully-qualified name}) for
+frames that require it:
@example
$ idest --set comment:eng:My_comment='Noise reduction on' track01.mp3
@@ -377,7 +444,7 @@ $ idest --latin1 --set artist='Llu@'is Llach' *.mp3
@end example
@node Delete
-@chapter Deleting Tags
+@chapter Deleting Tags and Frames
@xopindex{delete, described}
The @option{--delete} (@option{-d}) option instructs @command{idest}
@@ -391,11 +458,20 @@ $ idest --delete *.mp3
After this operation, all ID3 data are irrevocably lost, so use it
with caution.
- A list of frame names can be given as an argument to
+@xopindex{filter, used with --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
delete only comment and genre tags:
@example
+$ idest --delete --filter=comment,genre *.mp3
+@end example
+
+@noindent
+or
+
+@example
$ idest --delete=comment,genre *.mp3
@end example
@@ -404,7 +480,7 @@ all comment frames. To remove a particular one, use its qualified
form:
@example
-$ idest --delete=comment::Bit_Rate track01.mp3
+$ idest --delete --filter=comment::Bit_Rate track01.mp3
@end example
@node ID Versioning
diff --git a/examples/echo.scm b/examples/echo.scm
index 869b6b9..d6b07ab 100644
--- a/examples/echo.scm
+++ b/examples/echo.scm
@@ -1,24 +1,28 @@
-;; echo.scm - test a user script.
+;; echo.scm - test another Idest script.
;; Copyright (C) 2011 Sergey Poznyakoff
;; License GPLv3+: GNU GPL version 3 or later
;; <http://gnu.org/licenses/gpl.html>
;; This is free software: you are free to change and redistribute it.
;; There is NO WARRANTY, to the extent permitted by law.
-(let ((cmd (command-line)))
+(let* ((cmd (command-line))
+ (progname (car cmd)))
+ (set! %load-hook (lambda (filename)
+ (format #t "~A: loading ~a ...\n"
+ progname filename)))
(cond
((< (length cmd) 3)
- (error "usage: echo.scm SCRIPT FILE...")
+ (format (current-error-port) "usage: idest -S ~A SCRIPT FILE...~%"
+ progname)
(exit 1))
(else
(let ((file-name (list-ref cmd 1)))
(set-program-arguments (cons (car cmd) (list-tail cmd 2)))
- (load file-name)
+ (primitive-load-path file-name)
(cond
(idest-readonly
(format (current-error-port)
- "~A does not modify frames~%" file-name)
- (exit 1))
+ "~A: info: ~A does not modify frames~%" progname file-name))
((catch #t
(lambda ()
(procedure? idest-main))
@@ -32,6 +36,6 @@
(format #t "File ~A ~A~%" file result))))))
(else
(format (current-error-port)
- "idest-main is not defined in ~A~%" file-name)
+ "~A: idest-main is not defined in ~A~%" progname file-name)
(exit 1)))))))
diff --git a/src/idop.c b/src/idop.c
index e8e6aaf..316cd9c 100644
--- a/src/idop.c
+++ b/src/idop.c
@@ -125,6 +125,52 @@ output_list_free()
}
}
+#define DESCR_COLUMN 24
+static int
+describe_frame(const struct idest_frametab *ft, void *data)
+{
+ struct id3_frametype const *frametype;
+ int n;
+
+ frametype = id3_frametype_lookup(ft->id, 4);
+ assert(frametype != NULL);
+ printf("%s", ft->id);
+ n = 0;
+ if (ft->qc) {
+ int i;
+ for (i = 0; i < ft->qc; i++)
+ n += printf(":%s", ft->qv[i]);
+ }
+ while (++n < DESCR_COLUMN)
+ putchar(' ');
+
+ printf("%s\n", frametype->description);
+ return 0;
+}
+
+void
+list_supported_frames(void)
+{
+ if (filter_list) {
+ gl_list_iterator_t itr;
+ const void *p;
+
+ itr = gl_list_iterator(filter_list);
+
+ while (gl_list_iterator_next(&itr, &p, NULL)) {
+ const struct ed_item *item = p;
+ const struct idest_frametab *ft =
+ idest_frame_lookup(item->id);
+ if (!ft)
+ error(1, 0, "no such frame: %s",
+ item->id);
+ describe_frame(ft, NULL);
+ }
+ gl_list_iterator_free(&itr);
+ } else
+ frametab_enumerate(describe_frame, NULL, 1);
+}
+
void
safe_id3_file_update_and_close(struct id3_file *file)
{
diff --git a/src/main.c b/src/main.c
index 2d63b63..f23517e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -98,36 +98,6 @@ qv_free(size_t qc, char **qv)
free(qv);
}
-#define DESCR_COLUMN 24
-static int
-describe_frame(const struct idest_frametab *ft, void *data)
-{
- struct id3_frametype const *frametype;
- int n;
-
- frametype = id3_frametype_lookup(ft->id, 4);
- assert(frametype != NULL);
- printf("%s", ft->id);
- n = 0;
- if (ft->qc) {
- int i;
- for (i = 0; i < ft->qc; i++)
- n += printf(":%s", ft->qv[i]);
- }
- while (++n < DESCR_COLUMN)
- putchar(' ');
-
- printf("%s\n", frametype->description);
- return 0;
-}
-
-static void
-list_supported_frames(void)
-{
- frametab_enumerate(describe_frame, NULL, 1);
-}
-
-
void
verify_mp3(FILE *fp, const char *name)
{

Return to:

Send suggestions and report system problems to the System administrator.