+ public String uploadStickerPack(String path) throws IOException, StickerPackInvalidException {
+ JsonStickerPack pack = parseStickerPack(path);
+
+ if (pack.stickers == null) {
+ throw new StickerPackInvalidException("Must set a 'stickers' field.");
+ }
+
+ if (pack.stickers.isEmpty()) {
+ throw new StickerPackInvalidException("Must include stickers.");
+ }
+
+ List<StickerInfo> stickers = new ArrayList<>(pack.stickers.size());
+ for (int i = 0; i < pack.stickers.size(); i++) {
+ if (pack.stickers.get(i).file == null) {
+ throw new StickerPackInvalidException("Must set a 'file' field on each sticker.");
+ }
+ if (!stickerDataContainsPath(path, pack.stickers.get(i).file)) {
+ throw new StickerPackInvalidException("Could not find find " + pack.stickers.get(i).file);
+ }
+
+ StickerInfo stickerInfo = new StickerInfo(i, Optional.fromNullable(pack.stickers.get(i).emoji).or(""));
+ stickers.add(stickerInfo);
+ }
+
+ boolean uniqueCover = false;
+ StickerInfo cover = stickers.get(0);
+ if (pack.cover != null) {
+ if (pack.cover.file == null) {
+ throw new StickerPackInvalidException("Must set a 'file' field on the cover.");
+ }
+ if (!stickerDataContainsPath(path, pack.cover.file)) {
+ throw new StickerPackInvalidException("Could not find find cover " + pack.cover.file);
+ }
+
+ uniqueCover = true;
+ cover = new StickerInfo(pack.stickers.size(), Optional.fromNullable(pack.cover.emoji).or(""));
+ }
+
+ SignalServiceStickerManifest manifest = new SignalServiceStickerManifest(
+ Optional.fromNullable(pack.title).or(""),
+ Optional.fromNullable(pack.author).or(""),
+ cover,
+ stickers);
+
+ SignalServiceMessageSender messageSender = new SignalServiceMessageSender(
+ BaseConfig.serviceConfiguration,
+ null,
+ username,
+ account.getPassword(),
+ account.getDeviceId(),
+ account.getSignalProtocolStore(),
+ BaseConfig.USER_AGENT,
+ account.isMultiDevice(),
+ Optional.fromNullable(messagePipe),
+ Optional.fromNullable(unidentifiedMessagePipe),
+ Optional.<SignalServiceMessageSender.EventListener>absent());
+
+ System.out.println("Starting upload process...");
+ Pair<byte[], StickerUploadAttributesResponse> responsePair = messageSender.getStickerUploadAttributes(stickers.size() + (uniqueCover ? 1 : 0));
+ byte[] packKey = responsePair.first();
+ StickerUploadAttributesResponse response = responsePair.second();
+
+ System.out.println("Uploading manifest...");
+ messageSender.uploadStickerManifest(manifest, packKey, response.getManifest());
+
+ Map<Integer, StickerUploadAttributes> attrById = new HashMap<>();
+
+ for (StickerUploadAttributes attr : response.getStickers()) {
+ attrById.put(attr.getId(), attr);
+ }
+
+ for (int i = 0; i < pack.stickers.size(); i++) {
+ System.out.println("Uploading sticker " + (i+1) + "/" + pack.stickers.size() + "...");
+ StickerUploadAttributes attr = attrById.get(i);
+ if (attr == null) {
+ throw new StickerPackInvalidException("Upload attributes missing for id " + i);
+ }
+
+ byte[] data = readStickerDataFromPath(path, pack.stickers.get(i).file);
+ messageSender.uploadSticker(new ByteArrayInputStream(data), data.length, packKey, attr);
+ }
+
+ if (uniqueCover) {
+ System.out.println("Uploading unique cover...");
+ StickerUploadAttributes attr = attrById.get(pack.stickers.size());
+ if (attr == null) {
+ throw new StickerPackInvalidException("Upload attributes missing for cover with id " + pack.stickers.size());
+ }
+
+ byte[] data = readStickerDataFromPath(path, pack.cover.file);
+ messageSender.uploadSticker(new ByteArrayInputStream(data), data.length, packKey, attr);
+ }
+
+ return "https://signal.art/addstickers/#pack_id=" + response.getPackId() + "&pack_key=" + Hex.toStringCondensed(packKey).replaceAll(" ", "");
+ }
+
+ private static byte[] readStickerDataFromPath(String rootPath, String subFile) throws IOException, StickerPackInvalidException {
+ if (rootPath.endsWith(".zip")) {
+ ZipFile zip = new ZipFile(rootPath);
+ ZipEntry entry = zip.getEntry(subFile);
+ return IOUtils.readFully(zip.getInputStream(entry));
+ } else if (rootPath.endsWith(".json")) {
+ String dir = new File(rootPath).getParent();
+ FileInputStream fis = new FileInputStream(new File(dir, subFile));
+ return IOUtils.readFully(fis);
+ } else {
+ throw new StickerPackInvalidException("Must point to either a ZIP or JSON file.");
+ }
+ }
+
+ private static boolean stickerDataContainsPath(String rootPath, String subFile) throws IOException {
+ if (rootPath.endsWith(".zip")) {
+ ZipFile zip = new ZipFile(rootPath);
+ return zip.getEntry(subFile) != null;
+ } else if (rootPath.endsWith(".json")) {
+ String dir = new File(rootPath).getParent();
+ return new File(dir, subFile).exists();
+ } else {
+ return false;
+ }
+ }
+
+ private static JsonStickerPack parseStickerPack(String rootPath) throws IOException, StickerPackInvalidException {
+ if (!stickerDataContainsPath(rootPath, "manifest.json")) {
+ throw new StickerPackInvalidException("Could not find manifest.json");
+ }
+
+ String json = new String(readStickerDataFromPath(rootPath, "manifest.json"));
+
+ return new ObjectMapper().readValue(json, JsonStickerPack.class);
+ }
+