TrackDIDLAdapter.java

  1. /*
  2.  * *********************************************************************************************************************
  3.  *
  4.  * blueMarine II: Semantic Media Centre
  5.  * http://tidalwave.it/projects/bluemarine2
  6.  *
  7.  * Copyright (C) 2015 - 2021 by Tidalwave s.a.s. (http://tidalwave.it)
  8.  *
  9.  * *********************************************************************************************************************
  10.  *
  11.  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
  12.  * the License. You may obtain a copy of the License at
  13.  *
  14.  *     http://www.apache.org/licenses/LICENSE-2.0
  15.  *
  16.  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
  17.  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the
  18.  * specific language governing permissions and limitations under the License.
  19.  *
  20.  * *********************************************************************************************************************
  21.  *
  22.  * git clone https://bitbucket.org/tidalwave/bluemarine2-src
  23.  * git clone https://github.com/tidalwave-it/bluemarine2-src
  24.  *
  25.  * *********************************************************************************************************************
  26.  */
  27. package it.tidalwave.bluemarine2.upnp.mediaserver.impl.didl;

  28. import javax.annotation.Nonnull;
  29. import javax.annotation.concurrent.Immutable;
  30. import java.time.Duration;
  31. import java.io.IOException;
  32. import it.tidalwave.role.ui.Displayable;
  33. import org.fourthline.cling.support.model.DIDLObject;
  34. import org.fourthline.cling.support.model.Protocol;
  35. import org.fourthline.cling.support.model.ProtocolInfo;
  36. import org.fourthline.cling.support.model.Res;
  37. import org.fourthline.cling.support.model.StorageMedium;
  38. import org.fourthline.cling.support.model.dlna.DLNAProtocolInfo;
  39. import org.fourthline.cling.support.model.item.MusicTrack;
  40. import it.tidalwave.dci.annotation.DciRole;
  41. import it.tidalwave.bluemarine2.model.MediaItem.Metadata;
  42. import it.tidalwave.bluemarine2.model.audio.AudioFile;
  43. import it.tidalwave.bluemarine2.model.audio.Track;
  44. import it.tidalwave.bluemarine2.rest.spi.ResourceServer;
  45. import lombok.extern.slf4j.Slf4j;
  46. import static it.tidalwave.bluemarine2.model.MediaItem.Metadata.*;
  47. import static it.tidalwave.bluemarine2.model.role.AudioFileSupplier._AudioFileSupplier_;
  48. import static it.tidalwave.role.ui.Displayable._Displayable_;

  49. /***********************************************************************************************************************
  50.  *
  51.  * The {@link DIDLAdapter} for {@link Track}.
  52.  *
  53.  * @stereotype Role
  54.  *
  55.  * @author  Fabrizio Giudici
  56.  *
  57.  **********************************************************************************************************************/
  58. @Slf4j
  59. @Immutable @DciRole(datumType = Track.class)
  60. public class TrackDIDLAdapter extends DIDLAdapterSupport<Track>
  61.   {
  62.     public TrackDIDLAdapter (@Nonnull final Track track , @Nonnull final ResourceServer server)
  63.       {
  64.         super(track, server);
  65.       }

  66.     @Override @Nonnull
  67.     public DIDLObject toObject()
  68.       throws IOException
  69.       {
  70.         log.debug("toObject() - {}", datum);
  71.         // parentID not set here
  72.         final MusicTrack item = setCommonFields(new MusicTrack());
  73.         final AudioFile audioFile = datum.as(_AudioFileSupplier_).getAudioFile();
  74.         final Metadata trackMetadata = datum.getMetadata();
  75.         item.addResource(audioResourceOf(audioFile));
  76.         trackMetadata.get(TRACK_NUMBER).ifPresent(item::setOriginalTrackNumber);

  77.         datum.getRecord().flatMap(record -> record.maybeAs(_Displayable_))
  78.                          .map(Displayable::getDisplayName)
  79.                          .ifPresent(item::setAlbum);

  80. //        trackMetadata.get(DISK_COUNT);
  81. //        trackMetadata.get(DISK_NUMBER);
  82. //        trackMetadata.get(COMPOSER);
  83. //        trackMetadata.get(ARTIST);
  84. //        item.setContributors(contributors);
  85. //        item.setCreator(creator);
  86. //        item.setDate(date);
  87. //        item.setDescMetadata(descMetadata);
  88. //        item.setDescription(description);
  89. //        item.setLanguage(language);
  90. //        item.setLongDescription(description);
  91.         item.setStorageMedium(StorageMedium.HDD);

  92. //        item.setArtists(new PersonWithRole[] { new PersonWithRole("xyz", "AlbumArtist") });
  93. //        item.setGenres(new String[] { "Classical" });
  94. //        final Person publisher = new Person("Unknown");
  95. //        item.setPublishers(new Person[] { publisher });

  96. //        datum.getDiskNumber();

  97.         return item;
  98.       }

  99.     @Nonnull
  100.     private Res audioResourceOf (@Nonnull final AudioFile audioFile)
  101.       {
  102.         final ProtocolInfo protocolInfo = new DLNAProtocolInfo(Protocol.HTTP_GET, "*", "audio/mpeg", "*"); // FIXME: MIME
  103.         final Metadata audioFileMetadata = audioFile.getMetadata();
  104.         final Res resource = new Res(protocolInfo,
  105.                                      audioFileMetadata.get(FILE_SIZE).orElse(null),
  106.                                      server.absoluteUrl(String.format("rest/audiofile/%s/content", audioFile.getId().stringValue())));
  107.         audioFileMetadata.get(DURATION).ifPresent(duration -> resource.setDuration(durationToString(duration)));
  108.         audioFileMetadata.get(BIT_RATE).ifPresent(bitRate -> resource.setBitrate((long)(int)bitRate));
  109.         audioFileMetadata.get(BITS_PER_SAMPLE).ifPresent(bitPerSample -> resource.setBitsPerSample((long)(int)bitPerSample));
  110.         audioFileMetadata.get(CHANNELS).ifPresent(channels -> resource.setNrAudioChannels((long)(int)channels));
  111.         audioFileMetadata.get(SAMPLE_RATE).ifPresent(sampleRate -> resource.setSampleFrequency((long)(int)sampleRate));

  112.         return resource;
  113.       }

  114.     @Nonnull
  115.     private static String durationToString (@Nonnull final Duration duration)
  116.       {
  117.         final int d = (int)duration.getSeconds();
  118.         final int seconds = d % 60;
  119.         final int minutes = (d / 60) % 60;
  120.         final int hours = d / 3600;
  121.         return String.format("%d:%02d:%02d.000", hours, minutes, seconds);
  122.       }

  123.     /*
  124.         // TODO     <desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">SA_RINCON5127_42????35</desc>

  125.     <item id="T:\public_html\Jukebox\mp3\_Presets\10.dpl/0" parentID="T:\public_html\Jukebox\mp3\_Presets\10.dpl" restricted="False">
  126.         <upnp:albumArtURI">http://eng.linn.co.uk/~joshh/Jukebox/mp3/Amy%20Macdonald/This%20Is%20The%20Life/Folder.jpg</upnp:albumArtURI>
  127.         <upnp:artworkURI">http://eng.linn.co.uk/~joshh/Jukebox/mp3/Amy%20Macdonald/This%20Is%20The%20Life/Folder.jpg</upnp:artworkURI>
  128.         <upnp:genre">Pop</upnp:genre>
  129.         <upnp:artist role="Performer"">Amy Macdonald</upnp:artist>
  130.         <upnp:artist role="Composer"">Unknown</upnp:artist>
  131.         <upnp:artist role="AlbumArtist"">Unknown</upnp:artist>
  132.         <upnp:artist role="Conductor"">Unknown</upnp:artist>
  133.         <dc:date >Unknown</dc:date>
  134.         <upnp:originalDiscNumber">0</upnp:originalDiscNumber>
  135.         <upnp:originalDiscCount">0</upnp:originalDiscCount>
  136.     </item>

  137.     */
  138.   }