all repos — artbound-python @ 5ef1788dfade02080034166b4fd13fe3818ef069

A client-server reimplementation of the administration panel for ArtBound.

bugfix, update footer, polish
BiRabittoh birabittoh@tilde.team
Thu, 10 Aug 2023 18:04:34 +0200
commit

5ef1788dfade02080034166b4fd13fe3818ef069

parent

61c699ca6fc5947d28d19bddabb995e31c50a654

M artbound_python/static/script.jsartbound_python/static/script.js

@@ -10,6 +10,8 @@ IG_MAX_HEIGHT = 988,

WATERMARK = new Image(), IG_TEMPLATE = new Image(), + fanarts = new Array(), + months = new Set(), last_updated_link = document.getElementById("last-updated-link"), month_input = document.getElementById("month_input"), month_div = document.getElementById("month_div"),

@@ -23,8 +25,7 @@ canvas_link = document.getElementById("canvas-download"),

canvas_ig = document.getElementById("instagram-canvas"), fanart_template = document.getElementById("fanart-template").innerHTML; -let fanarts = new Array(), - new_entries = 0; +let new_entries = 0; WATERMARK.src = WATERMARK_SRC; IG_TEMPLATE.src = IG_TEMPLATE_SRC;

@@ -85,7 +86,7 @@

async function updateFanartList() { content_div.innerHTML = ""; get_button.disabled = false; - get_button.innerText = "Aggiungi"; + get_button.innerText = emoji_get; let i = 0; for (fanart of fanarts) {

@@ -104,7 +105,7 @@ }

} function getFanart(id) { - return fanarts.find(element => element.id == id) + return fanarts.find(element => element.id == id); } function toggleEntry(id) {

@@ -112,13 +113,13 @@ entry = getFanart(id);

if (!entry) return; entry.enabled = !entry.enabled; - updateFanartList() + updateFanartList(); } function saveCanvas(my_canvas, filename) { canvas_link.href = my_canvas.toDataURL("image/png").replace("image/png", "image/octet-stream"); canvas_link.setAttribute("download", filename); - canvas_link.click() + canvas_link.click(); } function reloadEntry(id) {

@@ -132,7 +133,7 @@ }

function selectAllNone(toggle) { fanarts.map(x => x.enabled = toggle) - updateFanartList() + updateFanartList(); } function clickCoordsToCanvas(clickX, clickY, c) {

@@ -180,7 +181,6 @@ const pos = fanarts.indexOf(entry);

const new_pos = pos + amount; if (new_pos <= -1 || new_pos >= fanarts.length) return; - [fanarts[pos], fanarts[new_pos]] = [fanarts[new_pos], fanarts[pos]]; updateFanartList(); }

@@ -190,7 +190,7 @@ const entry = fanarts.find(element => element.id == id);

if (!entry) return; if (!entry.enabled) return; entry.watermark.invert = entry.watermark.invert == '' ? 'invert(1)' : ''; - button.innerText = entry.watermark.invert ? "⚫" : "⚪"; + button.innerText = entry.watermark.invert ? emoji_color_black : emoji_color; const ctx = entry.canvas.getContext('2d'); setBaseImage(entry.image, entry.canvas, ctx); drawWatermark(entry.watermark, ctx);

@@ -228,13 +228,16 @@ saveCanvasIG(entry.canvas);

} function getArtworks() { + const month_value = month_input.value; + if (months.has(month_value)) return; get_button.disabled = true; - get_button.innerText = "…" - postData("/", { month: month_input.value }).then((data) => { - fanarts = fanarts.concat(data); + get_button.innerText = "🔄" + postData("/", { month: month_value }).then((data) => { + fanarts.push(...data); controls_div.hidden = false; updateOpacity(); updateFanartList(); + months.add(month_value); }); }

@@ -261,6 +264,6 @@ postData("/update").then((data) => {

last_updated_link.innerText = data.timestamp; if (data.new == 0) return; new_entries += data.new; - last_updated_link.innerText += ` (+${new_entries})`; + last_updated_link.innerText += ` (+${ new_entries })`; }); }
M artbound_python/static/style.cssartbound_python/static/style.css

@@ -57,6 +57,11 @@ .card-controls {

flex-direction: row-reverse; } +.card-text { + display: block; + padding-bottom: 10px; +} + body { background-color: var(--background0); color: var(--text);

@@ -98,3 +103,11 @@

.text-row { margin-top: 20px; } + +footer a { + text-decoration: underline; +} + +footer a:hover { + text-decoration: none; +}
M artbound_python/templates/help.htmlartbound_python/templates/help.html

@@ -34,8 +34,8 @@ <div class="container">

<div class="row text-row"> <div class="col-md-12"> <p> - ArtBound Panel è un modo intelligente per selezionare, ridimensionare, rinominare e marchiare - le fanart che arrivano ad EarthBound Café. + ArtBound Panel è uno strumento che aiuta a selezionare, ridimensionare, rinominare e marchiare + con facilità le fanart che arrivano ad Earthbound Café. </p> </div> </div>

@@ -43,10 +43,10 @@ <div class="row text-row">

<div class="col-md-12"> <h2 class="lead">Istruzioni</h2> <ol> - <li>Per prima cosa, seleziona il mese da cui vuoi estrarre le fanart e clicca sul tasto a + <li>Per prima cosa, seleziona il mese da cui vuoi estrarre le fanart e clicca sul tasto {{ emoji["get_first"] }} a fianco. Se le immagini non sono in cache potrebbe volerci un attimo.</li> - <li>Ripeti l'operazione precedente per integrare le fanart di eventuali altri mesi.</li> - <li>Disabilita le fanart non necessarie e ordina opportunamente il resto.</li> + <li>Ripeti l'operazione precedente ({{ emoji["get"] }}) per integrare le fanart di eventuali altri mesi.</li> + <li>Disabilita ({{ emoji["toggle"] }}) le fanart non necessarie e ordina ({{ emoji["prev"] }}, {{ emoji["next"] }}) opportunamente il resto.</li> <li>Usa il mouse o il touch screen per posizionare il watermark su ciascuna immagine.</li> <li>Usa i tasti {{ emoji["save"] }} o {{ emoji["save_ig"] }} per salvare i risultati su file. </li>

@@ -55,49 +55,47 @@ </div>

</div> <div class="row text-row"> <div class="col-md-12"> - <h2 class="lead">Comandi globali</h2> + <h2 class="lead">Comandi fanart</h2> <p> - Questi comandi sono posizionati sulla parte superiore centrale della pagina e permettono di - agire su tutte le fanart. + Questi comandi sono posizionati lungo la parte inferiore destra di ogni fanart e permettono di + agire su di essa. </p> <ul> - <li>{{ emoji["select_all"] }}: abilita tutte le fanart;</li> - <li>{{ emoji["select_none"] }}: disabilita tutte le fanart;</li> - <li>Slider: cambia l'opacità dei prossimi watermark;</li> - <li>{{ emoji["save"] }}: salva tutte le fanart nel formato base, per Facebook e Google Forms; - </li> - <li>{{ emoji["save_ig"] }}: salva tutte le fanart nel formato storia, per Instagram.</li> + <li>{{ emoji["prev"] }}: porta indietro la fanart;</li> + <li>{{ emoji["toggle"] }}: abilita o disabilita la fanart;</li> + <li>{{ emoji["color"] }}/{{ emoji["color_black"] }}: alterna tra watermark bianco e nero;</li> + <li>{{ emoji["save"] }}: salva la fanart nel formato base, per Facebook, Mastodon, Twitter e Google Forms;</li> + <li>{{ emoji["save_ig"] }}: salva la fanart nel formato storia, per Instagram.</li> + <li>{{ emoji["next"] }}: porta avanti la fanart.</li> </ul> </div> </div> <div class="row text-row"> <div class="col-md-12"> - <h2 class="lead">Comandi fanart</h2> + <h2 class="lead">Comandi globali</h2> <p> - Questi comandi sono posizionati lungo la parte inferiore destra di ogni fanart e permettono di - agire su di essa. + Questi comandi sono posizionati sulla parte superiore centrale della pagina e permettono di + agire su tutte le fanart. </p> <ul> - <li>{{ emoji["prev"] }}: porta indietro la fanart;</li> - <li>{{ emoji["toggle"] }}: abilita/disabilita la fanart;</li> - <li>{{ emoji["color"] }}: alterna tra watermark bianco e nero;</li> - <li>{{ emoji["save"] }}: salva la fanart nel formato base, per Facebook e Google Forms;</li> - <li>{{ emoji["save_ig"] }}: salva la fanart nel formato storia, per Instagram.</li> - <li>{{ emoji["next"] }}: porta avanti la fanart.</li> + <li>{{ emoji["select_all"] }}: abilita tutte le fanart;</li> + <li>{{ emoji["select_none"] }}: disabilita tutte le fanart;</li> + <li>Slider: cambia l'opacità dei prossimi watermark;</li> + <li>{{ emoji["save"] }}: salva tutte le fanart nel formato base;</li> + <li>{{ emoji["save_ig"] }}: salva tutte le fanart nel formato storia.</li> </ul> </div> </div> <div class="row text-row"> <div class="col-md-12 text-center"> - <a href="/" class="btn btn-primary">Home 🏠</a> + <a href="/" class="btn btn-primary">Home {{ emoji["home"] }}</a> </div> </div> </div> </main> <footer> <div class="container"> - <p>&copy; Earthbound Café, realizzato da <a href="mailto:andronacomarco@gmail.com">Marco Andronaco</a> - (BiRabittoh).</p> + <p>&copy; <a href="https://linktr.ee/earthboundcafe">Earthbound Café</a>, realizzato da <a href="https://birabittoh.github.io/">BiRabittoh</a>.</p> </div> </footer> <script src="/static/ext/js/jquery-3.2.1.slim.min.js"></script>
M artbound_python/templates/index.htmlartbound_python/templates/index.html

@@ -7,14 +7,13 @@ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<meta name="description" content="Un modo semplice e veloce per gestire le fanart di ArtBound."> <meta name="author" content="BiRabittoh"> <link rel="icon" - href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>✏️</text></svg>"> + href='data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>{{ emoji["favicon"] }}</text></svg>'> <title>ArtBound Panel</title> <link href="/static/ext/css/bootstrap.min.css" rel="stylesheet"> <link href="/static/style.css" rel="stylesheet"> </head> <body> - <a id="canvas-download" hidden></a> <main role="main"> <section class="jumbotron text-center"> <div class="container">

@@ -25,35 +24,47 @@ class="feather feather-activity">

<polygon points="14 2 18 6 7 17 3 17 3 13 14 2"></polygon> <line x1="3" y1="22" x2="21" y2="22"></line> </svg> - ArtBound Panel</a> + ArtBound Panel </h1> - <svg fill="white" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" - width="15" height="15" viewBox="0 0 420.827 420.827" - xml:space="preserve"> - <g><g><path d="M210.29,0C156,0,104.43,20.693,65.077,58.269C25.859,95.715,2.794,146.022,0.134,199.921 + <svg fill="white" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" width="15" height="15" viewBox="0 0 420.827 420.827" + xml:space="preserve"> + <g> + <g> + <path + d="M210.29,0C156,0,104.43,20.693,65.077,58.269C25.859,95.715,2.794,146.022,0.134,199.921 c-0.135,2.734,0.857,5.404,2.744,7.388c1.889,1.983,4.507,3.105,7.244,3.105h45.211c5.275,0,9.644-4.098,9.979-9.362 c4.871-76.214,68.553-135.914,144.979-135.914c80.105,0,145.275,65.171,145.275,145.276c0,80.105-65.17,145.276-145.275,145.276 c-18.109,0-35.772-3.287-52.501-9.771l17.366-15.425c2.686-2.354,3.912-5.964,3.217-9.468c-0.696-3.506-3.209-6.371-6.592-7.521 l-113-32.552c-3.387-1.149-7.122-0.407-9.81,1.948c-2.686,2.354-3.913,5.963-3.218,9.467L69.71,403.157 c0.696,3.505,3.209,6.372,6.591,7.521c3.383,1.147,7.122,0.408,9.81-1.946l18.599-16.298 - c31.946,18.574,68.456,28.394,105.581,28.394c116.021,0,210.414-94.392,210.414-210.414C420.705,94.391,326.312,0,210.29,0z"/> + c31.946,18.574,68.456,28.394,105.581,28.394c116.021,0,210.414-94.392,210.414-210.414C420.705,94.391,326.312,0,210.29,0z" /> <path d="M195.112,237.9h118.5c2.757,0,5-2.242,5-5v-30c0-2.757-2.243-5-5-5h-83.5v-91c0-2.757-2.243-5-5-5h-30 - c-2.757,0-5,2.243-5,5v126C190.112,235.658,192.355,237.9,195.112,237.9z"/></g></g></svg> - <a id="last-updated-link" href="#" class="lead" onclick="updateDb();"><?xml version="1.0" encoding="iso-8859-1"?> - {{ last_updated }}</a> + c-2.757,0-5,2.243-5,5v126C190.112,235.658,192.355,237.9,195.112,237.9z" /> + </g> + </g> + </svg> + <a id="last-updated-link" href="#" class="lead" onclick="updateDb();"> + <?xml version="1.0" encoding="iso-8859-1"?> + {{ last_updated }} + </a> <div id="month_div"> <label for="month_input" style="margin-right: 10px;">Scegli il mese: </label> <input id="month_input" type="month" value="{{ current_month }}"> - <a href="#" class="btn my-2 btn-go" onclick="handleAuthClick();" id="authorize_button" hidden>Vai</a> - <button class="btn btn-secondary my-2" onclick="getArtworks();" id="get_button">Ottieni</button> + <button class="btn btn-secondary my-2" onclick="getArtworks();" id="get_button">{{ emoji["get_first"] }}</button> </div> <div id="controls" hidden> - <a href="#" class="btn btn-secondary my-2" onclick="selectAllNone(1);" id="selectall_button">{{ emoji["select_all"] }}</a> - <a href="#" class="btn btn-secondary my-2" onclick="selectAllNone(0);" id="selectnone_button">{{ emoji["select_none"] }}</a> - <input type="range" class="form-range" id="opacity_range" min="0" max="1" step="0.01" oninput="updateOpacity();" value="0.4"> + <a href="#" class="btn btn-secondary my-2" onclick="selectAllNone(1);" id="selectall_button">{{ + emoji["select_all"] }}</a> + <a href="#" class="btn btn-secondary my-2" onclick="selectAllNone(0);" id="selectnone_button">{{ + emoji["select_none"] }}</a> + <input type="range" class="form-range" id="opacity_range" min="0" max="1" step="0.01" + oninput="updateOpacity();" value="0.4"> <label for="opacity_range" class="form-label" id="opacity_label"></label> - <a href="#" class="btn btn-secondary my-2" onclick="saveAll();" id="saveall_button">{{ emoji["save"] }}</a> - <a href="#" class="btn btn-secondary my-2" onclick="saveAllIG();" id="saveallig_button">{{ emoji["save_ig"] }}</a> + <a href="#" class="btn btn-secondary my-2" onclick="saveAll();" id="saveall_button">{{ emoji["save"] + }}</a> + <a href="#" class="btn btn-secondary my-2" onclick="saveAllIG();" id="saveallig_button">{{ + emoji["save_ig"] }}</a> </div> </div> </section>

@@ -62,7 +73,7 @@ <div class="container">

<div class="row" id="content"></div> <div class="row text-row"> <div class="col-md-12 text-center"> - <a href="/help" class="btn btn-primary">Info ❔</a> + <a href="/help" class="btn btn-primary">Info {{ emoji["help"] }}</a> </div> </div> </div>

@@ -70,18 +81,18 @@ </div>

</main> <footer> <div class="container"> - <p>&copy; Earthbound Café, realizzato da <a href="mailto:andronacomarco@gmail.com">Marco Andronaco</a> (BiRabittoh).</p> + <p>&copy; <a href="https://linktr.ee/earthboundcafe">Earthbound Café</a>, realizzato da <a + href="https://birabittoh.github.io/">BiRabittoh</a>.</p> </div> </footer> <template id="fanart-template"> - <div class="col-md-4 entry{| disabled |}" id="{| id |}" data-index="{| index |}"> + <div class="col-lg-4 entry{| disabled |}" id="{| id |}" data-index="{| index |}"> <div class="card mb-4 box-shadow my-card"> - <canvas class="card-img-top entry-img" - id="{| id |}" data-name="{| name |}" - data-content="{| content |}" + <canvas class="card-img-top entry-img" id="{| id |}" data-name="{| name |}" data-content="{| content |}" data-filename="{| filename |}"></canvas> <div class="card-body"> - <a class="card-text" title="Clicca per copiare." onclick="navigator.clipboard.writeText(this.innerText);">{| filename |}</a> + <a class="card-text" title="Clicca per copiare." + onclick="navigator.clipboard.writeText(this.innerText);">{| filename |}</a> <div class="d-flex justify-content-between align-items-center card-controls"> <div class="btn-group"> <button class="btn btn-sm btn-outline-secondary" onclick="moveUpDown('{| id |}', -1);">{{ emoji["prev"] }}</button>

@@ -96,10 +107,16 @@ </div>

</div> </div> </template> + <a id="canvas-download" hidden></a> <canvas width="1080" height="1920" id="instagram-canvas" hidden></canvas> <script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/2.3.0/mustache.min.js"></script> <script src="/static/ext/js/jquery-3.2.1.slim.min.js"></script> <script src="/static/ext/js/bootstrap.min.js"></script> + <script> + const emoji_color = '{{ emoji["color"] }}'; + const emoji_color_black = '{{ emoji["color_black"] }}'; + const emoji_get = '{{ emoji["get"] }}'; + </script> <script src="/static/script.js"></script> </body>
M artbound_python/views.pyartbound_python/views.py

@@ -7,14 +7,20 @@

database = DB() emoji = { + "favicon": "✏️", "select_all": "✅", "select_none": "❎", "save": "💾", "save_ig": "📷", "prev": "⬅️", "next": "➡️", + "get_first": "🔽", + "get": "⏬", "toggle": "♻️", "color": "⚪", + "color_black": "⚫", + "help": "❔", + "home": "🏠", } @app.route('/', methods=['GET', 'POST'])