Split metadata into format and content metadata.
[sonitus.git] / src / main / java / net / pterodactylus / sonitus / io / OggVorbisIdentifier.java
index ab732b8..9d38452 100644 (file)
@@ -20,8 +20,11 @@ package net.pterodactylus.sonitus.io;
 import java.io.IOException;
 import java.io.InputStream;
 
-import net.pterodactylus.sonitus.data.Format;
+import net.pterodactylus.sonitus.data.ContentMetadata;
+import net.pterodactylus.sonitus.data.FormatMetadata;
+import net.pterodactylus.sonitus.data.Metadata;
 
+import com.google.common.base.Optional;
 import com.jcraft.jogg.Packet;
 import com.jcraft.jogg.Page;
 import com.jcraft.jogg.StreamState;
@@ -30,7 +33,9 @@ import com.jcraft.jorbis.Comment;
 import com.jcraft.jorbis.Info;
 
 /**
- * Identifies Ogg Vorbis files.
+ * Identifies Ogg Vorbis files. <p> All knowledge used in this class has been
+ * taken from <a href="http://www.jcraft.com/jorbis/tutorial/Tutorial.html">jcraft.com/jorbis/tutorial/Tutorial.html</a>.
+ * </p>
  *
  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
  */
@@ -46,13 +51,16 @@ public class OggVorbisIdentifier {
 
        /**
         * Tries to parse the given stream as Ogg Vorbis file and returns a {@link
-        * Format} describing the stream.
+        * Metadata} describing the stream.
         *
         * @param inputStream
-        * @return
+        *              The input stream to identify as Ogg Vorbis
+        * @return The identified metadata, or {@link Optional#absent()} if the stream
+        *         could not be identified
         * @throws IOException
+        *              if an I/O error occurs
         */
-       public static Format identify(InputStream inputStream) throws IOException {
+       public static Optional<Metadata> identify(InputStream inputStream) throws IOException {
 
                /* stuff needed to decode Ogg. */
                Packet packet = new Packet();
@@ -79,7 +87,7 @@ public class OggVorbisIdentifier {
                        syncState.wrote(read);
                        switch (syncState.pageout(page)) {
                                case -1:
-                                       throw new IdentifierException("Hole in Ogg data!");
+                                       return Optional.absent();
                                case 1:
                                        if (!streamStateInitialized) {
                                                /* init stream state. */
@@ -90,11 +98,11 @@ public class OggVorbisIdentifier {
                                                streamStateInitialized = true;
                                        }
                                        if (streamState.pagein(page) == -1) {
-                                               throw new IdentifierException("Error parsing Ogg data!");
+                                               return Optional.absent();
                                        }
                                        switch (streamState.packetout(packet)) {
                                                case -1:
-                                                       throw new IdentifierException("Error parsing Ogg data!");
+                                                       return Optional.absent();
                                                case 1:
                                                        info.synthesis_headerin(comment, packet);
                                                        packetsRead++;
@@ -109,7 +117,40 @@ public class OggVorbisIdentifier {
                        buffer = syncState.data;
                }
 
-               return new Format(info.channels, info.rate, "Vorbis");
+               FormatMetadata formatMetadata = new FormatMetadata(info.channels, info.rate, "Vorbis");
+               ContentMetadata contentMetadata = new ContentMetadata("");
+               for (int c = 0; c < comment.comments; ++c) {
+                       String field = comment.getComment(c);
+                       Optional<String> extractedField = extractField(field, "ARTIST");
+                       if (extractedField.isPresent()) {
+                               contentMetadata = contentMetadata.artist(extractedField.get());
+                               continue;
+                       }
+                       extractedField = extractField(field, "TITLE");
+                       if (extractedField.isPresent()) {
+                               contentMetadata = contentMetadata.name(extractedField.get());
+                               continue;
+                       }
+               }
+               return Optional.of(new Metadata(formatMetadata, contentMetadata));
+       }
+
+       /**
+        * Extracts the content of the field from the comment if the comment contains
+        * the given field.
+        *
+        * @param comment
+        *              The comment to extract the value from
+        * @param fieldName
+        *              The name of the field to extract
+        * @return The extracted field, or {@link Optional#absent()} if the comment
+        *         does not contain the given field
+        */
+       private static Optional<String> extractField(String comment, String fieldName) {
+               if (comment.startsWith(fieldName + "=")) {
+                       return Optional.of(comment.substring(fieldName.length() + 1));
+               }
+               return Optional.absent();
        }
 
 }