Add release date and recording date fields to MediaMetadata.

PiperOrigin-RevId: 379962022
This commit is contained in:
samrobinson 2021-06-17 16:20:48 +01:00 committed by Oliver Woodman
parent 780760358e
commit d1aacc5f3b
3 changed files with 286 additions and 26 deletions

View file

@ -15,9 +15,12 @@
*/
package com.google.android.exoplayer2;
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.IntDef;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.util.Util;
@ -53,7 +56,12 @@ public final class MediaMetadata implements Bundleable {
@Nullable private Integer totalTrackCount;
@Nullable @FolderType private Integer folderType;
@Nullable private Boolean isPlayable;
@Nullable private Integer year;
@Nullable private Integer recordingYear;
@Nullable private Integer recordingMonth;
@Nullable private Integer recordingDay;
@Nullable private Integer releaseYear;
@Nullable private Integer releaseMonth;
@Nullable private Integer releaseDay;
@Nullable private CharSequence writer;
@Nullable private CharSequence composer;
@Nullable private CharSequence conductor;
@ -80,7 +88,12 @@ public final class MediaMetadata implements Bundleable {
this.totalTrackCount = mediaMetadata.totalTrackCount;
this.folderType = mediaMetadata.folderType;
this.isPlayable = mediaMetadata.isPlayable;
this.year = mediaMetadata.year;
this.recordingYear = mediaMetadata.recordingYear;
this.recordingMonth = mediaMetadata.recordingMonth;
this.recordingDay = mediaMetadata.recordingDay;
this.releaseYear = mediaMetadata.releaseYear;
this.releaseMonth = mediaMetadata.releaseMonth;
this.releaseDay = mediaMetadata.releaseDay;
this.writer = mediaMetadata.writer;
this.composer = mediaMetadata.composer;
this.conductor = mediaMetadata.conductor;
@ -189,9 +202,74 @@ public final class MediaMetadata implements Bundleable {
return this;
}
/** Sets the year. */
/** @deprecated Use {@link #setRecordingYear(Integer)} instead. */
@Deprecated
public Builder setYear(@Nullable Integer year) {
this.year = year;
return setRecordingYear(year);
}
/** Sets the year of the recording date. */
public Builder setRecordingYear(@Nullable Integer recordingYear) {
this.recordingYear = recordingYear;
return this;
}
/**
* Sets the month of the recording date.
*
* <p>Value must be between 1 and 12.
*/
public Builder setRecordingMonth(
@Nullable @IntRange(from = 1, to = 12) Integer recordingMonth) {
if (recordingMonth != null) {
checkArgument(recordingMonth >= 1 && recordingMonth <= 12);
}
this.recordingMonth = recordingMonth;
return this;
}
/**
* Sets the day of the recording date.
*
* <p>Value must be between 1 and 31.
*/
public Builder setRecordingDay(@Nullable @IntRange(from = 1, to = 31) Integer recordingDay) {
if (recordingDay != null) {
checkArgument(recordingDay >= 1 && recordingDay <= 31);
}
this.recordingDay = recordingDay;
return this;
}
/** Sets the year of the release date. */
public Builder setReleaseYear(@Nullable Integer releaseYear) {
this.releaseYear = releaseYear;
return this;
}
/**
* Sets the month of the release date.
*
* <p>Value must be between 1 and 12.
*/
public Builder setReleaseMonth(@Nullable @IntRange(from = 1, to = 12) Integer releaseMonth) {
if (releaseMonth != null) {
checkArgument(releaseMonth >= 1 && releaseMonth <= 12);
}
this.releaseMonth = releaseMonth;
return this;
}
/**
* Sets the day of the release date.
*
* <p>Value must be between 1 and 31.
*/
public Builder setReleaseDay(@Nullable @IntRange(from = 1, to = 31) Integer releaseDay) {
if (releaseDay != null) {
checkArgument(releaseDay >= 1 && releaseDay <= 31);
}
this.releaseDay = releaseDay;
return this;
}
@ -352,8 +430,37 @@ public final class MediaMetadata implements Bundleable {
@Nullable @FolderType public final Integer folderType;
/** Optional boolean for media playability. */
@Nullable public final Boolean isPlayable;
/** Optional year. */
@Nullable public final Integer year;
/** @deprecated Use {@link #recordingYear} instead. */
@Deprecated @Nullable public final Integer year;
/** Optional year of the recording date. */
@Nullable public final Integer recordingYear;
/**
* Optional month of the recording date.
*
* <p>Note that there is no guarantee that the month and day are a valid combination.
*/
@Nullable public final Integer recordingMonth;
/**
* Optional day of the recording date.
*
* <p>Note that there is no guarantee that the month and day are a valid combination.
*/
@Nullable public final Integer recordingDay;
/** Optional year of the release date. */
@Nullable public final Integer releaseYear;
/**
* Optional month of the release date.
*
* <p>Note that there is no guarantee that the month and day are a valid combination.
*/
@Nullable public final Integer releaseMonth;
/**
* Optional day of the release date.
*
* <p>Note that there is no guarantee that the month and day are a valid combination.
*/
@Nullable public final Integer releaseDay;
/** Optional writer. */
@Nullable public final CharSequence writer;
/** Optional composer. */
@ -390,7 +497,13 @@ public final class MediaMetadata implements Bundleable {
this.totalTrackCount = builder.totalTrackCount;
this.folderType = builder.folderType;
this.isPlayable = builder.isPlayable;
this.year = builder.year;
this.year = builder.recordingYear;
this.recordingYear = builder.recordingYear;
this.recordingMonth = builder.recordingMonth;
this.recordingDay = builder.recordingDay;
this.releaseYear = builder.releaseYear;
this.releaseMonth = builder.releaseMonth;
this.releaseDay = builder.releaseDay;
this.writer = builder.writer;
this.composer = builder.composer;
this.conductor = builder.conductor;
@ -429,7 +542,12 @@ public final class MediaMetadata implements Bundleable {
&& Util.areEqual(totalTrackCount, that.totalTrackCount)
&& Util.areEqual(folderType, that.folderType)
&& Util.areEqual(isPlayable, that.isPlayable)
&& Util.areEqual(year, that.year)
&& Util.areEqual(recordingYear, that.recordingYear)
&& Util.areEqual(recordingMonth, that.recordingMonth)
&& Util.areEqual(recordingDay, that.recordingDay)
&& Util.areEqual(releaseYear, that.releaseYear)
&& Util.areEqual(releaseMonth, that.releaseMonth)
&& Util.areEqual(releaseDay, that.releaseDay)
&& Util.areEqual(writer, that.writer)
&& Util.areEqual(composer, that.composer)
&& Util.areEqual(conductor, that.conductor)
@ -456,7 +574,12 @@ public final class MediaMetadata implements Bundleable {
totalTrackCount,
folderType,
isPlayable,
year,
recordingYear,
recordingMonth,
recordingDay,
releaseYear,
releaseMonth,
releaseDay,
writer,
composer,
conductor,
@ -485,7 +608,12 @@ public final class MediaMetadata implements Bundleable {
FIELD_TOTAL_TRACK_COUNT,
FIELD_FOLDER_TYPE,
FIELD_IS_PLAYABLE,
FIELD_YEAR,
FIELD_RECORDING_YEAR,
FIELD_RECORDING_MONTH,
FIELD_RECORDING_DAY,
FIELD_RELEASE_YEAR,
FIELD_RELEASE_MONTH,
FIELD_RELEASE_DAY,
FIELD_WRITER,
FIELD_COMPOSER,
FIELD_CONDUCTOR,
@ -511,12 +639,17 @@ public final class MediaMetadata implements Bundleable {
private static final int FIELD_TOTAL_TRACK_COUNT = 13;
private static final int FIELD_FOLDER_TYPE = 14;
private static final int FIELD_IS_PLAYABLE = 15;
private static final int FIELD_YEAR = 16;
private static final int FIELD_WRITER = 17;
private static final int FIELD_COMPOSER = 18;
private static final int FIELD_CONDUCTOR = 19;
private static final int FIELD_DISC_NUMBER = 20;
private static final int FIELD_TOTAL_DISC_COUNT = 21;
private static final int FIELD_RECORDING_YEAR = 16;
private static final int FIELD_RECORDING_MONTH = 17;
private static final int FIELD_RECORDING_DAY = 18;
private static final int FIELD_RELEASE_YEAR = 19;
private static final int FIELD_RELEASE_MONTH = 20;
private static final int FIELD_RELEASE_DAY = 21;
private static final int FIELD_WRITER = 22;
private static final int FIELD_COMPOSER = 23;
private static final int FIELD_CONDUCTOR = 24;
private static final int FIELD_DISC_NUMBER = 25;
private static final int FIELD_TOTAL_DISC_COUNT = 26;
private static final int FIELD_EXTRAS = 1000;
@Override
@ -554,8 +687,23 @@ public final class MediaMetadata implements Bundleable {
if (isPlayable != null) {
bundle.putBoolean(keyForField(FIELD_IS_PLAYABLE), isPlayable);
}
if (year != null) {
bundle.putInt(keyForField(FIELD_YEAR), year);
if (recordingYear != null) {
bundle.putInt(keyForField(FIELD_RECORDING_YEAR), recordingYear);
}
if (recordingMonth != null) {
bundle.putInt(keyForField(FIELD_RECORDING_MONTH), recordingMonth);
}
if (recordingDay != null) {
bundle.putInt(keyForField(FIELD_RECORDING_DAY), recordingDay);
}
if (releaseYear != null) {
bundle.putInt(keyForField(FIELD_RELEASE_YEAR), releaseYear);
}
if (releaseMonth != null) {
bundle.putInt(keyForField(FIELD_RELEASE_MONTH), releaseMonth);
}
if (releaseDay != null) {
bundle.putInt(keyForField(FIELD_RELEASE_DAY), releaseDay);
}
if (discNumber != null) {
bundle.putInt(keyForField(FIELD_DISC_NUMBER), discNumber);
@ -614,8 +762,23 @@ public final class MediaMetadata implements Bundleable {
if (bundle.containsKey(keyForField(FIELD_IS_PLAYABLE))) {
builder.setIsPlayable(bundle.getBoolean(keyForField(FIELD_IS_PLAYABLE)));
}
if (bundle.containsKey(keyForField(FIELD_YEAR))) {
builder.setYear(bundle.getInt(keyForField(FIELD_YEAR)));
if (bundle.containsKey(keyForField(FIELD_RECORDING_YEAR))) {
builder.setRecordingYear(bundle.getInt(keyForField(FIELD_RECORDING_YEAR)));
}
if (bundle.containsKey(keyForField(FIELD_RECORDING_MONTH))) {
builder.setRecordingMonth(bundle.getInt(keyForField(FIELD_RECORDING_MONTH)));
}
if (bundle.containsKey(keyForField(FIELD_RECORDING_DAY))) {
builder.setRecordingDay(bundle.getInt(keyForField(FIELD_RECORDING_DAY)));
}
if (bundle.containsKey(keyForField(FIELD_RELEASE_YEAR))) {
builder.setReleaseYear(bundle.getInt(keyForField(FIELD_RELEASE_YEAR)));
}
if (bundle.containsKey(keyForField(FIELD_RELEASE_MONTH))) {
builder.setReleaseMonth(bundle.getInt(keyForField(FIELD_RELEASE_MONTH)));
}
if (bundle.containsKey(keyForField(FIELD_RELEASE_DAY))) {
builder.setReleaseDay(bundle.getInt(keyForField(FIELD_RELEASE_DAY)));
}
if (bundle.containsKey(keyForField(FIELD_DISC_NUMBER))) {
builder.setDiscNumber(bundle.getInt(keyForField(FIELD_DISC_NUMBER)));

View file

@ -22,6 +22,8 @@ import android.os.Parcelable;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.util.Util;
import java.util.ArrayList;
import java.util.List;
/** Text information ID3 frame. */
public final class TextInformationFrame extends Id3Frame {
@ -76,11 +78,57 @@ public final class TextInformationFrame extends Id3Frame {
case "TYE":
case "TYER":
try {
builder.setYear(Integer.parseInt(value));
builder.setRecordingYear(Integer.parseInt(value));
} catch (NumberFormatException e) {
// Do nothing, invalid input.
}
break;
case "TDA":
case "TDAT":
try {
int month = Integer.parseInt(value.substring(2, 4));
int day = Integer.parseInt(value.substring(0, 2));
builder.setRecordingMonth(month).setRecordingDay(day);
} catch (NumberFormatException | StringIndexOutOfBoundsException e) {
// Do nothing, invalid input.
}
break;
case "TDRC":
List<Integer> recordingDate = parseId3v2point4TimestampFrameForDate(value);
switch (recordingDate.size()) {
case 3:
builder.setRecordingDay(recordingDate.get(2));
// fall through
case 2:
builder.setRecordingMonth(recordingDate.get(1));
// fall through
case 1:
builder.setRecordingYear(recordingDate.get(0));
// fall through
break;
default:
// Do nothing.
break;
}
break;
case "TDRL":
List<Integer> releaseDate = parseId3v2point4TimestampFrameForDate(value);
switch (releaseDate.size()) {
case 3:
builder.setReleaseDay(releaseDate.get(2));
// fall through
case 2:
builder.setReleaseMonth(releaseDate.get(1));
// fall through
case 1:
builder.setReleaseYear(releaseDate.get(0));
// fall through
break;
default:
// Do nothing.
break;
}
break;
case "TCM":
case "TCOM":
builder.setComposer(value);
@ -148,4 +196,28 @@ public final class TextInformationFrame extends Id3Frame {
return new TextInformationFrame[size];
}
};
// Private methods
private static List<Integer> parseId3v2point4TimestampFrameForDate(String value) {
// Timestamp string format is ISO-8601, can be `yyyy-MM-ddTHH:mm:ss`, or reduced precision
// at each point, for example `yyyy-MM` or `yyyy-MM-ddTHH:mm`.
List<Integer> dates = new ArrayList<>();
try {
if (value.length() >= 10) {
dates.add(Integer.parseInt(value.substring(0, 4)));
dates.add(Integer.parseInt(value.substring(5, 7)));
dates.add(Integer.parseInt(value.substring(8, 10)));
} else if (value.length() >= 7) {
dates.add(Integer.parseInt(value.substring(0, 4)));
dates.add(Integer.parseInt(value.substring(5, 7)));
} else if (value.length() >= 4) {
dates.add(Integer.parseInt(value.substring(0, 4)));
}
} catch (NumberFormatException e) {
// Invalid output, return.
return new ArrayList<>();
}
return dates;
}
}

View file

@ -54,7 +54,12 @@ public class MediaMetadataTest {
assertThat(mediaMetadata.totalTrackCount).isNull();
assertThat(mediaMetadata.folderType).isNull();
assertThat(mediaMetadata.isPlayable).isNull();
assertThat(mediaMetadata.year).isNull();
assertThat(mediaMetadata.recordingYear).isNull();
assertThat(mediaMetadata.recordingMonth).isNull();
assertThat(mediaMetadata.recordingDay).isNull();
assertThat(mediaMetadata.releaseYear).isNull();
assertThat(mediaMetadata.releaseMonth).isNull();
assertThat(mediaMetadata.releaseDay).isNull();
assertThat(mediaMetadata.composer).isNull();
assertThat(mediaMetadata.conductor).isNull();
assertThat(mediaMetadata.writer).isNull();
@ -105,7 +110,12 @@ public class MediaMetadataTest {
.setTotalTrackCount(12)
.setFolderType(MediaMetadata.FOLDER_TYPE_PLAYLISTS)
.setIsPlayable(true)
.setYear(2000)
.setRecordingYear(2000)
.setRecordingMonth(11)
.setRecordingDay(23)
.setReleaseYear(2001)
.setReleaseMonth(1)
.setReleaseDay(2)
.setComposer("Composer")
.setConductor("Conductor")
.setWriter("Writer")
@ -126,7 +136,10 @@ public class MediaMetadataTest {
String albumTitle = "album title";
String albumArtist = "album Artist";
String trackNumberInfo = "11/17";
String year = "2000";
String recordingYear = "2000";
String recordingMonth = "07";
String recordingDay = "10";
String releaseDate = "2001-01-02T00:00:00";
String composer = "composer";
String conductor = "conductor";
String writer = "writer";
@ -141,7 +154,14 @@ public class MediaMetadataTest {
/* id= */ "TP2", /* description= */ null, /* value= */ albumArtist),
new TextInformationFrame(
/* id= */ "TRK", /* description= */ null, /* value= */ trackNumberInfo),
new TextInformationFrame(/* id= */ "TYE", /* description= */ null, /* value= */ year),
new TextInformationFrame(
/* id= */ "TYE", /* description= */ null, /* value= */ recordingYear),
new TextInformationFrame(
/* id= */ "TDA",
/* description= */ null,
/* value= */ recordingDay + recordingMonth),
new TextInformationFrame(
/* id= */ "TDRL", /* description= */ null, /* value= */ releaseDate),
new TextInformationFrame(
/* id= */ "TCM", /* description= */ null, /* value= */ composer),
new TextInformationFrame(
@ -162,7 +182,12 @@ public class MediaMetadataTest {
assertThat(mediaMetadata.albumArtist.toString()).isEqualTo(albumArtist);
assertThat(mediaMetadata.trackNumber).isEqualTo(11);
assertThat(mediaMetadata.totalTrackCount).isEqualTo(17);
assertThat(mediaMetadata.year).isEqualTo(2000);
assertThat(mediaMetadata.recordingYear).isEqualTo(2000);
assertThat(mediaMetadata.recordingMonth).isEqualTo(7);
assertThat(mediaMetadata.recordingDay).isEqualTo(10);
assertThat(mediaMetadata.releaseYear).isEqualTo(2001);
assertThat(mediaMetadata.releaseMonth).isEqualTo(1);
assertThat(mediaMetadata.releaseDay).isEqualTo(2);
assertThat(mediaMetadata.composer.toString()).isEqualTo(composer);
assertThat(mediaMetadata.conductor.toString()).isEqualTo(conductor);
assertThat(mediaMetadata.writer.toString()).isEqualTo(writer);