PNG generation

This commit is contained in:
Marcin Kulik 2017-02-16 13:44:49 +01:00
parent 2e0cb5c3eb
commit f184616432
4 changed files with 91 additions and 3 deletions

View File

@ -19,6 +19,7 @@
[clj-bugsnag "0.2.9"]
[clj-aws-s3 "0.3.10" :exclusions [joda-time com.fasterxml.jackson.core/jackson-core com.fasterxml.jackson.core/jackson-annotations]]
[aleph "0.4.1"]
[pandect "0.6.1"]
[org.slf4j/slf4j-nop "1.7.21"]
[org.webjars/normalize.css "3.0.2"]
[duct/hikaricp-component "0.1.0"]

View File

@ -1,15 +1,38 @@
(ns asciinema.endpoint.asciicasts
(:require [asciinema.boundary
[asciicast-database :as adb]
[file-store :as fstore]]
[file-store :as fstore]
[user-database :as udb]]
[asciinema.model.asciicast :as asciicast]
[asciinema.util.io :refer [with-tmp-dir]]
[clojure.java.io :as io]
[clojure.java.shell :as shell]
[compojure.api.sweet :refer :all]
[environ.core :refer [env]]
[ring.util.http-response :as response]
[schema.core :as s]))
[schema.core :as s]
[clojure.string :as str]))
(defn exception-handler [^Exception e data request]
(throw e))
(defn a2png [in-url out-path {:keys [snapshot-at theme scale]}]
(let [a2png-bin (:a2png-bin env "a2png/a2png.sh")
{:keys [exit] :as result} (shell/sh a2png-bin
"-t" theme
"-s" (str scale)
in-url
out-path
(str snapshot-at))]
(when-not (zero? exit)
(throw (ex-info "a2png error" result)))))
(def Num (s/if #(str/includes? % ".")
Double
s/Int))
(def Theme (apply s/enum asciicast/themes))
(defn asciicasts-endpoint [{:keys [db file-store]}]
(api
{:exceptions {:handlers {:compojure.api.exception/default exception-handler}}}
@ -22,4 +45,28 @@
(let [path (asciicast/json-store-path asciicast)
filename (str "asciicast-" (:id asciicast) ".json")]
(fstore/serve-file file-store path (when dl {:filename filename})))
(response/not-found)))
(GET "/:token.png" []
:path-params [token :- String]
:query-params [{time :- Num nil}
{theme :- Theme nil}
{scale :- (s/enum "1" "2") nil}]
(if-let [asciicast (adb/get-asciicast-by-token db token)]
(let [user (udb/get-user-by-id db (:user_id asciicast))
png-params (cond-> (asciicast/png-params asciicast user)
time (assoc :snapshot-at time)
theme (assoc :theme theme)
scale (assoc :scale (Integer/parseInt scale)))
json-store-path (asciicast/json-store-path asciicast)
png-store-path (asciicast/png-store-path asciicast png-params)]
(with-tmp-dir [dir "asciinema-png-"]
(let [json-local-path (str dir "/asciicast.json")
png-local-path (str dir "/asciicast.png")]
(with-open [in (fstore/input-stream file-store json-store-path)]
(let [out (io/file json-local-path)]
(io/copy in out)))
(a2png json-local-path png-local-path png-params)
(fstore/put-file file-store (io/file png-local-path) png-store-path)))
(fstore/serve-file file-store png-store-path {}))
(response/not-found))))))

View File

@ -1,13 +1,38 @@
(ns asciinema.model.asciicast)
(ns asciinema.model.asciicast
(:require[pandect.algo.sha1 :as sha1]
[clojure.string :as str]))
(defn json-store-path [{:keys [id file stdout_frames]}]
(cond
file (str "asciicast/file/" id "/" file)
stdout_frames (str "asciicast/stdout_frames/" id "/" stdout_frames)))
(def themes #{"asciinema" "tango" "solarized-dark" "solarized-light" "monokai"})
(def default-theme "asciinema")
(defn theme-name [asciicast user]
(or (:theme_name asciicast)
(:theme_name user)
default-theme))
(defn snapshot-at [{:keys [snapshot_at duration]}]
(or snapshot_at (/ duration 2.0)))
(def default-png-scale 2)
(defn png-params [asciicast user]
{:snapshot-at (snapshot-at asciicast)
:theme (theme-name asciicast user)
:scale default-png-scale})
(defn- png-version [asciicast params]
(let [attrs (assoc params :id (:id asciicast))]
(->> attrs
(map (fn [[k v]] (str (name k) "=" v)))
(str/join "/")
(sha1/sha1))))
(defn png-store-path [asciicast params]
(let [ver (png-version asciicast params)
png-filename (str ver ".png")]
(str "png/" (:id asciicast) "/" png-filename)))

15
src/asciinema/util/io.clj Normal file
View File

@ -0,0 +1,15 @@
(ns asciinema.util.io
(:require [clojure.java.shell :as shell])
(:import java.nio.file.Files
java.nio.file.attribute.FileAttribute))
(defn create-tmp-dir [prefix]
(let [dir (Files/createTempDirectory prefix (into-array FileAttribute []))]
(.toFile dir)))
(defmacro with-tmp-dir [[sym prefix] & body]
`(let [~sym (create-tmp-dir ~prefix)]
(try
~@body
(finally
(shell/sh "rm" "-rf" (.getPath ~sym))))))