Sped up loading by a lot

This commit is contained in:
Ryan Ward 2020-02-15 23:12:15 -05:00
parent 75316cf1da
commit f0f2f9b8c7
11 changed files with 258 additions and 140 deletions

View File

@ -1,12 +1,15 @@
print(love.filesystem.createDirectory("Cache"))
local multi,thread = require("multi"):init()
local GLOBAL,THREAD = require("multi.integration.loveManager"):init()
local func = THREAD:newFunction(function(path)
require("love.image")
GLOBAL,THREAD = require("multi.integration.loveManager"):init()
local queue = multi:newSystemThreadedJobQueue(16)
local LoadImage = queue:newFunction(function(path)
return love.image.newImageData(path)
end)
local load = THREAD:newFunction(function(path)
local DownloadImage = queue:newFunction(function(url,hash)
print = THREAD:getConsole().print
require("love.image")
require("love.filesystem")
require("love.data")
local http = require("socket.http")
local request = require("luajit-request")
function download(path)
@ -16,10 +19,20 @@ local load = THREAD:newFunction(function(path)
return http.request(path)
end
end
return love.image.newImageData(love.filesystem.newFileData((download(path)),"temp"..path:sub(-4,-1)))
local data = download(url)
function IsImage(str)
return str:find("\0")~=nil -- Image Data will contain nul character
end
love.filesystem.createDirectory("Cache")
if IsImage(data or "") then
love.filesystem.write("Cache/"..hash..".jpg", data)
return love.image.newImageData("Cache/"..hash..".jpg")
else
return "noimage"
end
end)
local cache = {}
function gui:SetImage(i,inthread)
function gui:SetImage(i,inthread,backup)
if not i then return end
if type(i) == "userdata" and i:type() == "Image" then
self.Image=i
@ -31,7 +44,20 @@ function gui:SetImage(i,inthread)
self:SetImage(cache[i])
else
if i:match([[https?://]]) then
load(i).connect(function(img)
local hash = love.data.encode("string", "hex",love.data.hash("md5", i))
if love.filesystem.getInfo("Cache/"..hash..".jpg") then
self:SetImage("Cache/"..hash..".jpg")
return
end
DownloadImage(i,hash).connect(function(img)
if img == "noimage" then
print("Need backup")
if backup then
return self:SetImage(backup)
else
return nil
end
end
self.Image = love.graphics.newImage(img)
cache[i]=self.Image
self.ImageHeigth=self.Image:getHeight()

49
app.lua
View File

@ -13,55 +13,40 @@ local headersize = 80
local menusize = 350
local spdt = .005
local spd = 7
local sliderActive = false
local mm,bb
-- keep at top
local slider = thread:newFunction(function()
local menu,button = mm,bb
if sliderActive then return end
sliderActive = true
if not menu.Visible then
menu.Visible = true
for i=menusize/5,1,-1 do
menu:SetDualDim(-i*spd)
thread.sleep(spdt)
end
menu:SetDualDim(0)
button:SetImage("images/menuX.png")
else
for i=1,menusize/5 do
thread.sleep(spdt)
menu:SetDualDim(-i*spd)
end
menu.Visible = false
button:SetImage("images/menu.png")
end
sliderActive = false
end)
local head
function app.createPage(name,path)
local page = require("pages/"..path).init(app.workspace:newFullFrame(name),app.workspace)
page.Color = theme.menu
table.insert(app.pages,page)
page.Visible = false
page:SetDualDim(nil,nil,nil,nil,.1,.1,.8,.8)
page:setRoundness(10,10,180)
function page:Goto()
for i,v in pairs(app.pages) do
v.Visible = false
end
page.Visible = true
end
local button = app.menu:newTextLabel(name,name,0,(#app.pages-1)*(headersize/2),0,headersize/2,0,0,1)
local button
if head == app.header then
button = head:newTextButton(name,name,5,0,100,60)
else
button = head:newTextButton(name,name,5,0,100,60,1)
end
button:centerY()
head = button
button:fitFont()
button.Color = theme.menuitem
button:OnReleased(function()
page:Goto()
slider()
end)
print("done")
return page
end
local function init(a)
love.filesystem.setIdentity("MangaPro")
app.header = a:newFrame(0,0,0,headersize,0,0,1)
head = app.header
app.header.Color = theme.header
app.workspace = a:newFrame(0,headersize,0,-headersize,0,0,1,1)
app.menu = a:newFrame(0,headersize,menusize,-headersize,0,0,0,1)
@ -73,15 +58,9 @@ local function init(a)
end)
app.workspace.Color = Color.Black
app.menu.Visible = false
local menubutton = app.header:newImageLabel("images/menu.png",0,0,headersize,headersize)
menubutton.BorderSize = 0
mm,bb = app.menu,menubutton
menubutton:OnReleased(function()
slider()
end)
local search = app.createPage("Search","search")
app.createPage("Favorites","favs")
search:Goto()
--search:Goto()
end
return {
init = init

BIN
images/notfound.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 KiB

View File

@ -2,7 +2,12 @@ multi,thread = require("multi"):init()
THREAD = multi.integration.THREAD
local m = {}
m.azlist = {}
m.init = THREAD:newFunction(function()
local queue = multi:newSystemThreadedJobQueue(16)
queue:doToAll(function()
multi,thread = require("multi"):init()
http = require("socket.http") -- This is important
end)
m.init = queue:newFunction("init",function()
local http = require("socket.http")
local list = http.request("http://www.mangareader.net/alphabetical")
return list
@ -26,7 +31,7 @@ function m.storeList(list)
return titles
end
-- returns manga
m.getManga = THREAD:newFunction(function(title)
m.getManga = queue:newFunction("queue",function(title)
local http = require("socket.http")
local manga = http.request(title.Link)
local tab = {}
@ -47,16 +52,11 @@ m.getManga = THREAD:newFunction(function(title)
end
return tab
end)
local queue = multi:newSystemThreadedJobQueue(16)
queue:doToAll(function()
multi,thread = require("multi"):init()
http = require("socket.http") -- This is important
end)
queue:registerFunction("getImage",function(pageurl)
m.getImage = queue:newFunction("getImage",function(pageurl)
local page = http.request(pageurl)
return page:match([[id="imgholder.-src="([^"]*)]])
end)
queue:registerFunction("getPages",function(manga,chapter)
m._getPages = queue:newFunction("getPages",function(manga,chapter)
local tab = {}
local page = http.request(manga.Chapters[chapter].Link)
tab.pages = {page:match([[id="imgholder.-src="([^"]*)]])}
@ -70,23 +70,13 @@ end)
m.getPages = function(manga,chapter)
local http = require("socket.http")
local tab = {}
local cc = 0
local done = false
local page = http.request(manga.Chapters[chapter].Link)
tab.pages = {page:match([[id="imgholder.-src="([^"]*)]])}
tab.nextChapter = "http://www.mangareader.net"..page:match([[Next Chapter:.-href="([^"]*)]])
local lastJob
local conn = queue.OnJobCompleted(function(jid,link)
table.insert(tab.pages,link)
cc=cc+1
if jid==lastJob then
done = true
end
end)
local count = 0
for link,page in page:gmatch([[<option value="([^"]*)">(%d*)</option>]]) do
lastJob = queue:pushJob("getImage","http://www.mangareader.net"..link)
count = count + 1
m._getPages("http://www.mangareader.net"..link).connect(function(link)
table.insert(tab.pages,link)
end)
end
thread.hold(function()
return done

View File

@ -1071,7 +1071,7 @@ end
function multi:newLoop(func)
local c=self:newBase()
c.Type='loop'
local start=self.clock()
local start=clock()
local funcs = {}
if func then
funcs={func}
@ -1246,7 +1246,7 @@ function multi:newTStep(start,reset,count,set)
c.skip=skip or 0
c.count=count or 1*think
c.funcE={}
c.timer=self.clock()
c.timer=clock()
c.set=set or 1
c.funcS={}
function c:Update(start,reset,count,set)
@ -1255,12 +1255,12 @@ function multi:newTStep(start,reset,count,set)
self.endAt=reset or self.endAt
self.set=set or self.set
self.count=count or self.count or 1
self.timer=self.clock()
self.timer=clock()
self:Resume()
return self
end
function c:Act()
if self.clock()-self.timer>=self.set then
if clock()-self.timer>=self.set then
self:Reset()
if self.pos==self.start then
for fe=1,#self.funcS do
@ -1298,7 +1298,7 @@ function multi:newTStep(start,reset,count,set)
end
function c:Reset(n)
if n then self.set=n end
self.timer=self.clock()
self.timer=clock()
self:Resume()
return self
end
@ -1475,7 +1475,6 @@ function multi.holdFor(n,func)
end)
end
function thread:newFunction(func,holdme)
local done = false
return function(...)
local rets, err
local function wait(no)
@ -1488,9 +1487,12 @@ function thread:newFunction(func,holdme)
end
end)
else
while not rets do
while not rets and not err do
multi.scheduler:Act()
end
if err then
return nil,err
end
return unpack(rets)
end
end
@ -1504,11 +1506,11 @@ function thread:newFunction(func,holdme)
isTFunc = true,
wait = wait,
connect = function(f)
t.OnDeath(function(self,status,...) if done == false then f(...) done = true end end)
t.OnError(function(self,err) if done == false then f(self,err) done = true end end)
t.OnDeath(function(self,status,...) f(...) end)
t.OnError(function(self,err) f(err) end)
end
}
return temp,temp,temp,temp,temp,temp,temp
return temp
end
end
function thread.run(func)
@ -1557,41 +1559,41 @@ function multi:newThread(name,func,...)
if type(name) == "function" then
name = "Thread#"..threadCount
end
local env = {}
setmetatable(env,{
__index = Gref,
__newindex = function(t,k,v)
if type(v)=="function" then
rawset(t,k,thread:newFunction(v))
else
if type(v)=="table" then
if v.isTFunc then
if not _G["_stack_"] or #_G["_stack_"]==0 then
_G["_stack_"] = {}
local s = _G["_stack_"]
local a,b,c,d,e,f,g = v.wait(true)
table.insert(s,a)
table.insert(s,b)
table.insert(s,c)
table.insert(s,d)
table.insert(s,e)
table.insert(s,f)
local x = table.remove(_G["_stack_"])
rawset(t,k,x)
else
local x = table.remove(_G["_stack_"])
rawset(t,k,x)
end
else
Gref[k]=v
end
else
Gref[k]=v
end
end
end
})
setfenv(func,env)
-- local env = {}
-- setmetatable(env,{
-- __index = Gref,
-- __newindex = function(t,k,v)
-- if type(v)=="function" then
-- rawset(t,k,thread:newFunction(v))
-- else
-- if type(v)=="table" then
-- if v.isTFunc then
-- if not _G["_stack_"] or #_G["_stack_"]==0 then
-- _G["_stack_"] = {}
-- local s = _G["_stack_"]
-- local a,b,c,d,e,f,g = v.wait(true)
-- table.insert(s,a)
-- table.insert(s,b)
-- table.insert(s,c)
-- table.insert(s,d)
-- table.insert(s,e)
-- table.insert(s,f)
-- local x = table.remove(_G["_stack_"])
-- rawset(t,k,x)
-- else
-- local x = table.remove(_G["_stack_"])
-- rawset(t,k,x)
-- end
-- else
-- Gref[k]=v
-- end
-- else
-- Gref[k]=v
-- end
-- end
-- end
-- })
-- setfenv(func,env)
local c={}
c.TempRets = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil}
c.startArgs = {...}
@ -1676,8 +1678,13 @@ function multi.initThreads(justThreads)
local r1,r2,r3,r4,r5,r6
local ret,_
local function CheckRets(i)
if ret~=nil then
if ret~=nil and not(threads[i].isError) then
if not threads[i] then return end
if not _ then
threads[i].isError = true
threads[i].TempRets[1] = ret
return
end
threads[i].TempRets[1] = ret
threads[i].TempRets[2] = r1
threads[i].TempRets[3] = r2
@ -1740,24 +1747,23 @@ function multi.initThreads(justThreads)
end
multi.scheduler:OnLoop(function(self)
for i=#threads,1,-1 do
if not threads[i].__started then
if threads[i].isError then
threads[i].OnError:Fire(threads[i],unpack(threads[i].TempRets))
table.remove(threads,i)
end
if threads[i] and not threads[i].__started then
if coroutine.running() ~= threads[i].thread then
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6)
CheckRets(i)
_,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,unpack(threads[i].startArgs))
end
threads[i].__started = true
helper(i)
end
if not _ then
threads[i].OnError:Fire(threads[i],ret)
if threads[i] and not _ then
threads[i].OnError:Fire(threads[i],unpack(threads[i].TempRets))
threads[i].isError = true
end
if threads[i] and coroutine.status(threads[i].thread)=="dead" then
local tr = threads[i].TempRets
if ret == nil then
threads[i].OnDeath:Fire(threads[i],"ended",tr[1],tr[2],tr[3],tr[4],tr[5],tr[6],tr[7])
else
threads[i].OnDeath:Fire(threads[i],"ended",ret,r1,r2,r3,r4,r5,r6)
end
threads[i].OnDeath:Fire(threads[i],"ended",unpack(threads[i].TempRets or {}))
table.remove(threads,i)
elseif threads[i] and threads[i].task == "skip" then
threads[i].pos = threads[i].pos + 1
@ -1995,6 +2001,21 @@ function multi:newHyperThreadedProcess(name)
return c
end
-- Multi runners
function multi:lightloop()
if not isRunning then
local Loop=self.Mainloop
while true do
for _D=#Loop,1,-1 do
if Loop[_D].Active then
self.CID=_D
if not protect then
Loop[_D]:Act()
end
end
end
end
end
end
function multi:mainloop(settings)
multi.OnPreLoad:Fire()
multi.defaultSettings = settings or multi.defaultSettings

View File

@ -80,6 +80,33 @@ function multi:newSystemThreadedJobQueue(n)
function c:pushJob(name,...)
queueJob:push{name,jid,{...}}
jid = jid + 1
return jid-1
end
local nFunc = 0
function c:newFunction(name,func,holup) -- This registers with the queue
if type(name)=="function" then
holup = func
func = name
name = "JQ_Function_"..nFunc
end
nFunc = nFunc + 1
c:registerFunction(name,func)
return thread:newFunction(function(...)
local id = c:pushJob(name,...)
local link
local rets
link = c.OnJobCompleted(function(jid,...)
if id==jid then
rets = {...}
link:Remove()
end
end)
return thread.hold(function()
if rets then
return unpack(rets)
end
end)
end,holup),name
end
multi:newThread("JobQueueManager",function()
while true do

View File

@ -43,6 +43,13 @@ end
-- Step 2 set up the Linda objects
local __GlobalLinda = lanes.linda() -- handles global stuff
local __SleepingLinda = lanes.linda() -- handles sleeping stuff
local __ConsoleLinda = lanes.linda() -- handles console stuff
multi:newLoop(function()
local _,data = __ConsoleLinda:receive(0, "Q")
if data then
print(unpack(data))
end
end)
local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda,__SleepingLinda)
local threads = {}
local count = 1
@ -77,7 +84,10 @@ function multi:newSystemThread(name, func, ...)
local args = {...}
c.thread = lanes.gen(table.concat(c.loadString,","),{globals={
THREAD_NAME=name,
THREAD_ID=count
THREAD_ID=count,
THREAD = THREAD,
GLOBAL = GLOBAL,
_Console = __ConsoleLinda
},priority=c.priority}, func)(unpack(args))
count = count + 1
function c:kill()

View File

@ -54,6 +54,18 @@ local function INIT(__GlobalLinda,__SleepingLinda)
function THREAD.getCores()
return THREAD.__CORES
end
function THREAD.getConsole()
local c = {}
c.queue = _Console
function c.print(...)
c.queue:send("Q", {...})
end
function c.error(err)
c.queue:push{"ERROR in <"..__THREADNAME__..">: "..err,__THREADID__}
error(err)
end
return c
end
function THREAD.getThreads()
return GLOBAL.__THREADS__
end

View File

@ -99,6 +99,32 @@ function multi:newSystemThreadedJobQueue(n)
self.id = self.id + 1
self.queue:push{name,self.id,...}
return self.id
end
local nFunc = 0
function c:newFunction(name,func,holup) -- This registers with the queue
if type(name)=="function" then
holup = func
func = name
name = "JQ_Function_"..nFunc
end
nFunc = nFunc + 1
c:registerFunction(name,func)
return thread:newFunction(function(...)
local id = c:pushJob(name,...)
local link
local rets
link = c.OnJobCompleted(function(jid,...)
if id==jid then
rets = {...}
link:Remove()
end
end)
return thread.hold(function()
if rets then
return unpack(rets)
end
end)
end,holup),name
end
multi:newThread("jobManager",function()
while true do
@ -154,7 +180,7 @@ function multi:newSystemThreadedJobQueue(n)
queueReturn:push(tab)
end
end
end):OnError(function(...)
end).OnError(function(...)
error(...)
end)
multi:newThread("Idler",function()

View File

@ -47,9 +47,11 @@ local THREAD = require("multi.integration.loveManager.threads")
local GLOBAL = THREAD.getGlobal()
local THREAD_ID = 1
local OBJECT_ID = 0
local stf = 0
function THREAD:newFunction(func,holup)
stf = stf + 1
return function(...)
local t = multi:newSystemThread("SystemThreadedFunction"..math.random(0,999999999),func,...)
local t = multi:newSystemThread("STF"..stf,func,...)
return thread:newFunction(function()
return thread.hold(function()
if t.stab["returns"] then

View File

@ -5,7 +5,7 @@ local titles
multi:newThread(function()
titles = mangaReader.storeList(mangaReader.init())
end)
local scale = 2
local scale = 1
local mangaSize = {
x=200/scale,
y=288/scale
@ -52,6 +52,26 @@ for i=65,90 do
end
local function init(page,workspace)
local holder = page:newFrame("",15,80,-30,-95,0,0,1,1)
function addManga(manga,v)
local temp = holder:newImageButton(nil,0,0,mangaSize.x,mangaSize.y)
local text = temp:newTextLabel(v.Title,v.Title,0,-30,0,30,0,1,1)
text.Visibility = .6
text.Color = Color.Black
text.TextColor = Color.White
text.TextFormat = "center"
text:fitFont()
temp.BorderSize = 2
temp:SetImage(manga.Cover,nil,"Images/notfound.png")
temp:OnReleased(function(b,self)
print("Manga",v.Title)
end)
end
page:OnMouseWheelMoved(function(self,x,y)
holder:Move(0,y*60)
if holder.offset.pos.y>85 then
holder:SetDualDim(nil,85)
end
end)
holder.Visibility = 0
holder.BorderSize = 0
page.ClipDescendants = true
@ -65,12 +85,16 @@ local function init(page,workspace)
holder:SetDualDim((page.width-size)/2)
end)
local nav = page:newFrame(10,10,-20,40,0,0,1)
local SBL = page:newFrame(0,55,540,20)
local SBL = page:newFrame(0,55,0,40,0,0,1)
SBL.BorderSize = 0
for i,v in pairs(chars) do
local temp = SBL:newTextLabel(v,v,(i-1)*20,0,20,20)
local temp = SBL:newTextLabel(v,v,0,0,0,0,(i-1)/27,0,1/27,1)
temp.Color = theme.button
multi.setTimeout(function()
temp:fitFont()
end,.1)
temp:OnReleased(thread:newFunction(function()
holder:SetDualDim(nil,85)
thread.hold(function() return titles end)
local list = searchBy(temp.text)
local c = holder:getChildren()
@ -78,12 +102,9 @@ local function init(page,workspace)
c[i]:Destroy()
end
for i,v in pairs(list) do
thread.sleep(.5)
local manga = mangaReader.getManga(v).connect(function(manga)
print(v.Title,manga.Cover)
local temp = holder:newImageButton(nil,0,0,mangaSize.x,mangaSize.y)
temp.BorderSize = 2
temp:SetImage(manga.Cover)
thread.yield()
mangaReader.getManga(v).connect(function(manga)
addManga(manga,v)
end)
end
end))
@ -92,7 +113,6 @@ local function init(page,workspace)
local temp = holder:newImageLabel("images/test.jpg",0,0,mangaSize.x,mangaSize.y)
temp.BorderSize = 2
]]
SBL:centerX()
nav.Color = theme.header
nav:setRoundness(5,5,60)
local search = nav:newTextButton("Search","Search",5,5,60,-10,0,0,0,1)
@ -100,12 +120,17 @@ local function init(page,workspace)
search:fitFont()
local bar = nav:newTextBox("","",70,5,-75,-10,0,0,1,1)
search:OnReleased(thread:newFunction(function()
holder:SetDualDim(nil,85)
thread.hold(function() return titles end)
-- tprint(searchBy("a"))
-- tprint(searchFor(bar.text))
local list = searchFor(bar.text)
for i,v in pairs(list) do
mangaReader.getManga(v).connect(function(manga)
addManga(manga,v)
end)
-- local manga = mangaReader.getManga(title)
-- local page = mangaReader.getPages(manga,1)
-- print(page)
end
print(page)
end))
bar:fitFont()
bar.Color = theme.input