package comeon.core.mediareaders; import comeon.core.MediaUploadBatch; import comeon.model.Media; import comeon.model.User; import org.apache.commons.beanutils.*; import org.apache.commons.lang.WordUtils; import org.jaudiotagger.audio.AudioFile; import org.jaudiotagger.audio.AudioFileIO; import org.jaudiotagger.audio.AudioHeader; import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.tag.FieldKey; import org.jaudiotagger.tag.Tag; import org.jaudiotagger.tag.TagException; import org.jaudiotagger.tag.images.Artwork; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; public final class AudioReader extends AbstractMediaReader { private static final Logger LOGGER = LoggerFactory.getLogger(AudioReader.class); private static final EnumMap<FieldKey, String> FIELD_KEY_NAMES = new EnumMap<>(FieldKey.class); private static final LazyDynaClass TAG_DYNA_CLASS; static { final DynaProperty[] properties = Arrays.stream(FieldKey.values()) .filter(Predicate.isEqual(FieldKey.COVER_ART).negate()) .map(AudioReader::toName) .map(name -> new DynaProperty(name, String.class)).toArray(DynaProperty[]::new); TAG_DYNA_CLASS = new LazyDynaClass(Tag.class.getName(), null, properties); TAG_DYNA_CLASS.setReturnNull(true); FIELD_KEY_NAMES.putAll(Arrays.stream(FieldKey.values()) .filter(Predicate.isEqual(FieldKey.COVER_ART).negate()) .collect(Collectors.toMap(key -> key, AudioReader::toName))); } private static String toName(final FieldKey key) { return WordUtils.uncapitalize(WordUtils.capitalizeFully(key.name().replace('_', ' ')).replace(" ", "")); } public AudioReader(final File file, final User user) { super(file, user); } @Override protected Media buildMedia(final MediaUploadBatch context) throws MediaReaderException, IOException { final String fileName = getFile().getAbsolutePath(); try { final AudioFile audioFile = AudioFileIO.read(getFile()); final Tag tag = audioFile.getTag(); final AudioHeader header = audioFile.getAudioHeader(); final byte[] thumbnail; final List<Artwork> artwork = tag.getArtworkList(); if (artwork.isEmpty()) { thumbnail = new byte[0]; } else { thumbnail = artwork.get(0).getBinaryData(); } final Map<String, Object> metadata = new HashMap<>(2); metadata.put("Tags", copyTags(tag)); metadata.put("Headers", copyHeaders(header)); return new Media(getFile(), fileName, context.getTemplate(), metadata, thumbnail); } catch (final CannotReadException | TagException | ReadOnlyFileException | InvalidAudioFrameException e) { throw new MediaReaderException(e); } } private DynaBean copyTags(final Tag tag) { final LazyDynaBean bean = new LazyDynaBean(TAG_DYNA_CLASS); FIELD_KEY_NAMES.entrySet().forEach(e -> bean.set(e.getValue(), tag.getFirst(e.getKey()))); return bean; } private DynaBean copyHeaders(final AudioHeader header) { final WrapDynaClass clazz = WrapDynaClass.createDynaClass(header.getClass()); final LazyDynaBean bean = new LazyDynaBean(); Arrays.stream(clazz.getDynaProperties()) .map(DynaProperty::getName) .filter(Predicate.isEqual("class").negate()) .forEach(name -> { try { bean.set(name, String.valueOf(PropertyUtils.getProperty(header, name))); } catch (final IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { LOGGER.warn("Could not read property {} from {}", name, header); } }); return bean; } }