all repos — artbound-python @ 3d6c695d27ba8a782bd99f2410cea108f6bc3941

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

artbound_python/static/script.js (view raw)

  1const BS_COL_WIDTH = 4,
  2	MAX_WIDTH = MAX_HEIGHT = 1000,
  3	WATERMARK_SRC = "/static/res/wm.png",
  4	WATERMARK_WIDTH = 325,
  5	WATERMARK_HEIGHT = 98,
  6	IG_TEMPLATE_SRC = "/static/res/ig.png",
  7	IG_MIN_OFFSET_X = 0,
  8	IG_MIN_OFFSET_Y = 342,
  9	IG_MAX_WIDTH = 1080,
 10	IG_MAX_HEIGHT = 988,
 11
 12	WATERMARK = new Image(),
 13	IG_TEMPLATE = new Image(),
 14	date = new Date(),
 15	month_input = document.getElementById("month_input"),
 16	month_div = document.getElementById("month_div"),
 17	get_button = document.getElementById("get_button"),
 18	selectall_button = document.getElementById("selectall_button"),
 19	selectnone_button = document.getElementById("selectnone_button"),
 20	controls_div = document.getElementById("controls"),
 21	opacity_range = document.getElementById("opacity_range"),
 22	main_container_div = document.getElementById("main_container"),
 23	content_div = document.getElementById("content"),
 24	canvas_link = document.getElementById("canvas-download"),
 25	canvas_ig = document.getElementById("instagram-canvas"),
 26	fanart_template = document.getElementById("fanart-template").innerHTML;
 27
 28let fanarts = new Array(),
 29	watermark_invert = '';
 30
 31WATERMARK.src = WATERMARK_SRC;
 32IG_TEMPLATE.src = IG_TEMPLATE_SRC;
 33month_input.value = `${date.getFullYear()}-${("0" + (date.getMonth() + 1)).slice(-2)}`;
 34
 35function addCanvasEvents(element, ctx) {
 36	function abc(e) {
 37		if (element.enabled == 0) return;
 38		if (e.button == 0) {
 39			if (e.type == "mousedown") {
 40				element.clicked = true;
 41				console.log(element);
 42			}
 43			element.watermark.opacity = opacity_range.value;
 44			addWatermark(e, element, ctx);
 45		}
 46	}
 47
 48	if (element.clicked) {
 49		element.canvas.addEventListener('mousedown', abc);
 50		return;
 51	}
 52	element.canvas.addEventListener('mousemove', abc);
 53	element.canvas.addEventListener('mouseleave', () => {
 54		if (!element.clicked && element.enabled)
 55			setBaseImage(element.image, element.canvas, ctx);
 56	});
 57	element.canvas.addEventListener('mousedown', (e) => {
 58		abc(e);
 59		element.canvas.removeEventListener('mousemove', abc);
 60		element.canvas.addEventListener('mousedown', abc);
 61	});
 62}
 63
 64function createElementFromHTML(htmlString) {
 65	const div = document.createElement('div');
 66	div.innerHTML = htmlString.trim();
 67	return div.firstChild;
 68}
 69
 70function getNewCardHtml(element) {
 71
 72	const id = element.id,
 73		index = element.index,
 74		name = element.name,
 75		content = element.content,
 76		filename = `${('0' + element.index).slice(-2)} - ${element.name}.png`,
 77		disabled = element.enabled == 0 ? " entry-disabled" : "";
 78
 79	const html_string = Mustache.render("{{={| |}=}}" + fanart_template, { id, index, name, content, filename, disabled });
 80	element.div = createElementFromHTML(html_string);
 81	element.canvas = element.div.getElementsByTagName("canvas")[0];
 82
 83	const ctx = element.canvas.getContext("2d");
 84
 85	element.image = new Image();
 86	element.image.addEventListener("load", () => {
 87		const wm_info = element.watermark;
 88		setBaseImage(element.image, element.canvas, ctx);
 89		if (element.clicked) {
 90			drawWatermark(wm_info, ctx);
 91		}
 92		addCanvasEvents(element, ctx);
 93	});
 94	element.image.src = element.content;
 95
 96	return element.div;
 97}
 98
 99async function updateFanartList() {
100	main_container_div.hidden = false;
101	content_div.innerHTML = "";
102	get_button.disabled = false;
103	get_button.innerText = "Aggiungi";
104
105	let i = 0;
106	for (fanart of fanarts) {
107		if (fanart.enabled) {
108			i++;
109			fanart.index = i;
110			content_div.appendChild(getNewCardHtml(fanart));
111		}
112	}
113
114	for (fanart of fanarts) {
115		if (!fanart.enabled) {
116			fanart.index = 0;
117			content_div.appendChild(getNewCardHtml(fanart));
118		}
119	}
120}
121
122function getFanart(id) {
123	return fanarts.find(element => element.id == id)
124}
125
126function toggleEntry(id) {
127	entry = getFanart(id);
128	if (!entry) return;
129
130	entry.enabled = !entry.enabled;
131	updateFanartList()
132}
133
134function saveCanvas(my_canvas, filename) {
135	canvas_link.href = my_canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
136	canvas_link.setAttribute("download", filename);
137	canvas_link.click()
138}
139
140function reloadEntry(id) {
141	const fanart = getFanart(id);
142	if (!fanart) return;
143
144	const old_div = fanart.div;
145	content_div.replaceChild(getNewCardHtml(fanart), old_div);
146	old_div.remove();
147}
148
149function selectAllNone(toggle) {
150	fanarts.map(x => x.enabled = toggle)
151	updateFanartList()
152}
153
154function debugFn() {
155	fanarts = JSON.parse('[{"id":"1dE8L7w2DuOfQSJwf5oRjAeJ-VZfy5o-6","date":["03","08","2022"],"name":"Saro","content":"/static/res/wm.png","enabled":1,"index":1,"div":{}},{"id":"1ZO2poqaylmh7_FkEjRthozVXFpcP1Edx","date":["18","08","2022"],"name":"suchetto","content":"https://drive.google.com/uc?id=1ZO2poqaylmh7_FkEjRthozVXFpcP1Edx","enabled":1,"index":2,"div":{}},{"id":"1jkpZzqnQUdXv7QiW1khuwnSsdnjudBt-","date":["18","08","2022"],"name":"suca","content":"https://drive.google.com/uc?id=1clZbi1QzJQo_c7PGWx-nmLgfPhXqHdZR","enabled":1,"index":3,"div":{}}]');
156	controls_div.hidden = false;
157	updateOpacity();
158	updateFanartList();
159}
160
161function clickCoordsToCanvas(clickX, clickY, c) {
162	const rect = c.getBoundingClientRect();
163	const x = (clickX - rect.left) * c.width / c.clientWidth;
164	const y = (clickY - rect.top) * c.height / c.clientHeight;
165	return [x, y];
166}
167
168function drawWatermark(wm_info, ctx) {
169	ctx.globalAlpha = wm_info.opacity;
170	ctx.filter = wm_info.invert;
171	ctx.drawImage(WATERMARK, wm_info.x - (WATERMARK_WIDTH / 2), wm_info.y - (WATERMARK_HEIGHT / 2), WATERMARK_WIDTH, WATERMARK_HEIGHT);
172}
173
174function addWatermark(event, element, ctx) {
175	setBaseImage(element.image, element.canvas, ctx);
176	const [x, y] = clickCoordsToCanvas(event.clientX, event.clientY, element.canvas);
177	element.watermark.x = x;
178	element.watermark.y = y
179	drawWatermark(element.watermark, ctx);
180}
181
182function updateOpacity() {
183	opacity_label.innerHTML = Math.round(opacity_range.value * 100) + '%';
184}
185
186function getFactor(img_width, img_height, max_width, max_height) {
187	return Math.min(max_width / img_width, max_height / img_height);
188}
189
190function setBaseImage(img, c, ctx) {
191	const f = getFactor(img.width, img.height, MAX_WIDTH, MAX_HEIGHT);
192
193	const new_width = c.width = Math.ceil(img.width * f);
194	const new_height = c.height = Math.ceil(img.height * f)
195
196	ctx.imageSmoothingEnabled = (f < 1);
197	ctx.drawImage(img, 0, 0, new_width, new_height);
198}
199
200function moveUpDown(id, amount) {
201	const pos = fanarts.indexOf(fanarts.find(element => element.id == id));
202	const new_pos = pos + amount;
203
204	if (new_pos <= -1 || new_pos >= fanarts.length) {
205		return;
206	}
207
208	[fanarts[pos], fanarts[new_pos]] = [fanarts[new_pos], fanarts[pos]];
209
210	updateFanartList();
211}
212
213function toggleInvert(id, button) {
214	const entry = fanarts.find(element => element.id == id);
215	entry.watermark.invert = entry.watermark.invert == '' ? 'invert(1)' : '';
216	button.innerText = entry.watermark.invert ? "⚫" : "⚪";
217	const ctx = entry.canvas.getContext('2d');
218	setBaseImage(entry.image, entry.canvas, ctx);
219	drawWatermark(entry.watermark, ctx);
220}
221
222async function postData(url = "", data = {}, contentType = "application/json") {
223	const response = await fetch(url, { method: "POST", headers: { "Content-Type": contentType }, body: JSON.stringify(data) });
224	return response.json();
225}
226
227function saveEntry(id) {
228	entry = getFanart(id);
229	if (!entry) return;
230	saveCanvas(entry.canvas, entry.canvas.getAttribute("data-filename"));
231}
232
233function saveCanvasIG(my_canvas) {
234	const f = getFactor(my_canvas.width, my_canvas.height, IG_MAX_WIDTH, IG_MAX_HEIGHT);
235
236	const width = Math.ceil(my_canvas.width * f);
237	const height = Math.ceil(my_canvas.height * f);
238
239	const offset_x = Math.round((IG_MAX_WIDTH - width) / 2);
240	const offset_y = Math.round((IG_MAX_HEIGHT - height) / 2);
241
242	destCtx = canvas_ig.getContext('2d');
243	destCtx.drawImage(IG_TEMPLATE, 0, 0);
244	destCtx.drawImage(my_canvas, IG_MIN_OFFSET_X + offset_x, IG_MIN_OFFSET_Y + offset_y, width, height);
245	saveCanvas(canvas_ig, "IG - " + my_canvas.getAttribute("data-filename"));
246}
247
248function saveEntryIG(id) {
249	entry = getFanart(id);
250	if (!entry) return;
251	saveCanvasIG(entry.canvas);
252}
253
254function getArtworks() {
255	get_button.disabled = true;
256	get_button.innerText = "…"
257	postData("/", { month: month_input.value }).then((data) => {
258		//console.log(data);
259		fanarts = fanarts.concat(data);
260		controls_div.hidden = false;
261		updateOpacity();
262		updateFanartList();
263	});
264}
265
266function saveAll() {
267	const response = confirm("Vuoi davvero scaricare tutte le fanart?");
268	if (response == false) return;
269
270	fanarts.forEach((fanart) => {
271		if (fanart.enabled)
272			saveCanvas(fanart.canvas, fanart.canvas.getAttribute("data-filename"));
273	})
274}
275
276function saveAllIG() {
277	const response = confirm("Vuoi davvero scaricare tutte le storie per le fanart?");
278	if (response == false) return;
279
280	fanarts.forEach((fanart) => {
281		if (fanart.enabled)
282			saveCanvasIG(fanart.canvas);
283	});
284}