/* This file is part of Libresonic. Libresonic is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Libresonic is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Libresonic. If not, see <http://www.gnu.org/licenses/>. Copyright 2016 (C) Libresonic Authors Based upon Subsonic, Copyright 2009 (C) Sindre Mehus */ package org.libresonic.player.dao; import org.libresonic.player.domain.PodcastChannel; import org.libresonic.player.domain.PodcastEpisode; import org.libresonic.player.domain.PodcastStatus; import org.springframework.jdbc.core.RowMapper; import org.springframework.transaction.annotation.Transactional; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; /** * Provides database services for Podcast channels and episodes. * * @author Sindre Mehus */ public class PodcastDao extends AbstractDao { private static final String CHANNEL_INSERT_COLUMNS = "url, title, description, image_url, status, error_message"; private static final String CHANNEL_QUERY_COLUMNS = "id, " + CHANNEL_INSERT_COLUMNS; private static final String EPISODE_INSERT_COLUMNS = "channel_id, url, path, title, description, publish_date, " + "duration, bytes_total, bytes_downloaded, status, error_message"; private static final String EPISODE_QUERY_COLUMNS = "id, " + EPISODE_INSERT_COLUMNS; private PodcastChannelRowMapper channelRowMapper = new PodcastChannelRowMapper(); private PodcastEpisodeRowMapper episodeRowMapper = new PodcastEpisodeRowMapper(); /** * Creates a new Podcast channel. * * @param channel The Podcast channel to create. * @return The ID of the newly created channel. */ @Transactional public int createChannel(PodcastChannel channel) { String sql = "insert into podcast_channel (" + CHANNEL_INSERT_COLUMNS + ") values (" + questionMarks( CHANNEL_INSERT_COLUMNS) + ")"; update(sql, channel.getUrl(), channel.getTitle(), channel.getDescription(), channel.getImageUrl(), channel.getStatus().name(), channel.getErrorMessage()); return getJdbcTemplate().queryForObject("select max(id) from podcast_channel", Integer.class); } /** * Returns all Podcast channels. * * @return Possibly empty list of all Podcast channels. */ public List<PodcastChannel> getAllChannels() { String sql = "select " + CHANNEL_QUERY_COLUMNS + " from podcast_channel"; return query(sql, channelRowMapper); } /** * Returns a single Podcast channel. */ public PodcastChannel getChannel(int channelId) { String sql = "select " + CHANNEL_QUERY_COLUMNS + " from podcast_channel where id=?"; return queryOne(sql, channelRowMapper, channelId); } /** * Updates the given Podcast channel. * * @param channel The Podcast channel to update. */ public void updateChannel(PodcastChannel channel) { String sql = "update podcast_channel set url=?, title=?, description=?, image_url=?, status=?, error_message=? where id=?"; update(sql, channel.getUrl(), channel.getTitle(), channel.getDescription(), channel.getImageUrl(), channel.getStatus().name(), channel.getErrorMessage(), channel.getId()); } /** * Deletes the Podcast channel with the given ID. * * @param id The Podcast channel ID. */ public void deleteChannel(int id) { String sql = "delete from podcast_channel where id=?"; update(sql, id); } /** * Creates a new Podcast episode. * * @param episode The Podcast episode to create. */ public void createEpisode(PodcastEpisode episode) { String sql = "insert into podcast_episode (" + EPISODE_INSERT_COLUMNS + ") values (" + questionMarks( EPISODE_INSERT_COLUMNS) + ")"; update(sql, episode.getChannelId(), episode.getUrl(), episode.getPath(), episode.getTitle(), episode.getDescription(), episode.getPublishDate(), episode.getDuration(), episode.getBytesTotal(), episode.getBytesDownloaded(), episode.getStatus().name(), episode.getErrorMessage()); } /** * Returns all Podcast episodes for a given channel. * * @return Possibly empty list of all Podcast episodes for the given channel, sorted in * reverse chronological order (newest episode first). */ public List<PodcastEpisode> getEpisodes(int channelId) { String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where channel_id = ? " + "and status != ? order by publish_date desc"; return query(sql, episodeRowMapper, channelId, PodcastStatus.DELETED.name()); } /** * Returns the N newest episodes. * * @return Possibly empty list of the newest Podcast episodes, sorted in * reverse chronological order (newest episode first). */ public List<PodcastEpisode> getNewestEpisodes(int count) { String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where status = ? and publish_date is not null " + "order by publish_date desc limit ?"; return query(sql, episodeRowMapper, PodcastStatus.COMPLETED.name(), count); } /** * Returns the Podcast episode with the given ID. * * @param episodeId The Podcast episode ID. * @return The episode or <code>null</code> if not found. */ public PodcastEpisode getEpisode(int episodeId) { String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where id=?"; return queryOne(sql, episodeRowMapper, episodeId); } public PodcastEpisode getEpisodeByUrl(String url) { String sql = "select " + EPISODE_QUERY_COLUMNS + " from podcast_episode where url=?"; return queryOne(sql, episodeRowMapper, url); } /** * Updates the given Podcast episode. * * @param episode The Podcast episode to update. * @return The number of episodes updated (zero or one). */ public int updateEpisode(PodcastEpisode episode) { String sql = "update podcast_episode set url=?, path=?, title=?, description=?, publish_date=?, duration=?, " + "bytes_total=?, bytes_downloaded=?, status=?, error_message=? where id=?"; return update(sql, episode.getUrl(), episode.getPath(), episode.getTitle(), episode.getDescription(), episode.getPublishDate(), episode.getDuration(), episode.getBytesTotal(), episode.getBytesDownloaded(), episode.getStatus().name(), episode.getErrorMessage(), episode.getId()); } /** * Deletes the Podcast episode with the given ID. * * @param id The Podcast episode ID. */ public void deleteEpisode(int id) { String sql = "delete from podcast_episode where id=?"; update(sql, id); } private static class PodcastChannelRowMapper implements RowMapper { public Object mapRow(ResultSet rs, int rowNum) throws SQLException { return new PodcastChannel(rs.getInt(1), rs.getString(2), rs.getString(3), rs.getString(4), rs.getString(5), PodcastStatus.valueOf(rs.getString(6)), rs.getString(7)); } } private static class PodcastEpisodeRowMapper implements RowMapper<PodcastEpisode> { public PodcastEpisode mapRow(ResultSet rs, int rowNum) throws SQLException { return new PodcastEpisode(rs.getInt(1), rs.getInt(2), rs.getString(3), rs.getString(4), rs.getString(5), rs.getString(6), rs.getTimestamp(7), rs.getString(8), (Long) rs.getObject(9), (Long) rs.getObject(10), PodcastStatus.valueOf(rs.getString(11)), rs.getString(12)); } } }