11 Commits
1.0 ... 1.1.1

Author SHA1 Message Date
7174a1f2f2 bump to 1.1.1 2018-10-24 18:27:57 -04:00
1a8aaff933 Don't croak on overlong opustags 2018-10-02 18:48:09 -04:00
4973a4deab Become macOS compatible 2018-10-02 18:48:09 -04:00
8e9d98ac62 README: show alternatives 2017-10-01 12:26:56 +02:00
fcd647003b in-place 2013-01-02 10:59:43 +01:00
a8e22fb5db remove broken file on failure 2013-01-02 10:21:33 +01:00
f75e484ebb set-all: do not ignore the last unterminated line 2013-01-02 10:13:41 +01:00
6f6cf8024b readme: requirements 2013-01-02 10:04:25 +01:00
f1828d926f sentinel option 2013-01-01 23:35:11 +01:00
1021b4394d check in before out
so as not to create empty files
2013-01-01 23:31:25 +01:00
1e138ad00d bump version: 1.1 2013-01-01 23:28:09 +01:00
3 changed files with 118 additions and 37 deletions

View File

@ -3,6 +3,32 @@ opustags
View and edit Opus comments.
**Please note this project is old and not actively maintained.**
Maybe you should use something else.
It was built because at the time nothing supported Opus, but now things have
changed for the better.
For alternative, check out these projects:
- [EasyTAG](https://wiki.gnome.org/Apps/EasyTAG)
- [Beets](http://beets.io/)
- [Picard](https://picard.musicbrainz.org/)
- [puddletag](http://docs.puddletag.net/)
- [Quod Libet](https://quodlibet.readthedocs.io/en/latest/)
- [Goggles Music Manager](https://gogglesmm.github.io/)
See also these libraries if you need a lower-level access:
- [TagLib](http://taglib.org/)
- [mutagen](https://mutagen.readthedocs.io/en/latest/)
Requirements
------------
* A POSIX-compliant system,
* libogg.
Installing
----------

View File

@ -1,4 +1,4 @@
.TH opustags 1 "January 1st 2013"
.TH opustags 1 "January 2013"
.SH NAME
opustags \- Opus comment editor
.SH SYNOPSIS
@ -26,6 +26,7 @@ This could be useful to preview some changes before writing them.
As for the edition mode, you need to specify an output file (or \fB-\fP for
\fBstdout\fP). It must be different from the input file.
You may want to use \fB--overwrite\fP if you know what youre doing.
To overwrite the input file, use \fB--in-place\fP.
.PP
Tag edition can be made with the \fB--add\fP, \fB--delete\fP and \fB--set\fP
options. They can be written in any order and dont conflict with each other.
@ -57,6 +58,14 @@ specified output file. If \fIFILE\fP is \fB-\fP then the resulting Opus file
will be written to \fBstdout\fP. As the input file is read incrementally, the
output file cant be the same as the input file.
.TP
.B \-i, \-\-in-place \fR[\fP\fISUFFIX\fP\fR]\fP
Use this when you want to modify the input file in-place. This creates a
temporary file with the specified suffix (.otmp by default). This implies
\fB--overwrite\fP in that if a file with the same temporary name already
exists, it will be overwritten without warning. Of course, this overwrites
the input file too. You cannot use this option when the input file is actually
\fBstdin\fP.
.TP
.B \-y, \-\-overwrite
By default, \fBopustags\fP refuses to overwrite an already existent file. Use
this option to allow that. Note that this doesnt allow in-place edition, the
@ -89,10 +98,9 @@ or \fB--set\fP, which, in that case, are equivalent.
.B \-S, \-\-set-all
Sets the tags from scratch. All the original tags are deleted and new ones are
read from \fBstdin\fP. Each line must specify a \fIFIELD=VALUE\fP pair and be
LF-terminated. If the last line isnt terminated when the end of the stream is
reached, it is ignored. Invalid lines are skipped and cause a warning to be
issued. This could be useful for batch processing tags through an utility like
\fBsed\fP.
LF-terminated (except for the last line). Invalid lines are skipped and cause
a warning to be issued. Blank lines are ignored. This mode could be useful for
batch processing tags through an utility like \fBsed\fP.
.SH SEE ALSO
.BR vorbiscomment (1),
.BR sed (1)

View File

@ -7,6 +7,12 @@
#include <unistd.h>
#include <ogg/ogg.h>
#ifdef __APPLE__
#include <libkern/OSByteOrder.h>
#define htole32(x) OSSwapHostToLittleInt32(x)
#define le32toh(x) OSSwapLittleToHostInt32(x)
#endif
typedef struct {
uint32_t vendor_length;
const char *vendor_string;
@ -50,8 +56,10 @@ int parse_tags(char *data, long len, opus_tags *tags){
if(pos > len)
return -1;
}
if(pos != len)
return -1;
if(pos < len)
fprintf(stderr, "warning: %ld unused bytes at the end of the OpusTags packet\n", len - pos);
return 0;
}
@ -156,7 +164,7 @@ int write_page(ogg_page *og, FILE *stream){
return 0;
}
const char *version = "opustags version 1.0\n";
const char *version = "opustags version 1.1.1\n";
const char *usage =
"Usage: opustags --help\n"
@ -167,6 +175,7 @@ const char *help =
"Options:\n"
" -h, --help print this help\n"
" -o, --output write the modified tags to a file\n"
" -i, --in-place [SUFFIX] use a temporary file then replace the original file\n"
" -y, --overwrite overwrite the output file if it already exists\n"
" -d, --delete FIELD delete all the fields of a specified type\n"
" -a, --add FIELD=VALUE add a field\n"
@ -177,12 +186,14 @@ const char *help =
struct option options[] = {
{"help", no_argument, 0, 'h'},
{"output", required_argument, 0, 'o'},
{"in-place", optional_argument, 0, 'i'},
{"overwrite", no_argument, 0, 'y'},
{"delete", required_argument, 0, 'd'},
{"add", required_argument, 0, 'a'},
{"set", required_argument, 0, 's'},
{"delete-all", no_argument, 0, 'D'},
{"set-all", no_argument, 0, 'S'}
{"set-all", no_argument, 0, 'S'},
{NULL, 0, 0, 0}
};
int main(int argc, char **argv){
@ -191,7 +202,7 @@ int main(int argc, char **argv){
fputs(usage, stdout);
return EXIT_SUCCESS;
}
const char *path_in, *path_out = NULL;
char *path_in, *path_out = NULL, *inplace = NULL;
const char* to_add[argc];
const char* to_delete[argc];
int count_add = 0, count_delete = 0;
@ -200,7 +211,7 @@ int main(int argc, char **argv){
int overwrite = 0;
int print_help = 0;
int c;
while((c = getopt_long(argc, argv, "ho:yd:a:s:DS", options, NULL)) != -1){
while((c = getopt_long(argc, argv, "ho:i::yd:a:s:DS", options, NULL)) != -1){
switch(c){
case 'h':
print_help = 1;
@ -208,6 +219,9 @@ int main(int argc, char **argv){
case 'o':
path_out = optarg;
break;
case 'i':
inplace = optarg == NULL ? ".otmp" : optarg;
break;
case 'y':
overwrite = 1;
break;
@ -248,6 +262,10 @@ int main(int argc, char **argv){
fputs("invalid arguments\n", stderr);
return EXIT_FAILURE;
}
if(inplace && path_out){
fputs("cannot combine --in-place and --output\n", stderr);
return EXIT_FAILURE;
}
path_in = argv[optind];
if(path_out != NULL && strcmp(path_in, "-") != 0){
char canon_in[PATH_MAX+1], canon_out[PATH_MAX+1];
@ -258,30 +276,14 @@ int main(int argc, char **argv){
}
}
}
FILE *out = NULL;
if(path_out != NULL){
if(strcmp(path_out, "-") == 0)
out = stdout;
else{
if(!overwrite){
if(access(path_out, F_OK) == 0){
fprintf(stderr, "'%s' already exists (use -y to overwrite)\n", path_out);
return EXIT_FAILURE;
}
}
out = fopen(path_out, "w");
if(!out){
perror("fopen");
return EXIT_FAILURE;
}
}
}
FILE *in;
if(strcmp(path_in, "-") == 0){
if(set_all){
fputs("can't open stdin for input when -S is specified\n", stderr);
if(out)
fclose(out);
return EXIT_FAILURE;
}
if(inplace){
fputs("cannot modify stdin 'in-place'\n", stderr);
return EXIT_FAILURE;
}
in = stdin;
@ -290,10 +292,40 @@ int main(int argc, char **argv){
in = fopen(path_in, "r");
if(!in){
perror("fopen");
if(out)
fclose(out);
return EXIT_FAILURE;
}
FILE *out = NULL;
if(inplace != NULL){
path_out = malloc(strlen(path_in) + strlen(inplace) + 1);
if(path_out == NULL){
fputs("failure to allocate memory\n", stderr);
fclose(in);
return EXIT_FAILURE;
}
strcpy(path_out, path_in);
strcat(path_out, inplace);
}
if(path_out != NULL){
if(strcmp(path_out, "-") == 0)
out = stdout;
else{
if(!overwrite && !inplace){
if(access(path_out, F_OK) == 0){
fprintf(stderr, "'%s' already exists (use -y to overwrite)\n", path_out);
fclose(in);
return EXIT_FAILURE;
}
}
out = fopen(path_out, "w");
if(!out){
perror("fopen");
fclose(in);
if(inplace)
free(path_out);
return EXIT_FAILURE;
}
}
}
ogg_sync_state oy;
ogg_stream_state os, enc;
ogg_page og;
@ -380,16 +412,19 @@ int main(int argc, char **argv){
}
else{
char *raw_comment[256];
size_t raw_len = fread(raw_tags, 1, 16384, stdin);
if(raw_len == 16384)
size_t raw_len = fread(raw_tags, 1, 16383, stdin);
if(raw_len == 16383)
fputs("warning: truncating comment to 16 KiB\n", stderr);
raw_tags[raw_len] = '\0';
uint32_t raw_count = 0;
size_t field_len = 0;
int caught_eq = 0;
size_t i = 0;
char *cursor = raw_tags;
for(i=0; i<raw_len && raw_count < 256; i++){
if(raw_tags[i] == '\n'){
for(i=0; i <= raw_len && raw_count < 256; i++){
if(raw_tags[i] == '\n' || raw_tags[i] == '\0'){
if(field_len == 0)
continue;
if(caught_eq)
raw_comment[raw_count++] = cursor;
else
@ -460,7 +495,19 @@ int main(int argc, char **argv){
error = "opustags: invalid file";
if(error){
fprintf(stderr, "%s\n", error);
if(path_out != NULL && out != stdout)
remove(path_out);
if(inplace)
free(path_out);
return EXIT_FAILURE;
}
else if(inplace){
if(rename(path_out, path_in) == -1){
perror("rename");
free(path_out);
return EXIT_FAILURE;
}
free(path_out);
}
return EXIT_SUCCESS;
}