package io.evercam; import com.mashape.unirest.http.HttpResponse; import com.mashape.unirest.http.JsonNode; import com.mashape.unirest.http.Unirest; import com.mashape.unirest.http.exceptions.UnirestException; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.Map; public class Snapshot extends EvercamObject { static String URL = API.URL + "cameras"; Snapshot(JSONObject snapshotJsonObject) { jsonObject = snapshotJsonObject; } /** * Fetches a snapshot from the camera and stores it using the current timestamp * * @param cameraId the camera's unique identifier with Evercam * @param notes optional text note for this snapshot, if set to null, no text notes will * be saved with this camera. * @return the saved snapshot * @throws EvercamException if unable to save the snapshot */ public static Snapshot record(String cameraId, String notes) throws EvercamException { Snapshot snapshot = null; if (API.hasUserKeyPair()) { try { HttpResponse<JsonNode> response; if (notes == null) { response = Unirest.post(URL + '/' + cameraId + "/recordings/snapshots").fields(API.userKeyPairMap()) .field("with_data", true).asJson(); } else { response = Unirest.post(URL + '/' + cameraId + "/recordings/snapshots").fields(API.userKeyPairMap()) .field("notes", notes).field("with_data", true).asJson(); } if (response.getStatus() == CODE_OK) { JSONObject snapshotJsonObject = response.getBody().getObject(); snapshot = new Snapshot(snapshotJsonObject); } else { ErrorResponse errorResponse = new ErrorResponse(response.getBody().getObject()); throw new EvercamException(errorResponse.getMessage()); } } catch (JSONException e) { throw new EvercamException(e); } catch (UnirestException e) { throw new EvercamException(e); } } else { throw new EvercamException(EvercamException.MSG_USER_API_KEY_REQUIRED); } return snapshot; } /** * A wrap of GET /cameras/{id}/recordings/snapshots, returns all pages in one method * <p/> * Returns the list of all snapshots currently stored for specific camera * * @param cameraId the unique identifier of the camera * @throws EvercamException if user key and id not specified */ public static ArrayList<Snapshot> getRecordedSnapshots(String cameraId, int from, int to) throws EvercamException { ArrayList<Snapshot> snapshotList = new ArrayList<Snapshot>(); SnapshotsWithPaging snapshotsWithPaging = getSnapshotListWithPaging(cameraId, from, to, 100, 1); snapshotList.addAll(snapshotsWithPaging.getSnapshotsList()); int pages = snapshotsWithPaging.getTotalPages(); if (pages > 1) { for (int index = 2; index < pages; index++) { SnapshotsWithPaging moreWithPaging = getSnapshotListWithPaging(cameraId, from, to, 100, index); snapshotList.addAll(moreWithPaging.getSnapshotsList()); } } return snapshotList; } /** * GET /cameras/{id}/recordings/snapshots * <p/> * Returns the list of snapshots currently stored for specific camera with specific page * * @param cameraId the unique identifier of the camera * @throws EvercamException if user key and id not specified */ public static SnapshotsWithPaging getSnapshotListWithPaging(String cameraId, int from, int to, int limit, int page) throws EvercamException { if (API.hasUserKeyPair()) { Map<String, Object> fieldsMap = API.userKeyPairMap(); fieldsMap.put("from", from); fieldsMap.put("to", to); fieldsMap.put("limit", limit); fieldsMap.put("page", page); try { HttpResponse<JsonNode> response = Unirest.get(URL + "/" + cameraId + "/recordings/snapshots").queryString (fieldsMap).header("accept", "application/json").asJson(); if (response.getStatus() == CODE_OK) { return new SnapshotsWithPaging(response.getBody().getObject()); } else if (response.getStatus() == CODE_UNAUTHORISED || response.getStatus() == CODE_FORBIDDEN) { throw new EvercamException(EvercamException.MSG_INVALID_USER_KEY); } else if (response.getStatus() == CODE_SERVER_ERROR) { throw new EvercamException(EvercamException.MSG_SERVER_ERROR); } else { ErrorResponse errorResponse = new ErrorResponse(response.getBody().getObject()); throw new EvercamException(errorResponse.getMessage()); } } catch (UnirestException e) { throw new EvercamException(e); } catch (JSONException e) { throw new EvercamException(e); } } else { throw new EvercamException(EvercamException.MSG_USER_API_KEY_REQUIRED); } } /** * GET /cameras/{id}/recordings/snapshots/{year}/{month}/{day}/hours * <p/> * Returns list of specific hours in a given day which contains any snapshots * * @param cameraId the camera's unique identifier with Evercam * @param year year, for example 2013 * @param month month, for example 11 * @param day day, for example 17 * @throws EvercamException if user key pair is not specified */ public static ArrayList<Integer> getHoursContainSnapshots(String cameraId, int year, int month, int day) throws EvercamException { ArrayList<Integer> hoursList = new ArrayList<Integer>(); if (API.hasUserKeyPair()) { try { HttpResponse<JsonNode> response = Unirest.get(URL + "/" + cameraId + "/recordings/snapshots/" + year + '/' + month + '/' + day + "/hours").queryString(API.userKeyPairMap()).header("accept", "application/json").asJson(); if (response.getStatus() == CODE_OK) { JSONObject hoursArrayObject = response.getBody().getObject(); JSONArray hoursArray = hoursArrayObject.getJSONArray("hours"); if (hoursArray.length() != 0) { for (int index = 0; index < hoursArray.length(); index++) { hoursList.add(hoursArray.getInt(index)); } } } else if (response.getStatus() == CODE_UNAUTHORISED || response.getStatus() == CODE_FORBIDDEN) { throw new EvercamException(EvercamException.MSG_INVALID_USER_KEY); } else if (response.getStatus() == CODE_SERVER_ERROR) { throw new EvercamException(EvercamException.MSG_SERVER_ERROR); } else { ErrorResponse errorResponse = new ErrorResponse(response.getBody().getObject()); throw new EvercamException(errorResponse.getMessage()); } } catch (UnirestException e) { throw new EvercamException(e); } catch (JSONException e) { throw new EvercamException(e); } } else { throw new EvercamException(EvercamException.MSG_USER_API_KEY_REQUIRED); } return hoursList; } /** * GET /cameras/{id}/recordings/snapshots/{year}/{month}/days * <p/> * Returns list of specific days in a given month which contains any snapshots * * @param cameraId the camera's unique identifier with Evercam * @param year year, for example 2013 * @param month month, for example 11 * @throws EvercamException if user key pair is not specified */ public static ArrayList<Integer> getDaysContainSnapshots(String cameraId, int year, int month) throws EvercamException { ArrayList<Integer> daysList = new ArrayList<Integer>(); if (API.hasUserKeyPair()) { try { HttpResponse<JsonNode> response = Unirest.get(URL + "/" + cameraId + "/recordings/snapshots/" + year + '/' + month + "/days").queryString(API.userKeyPairMap()).header("accept", "application/json") .asJson(); if (response.getStatus() == CODE_OK) { JSONObject daysArrayObject = response.getBody().getObject(); JSONArray daysJsonArray = daysArrayObject.getJSONArray("days"); if (daysJsonArray.length() != 0) { for (int index = 0; index < daysJsonArray.length(); index++) { daysList.add(daysJsonArray.getInt(index)); } } } else if (response.getStatus() == CODE_UNAUTHORISED || response.getStatus() == CODE_FORBIDDEN) { throw new EvercamException(EvercamException.MSG_INVALID_USER_KEY); } else if (response.getStatus() == CODE_SERVER_ERROR) { throw new EvercamException(EvercamException.MSG_SERVER_ERROR); } else { ErrorResponse errorResponse = new ErrorResponse(response.getBody().getObject()); throw new EvercamException(errorResponse.getMessage()); } } catch (UnirestException e) { throw new EvercamException(e); } catch (JSONException e) { throw new EvercamException(e); } } else { throw new EvercamException(EvercamException.MSG_USER_API_KEY_REQUIRED); } return daysList; } /** * GET /cameras/{id}/recordings/snapshots/{timestamp} * <p/> * Returns the snapshot stored for this camera closest to the given timestamp * * @param cameraId the camera's unique identifier with Evercam * @param timeStamp snapshot Unix timestamp * @param withData whether it should send image data * @param range time range in seconds around specified timestamp. Default range is one second (so it matches only exact timestamp). */ public static Snapshot getByTime(String cameraId, int timeStamp, boolean withData, int range) throws EvercamException { String url = URL + "/" + cameraId + "/recordings/snapshots/" + timeStamp; if (withData) { url += "?with_data=true&range=" + range; } else { url += "?range=" + range; } ArrayList<Snapshot> snapshotList = getSnapshotsByUrl(url); if (snapshotList.size() > 0) { return snapshotList.get(0); } else { throw new EvercamException("Snapshot does not exist"); } } /** * GET /cameras/{id}/recordings/snapshots/latest * <p/> * Returns latest snapshot stored for this camera. * * @param cameraId the camera's unique identifier with Evercam * @param withData whether it should send image data * @throws EvercamException */ public static Snapshot getLatest(String cameraId, boolean withData) throws EvercamException { String url = URL + "/" + cameraId + "/recordings/snapshots/latest"; if (withData) { url += "?with_data=true"; } ArrayList<Snapshot> snapshotList = getSnapshotsByUrl(url); if (snapshotList.size() > 0) { return snapshotList.get(0); } else { throw new EvercamException("No snapshot saved for camera:" + cameraId); } } /** * Return snapshot list by request URL. This method is called by getLatest() and getByTime */ private static ArrayList<Snapshot> getSnapshotsByUrl(String url) throws EvercamException { ArrayList<Snapshot> snapshotList = new ArrayList<Snapshot>(); HttpResponse<JsonNode> response; if (API.hasUserKeyPair()) { try { response = Unirest.get(url).queryString(API.userKeyPairMap()).header("accept", "application/json").asJson(); if (response.getStatus() == CODE_OK) { JSONObject snapshotsObject = response.getBody().getObject(); JSONArray snapshotJsonArray = snapshotsObject.getJSONArray("snapshots"); if (snapshotJsonArray.length() != 0) { for (int index = 0; index < snapshotJsonArray.length(); index++) { JSONObject snapshotJsonObject = snapshotJsonArray.getJSONObject(0); snapshotList.add(new Snapshot(snapshotJsonObject)); } } } else if (response.getStatus() == CODE_UNAUTHORISED || response.getStatus() == CODE_FORBIDDEN) { throw new EvercamException(EvercamException.MSG_INVALID_USER_KEY); } else if (response.getStatus() == CODE_SERVER_ERROR) { throw new EvercamException(EvercamException.MSG_SERVER_ERROR); } else { ErrorResponse errorResponse = new ErrorResponse(response.getBody().getObject()); throw new EvercamException(errorResponse.getMessage()); } } catch (UnirestException e) { throw new EvercamException(e); } catch (JSONException e) { throw new EvercamException(e); } } else { throw new EvercamException(EvercamException.MSG_USER_API_KEY_REQUIRED); } return snapshotList; } /** * Return the pure base64 image data * * @param completeDataString the full data string with 'data:image/jpeg;base64,' */ public static String getBase64DataStringFrom(String completeDataString) { if (completeDataString != null) { return completeDataString.substring(completeDataString.indexOf(",") + 1); } return null; } /** * Return byte data from base64 data string * * @param base64DataString the base64 data in string format */ public static byte[] getDataFrom(String base64DataString) { if (base64DataString != null) { return org.apache.commons.codec.binary.Base64.decodeBase64(base64DataString); } return null; } public String getNotes() throws EvercamException { try { return jsonObject.getString("notes"); } catch (JSONException e) { return ""; } } public int getTimeStamp() throws EvercamException { try { return jsonObject.getInt("created_at"); } catch (JSONException e) { throw new EvercamException(e); } } public String getCompleteData() { try { return jsonObject.getString("data"); } catch (JSONException e) { return null; } } public String getBase64DataString() { String completeImageData = getCompleteData(); return getBase64DataStringFrom(completeImageData); } public byte[] getData() { String base64Data = getBase64DataString(); return getDataFrom(base64Data); } }