Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
File size: 5,227 Bytes
8ac3a87 31c4a0e c81c490 8ac3a87 898cc4c 66aed24 8ac3a87 66aed24 8ac3a87 08e6637 66aed24 fd3060e 08e6637 66aed24 fd3060e 66aed24 8ac3a87 fd3060e 66aed24 fd3060e 66aed24 fd3060e 66aed24 fd3060e 66aed24 8ac3a87 08e6637 66aed24 08e6637 8ac3a87 66aed24 31c4a0e 66aed24 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
import pathlib, os, uvicorn
BASE = pathlib.Path(__file__).parent
app = FastAPI()
app.mount("/static", StaticFiles(directory=BASE), name="static")
HTML = """
<!doctype html><html lang="ko"><head>
<meta charset="utf-8"><title>FlipBook Space</title>
<link rel="stylesheet" href="/static/flipbook.css">
<script src="/static/three.js"></script>
<script src="/static/iscroll.js"></script>
<script src="/static/mark.js"></script>
<script src="/static/mod3d.js"></script>
<script src="/static/pdf.js"></script>
<script src="/static/flipbook.js"></script>
<script src="/static/flipbook.book3.js"></script>
<script src="/static/flipbook.scroll.js"></script>
<script src="/static/flipbook.swipe.js"></script>
<script src="/static/flipbook.webgl.js"></script>
<style>
body{margin:0;background:#f0f0f0;font-family:sans-serif}
header{max-width:960px;margin:0 auto;padding:18px 20px;display:flex;align-items:center}
#homeBtn{display:none;width:38px;height:38px;border:none;border-radius:50%;cursor:pointer;
background:#0077c2;color:#fff;font-size:20px;margin-right:12px}
#homeBtn:hover{background:#005999}
h2{margin:0;font-size:1.5rem;font-weight:600}
#home,#viewerPage{max-width:960px;margin:0 auto;padding:0 20px 40px}
.grid{display:grid;grid-template-columns:repeat(auto-fill,180px);gap:16px;margin-top:24px}
.card{background:#fff;border:1px solid #ccc;border-radius:6px;cursor:pointer;box-shadow:0 2px 4px rgba(0,0,0,.12)}
.card img{width:100%;height:140px;object-fit:cover}
.card p{text-align:center;margin:6px 0}
button.upload{all:unset;cursor:pointer;border:1px solid #bbb;padding:8px 14px;border-radius:6px;background:#fff;margin:0 8px}
#viewer{width:100%;max-width:1200px;height:80vh;margin:24px auto;background:#fff;border:1px solid #ccc}
</style></head><body>
<header>
<button id="homeBtn" title="νμΌλ‘">β</button>
<h2>My FlipBook Projects</h2>
</header>
<section id="home">
<div>
<label class="upload">π· μ΄λ―Έμ§ <input id="imgInput" type="file" accept="image/*" multiple hidden></label>
<label class="upload">π PDF <input id="pdfInput" type="file" accept="application/pdf" hidden></label>
</div>
<div class="grid" id="grid"></div>
</section>
<section id="viewerPage" style="display:none">
<div id="viewer"></div>
</section>
<script>
let projects=[], fb=null;
const grid=$id('grid'), viewer=$id('viewer');
pdfjsLib.GlobalWorkerOptions.workerSrc='/static/pdf.worker.js';
/* π μ€λμ€ unlock β λ΄μ₯ Audio μ κ°μ MP3 κ²½λ‘ μ¬μ© */
['click','touchstart'].forEach(evt=>{
document.addEventListener(evt,function u(){new Audio('static/turnPage2.mp3')
.play().then(a=>a.pause()).catch(()=>{});document.removeEventListener(evt,u,{capture:true});},
{once:true,capture:true});
});
/* ββ μ νΈ ββ */
function $id(id){return document.getElementById(id)}
function addCard(i,thumb){
const d=document.createElement('div');d.className='card';d.onclick=()=>open(i);
d.innerHTML=`<img src="${thumb}"><p>νλ‘μ νΈ ${i+1}</p>`;grid.appendChild(d);
}
/* ββ μ΄λ―Έμ§ μ
λ‘λ ββ */
$id('imgInput').onchange=e=>{
const files=[...e.target.files]; if(!files.length) return;
const pages=[],tot=files.length;let done=0;
files.forEach((f,i)=>{const r=new FileReader();r.onload=x=>{pages[i]={src:x.target.result,thumb:x.target.result};
if(++done===tot) save(pages);};r.readAsDataURL(f);});
};
/* ββ PDF μ
λ‘λ ββ */
$id('pdfInput').onchange=e=>{
const file=e.target.files[0]; if(!file) return;
const fr=new FileReader();
fr.onload=v=>{
pdfjsLib.getDocument({data:v.target.result}).promise.then(async pdf=>{
const pages=[];
for(let p=1;p<=pdf.numPages;p++){
const pg=await pdf.getPage(p), vp=pg.getViewport({scale:1});
const c=document.createElement('canvas');c.width=vp.width;c.height=vp.height;
await pg.render({canvasContext:c.getContext('2d'),viewport:vp}).promise;
pages.push({src:c.toDataURL(),thumb:c.toDataURL()});
}
save(pages);
});
};fr.readAsArrayBuffer(file);
};
/* ββ νλ‘μ νΈ μ μ₯ ββ */
function save(pages){const id=projects.push(pages)-1;addCard(id,pages[0].thumb);}
/* ββ μΉ΄λ β FlipBook ββ */
function open(i){
toggle(false);
const pages=projects[i];
if(fb){fb.destroy();viewer.innerHTML='';}
fb=new FlipBook(viewer,{
pages,viewMode:'webgl',autoSize:true,flipDuration:800,backgroundColor:'#fff',
/* π λ΄μ₯ μ¬μ΄λ */
sound:true,
assets:{flipMp3:'static/turnPage2.mp3',hardFlipMp3:'static/turnPage2.mp3'},
controlsProps:{enableFullscreen:true,thumbnails:true}});
}
/* ββ λ€λΉκ²μ΄μ
ββ */
$id('homeBtn').onclick=()=>toggle(true);
function toggle(showHome){
$id('home').style.display=showHome?'block':'none';
$id('viewerPage').style.display=showHome?'none':'block';
$id('homeBtn').style.display=showHome?'none':'inline-block';
}
</script>
</body></html>
"""
@app.get("/", response_class=HTMLResponse)
async def root():
return HTML
if __name__ == "__main__":
uvicorn.run("app:app", host="0.0.0.0", port=int(os.getenv("PORT", 7860)))
|