mirror of https://github.com/getmango/Mango.git
Add `duktape.cr` and the `Plugin` class
This commit is contained in:
parent
a7f4e161de
commit
a812e3ed46
|
@ -20,6 +20,10 @@ shards:
|
|||
github: crystal-lang/crystal-db
|
||||
version: 0.9.0
|
||||
|
||||
duktape:
|
||||
github: jessedoyle/duktape.cr
|
||||
version: 0.20.0
|
||||
|
||||
exception_page:
|
||||
github: crystal-loot/exception_page
|
||||
version: 0.1.4
|
||||
|
@ -36,6 +40,10 @@ shards:
|
|||
github: jeromegn/kilt
|
||||
version: 0.4.0
|
||||
|
||||
myhtml:
|
||||
github: kostya/myhtml
|
||||
version: 1.5.1
|
||||
|
||||
radix:
|
||||
github: luislavena/radix
|
||||
version: 0.3.9
|
||||
|
|
|
@ -27,3 +27,8 @@ dependencies:
|
|||
github: crystal-ameba/ameba
|
||||
clim:
|
||||
github: at-grandpa/clim
|
||||
duktape:
|
||||
github: jessedoyle/duktape.cr
|
||||
version: ~> 0.20.0
|
||||
myhtml:
|
||||
github: kostya/myhtml
|
||||
|
|
|
@ -16,6 +16,7 @@ class Config
|
|||
property log_level : String = "info"
|
||||
property upload_path : String = File.expand_path "~/mango/uploads",
|
||||
home: true
|
||||
property plugin_path : String = File.expand_path "~/mango/plugins"
|
||||
property mangadex = Hash(String, String | Int32).new
|
||||
|
||||
@[YAML::Field(ignore: true)]
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
require "duktape/runtime"
|
||||
require "myhtml"
|
||||
require "http"
|
||||
|
||||
class Plugin
|
||||
class Error < ::Exception
|
||||
end
|
||||
|
||||
class MetadataError < Error
|
||||
end
|
||||
|
||||
class PluginException < Error
|
||||
end
|
||||
|
||||
class SyntaxError < Error
|
||||
end
|
||||
|
||||
{% for name in ["id", "title", "author", "version", "placeholder"] %}
|
||||
getter {{name.id}} = ""
|
||||
{% end %}
|
||||
getter wait_seconds : UInt64 = 0
|
||||
|
||||
def self.list
|
||||
dir = Config.current.plugin_path
|
||||
Dir.children(dir)
|
||||
.select do |f|
|
||||
fp = File.join dir, f
|
||||
File.file?(fp) && File.extname(fp) == ".js"
|
||||
end
|
||||
.map do |f|
|
||||
File.basename f, ".js"
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(@path : String)
|
||||
@rt = Duktape::Runtime.new do |sbx|
|
||||
sbx.push_global_object
|
||||
|
||||
sbx.del_prop_string -1, "print"
|
||||
sbx.del_prop_string -1, "alert"
|
||||
sbx.del_prop_string -1, "console"
|
||||
|
||||
def_helper_functions sbx
|
||||
end
|
||||
|
||||
js = File.open @path, &.gets_to_end
|
||||
eval js
|
||||
|
||||
begin
|
||||
data = eval_json "metadata"
|
||||
{% for name in ["id", "title", "author", "version", "placeholder"] %}
|
||||
@{{name.id}} = data[{{name}}].as_s
|
||||
{% end %}
|
||||
@wait_seconds = data["wait_seconds"].as_i.to_u64
|
||||
rescue e
|
||||
raise MetadataError.new "Failed to retrieve metadata from plugin " \
|
||||
"at #{@path}. Error: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
def search(query : String)
|
||||
eval_json "search('#{query}')"
|
||||
end
|
||||
|
||||
def select_chapter(id : String)
|
||||
eval_json "selectChapter('#{id}')"
|
||||
end
|
||||
|
||||
def next_page
|
||||
eval_json "nextPage()"
|
||||
end
|
||||
|
||||
private def eval(str)
|
||||
@rt.eval str
|
||||
rescue e : Duktape::SyntaxError
|
||||
raise SyntaxError.new e.message
|
||||
rescue e : Duktape::Error
|
||||
raise Error.new e.message
|
||||
end
|
||||
|
||||
private def eval_json(str)
|
||||
JSON.parse eval(str).as String
|
||||
end
|
||||
|
||||
private def def_helper_functions(sbx)
|
||||
sbx.push_object
|
||||
|
||||
sbx.push_proc LibDUK::VARARGS do |ptr|
|
||||
env = Duktape::Sandbox.new ptr
|
||||
url = env.require_string 0
|
||||
|
||||
headers = HTTP::Headers.new
|
||||
|
||||
if env.get_top == 2
|
||||
env.enum 1, LibDUK::Enum::OwnPropertiesOnly
|
||||
while env.next -1, true
|
||||
k = env.require_string -2
|
||||
v = env.require_string -1
|
||||
headers.add k, v
|
||||
env.pop_2
|
||||
end
|
||||
end
|
||||
|
||||
res = HTTP::Client.get url, headers
|
||||
body = res.body
|
||||
|
||||
env.push_string body
|
||||
env.call_success
|
||||
end
|
||||
sbx.put_prop_string -2, "get"
|
||||
|
||||
sbx.push_proc 2 do |ptr|
|
||||
env = Duktape::Sandbox.new ptr
|
||||
html = env.require_string 0
|
||||
selector = env.require_string 1
|
||||
|
||||
myhtml = Myhtml::Parser.new html
|
||||
json = myhtml.css(selector).map(&.to_html).to_a.to_json
|
||||
|
||||
env.push_string json
|
||||
env.call_success
|
||||
end
|
||||
sbx.put_prop_string -2, "css"
|
||||
|
||||
sbx.push_proc 1 do |ptr|
|
||||
env = Duktape::Sandbox.new ptr
|
||||
html = env.require_string 0
|
||||
|
||||
myhtml = Myhtml::Parser.new html
|
||||
root = myhtml.root
|
||||
|
||||
str = ""
|
||||
str = root.inner_text if root
|
||||
|
||||
env.push_string str
|
||||
env.call_success
|
||||
end
|
||||
sbx.put_prop_string -2, "innerText"
|
||||
|
||||
sbx.push_proc 1 do |ptr|
|
||||
env = Duktape::Sandbox.new ptr
|
||||
msg = env.require_string 0
|
||||
env.call_success
|
||||
|
||||
raise PluginException.new msg
|
||||
end
|
||||
sbx.put_prop_string -2, "raise"
|
||||
|
||||
sbx.put_prop_string -2, "mango"
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue