package com.torrenttunes.server.webservice;
import static com.torrenttunes.server.db.Tables.*;
import static spark.Spark.get;
import static spark.Spark.post;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.node.ObjectNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.torrenttunes.server.DataSources;
import com.torrenttunes.server.db.Actions;
import com.torrenttunes.server.db.Transformations;
import com.torrenttunes.server.db.Tables.SongView;
import com.torrenttunes.server.tools.Tools;
public class API {
static final Logger log = LoggerFactory.getLogger(API.class);
public static void setup() {
post("/torrent_upload", (req, res) -> {
try {
// apache commons-fileupload to handle file upload
DiskFileItemFactory factory = new DiskFileItemFactory();
factory.setRepository(new File(DataSources.TORRENTS_DIR()));
ServletFileUpload fileUpload = new ServletFileUpload(factory);
List<FileItem> items = fileUpload.parseRequest(req.raw());
// image is the field name that we want to save
FileItem item = items.stream()
.filter(e -> "torrent".equals(e.getFieldName()))
.findFirst().get();
String fileName = item.getName();
File torrentFile = new File(DataSources.TORRENTS_DIR(), fileName);
item.write(torrentFile);
Actions.saveTorrentFileToDB(torrentFile);
// a first test
log.info(fileName);
return "success";
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
}
});
post("/torrent_info_upload", (req, res) -> {
try {
log.info(req.body());
log.info(req.params().toString());
String json = req.body();
JsonNode jsonNode = Tools.jsonToNode(json);
Actions.updateSongInfo(jsonNode);
return "Saved info";
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
}
});
post("/add_play_count/:infoHash", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
String infoHash = req.params(":infoHash");
Tools.dbInit();
Actions.addToPlayCount(infoHash);
Tools.dbClose();
log.info("added to play count for infohash: " + infoHash);
return "Added play count";
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
}
});
post("/add_timeout_count/:infoHash", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
String infoHash = req.params(":infoHash");
Tools.dbInit();
Actions.addToTimeoutCount(infoHash);
Tools.dbClose();
log.info("added to timeout count for infohash: " + infoHash);
return "Added timeout count";
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
}
});
// Example:
// curl localhost:8080/remove_artist_server/c2b37a39-c66a-44b2-b190-a69485ae5d95
get("/remove_artist_server/:artistMBID", (req, res) -> {
try {
Tools.allowOnlyLocalHeaders(req, res);
String artistMBID = req.params(":artistMBID");
Tools.dbInit();
Actions.removeArtist(artistMBID);
return "Removed Artist MBID: " + artistMBID;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/remove_song_server/:songMBID", (req, res) -> {
try {
Tools.allowOnlyLocalHeaders(req, res);
String songMBID = req.params(":songMBID");
Tools.dbInit();
Actions.removeSong(songMBID);
return "Removed song MBID: " + songMBID;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/seeder_upload/:infoHash/:seeders", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
String infoHash = req.params(":infoHash");
String seeders = req.params(":seeders");
log.info("Seeder upload received for infohash: " + infoHash);
Tools.dbInit();
Actions.updateSeeders(infoHash, seeders);
return "Set seeders";
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/download_torrent/:infoHash", (req, res) -> {
try {
String infoHash = req.params(":infoHash");
Tools.dbInit();
// get torrent file location from infoHash
String torrentPath = SONG.findFirst("info_hash = ?", infoHash).
getString("torrent_path");
log.info("torrent downloaded from : " + torrentPath);
HttpServletResponse raw = res.raw();
raw.getOutputStream().write(Files.readAllBytes(Paths.get(torrentPath)));
raw.getOutputStream().flush();
raw.getOutputStream().close();
return res.raw();
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/download_torrent_info/:infoHash", (req, res) -> {
try {
String infoHash = req.params(":infoHash");
Tools.dbInit();
List<SongViewFast> svs = SONG_VIEW_FAST.find("info_hash = ?", infoHash).
orderBy("secondary_types asc");
SongViewFast sv = svs.get(0);
String json = sv.toJson(false);
// Reannounce the torrent:
// get the torrent
// String torrentFile = sv.getString("torrent_path");
// TrackedTorrent tt = TrackedTorrent.load(new File(torrentFile));
// tracker.announce(tt);
log.info("torrent json: " + json);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_songs", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String json = SONG.findAll().toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/song_search/:query", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String query = req.params(":query");
String json = null;
String queryStr = constructQueryString(query, "search_song");
log.info(queryStr);
json = SONG_VIEW_FAST.find(queryStr.toString()).limit(5).
orderBy("is_primary_album desc, plays desc").toJson(false);
log.info(json);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/artist_search/:query", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String query = req.params(":query");
String json = null;
String queryStr = constructQueryString(query, "search_artist");
log.info(queryStr);
json = ARTIST_SEARCH_VIEW.find(queryStr.toString()).limit(5).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/album_search/:query", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String query = req.params(":query");
String json = null;
String queryStr = constructQueryString(query, "search_album");
log.info(queryStr);
json = ALBUM_VIEW_FAST.find(queryStr.toString()).limit(5).
orderBy("is_primary_album desc, plays desc").toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_top_albums/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
String json = null;
String query ="select * from (\n"+
"\tselect * from album_view_fast \n"+
"\twhere artist_mbid=\"" + artistMbid + "\" \n"+
"\tand is_primary_album=0 \n"+
"\tand number_of_songs > 8\n"+
"\torder by number_of_songs desc limit 1) as a\n"+
"union all\n"+
"select * from (\n"+
"\tselect * from album_view_fast \n"+
"\twhere artist_mbid=\"" + artistMbid + "\" \n"+
"\tand is_primary_album=1 \n"+
"\torder by plays desc) as b\n"+
"limit 4;";
json = ALBUM_VIEW_FAST.findBySQL(query).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_top_songs/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
String json = null;
json = SONG_VIEW_FAST.find("artist_mbid = ? and is_primary_album = ?", artistMbid, true).
orderBy("plays desc").limit(15).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_all_albums/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
String json = null;
json = ALBUM_VIEW_FAST.find("artist_mbid = ? AND is_primary_album = ?",
artistMbid, true).
orderBy("year desc").toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_all_compilations/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
String json = null;
json = ALBUM_VIEW_FAST.find("artist_mbid = ? AND (primary_type != ? OR secondary_types is not ?)",
artistMbid, "Album", null).
orderBy("number_of_songs desc").toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_all_songs/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
String json = null;
json = SONG_VIEW_GROUPED.find("artist_mbid = ?", artistMbid).
orderBy("plays desc").toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_artist/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
ObjectNode on = Transformations.artistViewJson(artistMbid);
String json = Tools.nodeToJson(on);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_artist_tags/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
String json = ARTIST_TAG_VIEW.find("mbid = ?", artistMbid).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_related_artists/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
String json = RELATED_ARTIST_VIEW.findBySQL(
RELATED_ARTIST_VIEW_SQL, artistMbid, artistMbid).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_related_songs/:artistMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
String json = RELATED_SONG_VIEW.findBySQL(
RELATED_SONG_VIEW_SQL,
artistMbid).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_album/:albumMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String albumMbid = req.params(":albumMbid");
String json = null;
json = ALBUM_VIEW_FAST.findFirst("mbid = ?", albumMbid).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_album_songs/:albumMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String albumMbid = req.params(":albumMbid");
String json = null;
json = SONG_VIEW_FAST.find("release_group_mbid = ?", albumMbid).
orderBy("disc_number asc, track_number asc").toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_song/:songMBID", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String songMbid = req.params(":songMBID");
String json = null;
json = SONG_VIEW_FAST.findFirst("song_mbid = ?", songMbid).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_artists", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
// Tools.setJsonContentType(res);
String json = null;
//json = ARTIST.findAll().orderBy("name asc").toJson(false);
json = ARTIST.findAll()
.orderBy("case when lower(substr(name,1,3))='the' "
+ "then substr(name,5,length(name)-3) else name end;")
.toJson(false, "name", "mbid");
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_trending_albums", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String json = null;
json = ALBUM_VIEW_FAST.find("is_primary_album = ? and plays > ?", true, 0).
orderBy("created desc").limit(4).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_trending_songs", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.set15MinuteCache(req, res);
Tools.dbInit();
String json = null;
json = SONG_VIEW_GROUPED.find("is_primary_album = ? and plays > ?", true, 0).
orderBy("created desc").limit(15).toJson(false);
return json;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
get("/get_artist_discography_zip/:artistMbid", (req, res) -> {
File zipFile = null;
try {
Tools.allowAllHeaders(req, res);
Tools.dbInit();
String artistMbid = req.params(":artistMbid");
zipFile = Actions.createArtistDiscographyZipFile(artistMbid);
res.type("application/octet-stream");
res.header("Content-Disposition", "attachment; filename=\"" + zipFile.getName() + "\"");
res.header("Content-Length", String.valueOf(zipFile.length()));
res.header("Content-Transfer-Encoding", "binary");
return Tools.writeFileToResponse(zipFile, req, res);
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
zipFile.delete();
Tools.dbClose();
}
});
get("/get_album_zip/:albumMbid", (req, res) -> {
File zipFile = null;
try {
Tools.allowAllHeaders(req, res);
Tools.dbInit();
String albumMbid = req.params(":albumMbid");
zipFile = Actions.createAlbumZipFile(albumMbid);
res.type("application/octet-stream");
res.header("Content-Disposition", "attachment; filename=\"" + zipFile.getName() + "\"");
res.header("Content-Length", String.valueOf(zipFile.length()));
res.header("Content-Transfer-Encoding", "binary");
return Tools.writeFileToResponse(zipFile, req, res);
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
zipFile.delete();
Tools.dbClose();
}
});
get("/get_magnet_link/:songMbid", (req, res) -> {
try {
Tools.allowAllHeaders(req, res);
Tools.dbInit();
String songMbid = req.params(":songMbid");
String magnetLink = Actions.getSongMagnetLink(songMbid);
return magnetLink;
} catch (Exception e) {
res.status(666);
e.printStackTrace();
return e.getMessage();
} finally {
Tools.dbClose();
}
});
}
public static String constructQueryString(String query, String columnName) {
try {
query = java.net.URLDecoder.decode(query, "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
String[] splitWords = query.split(" ");
StringBuilder queryStr = new StringBuilder();
for(int i = 0;;) {
String word = splitWords[i++].replaceAll("'", "_");
String likeQuery = columnName + " like '%" + word + "%'";
queryStr.append(likeQuery);
if (i < splitWords.length) {
queryStr.append(" and ");
} else {
break;
}
}
return queryStr.toString();
}
}