mirror of
https://github.com/fmang/opustags.git
synced 2025-01-15 12:43:17 +01:00
Add option --vendor
This commit is contained in:
parent
330fe5e9f2
commit
dcb128f179
@ -64,6 +64,7 @@ Documentation
|
||||
-e, --edit edit tags interactively in VISUAL/EDITOR
|
||||
--output-cover FILE extract and save the cover art, if any
|
||||
--set-cover FILE sets the cover art
|
||||
--vendor print the vendor string
|
||||
--raw disable encoding conversion
|
||||
|
||||
See the man page, `opustags.1`, for extensive documentation.
|
||||
|
@ -121,6 +121,10 @@ Specify \fB-\fP to read the picture from standard input.
|
||||
In theory, an Opus file may contain multiple pictures with different roles, though in practice only
|
||||
the front cover really matters. opustags can currently only handle one front cover and nothing else.
|
||||
.TP
|
||||
.B \-\-vendor
|
||||
Print the vendor string from the OpusTags packet and do nothing else. Standard tags operations are
|
||||
not supported when specifying this flag.
|
||||
.TP
|
||||
.B \-\-raw
|
||||
OpusTags metadata should always be encoded in UTF-8, as per RFC 7845. However, some files may be
|
||||
corrupted or possibly even contain intentional binary data. In that case, --raw lets you edit that
|
||||
|
55
src/cli.cc
55
src/cli.cc
@ -38,6 +38,7 @@ Options:
|
||||
-e, --edit edit tags interactively in VISUAL/EDITOR
|
||||
--output-cover FILE extract and save the cover art, if any
|
||||
--set-cover FILE sets the cover art
|
||||
--vendor print the vendor string
|
||||
--raw disable encoding conversion
|
||||
|
||||
See the man page for extensive documentation.
|
||||
@ -56,6 +57,7 @@ static struct option getopt_options[] = {
|
||||
{"edit", no_argument, 0, 'e'},
|
||||
{"output-cover", required_argument, 0, 'c'},
|
||||
{"set-cover", required_argument, 0, 'C'},
|
||||
{"vendor", no_argument, 0, 'v'},
|
||||
{"raw", no_argument, 0, 'r'},
|
||||
{NULL, 0, 0, 0}
|
||||
};
|
||||
@ -123,6 +125,9 @@ ot::options ot::parse_options(int argc, char** argv, FILE* comments_input)
|
||||
throw status {st::bad_arguments, "Cannot specify --set-cover more than once."};
|
||||
set_cover = optarg;
|
||||
break;
|
||||
case 'v':
|
||||
opt.print_vendor = true;
|
||||
break;
|
||||
case 'r':
|
||||
opt.raw = true;
|
||||
break;
|
||||
@ -172,6 +177,8 @@ ot::options ot::parse_options(int argc, char** argv, FILE* comments_input)
|
||||
}
|
||||
}
|
||||
|
||||
bool read_only = !opt.in_place && !opt.path_out.has_value();
|
||||
|
||||
if (opt.in_place && opt.path_out)
|
||||
throw status {st::bad_arguments, "Cannot combine --in-place and --output."};
|
||||
|
||||
@ -184,7 +191,7 @@ ot::options ot::parse_options(int argc, char** argv, FILE* comments_input)
|
||||
if (opt.edit_interactively && (stdin_as_input || opt.path_out == "-" || opt.cover_out == "-"))
|
||||
throw status {st::bad_arguments, "Cannot edit interactively when standard input or standard output are already used."};
|
||||
|
||||
if (opt.edit_interactively && !opt.path_out.has_value() && !opt.in_place)
|
||||
if (opt.edit_interactively && read_only)
|
||||
throw status {st::bad_arguments, "Cannot edit interactively when no output is specified."};
|
||||
|
||||
if (opt.edit_interactively && (opt.delete_all || !opt.to_add.empty() || !opt.to_delete.empty()))
|
||||
@ -196,6 +203,9 @@ ot::options ot::parse_options(int argc, char** argv, FILE* comments_input)
|
||||
if (opt.cover_out && opt.paths_in.size() > 1)
|
||||
throw status {st::bad_arguments, "Cannot use --output-cover with multiple input files."};
|
||||
|
||||
if (opt.print_vendor && !read_only)
|
||||
throw status {st::bad_arguments, "--vendor is only supported in read-only mode."};
|
||||
|
||||
if (set_cover) {
|
||||
byte_string picture_data = ot::slurp_binary_file(set_cover->c_str());
|
||||
opt.to_delete.push_back(u8"METADATA_BLOCK_PICTURE"s);
|
||||
@ -231,6 +241,26 @@ static std::u8string format_value(const std::u8string& source)
|
||||
return formatted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the comment from UTF-8 to the system encoding if relevant, and print it with a trailing
|
||||
* line feed.
|
||||
*/
|
||||
static void puts_utf8(std::u8string_view str, FILE* output, bool raw)
|
||||
{
|
||||
if (raw) {
|
||||
fwrite(str.data(), 1, str.size(), output);
|
||||
} else {
|
||||
try {
|
||||
std::string local = ot::decode_utf8(str);
|
||||
fwrite(local.data(), 1, local.size(), output);
|
||||
} catch (ot::status& rc) {
|
||||
rc.message += " See --raw.";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
putc('\n', output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Print comments in a human readable format that can also be read back in by #read_comment.
|
||||
*
|
||||
@ -249,21 +279,8 @@ void ot::print_comments(const std::list<std::u8string>& comments, FILE* output,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::u8string utf8_comment = format_value(source_comment);
|
||||
// Convert the comment from UTF-8 to the system encoding if relevant.
|
||||
if (raw) {
|
||||
fwrite(utf8_comment.data(), 1, utf8_comment.size(), output);
|
||||
} else {
|
||||
try {
|
||||
std::string local = decode_utf8(utf8_comment);
|
||||
fwrite(local.data(), 1, local.size(), output);
|
||||
} catch (ot::status& rc) {
|
||||
rc.message += " See --raw.";
|
||||
throw;
|
||||
}
|
||||
}
|
||||
putc('\n', output);
|
||||
puts_utf8(utf8_comment, output, raw);
|
||||
}
|
||||
if (has_control)
|
||||
fputs("warning: Some tags contain control characters.\n", stderr);
|
||||
@ -498,8 +515,12 @@ static void process(ot::ogg_reader& reader, ot::ogg_writer* writer, const ot::op
|
||||
writer->write_header_packet(serialno, pageno, packet);
|
||||
pageno_offset = writer->next_page_no - 1 - reader.absolute_page_no;
|
||||
} else {
|
||||
if (opt.cover_out != "-")
|
||||
ot::print_comments(tags.comments, stdout, opt.raw);
|
||||
if (opt.cover_out != "-") {
|
||||
if (opt.print_vendor)
|
||||
puts_utf8(tags.vendor, stdout, opt.raw);
|
||||
else
|
||||
ot::print_comments(tags.comments, stdout, opt.raw);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (writer) {
|
||||
|
@ -3,7 +3,7 @@
|
||||
* \ingroup opus
|
||||
*
|
||||
* The way Opus is encapsulated into an Ogg stream, and the content of the packets we're dealing
|
||||
* with here is defined by [RFC 7584](https://tools.ietf.org/html/rfc7845.html).
|
||||
* with here is defined by [RFC 7845](https://tools.ietf.org/html/rfc7845.html).
|
||||
*
|
||||
* Section 3 "Packet Organization" is critical for us:
|
||||
*
|
||||
|
@ -515,6 +515,13 @@ struct options {
|
||||
* Option: --output-cover
|
||||
*/
|
||||
std::optional<std::string> cover_out;
|
||||
/**
|
||||
* Print the vendor string at the beginning of the OpusTags packet instead of printing the
|
||||
* tags. Only applicable in read-only mode.
|
||||
*
|
||||
* Option: --vendor
|
||||
*/
|
||||
bool print_vendor = false;
|
||||
/**
|
||||
* Disable encoding conversions. OpusTags are specified to always be encoded as UTF-8, but
|
||||
* if for some reason a specific file contains binary tags that someone would like to
|
||||
|
2
t/cli.cc
2
t/cli.cc
@ -185,6 +185,8 @@ void check_bad_arguments()
|
||||
"Cannot specify standard output for both --output and --output-cover.", "-o and --output-cover conflict");
|
||||
error_case({"opustags", "-i", "x", "y", "--output-cover", "z"},
|
||||
"Cannot use --output-cover with multiple input files.", "--output-cover with multiple input");
|
||||
error_case({"opustags", "-i", "--vendor", "x"},
|
||||
"--vendor is only supported in read-only mode.", "--vendor when editing");
|
||||
error_case({"opustags", "-d", "\xFF", "x"},
|
||||
"Could not encode argument into UTF-8:",
|
||||
"-d with binary data");
|
||||
|
39
t/opustags.t
39
t/opustags.t
@ -4,7 +4,8 @@ use strict;
|
||||
use warnings;
|
||||
use utf8;
|
||||
|
||||
use Test::More tests => 59;
|
||||
use Test::More tests => 60;
|
||||
use Test::Deep qw(cmp_deeply re);
|
||||
|
||||
use Digest::MD5;
|
||||
use File::Basename;
|
||||
@ -53,34 +54,9 @@ $help->[0] =~ /^([^\n]*+)/;
|
||||
my $version = $1;
|
||||
like($version, qr/^opustags version (\d+\.\d+\.\d+)/, 'get the version string');
|
||||
|
||||
my $expected_help = <<"EOF";
|
||||
$version
|
||||
|
||||
Usage: opustags --help
|
||||
opustags [OPTIONS] FILE
|
||||
opustags OPTIONS -i FILE...
|
||||
opustags OPTIONS FILE -o FILE
|
||||
|
||||
Options:
|
||||
-h, --help print this help
|
||||
-o, --output FILE specify the output file
|
||||
-i, --in-place overwrite the input files
|
||||
-y, --overwrite overwrite the output file if it already exists
|
||||
-a, --add FIELD=VALUE add a comment
|
||||
-d, --delete FIELD[=VALUE] delete previously existing comments
|
||||
-D, --delete-all delete all the previously existing comments
|
||||
-s, --set FIELD=VALUE replace a comment
|
||||
-S, --set-all import comments from standard input
|
||||
-e, --edit edit tags interactively in VISUAL/EDITOR
|
||||
--output-cover FILE extract and save the cover art, if any
|
||||
--set-cover FILE sets the cover art
|
||||
--raw disable encoding conversion
|
||||
|
||||
See the man page for extensive documentation.
|
||||
EOF
|
||||
|
||||
is_deeply(opustags('--help'), [$expected_help, '', 0], '--help displays the help message');
|
||||
is_deeply(opustags('-h'), [$expected_help, '', 0], '-h displays the help message too');
|
||||
my $expected_help = qr{opustags version .*\n\nUsage: opustags --help\n};
|
||||
cmp_deeply(opustags('--help'), [re($expected_help), '', 0], '--help displays the help message');
|
||||
cmp_deeply(opustags('-h'), [re($expected_help), '', 0], '-h displays the help message too');
|
||||
|
||||
is_deeply(opustags('--derp'), ['', <<"EOF", 512], 'unrecognized option shows an error');
|
||||
error: Unrecognized option '--derp'.
|
||||
@ -342,3 +318,8 @@ unlink('out.png');
|
||||
is_deeply(opustags(qw(-D --set-cover - gobble.opus), { in => "GIF8 x" }), [<<'END_OUT', '', 0], 'read the cover from stdin');
|
||||
METADATA_BLOCK_PICTURE=AAAAAwAAAAlpbWFnZS9naWYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZHSUY4IHg=
|
||||
END_OUT
|
||||
|
||||
####################################################################################################
|
||||
# Vendor string
|
||||
|
||||
is_deeply(opustags(qw(--vendor gobble.opus)), ["Lavf58.12.100\n", '', 0], 'print the vendor string');
|
||||
|
Loading…
x
Reference in New Issue
Block a user