Skip to content

Instantly share code, notes, and snippets.

@halcat0x15a
Last active March 12, 2018 10:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save halcat0x15a/60fc5981b37f5d08e372016e356fb725 to your computer and use it in GitHub Desktop.
Save halcat0x15a/60fc5981b37f5d08e372016e356fb725 to your computer and use it in GitHub Desktop.
package starlight
import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
import akka.stream.ActorMaterializer
import akka.stream.scaladsl.FileIO
import akka.stream.scaladsl.Source
import java.awt.RenderingHints
import java.awt.image.BufferedImage
import java.net.URL
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import java.nio.file.StandardOpenOption
import javax.imageio.ImageIO
import play.api.libs.json.JsValue
import play.api.libs.ws.ahc.AhcWSClient
import play.api.mvc.MultipartFormData
import scala.collection.JavaConverters._
import scala.concurrent.ExecutionContext
import scala.concurrent.Future
import scala.util.Failure
object Main {
def main(args: Array[String]): Unit = {
val accessToken = args(0)
val channel = args(1)
implicit val system = ActorSystem()
system.registerOnTermination {
System.exit(0)
}
implicit val materializer = ActorMaterializer()
val wsClient = AhcWSClient()
ImageIO.setUseCache(false)
val urls = Paths.get("urls.txt")
val files = if (Files.exists(urls)) {
Files.lines(urls).iterator.asScala.map { url =>
Paths.get(url).getFileName.toString
}.toSet
} else {
Set.empty[String]
}
val writer = system.actorOf(Props(classOf[FileWriter], urls))
import system.dispatcher
call(wsClient, files) { result =>
val title = s"[${result.title}]${result.name}"
upload(wsClient, accessToken, channel, result.id, title, result.image).map { url =>
writer ! url
}
}.andThen {
case Failure(e) => e.printStackTrace()
}.andThen {
case _ => wsClient.close()
}.andThen {
case _ => system.terminate()
}
}
def call(wsClient: AhcWSClient, files: Set[String])(f: KiraraResult => Future[Unit])(implicit ec: ExecutionContext) = {
wsClient.url("https://starlight.kirara.ca/api/v1/list/card_t").get().flatMap { response ⇒
Future.traverse((response.json \ "result").as[Seq[JsValue]]) { data =>
val id = (data \ "id").as[Int]
val rarity = (data \ "rarity_dep" \ "rarity").as[Int]
if (rarity == 7 && !files.contains(s"${id}.png")) {
val title = (data \ "title").as[String]
val name = (data \ "name_only").as[String]
f(KiraraResult(id, title, name, draw(id, true)))
} else {
Future.successful(())
}
}
}
}
def draw(id: Long, withSign: Boolean): BufferedImage = {
val char = ImageIO.read(new URL(s"https://truecolor.kirara.ca/spread/${id}.png"))
assert(char.getWidth == 1280)
val image = new BufferedImage(1280, 720, BufferedImage.TYPE_INT_ARGB)
val g = image.createGraphics
g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR)
g.drawImage(char, 0, 0, 1280, 720, 0, char.getHeight - 720, 1280, char.getHeight, null)
if (withSign) {
val sign = ImageIO.read(new URL(s"https://truecolor.kirara.ca/sign/${id}.png"))
val w = (sign.getWidth * 0.75).toInt
val h = (sign.getHeight * 0.75).toInt
g.drawImage(sign, 0, 720 - h, w, 720, 0, 0, sign.getWidth, sign.getHeight, null)
}
g.dispose()
image
}
def upload(wsClient: AhcWSClient, accessToken: String, channel: String, id: Long, title: String, image: BufferedImage)(implicit ec: ExecutionContext) = {
val temp = Files.createTempFile("starlight", "kirara")
ImageIO.write(image, "PNG", temp.toFile)
val form = List(
MultipartFormData.FilePart("file", s"${id}.png", Some("image/png"), FileIO.fromPath(temp)),
MultipartFormData.DataPart("token", accessToken),
MultipartFormData.DataPart("channels", channel),
MultipartFormData.DataPart("title", title)
)
wsClient.url("https://slack.com/api/files.upload").post(Source(form)).map { res =>
(res.json \ "file" \ "url_private").as[String]
}.andThen {
case _ => Files.delete(temp)
}
}
}
case class KiraraResult(id: Long, title: String, name: String, image: BufferedImage)
class FileWriter(out: Path) extends Actor {
def receive = {
case url: String => Files.write(out, (url + '\n').getBytes, StandardOpenOption.CREATE, StandardOpenOption.APPEND)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment