PNG generation
This commit is contained in:
parent
2e0cb5c3eb
commit
f184616432
@ -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"]
|
||||
|
@ -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))))))
|
||||
|
@ -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
15
src/asciinema/util/io.clj
Normal 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))))))
|
Loading…
Reference in New Issue
Block a user