diff options
Diffstat (limited to 'subsonic-main/src/main/java/net/sourceforge/subsonic/domain')
35 files changed, 4791 insertions, 0 deletions
diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Album.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Album.java new file mode 100644 index 00000000..23e8afaf --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Album.java @@ -0,0 +1,166 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.Date; + +/** + * @author Sindre Mehus + * @version $Id$ + */ +public class Album { + + private int id; + private String path; + private String name; + private String artist; + private int songCount; + private int durationSeconds; + private String coverArtPath; + private int playCount; + private Date lastPlayed; + private String comment; + private Date created; + private Date lastScanned; + private boolean present; + + public Album() { + } + + public Album(int id, String path, String name, String artist, int songCount, int durationSeconds, String coverArtPath, + int playCount, Date lastPlayed, String comment, Date created, Date lastScanned, boolean present) { + this.id = id; + this.path = path; + this.name = name; + this.artist = artist; + this.songCount = songCount; + this.durationSeconds = durationSeconds; + this.coverArtPath = coverArtPath; + this.playCount = playCount; + this.lastPlayed = lastPlayed; + this.comment = comment; + this.created = created; + this.lastScanned = lastScanned; + this.present = present; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getArtist() { + return artist; + } + + public void setArtist(String artist) { + this.artist = artist; + } + + public int getSongCount() { + return songCount; + } + + public void setSongCount(int songCount) { + this.songCount = songCount; + } + + public int getDurationSeconds() { + return durationSeconds; + } + + public void setDurationSeconds(int durationSeconds) { + this.durationSeconds = durationSeconds; + } + + public String getCoverArtPath() { + return coverArtPath; + } + + public void setCoverArtPath(String coverArtPath) { + this.coverArtPath = coverArtPath; + } + + public int getPlayCount() { + return playCount; + } + + public void setPlayCount(int playCount) { + this.playCount = playCount; + } + + public Date getLastPlayed() { + return lastPlayed; + } + + public void setLastPlayed(Date lastPlayed) { + this.lastPlayed = lastPlayed; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getLastScanned() { + return lastScanned; + } + + public void setLastScanned(Date lastScanned) { + this.lastScanned = lastScanned; + } + + public boolean isPresent() { + return present; + } + + public void setPresent(boolean present) { + this.present = present; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Artist.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Artist.java new file mode 100644 index 00000000..e6141f78 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Artist.java @@ -0,0 +1,95 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.Date; + +/** + * @author Sindre Mehus + * @version $Id$ + */ +public class Artist { + + private int id; + private String name; + private String coverArtPath; + private int albumCount; + private Date lastScanned; + private boolean present; + + public Artist() { + } + + public Artist(int id, String name, String coverArtPath, int albumCount, Date lastScanned, boolean present) { + this.id = id; + this.name = name; + this.coverArtPath = coverArtPath; + this.albumCount = albumCount; + this.lastScanned = lastScanned; + this.present = present; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getCoverArtPath() { + return coverArtPath; + } + + public void setCoverArtPath(String coverArtPath) { + this.coverArtPath = coverArtPath; + } + + public int getAlbumCount() { + return albumCount; + } + + public void setAlbumCount(int albumCount) { + this.albumCount = albumCount; + } + + public Date getLastScanned() { + return lastScanned; + } + + public void setLastScanned(Date lastScanned) { + this.lastScanned = lastScanned; + } + + public boolean isPresent() { + return present; + } + + public void setPresent(boolean present) { + this.present = present; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Avatar.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Avatar.java new file mode 100644 index 00000000..0089a8a3 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Avatar.java @@ -0,0 +1,75 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.Date; + +/** + * An icon representing a user. + * + * @author Sindre Mehus + */ +public class Avatar { + + private int id; + private String name; + private Date createdDate; + private String mimeType; + private int width; + private int height; + private byte[] data; + + public Avatar(int id, String name, Date createdDate, String mimeType, int width, int height, byte[] data) { + this.id = id; + this.name = name; + this.createdDate = createdDate; + this.mimeType = mimeType; + this.width = width; + this.height = height; + this.data = data; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public Date getCreatedDate() { + return createdDate; + } + + public String getMimeType() { + return mimeType; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public byte[] getData() { + return data; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/AvatarScheme.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/AvatarScheme.java new file mode 100644 index 00000000..024dcb24 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/AvatarScheme.java @@ -0,0 +1,52 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Enumeration of avatar schemes. + * + * @author Sindre Mehus + */ +public enum AvatarScheme { + + /** + * No avatar should be displayed. + */ + NONE(-1), + + /** + * One of the system avatars should be displayed. + */ + SYSTEM(0), + + /** + * The custom avatar should be displayed. + */ + CUSTOM(-2); + + private final int code; + + AvatarScheme(int code) { + this.code = code; + } + + public int getCode() { + return code; + } +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/CacheElement.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/CacheElement.java new file mode 100644 index 00000000..bb52eff7 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/CacheElement.java @@ -0,0 +1,65 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * @author Sindre Mehus + * @version $Id$ + */ +public class CacheElement { + + private final long id; + private final int type; + private final String key; + private final Object value; + private final long created; + + public CacheElement(int type, String key, Object value, long created) { + this.type = type; + this.key = key; + this.value = value; + this.created = created; + + id = createId(type, key); + } + + public static long createId(int type, String key) { + return ((long) type << 32) | Math.abs(key.hashCode()); + } + + public long getId() { + return id; + } + + public int getType() { + return type; + } + + public String getKey() { + return key; + } + + public Object getValue() { + return value; + } + + public long getCreated() { + return created; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/CoverArtScheme.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/CoverArtScheme.java new file mode 100644 index 00000000..91293e9f --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/CoverArtScheme.java @@ -0,0 +1,48 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Enumeration of cover art schemes. Each value contains a size, which indicates how big the + * scaled covert art images should be. + * + * @author Sindre Mehus + * @version $Revision: 1.3 $ $Date: 2005/06/15 18:10:40 $ + */ +public enum CoverArtScheme { + + OFF(0), + SMALL(70), + MEDIUM(100), + LARGE(150); + + private int size; + + CoverArtScheme(int size) { + this.size = size; + } + + /** + * Returns the covert art size for this scheme. + * @return the covert art size for this scheme. + */ + public int getSize() { + return size; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/InternetRadio.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/InternetRadio.java new file mode 100644 index 00000000..ae0c1f67 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/InternetRadio.java @@ -0,0 +1,168 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.Date; + +/** + * Represents an internet radio station. + * + * @author Sindre Mehus + * @version $Revision: 1.2 $ $Date: 2005/12/25 13:48:46 $ + */ +public class InternetRadio { + + private Integer id; + private String name; + private String streamUrl; + private String homepageUrl; + private boolean isEnabled; + private Date changed; + + /** + * Creates a new internet radio station. + * + * @param id The system-generated ID. + * @param name The user-defined name. + * @param streamUrl The stream URL for the station. + * @param homepageUrl The home page URL for the station. + * @param isEnabled Whether the station is enabled. + * @param changed When the corresponding database entry was last changed. + */ + public InternetRadio(Integer id, String name, String streamUrl, String homepageUrl, boolean isEnabled, Date changed) { + this.id = id; + this.name = name; + this.streamUrl = streamUrl; + this.homepageUrl = homepageUrl; + this.isEnabled = isEnabled; + this.changed = changed; + } + + /** + * Creates a new internet radio station. + * + * @param name The user-defined name. + * @param streamUrl The URL for the station. + * @param homepageUrl The home page URL for the station. + * @param isEnabled Whether the station is enabled. + * @param changed When the corresponding database entry was last changed. + */ + public InternetRadio(String name, String streamUrl, String homepageUrl, boolean isEnabled, Date changed) { + this(null, name, streamUrl, homepageUrl, isEnabled, changed); + } + + /** + * Returns the system-generated ID. + * + * @return The system-generated ID. + */ + public Integer getId() { + return id; + } + + /** + * Returns the user-defined name. + * + * @return The user-defined name. + */ + public String getName() { + return name; + } + + /** + * Sets the user-defined name. + * + * @param name The user-defined name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the stream URL of the radio station. + * + * @return The stream URL of the radio station. + */ + public String getStreamUrl() { + return streamUrl; + } + + /** + * Sets the stream URL of the radio station. + * + * @param streamUrl The stream URL of the radio station. + */ + public void setStreamUrl(String streamUrl) { + this.streamUrl = streamUrl; + } + + /** + * Returns the homepage URL of the radio station. + * + * @return The homepage URL of the radio station. + */ + public String getHomepageUrl() { + return homepageUrl; + } + + /** + * Sets the home page URL of the radio station. + * + * @param homepageUrl The home page URL of the radio station. + */ + public void setHomepageUrl(String homepageUrl) { + this.homepageUrl = homepageUrl; + } + + /** + * Returns whether the radio station is enabled. + * + * @return Whether the radio station is enabled. + */ + public boolean isEnabled() { + return isEnabled; + } + + /** + * Sets whether the radio station is enabled. + * + * @param enabled Whether the radio station is enabled. + */ + public void setEnabled(boolean enabled) { + isEnabled = enabled; + } + + /** + * Returns when the corresponding database entry was last changed. + * + * @return When the corresponding database entry was last changed. + */ + public Date getChanged() { + return changed; + } + + /** + * Sets when the corresponding database entry was last changed. + * + * @param changed When the corresponding database entry was last changed. + */ + public void setChanged(Date changed) { + this.changed = changed; + } +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaFile.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaFile.java new file mode 100644 index 00000000..4f315028 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaFile.java @@ -0,0 +1,449 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import net.sourceforge.subsonic.util.FileUtil; +import org.apache.commons.io.FilenameUtils; + +import java.io.File; +import java.util.Date; + +/** + * A media file (audio, video or directory) with an assortment of its meta data. + * + * @author Sindre Mehus + * @version $Id$ + */ +public class MediaFile { + + private int id; + private String path; + private String folder; + private MediaType mediaType; + private String format; + private String title; + private String albumName; + private String artist; + private String albumArtist; + private Integer discNumber; + private Integer trackNumber; + private Integer year; + private String genre; + private Integer bitRate; + private boolean variableBitRate; + private Integer durationSeconds; + private Long fileSize; + private Integer width; + private Integer height; + private String coverArtPath; + private String parentPath; + private int playCount; + private Date lastPlayed; + private String comment; + private Date created; + private Date changed; + private Date lastScanned; + private Date starredDate; + private Date childrenLastUpdated; + private boolean present; + + 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, + 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, + Date childrenLastUpdated, boolean present) { + this.id = id; + this.path = path; + this.folder = folder; + this.mediaType = mediaType; + this.format = format; + this.title = title; + this.albumName = albumName; + this.artist = artist; + this.albumArtist = albumArtist; + this.discNumber = discNumber; + this.trackNumber = trackNumber; + this.year = year; + this.genre = genre; + this.bitRate = bitRate; + this.variableBitRate = variableBitRate; + this.durationSeconds = durationSeconds; + this.fileSize = fileSize; + this.width = width; + this.height = height; + this.coverArtPath = coverArtPath; + this.parentPath = parentPath; + this.playCount = playCount; + this.lastPlayed = lastPlayed; + this.comment = comment; + this.created = created; + this.changed = changed; + this.lastScanned = lastScanned; + this.childrenLastUpdated = childrenLastUpdated; + this.present = present; + } + + public MediaFile() { + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getFolder() { + return folder; + } + + public void setFolder(String folder) { + this.folder = folder; + } + + public File getFile() { + // TODO: Optimize + return new File(path); + } + + public boolean exists() { + return FileUtil.exists(getFile()); + } + + public MediaType getMediaType() { + return mediaType; + } + + public void setMediaType(MediaType mediaType) { + this.mediaType = mediaType; + } + + public boolean isVideo() { + return mediaType == MediaType.VIDEO; + } + + public boolean isAudio() { + return mediaType == MediaType.MUSIC || mediaType == MediaType.AUDIOBOOK || mediaType == MediaType.PODCAST; + } + + public String getFormat() { + return format; + } + + public void setFormat(String format) { + this.format = format; + } + + public boolean isDirectory() { + return !isFile(); + } + + public boolean isFile() { + return mediaType != MediaType.DIRECTORY && mediaType != MediaType.ALBUM; + } + + public boolean isAlbum() { + return mediaType == MediaType.ALBUM; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAlbumName() { + return albumName; + } + + public void setAlbumName(String album) { + this.albumName = album; + } + + public String getArtist() { + return artist; + } + + public void setArtist(String artist) { + this.artist = artist; + } + + public String getAlbumArtist() { + return albumArtist; + } + + public void setAlbumArtist(String albumArtist) { + this.albumArtist = albumArtist; + } + + public String getName() { + if (isFile()) { + return title != null ? title : FilenameUtils.getBaseName(path); + } + + return FilenameUtils.getName(path); + } + + public Integer getDiscNumber() { + return discNumber; + } + + public void setDiscNumber(Integer discNumber) { + this.discNumber = discNumber; + } + + public Integer getTrackNumber() { + return trackNumber; + } + + public void setTrackNumber(Integer trackNumber) { + this.trackNumber = trackNumber; + } + + public Integer getYear() { + return year; + } + + public void setYear(Integer year) { + this.year = year; + } + + public String getGenre() { + return genre; + } + + public void setGenre(String genre) { + this.genre = genre; + } + + public Integer getBitRate() { + return bitRate; + } + + public void setBitRate(Integer bitRate) { + this.bitRate = bitRate; + } + + public boolean isVariableBitRate() { + return variableBitRate; + } + + public void setVariableBitRate(boolean variableBitRate) { + this.variableBitRate = variableBitRate; + } + + public Integer getDurationSeconds() { + return durationSeconds; + } + + public void setDurationSeconds(Integer durationSeconds) { + this.durationSeconds = durationSeconds; + } + + public String getDurationString() { + if (durationSeconds == null) { + return null; + } + + StringBuilder result = new StringBuilder(8); + + int seconds = durationSeconds; + + int hours = seconds / 3600; + seconds -= hours * 3600; + + int minutes = seconds / 60; + seconds -= minutes * 60; + + if (hours > 0) { + result.append(hours).append(':'); + if (minutes < 10) { + result.append('0'); + } + } + + result.append(minutes).append(':'); + if (seconds < 10) { + result.append('0'); + } + result.append(seconds); + + return result.toString(); + } + + public Long getFileSize() { + return fileSize; + } + + public void setFileSize(Long fileSize) { + this.fileSize = fileSize; + } + + public Integer getWidth() { + return width; + } + + public void setWidth(Integer width) { + this.width = width; + } + + public Integer getHeight() { + return height; + } + + public void setHeight(Integer height) { + this.height = height; + } + + public String getCoverArtPath() { + return coverArtPath; + } + + public void setCoverArtPath(String coverArtPath) { + this.coverArtPath = coverArtPath; + } + + + public String getParentPath() { + return parentPath; + } + + public void setParentPath(String parentPath) { + this.parentPath = parentPath; + } + + public File getParentFile() { + return getFile().getParentFile(); + } + + public int getPlayCount() { + return playCount; + } + + public void setPlayCount(int playCount) { + this.playCount = playCount; + } + + public Date getLastPlayed() { + return lastPlayed; + } + + public void setLastPlayed(Date lastPlayed) { + this.lastPlayed = lastPlayed; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getChanged() { + return changed; + } + + public void setChanged(Date changed) { + this.changed = changed; + } + + public Date getLastScanned() { + return lastScanned; + } + + public void setLastScanned(Date lastScanned) { + this.lastScanned = lastScanned; + } + + public Date getStarredDate() { + return starredDate; + } + + public void setStarredDate(Date starredDate) { + this.starredDate = starredDate; + } + + /** + * Returns when the children was last updated in the database. + */ + public Date getChildrenLastUpdated() { + return childrenLastUpdated; + } + + public void setChildrenLastUpdated(Date childrenLastUpdated) { + this.childrenLastUpdated = childrenLastUpdated; + } + + public boolean isPresent() { + return present; + } + + public void setPresent(boolean present) { + this.present = present; + } + + @Override + public boolean equals(Object o) { + return o instanceof MediaFile && ((MediaFile) o).path.equals(path); + } + + @Override + public int hashCode() { + return path.hashCode(); + } + + public File getCoverArtFile() { + // TODO: Optimize + return coverArtPath == null ? null : new File(coverArtPath); + } + + @Override + public String toString() { + return getName(); + } + + public static enum MediaType { + MUSIC, + PODCAST, + AUDIOBOOK, + VIDEO, + DIRECTORY, + ALBUM + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaFileComparator.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaFileComparator.java new file mode 100644 index 00000000..13b5bbbd --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaFileComparator.java @@ -0,0 +1,99 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.Comparator; + +import static net.sourceforge.subsonic.domain.MediaFile.MediaType.DIRECTORY; + +/** + * Comparator for sorting media files. + */ +public class MediaFileComparator implements Comparator<MediaFile> { + + private final boolean sortAlbumsByYear; + + public MediaFileComparator(boolean sortAlbumsByYear) { + this.sortAlbumsByYear = sortAlbumsByYear; + } + + public int compare(MediaFile a, MediaFile b) { + + // Directories before files. + if (a.isFile() && b.isDirectory()) { + return 1; + } + if (a.isDirectory() && b.isFile()) { + return -1; + } + + // Non-album directories before album directories. + if (a.isAlbum() && b.getMediaType() == DIRECTORY) { + return 1; + } + if (a.getMediaType() == DIRECTORY && b.isAlbum()) { + return -1; + } + + // Sort albums by year + if (sortAlbumsByYear && a.isAlbum() && b.isAlbum()) { + int i = nullSafeCompare(a.getYear(), b.getYear(), false); + if (i != 0) { + return i; + } + } + + if (a.isDirectory() && b.isDirectory()) { + return a.getName().compareToIgnoreCase(b.getName()); + } + + // Compare by disc and track numbers, if present. + Integer trackA = getSortableDiscAndTrackNumber(a); + Integer trackB = getSortableDiscAndTrackNumber(b); + int i = nullSafeCompare(trackA, trackB, false); + if (i != 0) { + return i; + } + + return a.getName().compareToIgnoreCase(b.getName()); + } + + private <T extends Comparable<T>> int nullSafeCompare(T a, T b, boolean nullIsSmaller) { + if (a == null && b == null) { + return 0; + } + if (a == null) { + return nullIsSmaller ? -1 : 1; + } + if (b == null) { + return nullIsSmaller ? 1 : -1; + } + return a.compareTo(b); + } + + private Integer getSortableDiscAndTrackNumber(MediaFile file) { + if (file.getTrackNumber() == null) { + return null; + } + + int discNumber = file.getDiscNumber() == null ? 1 : file.getDiscNumber(); + return discNumber * 1000 + file.getTrackNumber(); + } +} + diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaLibraryStatistics.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaLibraryStatistics.java new file mode 100644 index 00000000..c8b0cdd9 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MediaLibraryStatistics.java @@ -0,0 +1,62 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Contains media libaray statistics, including the number of artists, albums and songs. + * + * @author Sindre Mehus + * @version $Revision: 1.1 $ $Date: 2005/11/17 18:29:03 $ + */ +public class MediaLibraryStatistics { + + private int artistCount; + private int albumCount; + private int songCount; + private long totalLengthInBytes; + private long totalDurationInSeconds; + + public MediaLibraryStatistics(int artistCount, int albumCount, int songCount, long totalLengthInBytes, long totalDurationInSeconds) { + this.artistCount = artistCount; + this.albumCount = albumCount; + this.songCount = songCount; + this.totalLengthInBytes = totalLengthInBytes; + this.totalDurationInSeconds = totalDurationInSeconds; + } + + public int getArtistCount() { + return artistCount; + } + + public int getAlbumCount() { + return albumCount; + } + + public int getSongCount() { + return songCount; + } + + public long getTotalLengthInBytes() { + return totalLengthInBytes; + } + + public long getTotalDurationInSeconds() { + return totalDurationInSeconds; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MusicFolder.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MusicFolder.java new file mode 100644 index 00000000..613b0a7f --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MusicFolder.java @@ -0,0 +1,148 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.io.File; +import java.io.Serializable; +import java.util.Date; + +/** + * Represents a top level directory in which music or other media is stored. + * + * @author Sindre Mehus + * @version $Revision: 1.1 $ $Date: 2005/11/27 14:32:05 $ + */ +public class MusicFolder implements Serializable { + + private Integer id; + private File path; + private String name; + private boolean isEnabled; + private Date changed; + + /** + * Creates a new music folder. + * + * @param id The system-generated ID. + * @param path The path of the music folder. + * @param name The user-defined name. + * @param enabled Whether the folder is enabled. + * @param changed When the corresponding database entry was last changed. + */ + public MusicFolder(Integer id, File path, String name, boolean enabled, Date changed) { + this.id = id; + this.path = path; + this.name = name; + isEnabled = enabled; + this.changed = changed; + } + + /** + * Creates a new music folder. + * + * @param path The path of the music folder. + * @param name The user-defined name. + * @param enabled Whether the folder is enabled. + * @param changed When the corresponding database entry was last changed. + */ + public MusicFolder(File path, String name, boolean enabled, Date changed) { + this(null, path, name, enabled, changed); + } + + /** + * Returns the system-generated ID. + * + * @return The system-generated ID. + */ + public Integer getId() { + return id; + } + + /** + * Returns the path of the music folder. + * + * @return The path of the music folder. + */ + public File getPath() { + return path; + } + + /** + * Sets the path of the music folder. + * + * @param path The path of the music folder. + */ + public void setPath(File path) { + this.path = path; + } + + /** + * Returns the user-defined name. + * + * @return The user-defined name. + */ + public String getName() { + return name; + } + + /** + * Sets the user-defined name. + * + * @param name The user-defined name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns whether the folder is enabled. + * + * @return Whether the folder is enabled. + */ + public boolean isEnabled() { + return isEnabled; + } + + /** + * Sets whether the folder is enabled. + * + * @param enabled Whether the folder is enabled. + */ + public void setEnabled(boolean enabled) { + isEnabled = enabled; + } + + /** + * Returns when the corresponding database entry was last changed. + * + * @return When the corresponding database entry was last changed. + */ + public Date getChanged() { + return changed; + } + + /** + * Sets when the corresponding database entry was last changed. + * + * @param changed When the corresponding database entry was last changed. + */ + public void setChanged(Date changed) { + this.changed = changed; + } +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MusicIndex.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MusicIndex.java new file mode 100644 index 00000000..5753fa4d --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/MusicIndex.java @@ -0,0 +1,167 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.ArrayList; +import java.util.List; +import java.io.Serializable; + +/** + * A music index is a mapping from an index string to a list of prefixes. A complete index consists of a list of + * <code>MusicIndex</code> instances.<p/> + * <p/> + * For a normal alphabetical index, such a mapping would typically be <em>"A" -> ["A"]</em>. The index can also be used + * to group less frequently used letters, such as <em>"X-Å" -> ["X", "Y", "Z", "Æ", "Ø", "Å"]</em>, or to make multiple + * indexes for frequently used letters, such as <em>"SA" -> ["SA"]</em> and <em>"SO" -> ["SO"]</em><p/> + * <p/> + * Clicking on an index in the user interface will typically bring up a list of all music files that are categorized + * under that index. + * + * @author Sindre Mehus + */ +public class MusicIndex implements Serializable { + + public static final MusicIndex OTHER = new MusicIndex("#"); + + private final String index; + private final List<String> prefixes = new ArrayList<String>(); + + /** + * Creates a new index with the given index string. + * + * @param index The index string, e.g., "A" or "The". + */ + public MusicIndex(String index) { + this.index = index; + } + + /** + * Adds a prefix to this index. Music files that starts with this prefix will be categorized under this index entry. + * + * @param prefix The prefix. + */ + public void addPrefix(String prefix) { + prefixes.add(prefix); + } + + /** + * Returns the index name. + * + * @return The index name. + */ + public String getIndex() { + return index; + } + + /** + * Returns the list of prefixes. + * + * @return The list of prefixes. + */ + public List<String> getPrefixes() { + return prefixes; + } + + /** + * Returns whether this object is equal to another one. + * + * @param o Object to compare to. + * @return <code>true</code> if, and only if, the other object is a <code>MusicIndex</code> with the same + * index name as this one. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof MusicIndex)) { + return false; + } + + final MusicIndex musicIndex = (MusicIndex) o; + + if (index != null ? !index.equals(musicIndex.index) : musicIndex.index != null) { + return false; + } + + return true; + } + + /** + * Returns a hash code for this object. + * + * @return A hash code for this object. + */ + @Override + public int hashCode() { + return (index != null ? index.hashCode() : 0); + } + + /** + * An artist in an index. + */ + public static class Artist implements Comparable<Artist>, Serializable { + + private final String name; + private final String sortableName; + private final List<MediaFile> mediaFiles = new ArrayList<MediaFile>(); + + public Artist(String name, String sortableName) { + this.name = name; + this.sortableName = sortableName; + } + + public void addMediaFile(MediaFile mediaFile) { + mediaFiles.add(mediaFile); + } + + public String getName() { + return name; + } + + public String getSortableName() { + return sortableName; + } + + public List<MediaFile> getMediaFiles() { + return mediaFiles; + } + + public int compareTo(Artist artist) { + return sortableName.compareToIgnoreCase(artist.sortableName); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Artist artist = (Artist) o; + return sortableName.equalsIgnoreCase(artist.sortableName); + } + + @Override + public int hashCode() { + return sortableName.hashCode(); + } + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/NATPMPRouter.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/NATPMPRouter.java new file mode 100644 index 00000000..ef3821a1 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/NATPMPRouter.java @@ -0,0 +1,61 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import com.hoodcomputing.natpmp.MapRequestMessage; +import com.hoodcomputing.natpmp.NatPmpDevice; + +/** + * @author Sindre Mehus + * @version $Id$ + */ +public class NATPMPRouter implements Router { + + private final NatPmpDevice device; + + private NATPMPRouter(NatPmpDevice device) { + this.device = device; + } + + public static NATPMPRouter findRouter() { + try { + return new NATPMPRouter(new NatPmpDevice(false)); + } catch (Exception x) { + return null; + } + } + + public void addPortMapping(int externalPort, int internalPort, int leaseDuration) throws Exception { + + // Use one week if lease duration is "forever". + if (leaseDuration == 0) { + leaseDuration = 7 * 24 * 3600; + } + + MapRequestMessage map = new MapRequestMessage(true, internalPort, externalPort, leaseDuration, null); + device.enqueueMessage(map); + device.waitUntilQueueEmpty(); + } + + public void deletePortMapping(int externalPort, int internalPort) throws Exception { + MapRequestMessage map = new MapRequestMessage(true, internalPort, externalPort, 0, null); + device.enqueueMessage(map); + device.waitUntilQueueEmpty(); + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PlayQueue.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PlayQueue.java new file mode 100644 index 00000000..97748f72 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PlayQueue.java @@ -0,0 +1,417 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import net.sourceforge.subsonic.util.FileUtil; +import org.apache.commons.lang.StringUtils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * A playlist is a list of music files that are associated to a remote player. + * + * @author Sindre Mehus + */ +public class PlayQueue { + + private List<MediaFile> files = new ArrayList<MediaFile>(); + private boolean repeatEnabled; + private String name = "(unnamed)"; + private Status status = Status.PLAYING; + private RandomSearchCriteria randomSearchCriteria; + + /** + * The index of the current song, or -1 is the end of the playlist is reached. + * Note that both the index and the playlist size can be zero. + */ + private int index = 0; + + /** + * Used for undo functionality. + */ + private List<MediaFile> filesBackup = new ArrayList<MediaFile>(); + private int indexBackup = 0; + + /** + * Returns the user-defined name of the playlist. + * + * @return The name of the playlist, or <code>null</code> if no name has been assigned. + */ + public synchronized String getName() { + return name; + } + + /** + * Sets the user-defined name of the playlist. + * + * @param name The name of the playlist. + */ + public synchronized void setName(String name) { + this.name = name; + } + + /** + * Returns the current song in the playlist. + * + * @return The current song in the playlist, or <code>null</code> if no current song exists. + */ + public synchronized MediaFile getCurrentFile() { + if (index == -1 || index == 0 && size() == 0) { + setStatus(Status.STOPPED); + return null; + } else { + MediaFile file = files.get(index); + + // Remove file from playlist if it doesn't exist. + if (!file.exists()) { + files.remove(index); + index = Math.max(0, Math.min(index, size() - 1)); + return getCurrentFile(); + } + + return file; + } + } + + /** + * Returns all music files in the playlist. + * + * @return All music files in the playlist. + */ + public synchronized List<MediaFile> getFiles() { + return files; + } + + /** + * Returns the music file at the given index. + * + * @param index The index. + * @return The music file at the given index. + * @throws IndexOutOfBoundsException If the index is out of range. + */ + public synchronized MediaFile getFile(int index) { + return files.get(index); + } + + /** + * Skip to the next song in the playlist. + */ + public synchronized void next() { + index++; + + // Reached the end? + if (index >= size()) { + index = isRepeatEnabled() ? 0 : -1; + } + } + + /** + * Returns the number of songs in the playlists. + * + * @return The number of songs in the playlists. + */ + public synchronized int size() { + return files.size(); + } + + /** + * Returns whether the playlist is empty. + * + * @return Whether the playlist is empty. + */ + public synchronized boolean isEmpty() { + return files.isEmpty(); + } + + /** + * Returns the index of the current song. + * + * @return The index of the current song, or -1 if the end of the playlist is reached. + */ + public synchronized int getIndex() { + return index; + } + + /** + * Sets the index of the current song. + * + * @param index The index of the current song. + */ + public synchronized void setIndex(int index) { + makeBackup(); + this.index = Math.max(0, Math.min(index, size() - 1)); + setStatus(Status.PLAYING); + } + + /** + * Adds one or more music file to the playlist. + * + * @param append Whether existing songs in the playlist should be kept. + * @param mediaFiles The music files to add. + * @throws IOException If an I/O error occurs. + */ + public synchronized void addFiles(boolean append, Iterable<MediaFile> mediaFiles) throws IOException { + makeBackup(); + if (!append) { + index = 0; + files.clear(); + } + for (MediaFile mediaFile : mediaFiles) { + files.add(mediaFile); + } + setStatus(Status.PLAYING); + } + + /** + * Convenience method, equivalent to {@link #addFiles(boolean, Iterable)}. + */ + public synchronized void addFiles(boolean append, MediaFile... mediaFiles) throws IOException { + addFiles(append, Arrays.asList(mediaFiles)); + } + + /** + * Removes the music file at the given index. + * + * @param index The playlist index. + */ + public synchronized void removeFileAt(int index) { + makeBackup(); + index = Math.max(0, Math.min(index, size() - 1)); + if (this.index > index) { + this.index--; + } + files.remove(index); + + if (index != -1) { + this.index = Math.max(0, Math.min(this.index, size() - 1)); + } + } + + /** + * Clears the playlist. + */ + public synchronized void clear() { + makeBackup(); + files.clear(); + index = 0; + } + + /** + * Shuffles the playlist. + */ + public synchronized void shuffle() { + makeBackup(); + MediaFile currentFile = getCurrentFile(); + Collections.shuffle(files); + if (currentFile != null) { + index = files.indexOf(currentFile); + } + } + + /** + * Sorts the playlist according to the given sort order. + */ + public synchronized void sort(final SortOrder sortOrder) { + makeBackup(); + MediaFile currentFile = getCurrentFile(); + + Comparator<MediaFile> comparator = new Comparator<MediaFile>() { + public int compare(MediaFile a, MediaFile b) { + switch (sortOrder) { + case TRACK: + Integer trackA = a.getTrackNumber(); + Integer trackB = b.getTrackNumber(); + if (trackA == null) { + trackA = 0; + } + if (trackB == null) { + trackB = 0; + } + return trackA.compareTo(trackB); + + case ARTIST: + String artistA = StringUtils.trimToEmpty(a.getArtist()); + String artistB = StringUtils.trimToEmpty(b.getArtist()); + return artistA.compareTo(artistB); + + case ALBUM: + String albumA = StringUtils.trimToEmpty(a.getAlbumName()); + String albumB = StringUtils.trimToEmpty(b.getAlbumName()); + return albumA.compareTo(albumB); + default: + return 0; + } + } + }; + + Collections.sort(files, comparator); + if (currentFile != null) { + index = files.indexOf(currentFile); + } + } + + /** + * Moves the song at the given index one step up. + * + * @param index The playlist index. + */ + public synchronized void moveUp(int index) { + makeBackup(); + if (index <= 0 || index >= size()) { + return; + } + Collections.swap(files, index, index - 1); + + if (this.index == index) { + this.index--; + } else if (this.index == index - 1) { + this.index++; + } + } + + /** + * Moves the song at the given index one step down. + * + * @param index The playlist index. + */ + public synchronized void moveDown(int index) { + makeBackup(); + if (index < 0 || index >= size() - 1) { + return; + } + Collections.swap(files, index, index + 1); + + if (this.index == index) { + this.index++; + } else if (this.index == index + 1) { + this.index--; + } + } + + /** + * Returns whether the playlist is repeating. + * + * @return Whether the playlist is repeating. + */ + public synchronized boolean isRepeatEnabled() { + return repeatEnabled; + } + + /** + * Sets whether the playlist is repeating. + * + * @param repeatEnabled Whether the playlist is repeating. + */ + public synchronized void setRepeatEnabled(boolean repeatEnabled) { + this.repeatEnabled = repeatEnabled; + } + + /** + * Revert the last operation. + */ + public synchronized void undo() { + List<MediaFile> filesTmp = new ArrayList<MediaFile>(files); + int indexTmp = index; + + index = indexBackup; + files = filesBackup; + + indexBackup = indexTmp; + filesBackup = filesTmp; + } + + /** + * Returns the playlist status. + * + * @return The playlist status. + */ + public synchronized Status getStatus() { + return status; + } + + /** + * Sets the playlist status. + * + * @param status The playlist status. + */ + public synchronized void setStatus(Status status) { + this.status = status; + if (index == -1) { + index = Math.max(0, Math.min(index, size() - 1)); + } + } + + /** + * Returns the criteria used to generate this random playlist. + * + * @return The search criteria, or <code>null</code> if this is not a random playlist. + */ + public synchronized RandomSearchCriteria getRandomSearchCriteria() { + return randomSearchCriteria; + } + + /** + * Sets the criteria used to generate this random playlist. + * + * @param randomSearchCriteria The search criteria, or <code>null</code> if this is not a random playlist. + */ + public synchronized void setRandomSearchCriteria(RandomSearchCriteria randomSearchCriteria) { + this.randomSearchCriteria = randomSearchCriteria; + } + + /** + * Returns the total length in bytes. + * + * @return The total length in bytes. + */ + public synchronized long length() { + long length = 0; + for (MediaFile mediaFile : files) { + length += mediaFile.getFileSize(); + } + return length; + } + + private void makeBackup() { + filesBackup = new ArrayList<MediaFile>(files); + indexBackup = index; + } + + /** + * Playlist status. + */ + public enum Status { + PLAYING, + STOPPED + } + + /** + * Playlist sort order. + */ + public enum SortOrder { + TRACK, + ARTIST, + ALBUM + } +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Player.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Player.java new file mode 100644 index 00000000..e1780936 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Player.java @@ -0,0 +1,338 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import org.apache.commons.lang.StringUtils; + +import java.util.Date; + +/** + * Represens a remote player. A player has a unique ID, a user-defined name, a logged-on user, + * miscellaneous identifiers, and an associated playlist. + * + * @author Sindre Mehus + */ +public class Player { + + private String id; + private String name; + private PlayerTechnology technology = PlayerTechnology.WEB; + private String clientId; + private String type; + private String username; + private String ipAddress; + private boolean isDynamicIp = true; + private boolean isAutoControlEnabled = true; + private Date lastSeen; + private CoverArtScheme coverArtScheme = CoverArtScheme.MEDIUM; + private TranscodeScheme transcodeScheme = TranscodeScheme.OFF; + private PlayQueue playQueue; + + /** + * Returns the player ID. + * + * @return The player ID. + */ + public String getId() { + return id; + } + + /** + * Sets the player ID. + * + * @param id The player ID. + */ + public void setId(String id) { + this.id = id; + } + + /** + * Returns the user-defined player name. + * + * @return The user-defined player name. + */ + public String getName() { + return name; + } + + /** + * Sets the user-defined player name. + * + * @param name The user-defined player name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the player "technology", e.g., web, external or jukebox. + * + * @return The player technology. + */ + public PlayerTechnology getTechnology() { + return technology; + } + + /** + * Returns the third-party client ID (used if this player is managed over the + * Subsonic REST API). + * + * @return The client ID. + */ + public String getClientId() { + return clientId; + } + + /** + * Sets the third-party client ID (used if this player is managed over the + * Subsonic REST API). + * + * @param clientId The client ID. + */ + public void setClientId(String clientId) { + this.clientId = clientId; + } + + /** + * Sets the player "technology", e.g., web, external or jukebox. + * + * @param technology The player technology. + */ + public void setTechnology(PlayerTechnology technology) { + this.technology = technology; + } + + public boolean isJukebox() { + return technology == PlayerTechnology.JUKEBOX; + } + + public boolean isExternal() { + return technology == PlayerTechnology.EXTERNAL; + } + + public boolean isExternalWithPlaylist() { + return technology == PlayerTechnology.EXTERNAL_WITH_PLAYLIST; + } + + public boolean isWeb() { + return technology == PlayerTechnology.WEB; + } + + /** + * Returns the player type, e.g., WinAmp, iTunes. + * + * @return The player type. + */ + public String getType() { + return type; + } + + /** + * Sets the player type, e.g., WinAmp, iTunes. + * + * @param type The player type. + */ + public void setType(String type) { + this.type = type; + } + + /** + * Returns the logged-in user. + * + * @return The logged-in user. + */ + public String getUsername() { + return username; + } + + /** + * Sets the logged-in username. + * + * @param username The logged-in username. + */ + public void setUsername(String username) { + this.username = username; + } + + /** + * Returns whether the player is automatically started. + * + * @return Whether the player is automatically started. + */ + public boolean isAutoControlEnabled() { + return isAutoControlEnabled; + } + + /** + * Sets whether the player is automatically started. + * + * @param isAutoControlEnabled Whether the player is automatically started. + */ + public void setAutoControlEnabled(boolean isAutoControlEnabled) { + this.isAutoControlEnabled = isAutoControlEnabled; + } + + /** + * Returns the time when the player was last seen. + * + * @return The time when the player was last seen. + */ + public Date getLastSeen() { + return lastSeen; + } + + /** + * Sets the time when the player was last seen. + * + * @param lastSeen The time when the player was last seen. + */ + public void setLastSeen(Date lastSeen) { + this.lastSeen = lastSeen; + } + + /** + * Returns the cover art scheme. + * + * @return The cover art scheme. + */ + public CoverArtScheme getCoverArtScheme() { + return coverArtScheme; + } + + /** + * Sets the cover art scheme. + * + * @param coverArtScheme The cover art scheme. + */ + public void setCoverArtScheme(CoverArtScheme coverArtScheme) { + this.coverArtScheme = coverArtScheme; + } + + /** + * Returns the transcode scheme. + * + * @return The transcode scheme. + */ + public TranscodeScheme getTranscodeScheme() { + return transcodeScheme; + } + + /** + * Sets the transcode scheme. + * + * @param transcodeScheme The transcode scheme. + */ + public void setTranscodeScheme(TranscodeScheme transcodeScheme) { + this.transcodeScheme = transcodeScheme; + } + + /** + * Returns the IP address of the player. + * + * @return The IP address of the player. + */ + public String getIpAddress() { + return ipAddress; + } + + /** + * Sets the IP address of the player. + * + * @param ipAddress The IP address of the player. + */ + public void setIpAddress(String ipAddress) { + this.ipAddress = ipAddress; + } + + /** + * Returns whether this player has a dynamic IP address. + * + * @return Whether this player has a dynamic IP address. + */ + public boolean isDynamicIp() { + return isDynamicIp; + } + + /** + * Sets whether this player has a dynamic IP address. + * + * @param dynamicIp Whether this player has a dynamic IP address. + */ + public void setDynamicIp(boolean dynamicIp) { + isDynamicIp = dynamicIp; + } + + /** + * Returns the player's playlist. + * + * @return The player's playlist + */ + public PlayQueue getPlayQueue() { + return playQueue; + } + + /** + * Sets the player's playlist. + * + * @param playQueue The player's playlist. + */ + public void setPlayQueue(PlayQueue playQueue) { + this.playQueue = playQueue; + } + + /** + * Returns a long description of the player, e.g., <code>Player 3 [admin]</code> + * + * @return A long description of the player. + */ + public String getDescription() { + StringBuilder builder = new StringBuilder(); + if (name != null) { + builder.append(name); + } else { + builder.append("Player ").append(id); + } + + builder.append(" [").append(username).append(']'); + return builder.toString(); + } + + /** + * Returns a short description of the player, e.g., <code>Player 3</code> + * + * @return A short description of the player. + */ + public String getShortDescription() { + if (StringUtils.isNotBlank(name)) { + return name; + } + return "Player " + id; + } + + /** + * Returns a string representation of the player. + * + * @return A string representation of the player. + * @see #getDescription() + */ + @Override + public String toString() { + return getDescription(); + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PlayerTechnology.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PlayerTechnology.java new file mode 100644 index 00000000..5ba3ff71 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PlayerTechnology.java @@ -0,0 +1,49 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Enumeration of player technologies. + * + * @author Sindre Mehus + */ +public enum PlayerTechnology { + + /** + * Plays music directly in the web browser using the integrated Flash player. + */ + WEB, + + /** + * Plays music in an external player, such as WinAmp or Windows Media Player. + */ + EXTERNAL, + + /** + * Same as above, but the playlist is managed by the player, rather than the Subsonic server. + * In this mode, skipping within songs is possible. + */ + EXTERNAL_WITH_PLAYLIST, + + /** + * Plays music directly on the audio device of the Subsonic server. + */ + JUKEBOX + +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Playlist.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Playlist.java new file mode 100644 index 00000000..80555ec7 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Playlist.java @@ -0,0 +1,141 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import net.sourceforge.subsonic.util.StringUtil; + +import java.util.Date; + +/** + * @author Sindre Mehus + */ +public class Playlist { + + private int id; + private String username; + private boolean isPublic; + private String name; + private String comment; + private int fileCount; + private int durationSeconds; + private Date created; + private Date changed; + private String importedFrom; + + public Playlist() { + } + + public Playlist(int id, String username, boolean isPublic, String name, String comment, int fileCount, + int durationSeconds, Date created, Date changed, String importedFrom) { + this.id = id; + this.username = username; + this.isPublic = isPublic; + this.name = name; + this.comment = comment; + this.fileCount = fileCount; + this.durationSeconds = durationSeconds; + this.created = created; + this.changed = changed; + this.importedFrom = importedFrom; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public boolean isPublic() { + return isPublic; + } + + public void setPublic(boolean isPublic) { + this.isPublic = isPublic; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + + public int getFileCount() { + return fileCount; + } + + public void setFileCount(int fileCount) { + this.fileCount = fileCount; + } + + public int getDurationSeconds() { + return durationSeconds; + } + + public void setDurationSeconds(int durationSeconds) { + this.durationSeconds = durationSeconds; + } + + public String getDurationAsString() { + return StringUtil.formatDuration(durationSeconds); + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getChanged() { + return changed; + } + + public void setChanged(Date changed) { + this.changed = changed; + } + + public String getImportedFrom() { + return importedFrom; + } + + public void setImportedFrom(String importedFrom) { + this.importedFrom = importedFrom; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastChannel.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastChannel.java new file mode 100644 index 00000000..1127a5cb --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastChannel.java @@ -0,0 +1,96 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import net.sourceforge.subsonic.util.StringUtil; + +/** + * A Podcast channel. Each channel contain several episodes. + * + * @author Sindre Mehus + * @see PodcastEpisode + */ +public class PodcastChannel { + + private Integer id; + private String url; + private String title; + private String description; + private PodcastStatus status; + private String errorMessage; + + public PodcastChannel(Integer id, String url, String title, String description, + PodcastStatus status, String errorMessage) { + this.id = id; + this.url = url; + this.title = StringUtil.removeMarkup(title); + this.description = StringUtil.removeMarkup(description); + this.status = status; + this.errorMessage = errorMessage; + } + + public PodcastChannel(String url) { + this.url = url; + status = PodcastStatus.NEW; + } + + public Integer getId() { + return id; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public PodcastStatus getStatus() { + return status; + } + + public void setStatus(PodcastStatus status) { + this.status = status; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastEpisode.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastEpisode.java new file mode 100644 index 00000000..b5a835cb --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastEpisode.java @@ -0,0 +1,172 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.Date; + +import net.sourceforge.subsonic.util.StringUtil; + +/** + * A Podcast episode belonging to a channel. + * + * @author Sindre Mehus + * @see PodcastChannel + */ +public class PodcastEpisode { + + private Integer id; + private Integer mediaFileId; + private Integer channelId; + private String url; + private String path; + private String title; + private String description; + private Date publishDate; + private String duration; + private Long bytesTotal; + private Long bytesDownloaded; + private PodcastStatus status; + private String errorMessage; + + public PodcastEpisode(Integer id, Integer channelId, String url, String path, String title, + String description, Date publishDate, String duration, Long length, Long bytesDownloaded, + PodcastStatus status, String errorMessage) { + this.id = id; + this.channelId = channelId; + this.url = url; + this.path = path; + this.title = StringUtil.removeMarkup(title); + this.description = StringUtil.removeMarkup(description); + this.publishDate = publishDate; + this.duration = duration; + this.bytesTotal = length; + this.bytesDownloaded = bytesDownloaded; + this.status = status; + this.errorMessage = errorMessage; + } + + public Integer getId() { + return id; + } + + public Integer getChannelId() { + return channelId; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public Date getPublishDate() { + return publishDate; + } + + public void setPublishDate(Date publishDate) { + this.publishDate = publishDate; + } + + public String getDuration() { + return duration; + } + + public void setDuration(String duration) { + this.duration = duration; + } + + public Long getBytesTotal() { + return bytesTotal; + } + + public void setBytesTotal(Long bytesTotal) { + this.bytesTotal = bytesTotal; + } + + public Long getBytesDownloaded() { + return bytesDownloaded; + } + + public Double getCompletionRate() { + if (bytesTotal == null || bytesTotal == 0) { + return null; + } + if (bytesDownloaded == null) { + return 0.0; + } + + double d = bytesDownloaded; + double t = bytesTotal; + return d / t; + } + + public void setBytesDownloaded(Long bytesDownloaded) { + this.bytesDownloaded = bytesDownloaded; + } + + public PodcastStatus getStatus() { + return status; + } + + public void setStatus(PodcastStatus status) { + this.status = status; + } + + public String getErrorMessage() { + return errorMessage; + } + + public void setErrorMessage(String errorMessage) { + this.errorMessage = errorMessage; + } + + public Integer getMediaFileId() { + return mediaFileId; + } + + public void setMediaFileId(Integer mediaFileId) { + this.mediaFileId = mediaFileId; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastStatus.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastStatus.java new file mode 100644 index 00000000..57cad155 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/PodcastStatus.java @@ -0,0 +1,29 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Enumeration of statuses for {@link PodcastChannel} and + * {@link PodcastEpisode}. + * + * @author Sindre Mehus + */ +public enum PodcastStatus { + NEW, DOWNLOADING, COMPLETED, ERROR, DELETED, SKIPPED +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/RandomSearchCriteria.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/RandomSearchCriteria.java new file mode 100644 index 00000000..d52cec39 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/RandomSearchCriteria.java @@ -0,0 +1,70 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Defines criteria used when generating random playlists. + * + * @author Sindre Mehus + * @see net.sourceforge.subsonic.service.SearchService#getRandomSongs + */ +public class RandomSearchCriteria { + private final int count; + private final String genre; + private final Integer fromYear; + private final Integer toYear; + private final Integer musicFolderId; + + /** + * Creates a new instance. + * + * @param count Maximum number of songs to return. + * @param genre Only return songs of the given genre. May be <code>null</code>. + * @param fromYear Only return songs released after (or in) this year. May be <code>null</code>. + * @param toYear Only return songs released before (or in) this year. May be <code>null</code>. + * @param musicFolderId Only return songs from this music folder. May be <code>null</code>. + */ + public RandomSearchCriteria(int count, String genre, Integer fromYear, Integer toYear, Integer musicFolderId) { + this.count = count; + this.genre = genre; + this.fromYear = fromYear; + this.toYear = toYear; + this.musicFolderId = musicFolderId; + } + + public int getCount() { + return count; + } + + public String getGenre() { + return genre; + } + + public Integer getFromYear() { + return fromYear; + } + + public Integer getToYear() { + return toYear; + } + + public Integer getMusicFolderId() { + return musicFolderId; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Router.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Router.java new file mode 100644 index 00000000..ede9d19e --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Router.java @@ -0,0 +1,43 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * @author Sindre Mehus + * @version $Id$ + */ +public interface Router { + + /** + * Adds a NAT entry on the UPNP device. + * + * @param externalPort The external port to open on the UPNP device an map on the internal client. + * @param internalPort The internal client port where data should be redirected. + * @param leaseDuration Seconds the lease duration in seconds, or 0 for an infinite time. + */ + void addPortMapping(int externalPort, int internalPort, int leaseDuration) throws Exception; + + /** + * Deletes a NAT entry on the UPNP device. + * + * @param externalPort The external port of the NAT entry to delete. + * @param internalPort The internal port of the NAT entry to delete. + */ + void deletePortMapping(int externalPort, int internalPort) throws Exception; +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SBBIRouter.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SBBIRouter.java new file mode 100644 index 00000000..a639e665 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SBBIRouter.java @@ -0,0 +1,63 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import net.sbbi.upnp.impls.InternetGatewayDevice; + +import java.io.IOException; +import java.net.InetAddress; + +/** + * @author Sindre Mehus + */ +public class SBBIRouter implements Router { + + // The timeout in milliseconds for finding a router device. + private static final int DISCOVERY_TIMEOUT = 3000; + + private final InternetGatewayDevice device; + + private SBBIRouter(InternetGatewayDevice device) { + this.device = device; + } + + public static SBBIRouter findRouter() throws Exception { + InternetGatewayDevice[] devices; + try { + devices = InternetGatewayDevice.getDevices(DISCOVERY_TIMEOUT); + } catch (IOException e) { + throw new Exception("Could not find router", e); + } + + if (devices == null || devices.length == 0) { + return null; + } + + return new SBBIRouter(devices[0]); + } + + public void addPortMapping(int externalPort, int internalPort, int leaseDuration) throws Exception { + String localIp = InetAddress.getLocalHost().getHostAddress(); + device.addPortMapping("Subsonic", null, internalPort, externalPort, localIp, leaseDuration, "TCP"); + } + + public void deletePortMapping(int externalPort, int internal) throws Exception { + device.deletePortMapping(null, externalPort, "TCP"); + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SearchCriteria.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SearchCriteria.java new file mode 100644 index 00000000..f06a6512 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SearchCriteria.java @@ -0,0 +1,59 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import net.sourceforge.subsonic.service.MediaScannerService; +import net.sourceforge.subsonic.service.SearchService; + +/** + * Defines criteria used when searching. + * + * @author Sindre Mehus + * @see SearchService#search + */ +public class SearchCriteria { + + private String query; + private int offset; + private int count; + + public void setQuery(String query) { + this.query = query; + } + + public String getQuery() { + return query; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + public int getCount() { + return count; + } + + public void setCount(int count) { + this.count = count; + } +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SearchResult.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SearchResult.java new file mode 100644 index 00000000..bf4b370a --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/SearchResult.java @@ -0,0 +1,69 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.ArrayList; +import java.util.List; + +import net.sourceforge.subsonic.service.MediaScannerService; +import net.sourceforge.subsonic.service.SearchService; + +/** + * The outcome of a search. + * + * @author Sindre Mehus + * @see SearchService#search + */ +public class SearchResult { + + private final List<MediaFile> mediaFiles = new ArrayList<MediaFile>(); + private final List<Artist> artists = new ArrayList<Artist>(); + private final List<Album> albums = new ArrayList<Album>(); + + private int offset; + private int totalHits; + + public List<MediaFile> getMediaFiles() { + return mediaFiles; + } + + public List<Artist> getArtists() { + return artists; + } + + public List<Album> getAlbums() { + return albums; + } + + public int getOffset() { + return offset; + } + + public void setOffset(int offset) { + this.offset = offset; + } + + public int getTotalHits() { + return totalHits; + } + + public void setTotalHits(int totalHits) { + this.totalHits = totalHits; + } +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Share.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Share.java new file mode 100644 index 00000000..7494769b --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Share.java @@ -0,0 +1,100 @@ +package net.sourceforge.subsonic.domain; + +import java.util.Date; + +/** + * A collection of media files that is shared with someone, and accessible via a direct URL. + * + * @author Sindre Mehus + * @version $Id$ + */ +public class Share { + + private int id; + private String name; + private String description; + private String username; + private Date created; + private Date expires; + private Date lastVisited; + private int visitCount; + + public Share() { + } + + public Share(int id, String name, String description, String username, Date created, + Date expires, Date lastVisited, int visitCount) { + this.id = id; + this.name = name; + this.description = description; + this.username = username; + this.created = created; + this.expires = expires; + this.lastVisited = lastVisited; + this.visitCount = visitCount; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Date getCreated() { + return created; + } + + public void setCreated(Date created) { + this.created = created; + } + + public Date getExpires() { + return expires; + } + + public void setExpires(Date expires) { + this.expires = expires; + } + + public Date getLastVisited() { + return lastVisited; + } + + public void setLastVisited(Date lastVisited) { + this.lastVisited = lastVisited; + } + + public int getVisitCount() { + return visitCount; + } + + public void setVisitCount(int visitCount) { + this.visitCount = visitCount; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Theme.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Theme.java new file mode 100644 index 00000000..f8bd66bd --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Theme.java @@ -0,0 +1,42 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Contains the ID and name for a theme. + * + * @author Sindre Mehus + */ +public class Theme { + private String id; + private String name; + + public Theme(String id, String name) { + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public String getName() { + return name; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/TranscodeScheme.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/TranscodeScheme.java new file mode 100644 index 00000000..f45b452a --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/TranscodeScheme.java @@ -0,0 +1,104 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Enumeration of transcoding schemes. Transcoding is the process of + * converting an audio stream to a lower bit rate. + * + * @author Sindre Mehus + */ +public enum TranscodeScheme { + + OFF(0), + MAX_32(32), + MAX_40(40), + MAX_48(48), + MAX_56(56), + MAX_64(64), + MAX_80(80), + MAX_96(96), + MAX_112(112), + MAX_128(128), + MAX_160(160), + MAX_192(192), + MAX_224(224), + MAX_256(256), + MAX_320(320); + + private int maxBitRate; + + TranscodeScheme(int maxBitRate) { + this.maxBitRate = maxBitRate; + } + + /** + * Returns the maximum bit rate for this transcoding scheme. + * + * @return The maximum bit rate for this transcoding scheme. + */ + public int getMaxBitRate() { + return maxBitRate; + } + + /** + * Returns the strictest transcode scheme (i.e., the scheme with the lowest max bitrate). + * + * @param other The other transcode scheme. May be <code>null</code>, in which case 'this' is returned. + * @return The strictest scheme. + */ + public TranscodeScheme strictest(TranscodeScheme other) { + if (other == null || other == TranscodeScheme.OFF) { + return this; + } + + if (this == TranscodeScheme.OFF) { + return other; + } + + return maxBitRate < other.maxBitRate ? this : other; + } + + /** + * Returns a human-readable string representation of this object. + * + * @return A human-readable string representation of this object. + */ + public String toString() { + if (this == OFF) { + return "No limit"; + } + return "" + getMaxBitRate() + " Kbps"; + } + + /** + * Returns the enum constant which corresponds to the given max bit rate. + * + * @param maxBitRate The max bit rate. + * @return The corresponding enum, or <code>null</code> if not found. + */ + public static TranscodeScheme valueOf(int maxBitRate) { + for (TranscodeScheme scheme : values()) { + if (scheme.getMaxBitRate() == maxBitRate) { + return scheme; + } + } + return null; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Transcoding.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Transcoding.java new file mode 100644 index 00000000..57c8316f --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Transcoding.java @@ -0,0 +1,221 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import net.sourceforge.subsonic.util.StringUtil; + +/** + * Contains the configuration for a transcoding, i.e., a specification of how a given media format + * should be converted to another. + * <br/> + * A transcoding may contain up to three steps. Typically you need to convert in several steps, for + * instance from OGG to WAV to MP3. + * + * @author Sindre Mehus + */ +public class Transcoding { + + private Integer id; + private String name; + private String sourceFormats; + private String targetFormat; + private String step1; + private String step2; + private String step3; + private boolean defaultActive; + + /** + * Creates a new transcoding specification. + * + * @param id The system-generated ID. + * @param name The user-defined name. + * @param sourceFormats The source formats, e.g., "ogg wav aac". + * @param targetFormat The target format, e.g., "mp3". + * @param step1 The command to execute in step 1. + * @param step2 The command to execute in step 2. + * @param step3 The command to execute in step 3. + * @param defaultActive Whether the transcoding should be automatically activated for all players. + */ + public Transcoding(Integer id, String name, String sourceFormats, String targetFormat, String step1, + String step2, String step3, boolean defaultActive) { + this.id = id; + this.name = name; + this.sourceFormats = sourceFormats; + this.targetFormat = targetFormat; + this.step1 = step1; + this.step2 = step2; + this.step3 = step3; + this.defaultActive = defaultActive; + } + + /** + * Returns the system-generated ID. + * + * @return The system-generated ID. + */ + public Integer getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + /** + * Returns the user-defined name. + * + * @return The user-defined name. + */ + public String getName() { + return name; + } + + /** + * Sets the user-defined name. + * + * @param name The user-defined name. + */ + public void setName(String name) { + this.name = name; + } + + /** + * Returns the source format, e.g., "ogg wav aac". + * + * @return The source format, e.g., "ogg wav aac". + */ + public String getSourceFormats() { + return sourceFormats; + } + + public String[] getSourceFormatsAsArray() { + return StringUtil.split(sourceFormats); + } + + /** + * Sets the source formats, e.g., "ogg wav aac". + * + * @param sourceFormats The source formats, e.g., "ogg wav aac". + */ + public void setSourceFormats(String sourceFormats) { + this.sourceFormats = sourceFormats; + } + + /** + * Returns the target format, e.g., mp3. + * + * @return The target format, e.g., mp3. + */ + public String getTargetFormat() { + return targetFormat; + } + + /** + * Sets the target format, e.g., mp3. + * + * @param targetFormat The target format, e.g., mp3. + */ + public void setTargetFormat(String targetFormat) { + this.targetFormat = targetFormat; + } + + /** + * Returns the command to execute in step 1. + * + * @return The command to execute in step 1. + */ + public String getStep1() { + return step1; + } + + /** + * Sets the command to execute in step 1. + * + * @param step1 The command to execute in step 1. + */ + public void setStep1(String step1) { + this.step1 = step1; + } + + /** + * Returns the command to execute in step 2. + * + * @return The command to execute in step 2. + */ + public String getStep2() { + return step2; + } + + /** + * Sets the command to execute in step 2. + * + * @param step2 The command to execute in step 2. + */ + public void setStep2(String step2) { + this.step2 = step2; + } + + /** + * Returns the command to execute in step 3. + * + * @return The command to execute in step 3. + */ + public String getStep3() { + return step3; + } + + /** + * Sets the command to execute in step 3. + * + * @param step3 The command to execute in step 3. + */ + public void setStep3(String step3) { + this.step3 = step3; + } + + /** + * Returns whether the transcoding should be automatically activated for all players + */ + public boolean isDefaultActive() { + return defaultActive; + } + + /** + * Sets whether the transcoding should be automatically activated for all players + */ + public void setDefaultActive(boolean defaultActive) { + this.defaultActive = defaultActive; + } + + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + Transcoding that = (Transcoding) o; + return !(id != null ? !id.equals(that.id) : that.id != null); + } + + public int hashCode() { + return (id != null ? id.hashCode() : 0); + } +}
\ No newline at end of file diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/TransferStatus.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/TransferStatus.java new file mode 100644 index 00000000..06930ae3 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/TransferStatus.java @@ -0,0 +1,303 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.io.File; + +import net.sourceforge.subsonic.util.BoundedList; + +/** + * Status for a single transfer (stream, download or upload). + * + * @author Sindre Mehus + */ +public class TransferStatus { + + private static final int HISTORY_LENGTH = 200; + private static final long SAMPLE_INTERVAL_MILLIS = 5000; + + private Player player; + private File file; + private long bytesTransfered; + private long bytesSkipped; + private long bytesTotal; + private final SampleHistory history = new SampleHistory(); + private boolean terminated; + private boolean active = true; + + /** + * Return the number of bytes transferred. + * + * @return The number of bytes transferred. + */ + public synchronized long getBytesTransfered() { + return bytesTransfered; + } + + /** + * Adds the given byte count to the total number of bytes transferred. + * + * @param byteCount The byte count. + */ + public synchronized void addBytesTransfered(long byteCount) { + setBytesTransfered(bytesTransfered + byteCount); + } + + /** + * Sets the number of bytes transferred. + * + * @param bytesTransfered The number of bytes transferred. + */ + public synchronized void setBytesTransfered(long bytesTransfered) { + this.bytesTransfered = bytesTransfered; + createSample(bytesTransfered, false); + } + + private void createSample(long bytesTransfered, boolean force) { + long now = System.currentTimeMillis(); + + if (history.isEmpty()) { + history.add(new Sample(bytesTransfered, now)); + } else { + Sample lastSample = history.getLast(); + if (force || now - lastSample.getTimestamp() > TransferStatus.SAMPLE_INTERVAL_MILLIS) { + history.add(new Sample(bytesTransfered, now)); + } + } + } + + /** + * Returns the number of milliseconds since the transfer status was last updated. + * + * @return Number of milliseconds, or <code>0</code> if never updated. + */ + public synchronized long getMillisSinceLastUpdate() { + if (history.isEmpty()) { + return 0L; + } + return System.currentTimeMillis() - history.getLast().timestamp; + } + + /** + * Returns the total number of bytes, or 0 if unknown. + * + * @return The total number of bytes, or 0 if unknown. + */ + public long getBytesTotal() { + return bytesTotal; + } + + /** + * Sets the total number of bytes, or 0 if unknown. + * + * @param bytesTotal The total number of bytes, or 0 if unknown. + */ + public void setBytesTotal(long bytesTotal) { + this.bytesTotal = bytesTotal; + } + + /** + * Returns the number of bytes that has been skipped (for instance when + * resuming downloads). + * + * @return The number of skipped bytes. + */ + public synchronized long getBytesSkipped() { + return bytesSkipped; + } + + /** + * Sets the number of bytes that has been skipped (for instance when + * resuming downloads). + * + * @param bytesSkipped The number of skipped bytes. + */ + public synchronized void setBytesSkipped(long bytesSkipped) { + this.bytesSkipped = bytesSkipped; + } + + + /** + * Adds the given byte count to the total number of bytes skipped. + * + * @param byteCount The byte count. + */ + public synchronized void addBytesSkipped(long byteCount) { + bytesSkipped += byteCount; + } + + /** + * Returns the file that is currently being transferred. + * + * @return The file that is currently being transferred. + */ + public synchronized File getFile() { + return file; + } + + /** + * Sets the file that is currently being transferred. + * + * @param file The file that is currently being transferred. + */ + public synchronized void setFile(File file) { + this.file = file; + } + + /** + * Returns the remote player for the stream. + * + * @return The remote player for the stream. + */ + public synchronized Player getPlayer() { + return player; + } + + /** + * Sets the remote player for the stream. + * + * @param player The remote player for the stream. + */ + public synchronized void setPlayer(Player player) { + this.player = player; + } + + /** + * Returns a history of samples for the stream + * + * @return A (copy of) the history list of samples. + */ + public synchronized SampleHistory getHistory() { + return new SampleHistory(history); + } + + /** + * Returns the history length in milliseconds. + * + * @return The history length in milliseconds. + */ + public long getHistoryLengthMillis() { + return TransferStatus.SAMPLE_INTERVAL_MILLIS * (TransferStatus.HISTORY_LENGTH - 1); + } + + /** + * Indicate that the stream should be terminated. + */ + public void terminate() { + terminated = true; + } + + /** + * Returns whether this stream has been terminated. + * Not that the <em>terminated status</em> is cleared by this method. + * + * @return Whether this stream has been terminated. + */ + public boolean terminated() { + boolean result = terminated; + terminated = false; + return result; + } + + /** + * Returns whether this transfer is active, i.e., if the connection is still established. + * + * @return Whether this transfer is active. + */ + public boolean isActive() { + return active; + } + + /** + * Sets whether this transfer is active, i.e., if the connection is still established. + * + * @param active Whether this transfer is active. + */ + public void setActive(boolean active) { + this.active = active; + + if (active) { + setBytesSkipped(0L); + setBytesTotal(0L); + setBytesTransfered(0L); + } else { + createSample(getBytesTransfered(), true); + } + } + + /** + * A sample containing a timestamp and the number of bytes transferred up to that point in time. + */ + public static class Sample { + private long bytesTransfered; + private long timestamp; + + /** + * Creates a new sample. + * + * @param bytesTransfered The total number of bytes transferred. + * @param timestamp A point in time, in milliseconds. + */ + public Sample(long bytesTransfered, long timestamp) { + this.bytesTransfered = bytesTransfered; + this.timestamp = timestamp; + } + + /** + * Returns the number of bytes transferred. + * + * @return The number of bytes transferred. + */ + public long getBytesTransfered() { + return bytesTransfered; + } + + /** + * Returns the timestamp of the sample. + * + * @return The timestamp in milliseconds. + */ + public long getTimestamp() { + return timestamp; + } + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("TransferStatus-").append(hashCode()).append(" [player: ").append(player.getId()).append(", file: "); + builder.append(file).append(", terminated: ").append(terminated).append(", active: ").append(active).append("]"); + return builder.toString(); + } + + /** + * Contains recent history of samples. + */ + public static class SampleHistory extends BoundedList<Sample> { + + public SampleHistory() { + super(HISTORY_LENGTH); + } + + public SampleHistory(SampleHistory other) { + super(HISTORY_LENGTH); + addAll(other); + } + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/User.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/User.java new file mode 100644 index 00000000..95e51004 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/User.java @@ -0,0 +1,245 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Represent a user. + * + * @author Sindre Mehus + */ +public class User { + + public static final String USERNAME_ADMIN = "admin"; + + private final String username; + private String password; + private String email; + private boolean ldapAuthenticated; + private long bytesStreamed; + private long bytesDownloaded; + private long bytesUploaded; + + private boolean isAdminRole; + private boolean isSettingsRole; + private boolean isDownloadRole; + private boolean isUploadRole; + private boolean isPlaylistRole; + private boolean isCoverArtRole; + private boolean isCommentRole; + private boolean isPodcastRole; + private boolean isStreamRole; + private boolean isJukeboxRole; + private boolean isShareRole; + + public User(String username, String password, String email, boolean ldapAuthenticated, + long bytesStreamed, long bytesDownloaded, long bytesUploaded) { + this.username = username; + this.password = password; + this.email = email; + this.ldapAuthenticated = ldapAuthenticated; + this.bytesStreamed = bytesStreamed; + this.bytesDownloaded = bytesDownloaded; + this.bytesUploaded = bytesUploaded; + } + + public User(String username, String password, String email) { + this(username, password, email, false, 0, 0, 0); + } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public boolean isLdapAuthenticated() { + return ldapAuthenticated; + } + + public void setLdapAuthenticated(boolean ldapAuthenticated) { + this.ldapAuthenticated = ldapAuthenticated; + } + + public long getBytesStreamed() { + return bytesStreamed; + } + + public void setBytesStreamed(long bytesStreamed) { + this.bytesStreamed = bytesStreamed; + } + + public long getBytesDownloaded() { + return bytesDownloaded; + } + + public void setBytesDownloaded(long bytesDownloaded) { + this.bytesDownloaded = bytesDownloaded; + } + + public long getBytesUploaded() { + return bytesUploaded; + } + + public void setBytesUploaded(long bytesUploaded) { + this.bytesUploaded = bytesUploaded; + } + + public boolean isAdminRole() { + return isAdminRole; + } + + public void setAdminRole(boolean isAdminRole) { + this.isAdminRole = isAdminRole; + } + + public boolean isSettingsRole() { + return isSettingsRole; + } + + public void setSettingsRole(boolean isSettingsRole) { + this.isSettingsRole = isSettingsRole; + } + + public boolean isCommentRole() { + return isCommentRole; + } + + public void setCommentRole(boolean isCommentRole) { + this.isCommentRole = isCommentRole; + } + + public boolean isDownloadRole() { + return isDownloadRole; + } + + public void setDownloadRole(boolean isDownloadRole) { + this.isDownloadRole = isDownloadRole; + } + + public boolean isUploadRole() { + return isUploadRole; + } + + public void setUploadRole(boolean isUploadRole) { + this.isUploadRole = isUploadRole; + } + + public boolean isPlaylistRole() { + return isPlaylistRole; + } + + public void setPlaylistRole(boolean isPlaylistRole) { + this.isPlaylistRole = isPlaylistRole; + } + + public boolean isCoverArtRole() { + return isCoverArtRole; + } + + public void setCoverArtRole(boolean isCoverArtRole) { + this.isCoverArtRole = isCoverArtRole; + } + + public boolean isPodcastRole() { + return isPodcastRole; + } + + public void setPodcastRole(boolean isPodcastRole) { + this.isPodcastRole = isPodcastRole; + } + + public boolean isStreamRole() { + return isStreamRole; + } + + public void setStreamRole(boolean streamRole) { + isStreamRole = streamRole; + } + + public boolean isJukeboxRole() { + return isJukeboxRole; + } + + public void setJukeboxRole(boolean jukeboxRole) { + isJukeboxRole = jukeboxRole; + } + + public boolean isShareRole() { + return isShareRole; + } + + public void setShareRole(boolean shareRole) { + isShareRole = shareRole; + } + + @Override + public String toString() { + StringBuffer result = new StringBuffer(username); + + if (isAdminRole) { + result.append(" [admin]"); + } + if (isSettingsRole) { + result.append(" [settings]"); + } + if (isDownloadRole) { + result.append(" [download]"); + } + if (isUploadRole) { + result.append(" [upload]"); + } + if (isPlaylistRole) { + result.append(" [playlist]"); + } + if (isCoverArtRole) { + result.append(" [coverart]"); + } + if (isCommentRole) { + result.append(" [comment]"); + } + if (isPodcastRole) { + result.append(" [podcast]"); + } + if (isStreamRole) { + result.append(" [stream]"); + } + if (isJukeboxRole) { + result.append(" [jukebox]"); + } + if (isShareRole) { + result.append(" [share]"); + } + + return result.toString(); + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/UserSettings.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/UserSettings.java new file mode 100644 index 00000000..856591bc --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/UserSettings.java @@ -0,0 +1,328 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import java.util.*; + +/** + * Represent user-specific settings. + * + * @author Sindre Mehus + */ +public class UserSettings { + + private String username; + private Locale locale; + private String themeId; + private boolean showNowPlayingEnabled; + private boolean showChatEnabled; + private boolean finalVersionNotificationEnabled; + private boolean betaVersionNotificationEnabled; + private Visibility mainVisibility = new Visibility(); + private Visibility playlistVisibility = new Visibility(); + private boolean lastFmEnabled; + private String lastFmUsername; + private String lastFmPassword; + private TranscodeScheme transcodeScheme = TranscodeScheme.OFF; + private int selectedMusicFolderId = -1; + private boolean partyModeEnabled; + private boolean nowPlayingAllowed; + private AvatarScheme avatarScheme = AvatarScheme.NONE; + private Integer systemAvatarId; + private Date changed = new Date(); + + public UserSettings(String username) { + this.username = username; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public Locale getLocale() { + return locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } + + public String getThemeId() { + return themeId; + } + + public void setThemeId(String themeId) { + this.themeId = themeId; + } + + public boolean isShowNowPlayingEnabled() { + return showNowPlayingEnabled; + } + + public void setShowNowPlayingEnabled(boolean showNowPlayingEnabled) { + this.showNowPlayingEnabled = showNowPlayingEnabled; + } + + public boolean isShowChatEnabled() { + return showChatEnabled; + } + + public void setShowChatEnabled(boolean showChatEnabled) { + this.showChatEnabled = showChatEnabled; + } + + public boolean isFinalVersionNotificationEnabled() { + return finalVersionNotificationEnabled; + } + + public void setFinalVersionNotificationEnabled(boolean finalVersionNotificationEnabled) { + this.finalVersionNotificationEnabled = finalVersionNotificationEnabled; + } + + public boolean isBetaVersionNotificationEnabled() { + return betaVersionNotificationEnabled; + } + + public void setBetaVersionNotificationEnabled(boolean betaVersionNotificationEnabled) { + this.betaVersionNotificationEnabled = betaVersionNotificationEnabled; + } + + public Visibility getMainVisibility() { + return mainVisibility; + } + + public void setMainVisibility(Visibility mainVisibility) { + this.mainVisibility = mainVisibility; + } + + public Visibility getPlaylistVisibility() { + return playlistVisibility; + } + + public void setPlaylistVisibility(Visibility playlistVisibility) { + this.playlistVisibility = playlistVisibility; + } + + public boolean isLastFmEnabled() { + return lastFmEnabled; + } + + public void setLastFmEnabled(boolean lastFmEnabled) { + this.lastFmEnabled = lastFmEnabled; + } + + public String getLastFmUsername() { + return lastFmUsername; + } + + public void setLastFmUsername(String lastFmUsername) { + this.lastFmUsername = lastFmUsername; + } + + public String getLastFmPassword() { + return lastFmPassword; + } + + public void setLastFmPassword(String lastFmPassword) { + this.lastFmPassword = lastFmPassword; + } + + public TranscodeScheme getTranscodeScheme() { + return transcodeScheme; + } + + public void setTranscodeScheme(TranscodeScheme transcodeScheme) { + this.transcodeScheme = transcodeScheme; + } + + public int getSelectedMusicFolderId() { + return selectedMusicFolderId; + } + + public void setSelectedMusicFolderId(int selectedMusicFolderId) { + this.selectedMusicFolderId = selectedMusicFolderId; + } + + public boolean isPartyModeEnabled() { + return partyModeEnabled; + } + + public void setPartyModeEnabled(boolean partyModeEnabled) { + this.partyModeEnabled = partyModeEnabled; + } + + public boolean isNowPlayingAllowed() { + return nowPlayingAllowed; + } + + public void setNowPlayingAllowed(boolean nowPlayingAllowed) { + this.nowPlayingAllowed = nowPlayingAllowed; + } + + public AvatarScheme getAvatarScheme() { + return avatarScheme; + } + + public void setAvatarScheme(AvatarScheme avatarScheme) { + this.avatarScheme = avatarScheme; + } + + public Integer getSystemAvatarId() { + return systemAvatarId; + } + + public void setSystemAvatarId(Integer systemAvatarId) { + this.systemAvatarId = systemAvatarId; + } + + /** + * Returns when the corresponding database entry was last changed. + * + * @return When the corresponding database entry was last changed. + */ + public Date getChanged() { + return changed; + } + + /** + * Sets when the corresponding database entry was last changed. + * + * @param changed When the corresponding database entry was last changed. + */ + public void setChanged(Date changed) { + this.changed = changed; + } + + /** + * Configuration of what information to display about a song. + */ + public static class Visibility { + private int captionCutoff; + private boolean isTrackNumberVisible; + private boolean isArtistVisible; + private boolean isAlbumVisible; + private boolean isGenreVisible; + private boolean isYearVisible; + private boolean isBitRateVisible; + private boolean isDurationVisible; + private boolean isFormatVisible; + private boolean isFileSizeVisible; + + public Visibility() {} + + public Visibility(int captionCutoff, boolean trackNumberVisible, boolean artistVisible, boolean albumVisible, + boolean genreVisible, boolean yearVisible, boolean bitRateVisible, + boolean durationVisible, boolean formatVisible, boolean fileSizeVisible) { + this.captionCutoff = captionCutoff; + isTrackNumberVisible = trackNumberVisible; + isArtistVisible = artistVisible; + isAlbumVisible = albumVisible; + isGenreVisible = genreVisible; + isYearVisible = yearVisible; + isBitRateVisible = bitRateVisible; + isDurationVisible = durationVisible; + isFormatVisible = formatVisible; + isFileSizeVisible = fileSizeVisible; + } + + public int getCaptionCutoff() { + return captionCutoff; + } + + public void setCaptionCutoff(int captionCutoff) { + this.captionCutoff = captionCutoff; + } + + public boolean isTrackNumberVisible() { + return isTrackNumberVisible; + } + + public void setTrackNumberVisible(boolean trackNumberVisible) { + isTrackNumberVisible = trackNumberVisible; + } + + public boolean isArtistVisible() { + return isArtistVisible; + } + + public void setArtistVisible(boolean artistVisible) { + isArtistVisible = artistVisible; + } + + public boolean isAlbumVisible() { + return isAlbumVisible; + } + + public void setAlbumVisible(boolean albumVisible) { + isAlbumVisible = albumVisible; + } + + public boolean isGenreVisible() { + return isGenreVisible; + } + + public void setGenreVisible(boolean genreVisible) { + isGenreVisible = genreVisible; + } + + public boolean isYearVisible() { + return isYearVisible; + } + + public void setYearVisible(boolean yearVisible) { + isYearVisible = yearVisible; + } + + public boolean isBitRateVisible() { + return isBitRateVisible; + } + + public void setBitRateVisible(boolean bitRateVisible) { + isBitRateVisible = bitRateVisible; + } + + public boolean isDurationVisible() { + return isDurationVisible; + } + + public void setDurationVisible(boolean durationVisible) { + isDurationVisible = durationVisible; + } + + public boolean isFormatVisible() { + return isFormatVisible; + } + + public void setFormatVisible(boolean formatVisible) { + isFormatVisible = formatVisible; + } + + public boolean isFileSizeVisible() { + return isFileSizeVisible; + } + + public void setFileSizeVisible(boolean fileSizeVisible) { + isFileSizeVisible = fileSizeVisible; + } + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Version.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Version.java new file mode 100644 index 00000000..c4d42a99 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/Version.java @@ -0,0 +1,141 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Represents the version number of Subsonic. + * + * @author Sindre Mehus + * @version $Revision: 1.3 $ $Date: 2006/01/20 21:25:16 $ + */ +public class Version implements Comparable<Version> { + private int major; + private int minor; + private int beta; + private int bugfix; + + /** + * Creates a new version instance by parsing the given string. + * @param version A string of the format "1.27", "1.27.2" or "1.27.beta3". + */ + public Version(String version) { + String[] s = version.split("\\."); + major = Integer.valueOf(s[0]); + minor = Integer.valueOf(s[1]); + + if (s.length > 2) { + if (s[2].contains("beta")) { + beta = Integer.valueOf(s[2].replace("beta", "")); + } else { + bugfix = Integer.valueOf(s[2]); + } + } + } + + public int getMajor() { + return major; + } + + public int getMinor() { + return minor; + } + + /** + * Return whether this object is equal to another. + * @param o Object to compare to. + * @return Whether this object is equals to another. + */ + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + final Version version = (Version) o; + + if (beta != version.beta) return false; + if (bugfix != version.bugfix) return false; + if (major != version.major) return false; + return minor == version.minor; + } + + /** + * Returns a hash code for this object. + * @return A hash code for this object. + */ + public int hashCode() { + int result; + result = major; + result = 29 * result + minor; + result = 29 * result + beta; + result = 29 * result + bugfix; + return result; + } + + /** + * Returns a string representation of the form "1.27", "1.27.2" or "1.27.beta3". + * @return A string representation of the form "1.27", "1.27.2" or "1.27.beta3". + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + buf.append(major).append('.').append(minor); + if (beta != 0) { + buf.append(".beta").append(beta); + } else if (bugfix != 0) { + buf.append('.').append(bugfix); + } + + return buf.toString(); + } + + /** + * Compares this object with the specified object for order. + * @param version The object to compare to. + * @return A negative integer, zero, or a positive integer as this object is less than, equal to, or + * greater than the specified object. + */ + public int compareTo(Version version) { + if (major < version.major) { + return -1; + } else if (major > version.major) { + return 1; + } + + if (minor < version.minor) { + return -1; + } else if (minor > version.minor) { + return 1; + } + + if (bugfix < version.bugfix) { + return -1; + } else if (bugfix > version.bugfix) { + return 1; + } + + int thisBeta = beta == 0 ? Integer.MAX_VALUE : beta; + int otherBeta = version.beta == 0 ? Integer.MAX_VALUE : version.beta; + + if (thisBeta < otherBeta) { + return -1; + } else if (thisBeta > otherBeta) { + return 1; + } + + return 0; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/VideoTranscodingSettings.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/VideoTranscodingSettings.java new file mode 100644 index 00000000..18661ba4 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/VideoTranscodingSettings.java @@ -0,0 +1,50 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +/** + * Parameters used when transcoding videos. + * + * @author Sindre Mehus + * @version $Id$ + */ +public class VideoTranscodingSettings { + + private final int width; + private final int height; + private final int timeOffset; + + public VideoTranscodingSettings(int width, int height, int timeOffset) { + this.width = width; + this.height = height; + this.timeOffset = timeOffset; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public int getTimeOffset() { + return timeOffset; + } +} diff --git a/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/WeUPnPRouter.java b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/WeUPnPRouter.java new file mode 100644 index 00000000..e36701e8 --- /dev/null +++ b/subsonic-main/src/main/java/net/sourceforge/subsonic/domain/WeUPnPRouter.java @@ -0,0 +1,56 @@ +/* + This file is part of Subsonic. + + Subsonic 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. + + Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.domain; + +import org.wetorrent.upnp.GatewayDevice; +import org.wetorrent.upnp.GatewayDiscover; + +import java.net.InetAddress; + +/** + * @author Sindre Mehus + * @version $Id$ + */ +public class WeUPnPRouter implements Router { + private final GatewayDevice device; + + private WeUPnPRouter(GatewayDevice device) { + this.device = device; + } + + public static WeUPnPRouter findRouter() throws Exception { + GatewayDiscover discover = new GatewayDiscover(); + discover.discover(); + GatewayDevice device = discover.getValidGateway(); + if (device == null) { + return null; + } + + return new WeUPnPRouter(device); + } + + public void addPortMapping(int externalPort, int internalPort, int leaseDuration) throws Exception { + String localIp = InetAddress.getLocalHost().getHostAddress(); + device.addPortMapping(externalPort, internalPort, localIp, "TCP", "Subsonic"); + } + + public void deletePortMapping(int externalPort, int internalPort) throws Exception { + device.deletePortMapping(externalPort, "TCP"); + } +} |