Issue #164: Show link to MusicBrainz release on album pages

master
François-Xavier Thomas 7 years ago
parent 40c9debf8e
commit c76a92746d
  1. 10
      airsonic-main/src/main/java/org/airsonic/player/controller/MainController.java
  2. 13
      airsonic-main/src/main/java/org/airsonic/player/dao/AlbumDao.java
  3. 14
      airsonic-main/src/main/java/org/airsonic/player/dao/MediaFileDao.java
  4. 12
      airsonic-main/src/main/java/org/airsonic/player/domain/Album.java
  5. 12
      airsonic-main/src/main/java/org/airsonic/player/domain/MediaFile.java
  6. 1
      airsonic-main/src/main/java/org/airsonic/player/service/MediaFileService.java
  7. 3
      airsonic-main/src/main/java/org/airsonic/player/service/MediaScannerService.java
  8. 1
      airsonic-main/src/main/java/org/airsonic/player/service/metadata/JaudiotaggerParser.java
  9. 9
      airsonic-main/src/main/java/org/airsonic/player/service/metadata/MetaData.java
  10. 17
      airsonic-main/src/main/resources/liquibase/6.4/add-album-mb-release-id.xml
  11. 17
      airsonic-main/src/main/resources/liquibase/6.4/add-media-file-mb-release-id.xml
  12. 7
      airsonic-main/src/main/resources/liquibase/6.4/changelog.xml
  13. 1
      airsonic-main/src/main/resources/liquibase/db-changelog.xml
  14. 5
      airsonic-main/src/main/webapp/WEB-INF/jsp/albumMain.jsp

@ -134,6 +134,7 @@ public class MainController {
map.put("sieblingAlbums", sieblingAlbums); map.put("sieblingAlbums", sieblingAlbums);
map.put("artist", guessArtist(children)); map.put("artist", guessArtist(children));
map.put("album", guessAlbum(children)); map.put("album", guessAlbum(children));
map.put("musicBrainzReleaseId", guessMusicBrainzReleaseId(children));
} }
try { try {
@ -241,6 +242,15 @@ public class MainController {
return null; return null;
} }
private String guessMusicBrainzReleaseId(List<MediaFile> children) {
for (MediaFile child : children) {
if (child.isFile() && child.getMusicBrainzReleaseId() != null) {
return child.getMusicBrainzReleaseId();
}
}
return null;
}
private List<MediaFile> getMultiFolderChildren(List<MediaFile> mediaFiles) throws IOException { private List<MediaFile> getMultiFolderChildren(List<MediaFile> mediaFiles) throws IOException {
SortedSet<MediaFile> result = new TreeSet<>(new MediaFileComparator(settingsService.isSortAlbumsByYear())); SortedSet<MediaFile> result = new TreeSet<>(new MediaFileComparator(settingsService.isSortAlbumsByYear()));
for (MediaFile mediaFile : mediaFiles) { for (MediaFile mediaFile : mediaFiles) {

@ -40,7 +40,8 @@ import java.util.*;
@Repository @Repository
public class AlbumDao extends AbstractDao { public class AlbumDao extends AbstractDao {
private static final String INSERT_COLUMNS = "path, name, artist, song_count, duration_seconds, cover_art_path, " + private static final String INSERT_COLUMNS = "path, name, artist, song_count, duration_seconds, cover_art_path, " +
"year, genre, play_count, last_played, comment, created, last_scanned, present, folder_id"; "year, genre, play_count, last_played, comment, created, last_scanned, present, " +
"folder_id, mb_release_id";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS; private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
@ -127,19 +128,20 @@ public class AlbumDao extends AbstractDao {
"created=?," + "created=?," +
"last_scanned=?," + "last_scanned=?," +
"present=?, " + "present=?, " +
"folder_id=? " + "folder_id=?, " +
"mb_release_id=? " +
"where artist=? and name=?"; "where artist=? and name=?";
int n = update(sql, album.getPath(), album.getSongCount(), album.getDurationSeconds(), album.getCoverArtPath(), album.getYear(), int n = update(sql, album.getPath(), album.getSongCount(), album.getDurationSeconds(), album.getCoverArtPath(), album.getYear(),
album.getGenre(), album.getPlayCount(), album.getLastPlayed(), album.getComment(), album.getCreated(), album.getGenre(), album.getPlayCount(), album.getLastPlayed(), album.getComment(), album.getCreated(),
album.getLastScanned(), album.isPresent(), album.getFolderId(), album.getArtist(), album.getName()); album.getLastScanned(), album.isPresent(), album.getFolderId(), album.getMusicBrainzReleaseId(), album.getArtist(), album.getName());
if (n == 0) { if (n == 0) {
update("insert into album (" + INSERT_COLUMNS + ") values (" + questionMarks(INSERT_COLUMNS) + ")", album.getPath(), update("insert into album (" + INSERT_COLUMNS + ") values (" + questionMarks(INSERT_COLUMNS) + ")", album.getPath(),
album.getName(), album.getArtist(), album.getSongCount(), album.getDurationSeconds(), album.getName(), album.getArtist(), album.getSongCount(), album.getDurationSeconds(),
album.getCoverArtPath(), album.getYear(), album.getGenre(), album.getPlayCount(), album.getLastPlayed(), album.getCoverArtPath(), album.getYear(), album.getGenre(), album.getPlayCount(), album.getLastPlayed(),
album.getComment(), album.getCreated(), album.getLastScanned(), album.isPresent(), album.getFolderId()); album.getComment(), album.getCreated(), album.getLastScanned(), album.isPresent(), album.getFolderId(), album.getMusicBrainzReleaseId());
} }
int id = queryForInt("select id from album where artist=? and name=?", null, album.getArtist(), album.getName()); int id = queryForInt("select id from album where artist=? and name=?", null, album.getArtist(), album.getName());
@ -404,7 +406,8 @@ public class AlbumDao extends AbstractDao {
rs.getTimestamp(13), rs.getTimestamp(13),
rs.getTimestamp(14), rs.getTimestamp(14),
rs.getBoolean(15), rs.getBoolean(15),
rs.getInt(16)); rs.getInt(16),
rs.getString(17));
} }
} }
} }

@ -45,7 +45,8 @@ public class MediaFileDao extends AbstractDao {
private static final Logger logger = LoggerFactory.getLogger(MediaFileDao.class); private static final Logger logger = LoggerFactory.getLogger(MediaFileDao.class);
private static final String INSERT_COLUMNS = "path, folder, type, format, title, album, artist, album_artist, disc_number, " + private static final String INSERT_COLUMNS = "path, folder, type, format, title, album, artist, album_artist, disc_number, " +
"track_number, year, genre, bit_rate, variable_bit_rate, duration_seconds, file_size, width, height, cover_art_path, " + "track_number, year, genre, bit_rate, variable_bit_rate, duration_seconds, file_size, width, height, cover_art_path, " +
"parent_path, play_count, last_played, comment, created, changed, last_scanned, children_last_updated, present, version"; "parent_path, play_count, last_played, comment, created, changed, last_scanned, children_last_updated, present, " +
"version, mb_release_id";
private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS; private static final String QUERY_COLUMNS = "id, " + INSERT_COLUMNS;
private static final String GENRE_COLUMNS = "name, song_count, album_count"; private static final String GENRE_COLUMNS = "name, song_count, album_count";
@ -162,7 +163,8 @@ public class MediaFileDao extends AbstractDao {
"last_scanned=?," + "last_scanned=?," +
"children_last_updated=?," + "children_last_updated=?," +
"present=?, " + "present=?, " +
"version=? " + "version=?, " +
"mb_release_id=? " +
"where path=?"; "where path=?";
logger.trace("Updating media file {}", Util.debugObject(file)); logger.trace("Updating media file {}", Util.debugObject(file));
@ -172,7 +174,8 @@ public class MediaFileDao extends AbstractDao {
file.getAlbumArtist(), file.getDiscNumber(), file.getTrackNumber(), file.getYear(), file.getGenre(), file.getBitRate(), file.getAlbumArtist(), file.getDiscNumber(), file.getTrackNumber(), file.getYear(), file.getGenre(), file.getBitRate(),
file.isVariableBitRate(), file.getDurationSeconds(), file.getFileSize(), file.getWidth(), file.getHeight(), file.isVariableBitRate(), file.getDurationSeconds(), file.getFileSize(), file.getWidth(), file.getHeight(),
file.getCoverArtPath(), file.getParentPath(), file.getPlayCount(), file.getLastPlayed(), file.getComment(), file.getCoverArtPath(), file.getParentPath(), file.getPlayCount(), file.getLastPlayed(), file.getComment(),
file.getChanged(), file.getLastScanned(), file.getChildrenLastUpdated(), file.isPresent(), VERSION, file.getPath()); file.getChanged(), file.getLastScanned(), file.getChildrenLastUpdated(), file.isPresent(), VERSION,
file.getMusicBrainzReleaseId(), file.getPath());
if (n == 0) { if (n == 0) {
@ -190,7 +193,7 @@ public class MediaFileDao extends AbstractDao {
file.isVariableBitRate(), file.getDurationSeconds(), file.getFileSize(), file.getWidth(), file.getHeight(), file.isVariableBitRate(), file.getDurationSeconds(), file.getFileSize(), file.getWidth(), file.getHeight(),
file.getCoverArtPath(), file.getParentPath(), file.getPlayCount(), file.getLastPlayed(), file.getComment(), file.getCoverArtPath(), file.getParentPath(), file.getPlayCount(), file.getLastPlayed(), file.getComment(),
file.getCreated(), file.getChanged(), file.getLastScanned(), file.getCreated(), file.getChanged(), file.getLastScanned(),
file.getChildrenLastUpdated(), file.isPresent(), VERSION); file.getChildrenLastUpdated(), file.isPresent(), VERSION, file.getMusicBrainzReleaseId());
} }
int id = queryForInt("select id from media_file where path=?", null, file.getPath()); int id = queryForInt("select id from media_file where path=?", null, file.getPath());
@ -717,7 +720,8 @@ public class MediaFileDao extends AbstractDao {
rs.getTimestamp(27), rs.getTimestamp(27),
rs.getTimestamp(28), rs.getTimestamp(28),
rs.getBoolean(29), rs.getBoolean(29),
rs.getInt(30)); rs.getInt(30),
rs.getString(31));
} }
} }

@ -43,13 +43,14 @@ public class Album {
private Date lastScanned; private Date lastScanned;
private boolean present; private boolean present;
private Integer folderId; private Integer folderId;
private String musicBrainzReleaseId;
public Album() { public Album() {
} }
public Album(int id, String path, String name, String artist, int songCount, int durationSeconds, String coverArtPath, public Album(int id, String path, String name, String artist, int songCount, int durationSeconds, String coverArtPath,
Integer year, String genre, int playCount, Date lastPlayed, String comment, Date created, Date lastScanned, Integer year, String genre, int playCount, Date lastPlayed, String comment, Date created, Date lastScanned,
boolean present, Integer folderId) { boolean present, Integer folderId, String musicBrainzReleaseId) {
this.id = id; this.id = id;
this.path = path; this.path = path;
this.name = name; this.name = name;
@ -66,6 +67,7 @@ public class Album {
this.lastScanned = lastScanned; this.lastScanned = lastScanned;
this.folderId = folderId; this.folderId = folderId;
this.present = present; this.present = present;
this.musicBrainzReleaseId = musicBrainzReleaseId;
} }
public int getId() { public int getId() {
@ -195,4 +197,12 @@ public class Album {
public Integer getFolderId() { public Integer getFolderId() {
return folderId; return folderId;
} }
public String getMusicBrainzReleaseId() {
return musicBrainzReleaseId;
}
public void setMusicBrainzReleaseId(String musicBrainzReleaseId) {
this.musicBrainzReleaseId = musicBrainzReleaseId;
}
} }

@ -67,12 +67,13 @@ public class MediaFile {
private Date childrenLastUpdated; private Date childrenLastUpdated;
private boolean present; private boolean present;
private int version; private int version;
private String musicBrainzReleaseId;
public MediaFile(int id, String path, String folder, MediaType mediaType, String format, String title, public MediaFile(int id, String path, String folder, MediaType mediaType, String format, String title,
String albumName, String artist, String albumArtist, Integer discNumber, Integer trackNumber, Integer year, String genre, Integer bitRate, String albumName, String artist, String albumArtist, Integer discNumber, Integer trackNumber, Integer year, String genre, Integer bitRate,
boolean variableBitRate, Integer durationSeconds, Long fileSize, Integer width, Integer height, String coverArtPath, boolean variableBitRate, Integer durationSeconds, Long fileSize, Integer width, Integer height, String coverArtPath,
String parentPath, int playCount, Date lastPlayed, String comment, Date created, Date changed, Date lastScanned, String parentPath, int playCount, Date lastPlayed, String comment, Date created, Date changed, Date lastScanned,
Date childrenLastUpdated, boolean present, int version) { Date childrenLastUpdated, boolean present, int version, String musicBrainzReleaseId) {
this.id = id; this.id = id;
this.path = path; this.path = path;
this.folder = folder; this.folder = folder;
@ -103,6 +104,7 @@ public class MediaFile {
this.childrenLastUpdated = childrenLastUpdated; this.childrenLastUpdated = childrenLastUpdated;
this.present = present; this.present = present;
this.version = version; this.version = version;
this.musicBrainzReleaseId = musicBrainzReleaseId;
} }
public MediaFile() { public MediaFile() {
@ -405,6 +407,14 @@ public class MediaFile {
this.starredDate = starredDate; this.starredDate = starredDate;
} }
public String getMusicBrainzReleaseId() {
return musicBrainzReleaseId;
}
public void setMusicBrainzReleaseId(String musicBrainzReleaseId) {
this.musicBrainzReleaseId = musicBrainzReleaseId;
}
/** /**
* Returns when the children was last updated in the database. * Returns when the children was last updated in the database.
*/ */

@ -503,6 +503,7 @@ public class MediaFileService {
mediaFile.setVariableBitRate(metaData.getVariableBitRate()); mediaFile.setVariableBitRate(metaData.getVariableBitRate());
mediaFile.setHeight(metaData.getHeight()); mediaFile.setHeight(metaData.getHeight());
mediaFile.setWidth(metaData.getWidth()); mediaFile.setWidth(metaData.getWidth());
mediaFile.setMusicBrainzReleaseId(metaData.getMusicBrainzReleaseId());
} }
String format = StringUtils.trimToNull(StringUtils.lowerCase(FilenameUtils.getExtension(mediaFile.getPath()))); String format = StringUtils.trimToNull(StringUtils.lowerCase(FilenameUtils.getExtension(mediaFile.getPath())));
mediaFile.setFormat(format); mediaFile.setFormat(format);

@ -298,6 +298,9 @@ public class MediaScannerService {
album.setArtist(artist); album.setArtist(artist);
album.setCreated(file.getChanged()); album.setCreated(file.getChanged());
} }
if (file.getMusicBrainzReleaseId() != null) {
album.setMusicBrainzReleaseId(file.getMusicBrainzReleaseId());
}
if (file.getYear() != null) { if (file.getYear() != null) {
album.setYear(file.getYear()); album.setYear(file.getYear());
} }

@ -92,6 +92,7 @@ public class JaudiotaggerParser extends MetaDataParser {
metaData.setGenre(mapGenre(getTagField(tag, FieldKey.GENRE))); metaData.setGenre(mapGenre(getTagField(tag, FieldKey.GENRE)));
metaData.setDiscNumber(parseInteger(getTagField(tag, FieldKey.DISC_NO))); metaData.setDiscNumber(parseInteger(getTagField(tag, FieldKey.DISC_NO)));
metaData.setTrackNumber(parseTrackNumber(getTagField(tag, FieldKey.TRACK))); metaData.setTrackNumber(parseTrackNumber(getTagField(tag, FieldKey.TRACK)));
metaData.setMusicBrainzReleaseId(getTagField(tag, FieldKey.MUSICBRAINZ_RELEASEID));
String songArtist = getTagField(tag, FieldKey.ARTIST); String songArtist = getTagField(tag, FieldKey.ARTIST);
String albumArtist = getTagField(tag, FieldKey.ALBUM_ARTIST); String albumArtist = getTagField(tag, FieldKey.ALBUM_ARTIST);

@ -38,6 +38,7 @@ public class MetaData {
private Integer durationSeconds; private Integer durationSeconds;
private Integer width; private Integer width;
private Integer height; private Integer height;
private String musicBrainzReleaseId;
public Integer getDiscNumber() { public Integer getDiscNumber() {
return discNumber; return discNumber;
@ -142,4 +143,12 @@ public class MetaData {
public void setHeight(Integer height) { public void setHeight(Integer height) {
this.height = height; this.height = height;
} }
public String getMusicBrainzReleaseId() {
return musicBrainzReleaseId;
}
public void setMusicBrainzReleaseId(String musicBrainzReleaseId) {
this.musicBrainzReleaseId = musicBrainzReleaseId;
}
} }

@ -0,0 +1,17 @@
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="add-album-mb-release-id" author="fxthomas">
<preConditions onFail="MARK_RAN">
<not>
<columnExists tableName="album" columnName="mb_release_id" />
</not>
</preConditions>
<addColumn tableName="album">
<column name="mb_release_id" type="${varchar_type}">
<constraints nullable="true" />
</column>
</addColumn>
</changeSet>
</databaseChangeLog>

@ -0,0 +1,17 @@
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<changeSet id="add-media-file-mb-release-id" author="fxthomas">
<preConditions onFail="MARK_RAN">
<not>
<columnExists tableName="media_file" columnName="mb_release_id" />
</not>
</preConditions>
<addColumn tableName="media_file">
<column name="mb_release_id" type="${varchar_type}">
<constraints nullable="true" />
</column>
</addColumn>
</changeSet>
</databaseChangeLog>

@ -0,0 +1,7 @@
<databaseChangeLog
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
<include file="add-media-file-mb-release-id.xml" relativeToChangelogFile="true"/>
<include file="add-album-mb-release-id.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>

@ -10,4 +10,5 @@
<include file="legacy/legacy-changelog.xml" relativeToChangelogFile="true"/> <include file="legacy/legacy-changelog.xml" relativeToChangelogFile="true"/>
<include file="6.2/changelog.xml" relativeToChangelogFile="true"/> <include file="6.2/changelog.xml" relativeToChangelogFile="true"/>
<include file="6.3/changelog.xml" relativeToChangelogFile="true"/> <include file="6.3/changelog.xml" relativeToChangelogFile="true"/>
<include file="6.4/changelog.xml" relativeToChangelogFile="true"/>
</databaseChangeLog> </databaseChangeLog>

@ -262,6 +262,11 @@
<span class="header"><a target="_blank" href="${wikipediaUrl}">Wikipedia</a></span> | <span class="header"><a target="_blank" href="${wikipediaUrl}">Wikipedia</a></span> |
<span class="header"><a target="_blank" href="${allmusicUrl}">allmusic</a></span> | <span class="header"><a target="_blank" href="${allmusicUrl}">allmusic</a></span> |
<span class="header"><a target="_blank" href="${lastFmUrl}">Last.fm</a></span> | <span class="header"><a target="_blank" href="${lastFmUrl}">Last.fm</a></span> |
<c:if test="${not empty model.musicBrainzReleaseId}">
<sub:url value="https://musicbrainz.org/release/${model.musicBrainzReleaseId}" var="musicBrainzUrl" encoding="UTF-8">
</sub:url>
<span class="header"><a target="_blank" href="${musicBrainzUrl}">MusicBrainz</a></span> |
</c:if>
<span class="header"> <span class="header">
<fmt:message key="main.playcount"><fmt:param value="${model.dir.playCount}"/></fmt:message> <fmt:message key="main.playcount"><fmt:param value="${model.dir.playCount}"/></fmt:message>
<c:if test="${not empty model.dir.lastPlayed}"> <c:if test="${not empty model.dir.lastPlayed}">

Loading…
Cancel
Save