package com.openseedbox.models; import java.util.*; import org.apache.commons.lang.StringUtils; import com.openseedbox.backend.*; import com.openseedbox.code.Util; import com.openseedbox.gson.SerializedAccessorName; import com.openseedbox.gson.UseAccessor; import siena.Column; import siena.Table; @Table("torrent_group") @UseAccessor public class UserTorrent extends ModelBase { @Column("group_name") private String groupName; @Column("user_id") private User user; @Column("torrent_hash") private String torrentHash; private transient Torrent torrent; private boolean paused; private boolean running; public static int getAverageTorrentsPerUser() { return -1; } public static List<UserTorrent> getByUser(User u) { return UserTorrent.all().filter("user", u).fetch(); } public static List<UserTorrent> getByUserAndGroup(User u, String group) { return UserTorrent.all() .filter("user", u).filter("groupName", group).fetch(); } public static UserTorrent getByUser(User u, String hash) { return UserTorrent.all().filter("user", u) .filter("torrentHash", hash).get(); } public static List<UserTorrent> getByUser(User u, List<String> hashes) { return UserTorrent.all().filter("user", u) .filter("torrentHash IN", hashes).fetch(); } public static List<UserTorrent> getByHash(String hash) { return UserTorrent.all().filter("torrentHash", hash).fetch(); } public static int getUsersWithTorrentCount(String hash) { return UserTorrent.all().filter("torrentHash", hash).count(); } public static void blankOutGroup(User u, String group) { List<UserTorrent> list = UserTorrent.getByUserAndGroup(u, group); for (UserTorrent ut : list) { ut.setGroupName(null); } UserTorrent.batch().update(list); } public static boolean isTorrentStoppedByAllUsers(String hash) { int count = UserTorrent.all().filter("torrentHash", hash).count(); int paused = UserTorrent.all().filter("torrentHash", hash).filter("paused", true).count(); return (count == paused); } public static boolean isTorrentStartedByAUser(String hash) { return UserTorrent.all().filter("torrentHash", hash).filter("paused", false).count() >= 1; } @SerializedAccessorName("nice-status") public String getNiceStatus() { TorrentState ts = this.getTorrent().getStatus(); if (this.isPaused()) { return "Paused"; } else if (running && ts == TorrentState.PAUSED) { return "Running"; } switch (ts) { case DOWNLOADING: return "Downloading"; case SEEDING: return "Seeding"; case PAUSED: return "Paused"; case METADATA_DOWNLOADING: return "Metadata Downloading"; case ERROR: if (this.getTorrent().getDownloadSpeedBytes() > 0) { return "Downloading"; } return "Error"; } return null; } @SerializedAccessorName("nice-sub-status") public String getNiceSubStatus() { if (this.isPaused()) { return ""; } String ret = ""; Torrent t = getTorrent(); if (t.hasErrorOccured() && (t.getDownloadSpeedBytes() == 0)) { return ""; } if (t.isSeeding()) { ret += String.format("at %s/s", Util.getBestRate(t.getUploadSpeedBytes())); } if (t.isMetadataDownloading()) { ret += t.isPaused() ? "(Metadata " : "("; ret += Util.formatPercentage(t.getMetadataPercentComplete() * 100) + "%"; ret += ")"; } else if (t.getPercentComplete() < 1 && !t.isPaused()) { ret += Util.formatPercentage((t.getPercentComplete() * 100)) + "%"; } if (t.isComplete()) { if (!t.isPaused()) { ret += String.format(" (%s %s)", Util.getBestRate(t.getUploadedBytes()), "seeded, ratio: " + Util.getSignificantFigures(t.getRatio(), 2)); } } else { if (!t.isMetadataDownloading()) { ret += String.format(" (%s downloaded)", Util.getBestRate(t.getDownloadedBytes())); } } return ret; } public String getNiceTotalSize() { String ts = getStats().getTotalSize(); return (!ts.equals("N/A")) ? ts : "Unknown"; } @SerializedAccessorName("nice-stats") public NiceStats getStats() { return new NiceStats(this.getTorrent()); } public List<TreeNode> getFilesAsTree() { List<TreeNode> mapTree = new ArrayList<TreeNode>(); for (IFile f : getTorrent().getFiles()) { String[] paths = f.getFullPath().split("/"); //Logger.info("paths: %s", paths.length); List<TreeNode> parent = mapTree; for (int x = 0; x < paths.length; x++) { String path = paths[x]; TreeNode n = getTreeNode(parent, path); TreeNode newTn; if (n == null) { newTn = new TreeNode(); newTn.name = path; //only set the file on the final node so earlier nodes //dont keep getting overwritten when multiple files match if (paths.length - 1 == x) { newTn.file = f; } newTn.level = x; newTn.fullPath = getFullPath(paths, x); parent.add(newTn); //Logger.info("added:%s", newTn.name); } else { newTn = n; } Collections.sort(newTn.children); parent = newTn.children; } } return mapTree; } private TreeNode getTreeNode(List<TreeNode> t, String name) { for (TreeNode tn : t) { if (tn.name.equals(name)) { return tn; } } return null; } private String getFullPath(String[] path, int level) { return StringUtils.join(path, "/", 0, level + 1); } /* Getters and Setters */ @SerializedAccessorName("group") public String getGroupName() { if (groupName == null) { return User.TORRENT_GROUP_UNGROUPED; } return groupName; } public void setGroupName(String groupName) { this.groupName = groupName; } public User getUser() { return user; } public void setUser(User user) { this.user = user; } @SerializedAccessorName("hash") public String getTorrentHash() { return torrentHash; } public void setTorrentHash(String hashString) { this.torrentHash = hashString; } public void setTorrent(Torrent t) { this.torrent = t; } @SerializedAccessorName("torrent-data") public Torrent getTorrent() { if (this.torrent == null) { this.torrent = Torrent.getByHash(this.getTorrentHash()); } return torrent; } public boolean isPaused() { return paused; } public void setPaused(boolean paused) { this.paused = paused; } public boolean isRunning() { if (isPaused()) { return false; } return running; } public void setRunning(boolean running) { this.running = running; } /* End Getters and Setters */ @UseAccessor public class TreeNode extends AbstractFile implements Comparable { private String name = ""; private IFile file = null; private List<TreeNode> children = new ArrayList<TreeNode>(); private int level = 0; private String fullPath = ""; @Override public String toString() { return String.format("TreeNode, name: %s, children:%s", name, children.size()); } public int compareTo(Object t) { if (t instanceof TreeNode) { TreeNode tn = (TreeNode) t; return this.name.compareTo(tn.name); } return -1; } public boolean isAnyChildWanted() { boolean wanted = false; for (TreeNode tn : this.children) { if (tn.file != null && tn.file.isWanted()) { wanted = true; break; } wanted = tn.isAnyChildWanted(); if (wanted) { break; } } return wanted; } public boolean isAnyChildIncomplete() { boolean complete = false; for (TreeNode tn : this.children) { if (tn.file != null && !tn.file.isCompleted()) { complete = true; break; } complete = tn.isAnyChildIncomplete(); if (complete) { break; } } return complete; } @SerializedAccessorName("total-size-bytes") public long getTotalSize() { long total = 0l; if (this.file != null) { total += this.file.getFileSizeBytes(); } else { for (TreeNode child : this.children) { total += child.getTotalSize(); } } return total; } public String getDownloadLink() { if (this.file != null) { return this.file.getDownloadLink(); } return null; } /* Getters and Setters */ public String getName() { return name; } public void setName(String name) { this.name = name; } public IFile getFile() { return file; } public void setFile(IFile file) { this.file = file; } @SerializedAccessorName("children") public List<TreeNode> getChildren() { return children; } public void setChildren(List<TreeNode> children) { this.children = children; } public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } public String getFullPath() { return fullPath; } public void setFullPath(String fullPath) { this.fullPath = fullPath; } public String getId() { if (file != null) { return file.getId(); } return ""; } public boolean isWanted() { if (file != null) { return file.isWanted(); } return isAnyChildWanted(); } public long getBytesCompleted() { if (file != null) { return file.getBytesCompleted(); } long ret = -1; for (TreeNode c : this.children) { ret += c.getBytesCompleted(); } return ret; } public long getFileSizeBytes() { if (file != null) { return file.getFileSizeBytes(); } return getTotalSize(); } public int getPriority() { if (file != null) { return file.getPriority(); } return -1; } @Override public double getPercentComplete() { if (isCompleted()) { return 1d; } return super.getPercentComplete(); } @Override public boolean isCompleted() { return !isAnyChildIncomplete(); } /* End Getters and Setters */ } @UseAccessor public class NiceStats { private ITorrent t; public NiceStats(ITorrent t) { this.t = t; } @SerializedAccessorName("total-size") public String getTotalSize() { if (!t.isMetadataDownloading()) { return Util.getBestRate(t.getTotalSizeBytes()); } return "N/A"; } @SerializedAccessorName("download-speed") public String getDownloadSpeed() { if (!t.isMetadataDownloading()) { return Util.getBestRate(t.getDownloadSpeedBytes()); } return "N/A"; } @SerializedAccessorName("upload-speed") public String getUploadSpeed() { if (!t.isMetadataDownloading()) { return Util.getBestRate(t.getUploadSpeedBytes()); } return "N/A"; } @SerializedAccessorName("amount-downloaded") public String getAmountDownloaded() { if (!t.isMetadataDownloading()) { return Util.getBestRate(t.getDownloadedBytes()); } return "N/A"; } @SerializedAccessorName("amount-uploaded") public String getAmountUploaded() { if (!t.isMetadataDownloading()) { return Util.getBestRate(t.getUploadedBytes()); } return "N/A"; } @SerializedAccessorName("ratio") public String getRatio() { if (!t.isMetadataDownloading()) { return Util.formatPercentage(t.getRatio()); } return "N/A"; } @SerializedAccessorName("percent-complete") public String getPercentComplete() { return Util.formatPercentage(t.getPercentComplete() * 100) + "%"; } @SerializedAccessorName("metadata-percent-complete") public String getMetadataPercentComplete() { return Util.formatPercentage(t.getMetadataPercentComplete() * 100) + "%"; } } }