This is an automated email from the ASF dual-hosted git repository.

tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git


The following commit(s) were added to refs/heads/main by this push:
     new 6f2aa85fef [TIKA-4780] Map ID3 TCOP and Vorbis COPYRIGHT to 
xmpDM:copyright (#2940)
6f2aa85fef is described below

commit 6f2aa85fef428955224842e7515a6fa7165172d8
Author: Dominik Schmidt <[email protected]>
AuthorDate: Fri Jul 10 15:09:28 2026 +0200

    [TIKA-4780] Map ID3 TCOP and Vorbis COPYRIGHT to xmpDM:copyright (#2940)
    
    The MP4 parser already maps the cprt atom to xmpDM:copyright, but the
    copyright message was dropped for the other audio formats.
    
    MP3: handle the ID3v2 TCOP frame (TCR in ID3v2.2) following the same
    pattern as the composer mapping; ID3v1 has no copyright field. The
    ID3v2.3 and ID3v2.4 test fixtures gain a TCOP frame.
    
    Ogg family (Vorbis/Opus/Speex/FLAC): map the copyright comment in the
    shared OggAudioParser.extractComments. xmpDM:copyright is single-valued,
    so the first comment is mapped; like the vendor comment, the raw values
    all stay available under the generic vorbis:copyright name, making this
    purely additive.
---
 .../tika/parser/mp3/CompositeTagHandler.java       |   9 +++
 .../java/org/apache/tika/parser/mp3/ID3Tags.java   |   5 ++
 .../org/apache/tika/parser/mp3/ID3v1Handler.java   |   8 +++
 .../org/apache/tika/parser/mp3/ID3v22Handler.java  |   8 +++
 .../org/apache/tika/parser/mp3/ID3v23Handler.java  |   8 +++
 .../org/apache/tika/parser/mp3/ID3v24Handler.java  |   8 +++
 .../java/org/apache/tika/parser/mp3/Mp3Parser.java |   1 +
 .../org/apache/tika/parser/ogg/OggAudioParser.java |   7 ++
 .../org/apache/tika/parser/mp3/Mp3ParserTest.java  |   2 +
 .../apache/tika/parser/ogg/OggAudioParserTest.java |  80 +++++++++++++++++++++
 .../test/resources/test-documents/testMP3id3v2.mp3 | Bin 39577 -> 39602 bytes
 .../resources/test-documents/testMP3id3v24.mp3     | Bin 39471 -> 39496 bytes
 12 files changed, 136 insertions(+)

diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/CompositeTagHandler.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/CompositeTagHandler.java
index b7d2d75427..01ec494ada 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/CompositeTagHandler.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/CompositeTagHandler.java
@@ -76,6 +76,15 @@ public class CompositeTagHandler implements ID3Tags {
         return null;
     }
 
+    public String getCopyright() {
+        for (ID3Tags tag : tags) {
+            if (tag.getCopyright() != null) {
+                return tag.getCopyright();
+            }
+        }
+        return null;
+    }
+
     public String getYear() {
         for (ID3Tags tag : tags) {
             if (tag.getYear() != null) {
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3Tags.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3Tags.java
index 9217156f6c..c314734881 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3Tags.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3Tags.java
@@ -184,6 +184,11 @@ public interface ID3Tags {
 
     String getComposer();
 
+    /**
+     * The copyright message, if any
+     */
+    String getCopyright();
+
     String getCompilation();
 
     /**
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v1Handler.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v1Handler.java
index 7029d41d77..56c941cd93 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v1Handler.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v1Handler.java
@@ -154,6 +154,14 @@ public class ID3v1Handler implements ID3Tags {
         return null;
     }
 
+    /**
+     * ID3v1 doesn't have copyright messages,
+     * so returns null;
+     */
+    public String getCopyright() {
+        return null;
+    }
+
     /**
      * ID3v1 doesn't have album-wide artists,
      * so returns null;
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v22Handler.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v22Handler.java
index 830f4d4431..5f0102cd03 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v22Handler.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v22Handler.java
@@ -38,6 +38,7 @@ public class ID3v22Handler implements ID3Tags {
     private String album;
     private String year;
     private String composer;
+    private String copyright;
     private String genre;
     private String trackNumber;
     private String albumArtist;
@@ -67,6 +68,9 @@ public class ID3v22Handler implements ID3Tags {
                 case "TCM":
                     composer = getTagString(tag.data, 0, tag.data.length);
                     break;
+                case "TCR":
+                    copyright = getTagString(tag.data, 0, tag.data.length);
+                    break;
                 case "COM":
                     comments.add(getComment(tag.data, 0, tag.data.length));
                     break;
@@ -133,6 +137,10 @@ public class ID3v22Handler implements ID3Tags {
         return composer;
     }
 
+    public String getCopyright() {
+        return copyright;
+    }
+
     public List<ID3Comment> getComments() {
         return comments;
     }
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v23Handler.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v23Handler.java
index 23284d6773..9d10a5ac29 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v23Handler.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v23Handler.java
@@ -38,6 +38,7 @@ public class ID3v23Handler implements ID3Tags {
     private String album;
     private String year;
     private String composer;
+    private String copyright;
     private String genre;
     private String trackNumber;
     private String albumArtist;
@@ -68,6 +69,9 @@ public class ID3v23Handler implements ID3Tags {
                 case "TCOM":
                     composer = getTagString(tag.data, 0, tag.data.length);
                     break;
+                case "TCOP":
+                    copyright = getTagString(tag.data, 0, tag.data.length);
+                    break;
                 case "COMM":
                     comments.add(getComment(tag.data, 0, tag.data.length));
                     break;
@@ -119,6 +123,10 @@ public class ID3v23Handler implements ID3Tags {
         return composer;
     }
 
+    public String getCopyright() {
+        return copyright;
+    }
+
     public List<ID3Comment> getComments() {
         return comments;
     }
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v24Handler.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v24Handler.java
index 9e53b77409..f9d7b106a8 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v24Handler.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/ID3v24Handler.java
@@ -39,6 +39,7 @@ public class ID3v24Handler implements ID3Tags {
     private String album;
     private String year;
     private String composer;
+    private String copyright;
     private String genre;
     private String trackNumber;
     private String albumArtist;
@@ -74,6 +75,9 @@ public class ID3v24Handler implements ID3Tags {
                 case "TCOM":
                     composer = getTagString(tag.data, 0, tag.data.length);
                     break;
+                case "TCOP":
+                    copyright = getTagString(tag.data, 0, tag.data.length);
+                    break;
                 case "COMM":
                     comments.add(getComment(tag.data, 0, tag.data.length));
                     break;
@@ -125,6 +129,10 @@ public class ID3v24Handler implements ID3Tags {
         return composer;
     }
 
+    public String getCopyright() {
+        return copyright;
+    }
+
     public List<ID3Comment> getComments() {
         return comments;
     }
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/Mp3Parser.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/Mp3Parser.java
index 0fedb73b35..81b3ad7375 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/Mp3Parser.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/mp3/Mp3Parser.java
@@ -185,6 +185,7 @@ public class Mp3Parser implements Parser {
             metadata.set(XMPDM.ARTIST, tag.getArtist());
             metadata.set(XMPDM.ALBUM_ARTIST, tag.getAlbumArtist());
             metadata.set(XMPDM.COMPOSER, tag.getComposer());
+            metadata.set(XMPDM.COPYRIGHT, tag.getCopyright());
             metadata.set(XMPDM.ALBUM, tag.getAlbum());
             metadata.set(XMPDM.COMPILATION, tag.getCompilation());
             metadata.set(XMPDM.RELEASE_DATE, tag.getYear());
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/ogg/OggAudioParser.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/ogg/OggAudioParser.java
index 52538307f2..defb63361c 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/ogg/OggAudioParser.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/main/java/org/apache/tika/parser/ogg/OggAudioParser.java
@@ -74,6 +74,13 @@ public abstract class OggAudioParser extends AbstractParser {
         metadata.add(XMP.CREATOR_TOOL, comments.getVendor());
         metadata.add("vorbis:vendor", comments.getVendor());
 
+        //xmpDM:copyright is single-valued, so map the first comment; like
+        //vendor, the raw comments also stay available under the vorbis: name
+        List<String> copyrights = comments.getComments("copyright");
+        if (!copyrights.isEmpty()) {
+            metadata.set(XMPDM.COPYRIGHT, copyrights.get(0));
+        }
+
         for (String comment : comments.getComments("comment")) {
             metadata.add(XMPDM.LOG_COMMENT.getName(), comment);
         }
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/mp3/Mp3ParserTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/mp3/Mp3ParserTest.java
index c5d098ffc7..935b4be893 100644
--- 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/mp3/Mp3ParserTest.java
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/mp3/Mp3ParserTest.java
@@ -104,6 +104,7 @@ public class Mp3ParserTest extends TikaTest {
         assertEquals("Test Artist", metadata.get(XMPDM.ARTIST));
         assertEquals("Test Album Artist", metadata.get(XMPDM.ALBUM_ARTIST));
         assertEquals(null, metadata.get(XMPDM.COMPOSER));
+        assertEquals("Test Copyright", metadata.get(XMPDM.COPYRIGHT));
         assertEquals("2008", metadata.get(XMPDM.RELEASE_DATE));
         assertEquals("Rock", metadata.get(XMPDM.GENRE));
         assertEquals("XXX - ID3v1 Comment\nTest Comment",
@@ -187,6 +188,7 @@ public class Mp3ParserTest extends TikaTest {
         assertEquals("Test Artist", metadata.get(XMPDM.ARTIST));
         assertEquals("Test Album Artist", metadata.get(XMPDM.ALBUM_ARTIST));
         assertEquals(null, metadata.get(XMPDM.COMPOSER));
+        assertEquals("Test Copyright", metadata.get(XMPDM.COPYRIGHT));
         assertEquals("2008", metadata.get(XMPDM.RELEASE_DATE));
         assertEquals("Rock", metadata.get(XMPDM.GENRE));
         assertEquals("1", metadata.get(XMPDM.COMPILATION));
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/ogg/OggAudioParserTest.java
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/ogg/OggAudioParserTest.java
new file mode 100644
index 0000000000..549885a076
--- /dev/null
+++ 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/java/org/apache/tika/parser/ogg/OggAudioParserTest.java
@@ -0,0 +1,80 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.tika.parser.ogg;
+
+import static org.junit.jupiter.api.Assertions.assertArrayEquals;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.gagravarr.vorbis.VorbisComments;
+import org.junit.jupiter.api.Test;
+import org.xml.sax.helpers.DefaultHandler;
+
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.metadata.XMPDM;
+import org.apache.tika.sax.XHTMLContentHandler;
+
+/**
+ * Tests the mapping of Vorbis-style comments shared by all Ogg family parsers
+ * (Vorbis, Opus, Speex, FLAC). The comments are fed into
+ * {@link OggAudioParser#extractComments} directly; building a valid Ogg
+ * container around them would exercise the container library rather than the
+ * mapping under test.
+ */
+public class OggAudioParserTest {
+
+    @Test
+    public void testCopyrightCommentIsMapped() throws Exception {
+        Metadata metadata = extractComments("copyright", "Test Copyright");
+
+        assertEquals("Test Copyright", metadata.get(XMPDM.COPYRIGHT));
+        //like vendor, the raw comment stays available under the vorbis: name
+        assertEquals("Test Copyright", metadata.get("vorbis:copyright"));
+    }
+
+    @Test
+    public void testAdditionalCopyrightCommentsAreKept() throws Exception {
+        Metadata metadata = extractComments("copyright", "Test Copyright",
+                "copyright", "Second Copyright");
+
+        //xmpDM:copyright is single-valued: the first comment wins, while the
+        //vorbis: passthrough keeps all values
+        assertEquals("Test Copyright", metadata.get(XMPDM.COPYRIGHT));
+        assertArrayEquals(new String[]{"Test Copyright", "Second Copyright"},
+                metadata.getValues("vorbis:copyright"));
+    }
+
+    /**
+     * Runs the given key/value comment pairs through the shared comment
+     * extraction and returns the resulting metadata.
+     */
+    private static Metadata extractComments(String... keysAndValues) throws 
Exception {
+        VorbisComments comments = new VorbisComments();
+        comments.addComment("title", "Test Title");
+        comments.addComment("artist", "Test Artist");
+        comments.addComment("album", "Test Album");
+        for (int i = 0; i < keysAndValues.length; i += 2) {
+            comments.addComment(keysAndValues[i], keysAndValues[i + 1]);
+        }
+
+        Metadata metadata = new Metadata();
+        XHTMLContentHandler xhtml = new XHTMLContentHandler(new 
DefaultHandler(), metadata);
+        xhtml.startDocument();
+        OggAudioParser.extractComments(metadata, xhtml, comments);
+        xhtml.endDocument();
+        return metadata;
+    }
+}
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP3id3v2.mp3
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP3id3v2.mp3
index ac96becdc9..ce40b263df 100644
Binary files 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP3id3v2.mp3
 and 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP3id3v2.mp3
 differ
diff --git 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP3id3v24.mp3
 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP3id3v24.mp3
index 704921bd86..368360b6a5 100644
Binary files 
a/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP3id3v24.mp3
 and 
b/tika-parsers/tika-parsers-standard/tika-parsers-standard-modules/tika-parser-audiovideo-module/src/test/resources/test-documents/testMP3id3v24.mp3
 differ

Reply via email to