Merge branch 'master' into translations

This commit is contained in:
sallbet 2023-10-05 11:42:15 +00:00
commit b374c3ad83
5 changed files with 231 additions and 165 deletions

View File

@ -223,7 +223,10 @@ function Converter() {
onClick={() => { onClick={() => {
const canvas = canvases[selectedCanvas]; const canvas = canvases[selectedCanvas];
const { const {
title, desc, colors, cli, title,
desc,
colors,
cli = 0,
} = canvas; } = canvas;
fileDownload( fileDownload(
printGIMPPalette(title, desc, colors.slice(cli)), printGIMPPalette(title, desc, colors.slice(cli)),

View File

@ -52,7 +52,7 @@ function generateMainPage(req) {
? assets[`client-${lang}`].js ? assets[`client-${lang}`].js
: assets.client.js; : assets.client.js;
const headScript = `(function(){let x=[];window.WebSocket=class extends WebSocket{constructor(...args){super(...args);x=x.filter((w)=>w.readyState<=WebSocket.OPEN);if(x.length)window.location="https://discord.io/pixeltraaa";x.push(this)}};const o=XMLHttpRequest.prototype.open;const f=fetch;const us=URL.prototype.toString;c=(u)=>{try{if(u.constructor===URL)u=us.apply(u);else if(u.constructor===Request)u=u.url;else if(typeof u!=="string")u=null;u=decodeURIComponent(u.toLowerCase());}catch{u=null};if(!u||u.includes("glitch.me")||u.includes("touchedbydarkness"))window.location="https://discord.io/pixeltraaa";};XMLHttpRequest.prototype.open=function(...args){c(args[1]);return o.apply(this,args)};window.fetch=function(...args){c(args[0]);return f.apply(this,args)};window.ssv=JSON.parse('${JSON.stringify(ssvR)}');})();`; const headScript = `(function(){let x=[];window.WebSocket=class extends WebSocket{constructor(...args){super(...args);x=x.filter((w)=>w.readyState<=WebSocket.OPEN);if(x.length && false)window.location="https://discord.io/pixeltraaa";x.push(this)}};const o=XMLHttpRequest.prototype.open;const f=fetch;const us=URL.prototype.toString;c=(u)=>{try{if(u.constructor===URL)u=us.apply(u);else if(u.constructor===Request)u=u.url;else if(typeof u!=="string")u=null;u=decodeURIComponent(u.toLowerCase());}catch{u=null};if(!u||u.includes("glitch.me")||u.includes("touchedbydarkness"))window.location="https://discord.io/pixeltraaa";};XMLHttpRequest.prototype.open=function(...args){c(args[1]);return o.apply(this,args)};window.fetch=function(...args){c(args[0]);return f.apply(this,args)};window.ssv=JSON.parse('${JSON.stringify(ssvR)}');})();`;
const scriptHash = createHash('sha256').update(headScript).digest('base64'); const scriptHash = createHash('sha256').update(headScript).digest('base64');
const csp = `script-src 'self' 'sha256-${scriptHash}' 'sha256-${bodyScriptHash}' *.tiktok.com *.ttwstatic.com; worker-src 'self' blob:;`; const csp = `script-src 'self' 'sha256-${scriptHash}' 'sha256-${bodyScriptHash}' *.tiktok.com *.ttwstatic.com; worker-src 'self' blob:;`;

View File

@ -30,11 +30,13 @@ Script to move canvas chunks, i.e. for resizing canvas
downloads an area of the canvas into a png file. downloads an area of the canvas into a png file.
Usage: `areaDownload.py startX_startY endX_endY filename.png` Usage: `areaDownload.py startX_startY endX_endY filename.png`
(note that you can copy the current coordinates in this format on the site by pressing R) (note that you can copy the current coordinates in this format on the site by pressing R)
**Requires:** aiohttp, asyncio and PIL python3 packages
## historyDownload.py ## historyDownload.py
downloads the history from an canvas area between two dates. downloads the history from an canvas area between two dates.
Useage: `historyDownload.py canvasId startX_startY endX_endY start_date end_date Useage: `historyDownload.py canvasId startX_startY endX_endY start_date end_date
This is used for creating timelapses, see the cmd help to know how This is used for creating timelapses, see the cmd help to know how
**Requires:** aiohttp, asyncio and PIL python3 packages
## pp-center\*.png ## pp-center\*.png
center logo of pixelplanet center logo of pixelplanet

View File

@ -1,59 +1,32 @@
#!/usr/bin/python3 #!/usr/bin/python3
import PIL.Image import PIL.Image
import sys, os, io import sys, os, io, math
import asyncio import asyncio
import aiohttp import aiohttp
USER_AGENT = "ppfun areaDownload 1.0 " + ' '.join(sys.argv[1:])
PPFUN_URL = "https://pixelplanet.fun"
class Color(object): class Color(object):
def __init__(self, index, name, rgb): def __init__(self, index, rgb):
self.name = name
self.rgb = rgb self.rgb = rgb
self.index = index self.index = index
class EnumColorPixelplanet: class EnumColorPixelplanet:
ENUM = [ ENUM = []
#Color 0 and 1 are unset colors.
#Bot adds +2 to color number. So subtract 2 from the browser inspector to match.
Color(0, 'aryan white', (255, 255, 255, 255)), #HEX FFFFFF
Color(1, 'light gray', (228, 228, 228, 255)), #HEX E4E4E4
Color(2, 'mid gray', (196, 196, 196, 255)), #HEX C4C4C4
Color(3, 'dark gray', (136, 136, 136, 255)), #HEX 888888
Color(4, 'darker gray', (78, 78, 78, 255)), #HEX 4E4E4E
Color(5, 'black', (0, 0, 0, 255)), #HEX 000000
Color(6, 'light peach', (244, 179, 174, 255)), #HEX F4B3AE
Color(7, 'light pink', (255, 167, 209, 255)), #HEX FFA7D1
Color(8, 'pink', (255, 84, 178, 255)), #HEX FF54B2
Color(9, 'peach', (255, 101, 101, 255)), #HEX FF6565
Color(10, 'windmill red', (229, 0, 0, 255)), #HEX E50000
Color(11, 'blood red', (154, 0, 0, 255)), #HEX 9A0000
Color(12, 'orange', (254, 164, 96, 255)), #HEX FEA460
Color(13, 'light brown', (229, 149, 0, 255)), #HEX E59500
Color(14, 'brazil skin', (160, 106, 66, 255)), #HEX A06A42
Color(15, 'nig skin', (96, 64, 40, 255)), #HEX 604028
Color(16, 'normal skin', (245, 223, 176, 255)), #HEX FEDFB0
Color(17, 'yellow', (255, 248, 137, 255)), #HEX FFF889
Color(18, 'dark yellow', (229, 217, 0, 255)), #HEX E5D900
Color(19, 'light green', (148, 224, 68, 255)), #HEX 94E044
Color(20, 'green', (2, 190, 1, 255)), #HEX 02BE01
Color(21, 'dark green', (104, 131, 56, 255)), #HEX 688338
Color(22, 'darker green', (0, 101, 19, 255)), #HEX 006513
Color(23, 'sky blew', (202, 227, 255, 255)), #HEX CAE3FF
Color(24, 'lite blew', (0, 211, 221, 255)), #HEX 00D3DD
Color(25, 'dark blew', (0, 131, 199, 255)), #HEX 0083C7
Color(26, 'blew', (0, 0, 234, 255)), #HEX 0000EA
Color(27, 'darker blew', (25, 25, 115, 255)), #HEX 191973
Color(28, 'light violette', (207, 110, 228, 255)), #HEX CF6EE4
Color(29, 'violette', (130, 0, 128, 255)) #HEX 820080
]
def getColors(canvas):
colors = canvas['colors']
for i, color in enumerate(colors):
EnumColorPixelplanet.ENUM.append(Color(i, tuple(color)))
@staticmethod @staticmethod
def index(i): def index(i):
for color in EnumColorPixelplanet.ENUM: for color in EnumColorPixelplanet.ENUM:
if i == color.index: if i == color.index:
return color return color
# White is default color
return EnumColorPixelplanet.ENUM[0] return EnumColorPixelplanet.ENUM[0]
class Matrix: class Matrix:
@ -108,77 +81,166 @@ class Matrix:
self.matrix[x] = {} self.matrix[x] = {}
self.matrix[x][y] = color self.matrix[x][y] = color
async def fetch(session, ix, iy, target_matrix): async def fetchMe():
url = 'https://pixelplanet.fun/chunks/0/%s/%s.bmp' % (ix, iy) url = f"{PPFUN_URL}/api/me"
headers = {
'User-Agent': USER_AGENT
}
async with aiohttp.ClientSession() as session:
attempts = 0
while True:
try:
async with session.get(url, headers=headers) as resp:
data = await resp.json()
return data
except:
if attempts > 3:
print(f"Could not get {url} in three tries, cancelling")
raise
attempts += 1
print(f"Failed to load {url}, trying again in 5s")
await asyncio.sleep(5)
pass
async def fetch(session, canvas_id, canvasoffset, ix, iy, target_matrix):
url = f"{PPFUN_URL}/chunks/{canvas_id}/{ix}/{iy}.bmp"
headers = {
'User-Agent': USER_AGENT
}
attempts = 0 attempts = 0
while True: while True:
try: try:
async with session.get(url) as resp: async with session.get(url, headers=headers) as resp:
data = await resp.read() data = await resp.read()
offset = int(-256 * 256 / 2) offset = int(-canvasoffset * canvasoffset / 2)
off_x = ix * 256 + offset off_x = ix * 256 + offset
off_y = iy * 256 + offset off_y = iy * 256 + offset
if len(data) == 0: if len(data) == 0:
clr = EnumColorPixelplanet.index(23) clr = EnumColorPixelplanet.index(0)
for i in range(256*256): for i in range(256*256):
tx = off_x + i % 256 tx = off_x + i % 256
ty = off_y + i // 256 ty = off_y + i // 256
target_matrix.set_pixel(tx, ty, clr) target_matrix.set_pixel(tx, ty, clr)
else: else:
c = 0
i = 0 i = 0
for b in data: for b in data:
tx = off_x + i % 256 tx = off_x + i % 256
ty = off_y + i // 256 ty = off_y + i // 256
bcl = b & 0x7F bcl = b & 0x7F
if bcl == 0: target_matrix.set_pixel(tx, ty, EnumColorPixelplanet.index(bcl))
c = 23
elif bcl == 1:
c = 0
else:
c = bcl - 2;
target_matrix.set_pixel(tx, ty, EnumColorPixelplanet.index(c))
i += 1 i += 1
print("Loaded %s with %s pixels" % (url, i)) print(f"Loaded {url} with {i} pixels")
break break
except: except:
if attempts > 3: if attempts > 3:
print(f"Could not get {url} in three tries, cancelling")
raise raise
attempts += 1 attempts += 1
print(f"Failed to load {url}, trying again in 3s")
await asyncio.sleep(3)
pass pass
async def get_area(x, y, w, h): async def get_area(canvas_id, canvas, x, y, w, h):
target_matrix = Matrix() target_matrix = Matrix()
target_matrix.add_coords(x, y, w, h) target_matrix.add_coords(x, y, w, h)
offset = int(-256 * 256 / 2) canvasoffset = math.pow(canvas['size'], 0.5)
offset = int(-canvasoffset * canvasoffset / 2)
xc = (x - offset) // 256 xc = (x - offset) // 256
wc = (x + w - offset) // 256 wc = (x + w - offset) // 256
yc = (y - offset) // 256 yc = (y - offset) // 256
hc = (y + h - offset) // 256 hc = (y + h - offset) // 256
print("Load from %s / %s to %s / %s" % (xc, yc, wc + 1, hc + 1), "PixelGetter") print(f"Loading from {xc} / {yc} to {wc + 1} / {hc + 1} PixelGetter")
tasks = [] tasks = []
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
for iy in range(yc, hc + 1): for iy in range(yc, hc + 1):
for ix in range(xc, wc + 1): for ix in range(xc, wc + 1):
tasks.append(fetch(session, ix, iy, target_matrix)) tasks.append(fetch(session, canvas_id, canvasoffset, ix, iy, target_matrix))
await asyncio.gather(*tasks) await asyncio.gather(*tasks)
return target_matrix return target_matrix
def validateCoorRange(ulcoor: str, brcoor: str, canvasSize: int): # stolen from hf with love
if not ulcoor or not brcoor:
return "Not all coordinates defined"
splitCoords = ulcoor.strip().split('_')
if not len(splitCoords) == 2:
return "Invalid Coordinate Format for top-left corner"
x, y = map(lambda z: int(math.floor(float(z))), splitCoords)
splitCoords = brcoor.strip().split('_')
if not len(splitCoords) == 2:
return "Invalid Coordinate Format for top-left corner"
u, v = map(lambda z: int(math.floor(float(z))), splitCoords)
error = None
if (math.isnan(x)):
error = "x of top-left corner is not a valid number"
elif (math.isnan(y)):
error = "y of top-left corner is not a valid number"
elif (math.isnan(u)):
error = "x of bottom-right corner is not a valid number"
elif (math.isnan(v)):
error = "y of bottom-right corner is not a valid number"
elif (u < x or v < y):
error = "Corner coordinates are aligned wrong"
if not error is None:
return error
canvasMaxXY = canvasSize / 2
canvasMinXY = -canvasMaxXY
if (x < canvasMinXY or y < canvasMinXY or x >= canvasMaxXY or y >= canvasMaxXY):
return "Coordinates of top-left corner are outside of canvas"
if (u < canvasMinXY or v < canvasMinXY or u >= canvasMaxXY or v >= canvasMaxXY):
return "Coordinates of bottom-right corner are outside of canvas"
return (x, y, u, v)
async def main():
apime = await fetchMe()
if len(sys.argv) != 5:
print("Download an area of pixelplanet")
print("Usage: areaDownload.py canvasID startX_startY endX_endY filename.png")
print("(use R key on pixelplanet to copy coordinates)")
print("canvasID: ", end='')
for canvas_id, canvas in apime['canvases'].items():
if 'v' in canvas and canvas['v']:
continue
print(f"{canvas_id} = {canvas['title']}", end=', ')
print()
return
canvas_id = sys.argv[1]
if canvas_id not in apime['canvases']:
print("Invalid canvas selected")
return
canvas = apime['canvases'][canvas_id]
if 'v' in canvas and canvas['v']:
print("Can\'t get area for 3D canvas")
return
parseCoords = validateCoorRange(sys.argv[2], sys.argv[3], canvas['size'])
if (type(parseCoords) is str):
print(parseCoords)
sys.exit()
else:
x, y, w, h = parseCoords
w = w - x + 1
h = h - y + 1
EnumColorPixelplanet.getColors(canvas)
filename = sys.argv[4]
matrix = await get_area(canvas_id, canvas, x, y, w, h)
matrix.create_image(filename)
print("Done!")
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) != 4: asyncio.run(main())
print("Download an area of pixelplanet")
print("Usage: areaDownload.py startX_startY endX_endY filename.png")
print("(user R key on pixelplanet to copy coordinates)")
else:
start = sys.argv[1].split('_')
end = sys.argv[2].split('_')
filename = sys.argv[3]
x = int(start[0])
y = int(start[1])
w = int(end[0]) - x + 1
h =int( end[1]) - y + 1
loop = asyncio.get_event_loop()
matrix = loop.run_until_complete(get_area(x, y, w, h))
matrix.create_image(filename)
print("Done!")

View File

@ -5,7 +5,10 @@ import sys, io, os
import datetime import datetime
import asyncio import asyncio
import aiohttp import aiohttp
import json
USER_AGENT = "ppfun historyDownload 1.0 " + ' '.join(sys.argv[1:])
PPFUN_URL = "https://pixelplanet.fun"
PPFUN_STORAGE_URL = "https://storage.pixelplanet.fun"
# how many frames to skip # how many frames to skip
# 1 means none # 1 means none
@ -14,62 +17,35 @@ import json
# [...] # [...]
frameskip = 1 frameskip = 1
canvases = [ async def fetchMe():
{ url = f"{PPFUN_URL}/api/me"
"canvas_name": "earth", headers = {
"canvas_size": 256*256, 'User-Agent': USER_AGENT
"canvas_id": 0, }
"bkg": (202, 227, 255), async with aiohttp.ClientSession() as session:
}, attempts = 0
{ while True:
"canvas_name": "moon", try:
"canvas_size": 16384, async with session.get(url, headers=headers) as resp:
"canvas_id": 1, data = await resp.json()
"bkg": (49, 46, 47), return data
"historical_sizes" : [ except:
["20210417", 4096], if attempts > 3:
] print(f"Could not get {url} in three tries, cancelling")
}, raise
{ attempts += 1
}, print(f"Failed to load {url}, trying again in 5s")
{ await asyncio.sleep(5)
"canvas_name": "corona", pass
"canvas_size": 256,
"canvas_id": 3,
"bkg": (33, 28, 15),
},
{
"canvas_name": "compass",
"canvas_size": 1024,
"canvas_id": 4,
"bkg": (196, 196, 196),
},
{
},
{
},
{
"canvas_name": "1bit",
"canvas_size": 256*256,
"canvas_id": 7,
"bkg": (0, 0, 0),
},
{
"canvas_name": "top10",
"canvas_size": 2048,
"canvas_id": 8,
"bkg": (197, 204, 184),
"historical_sizes" : [
["20220626", 1024],
]
},
]
async def fetch(session, url, offx, offy, image, bkg, needed = False): async def fetch(session, url, offx, offy, image, bkg, needed = False):
attempts = 0 attempts = 0
headers = {
'User-Agent': USER_AGENT
}
while True: while True:
try: try:
async with session.get(url) as resp: async with session.get(url, headers=headers) as resp:
if resp.status == 404: if resp.status == 404:
if needed: if needed:
img = PIL.Image.new('RGB', (256, 256), color=bkg) img = PIL.Image.new('RGB', (256, 256), color=bkg)
@ -91,11 +67,9 @@ async def fetch(session, url, offx, offy, image, bkg, needed = False):
attempts += 1 attempts += 1
pass pass
async def get_area(canvas, x, y, w, h, start_date, end_date): async def get_area(canvas_id, canvas, x, y, w, h, start_date, end_date):
canvas_data = canvases[canvas] canvas_size = canvas["size"]
canvas_id = canvas_data["canvas_id"] bkg = tuple(canvas['colors'][0])
canvas_size = canvas_data["canvas_size"]
bkg = canvas_data["bkg"]
delta = datetime.timedelta(days=1) delta = datetime.timedelta(days=1)
end_date = end_date.strftime("%Y%m%d") end_date = end_date.strftime("%Y%m%d")
@ -110,8 +84,8 @@ async def get_area(canvas, x, y, w, h, start_date, end_date):
start_date = start_date + delta start_date = start_date + delta
fetch_canvas_size = canvas_size fetch_canvas_size = canvas_size
if 'historical_sizes' in canvas_data: if 'historicalSizes' in canvas:
for ts in canvas_data['historical_sizes']: for ts in canvas['historicalSizes']:
date = ts[0] date = ts[0]
size = ts[1] size = ts[1]
if iter_date <= date: if iter_date <= date:
@ -122,14 +96,14 @@ async def get_area(canvas, x, y, w, h, start_date, end_date):
wc = (x + w - offset) // 256 wc = (x + w - offset) // 256
yc = (y - offset) // 256 yc = (y - offset) // 256
hc = (y + h - offset) // 256 hc = (y + h - offset) // 256
print("Load from %s / %s to %s / %s" % (xc, yc, wc + 1, hc + 1)) print("Load from %s / %s to %s / %s with canvas size %s" % (xc, yc, wc + 1, hc + 1, fetch_canvas_size))
tasks = [] tasks = []
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
image = PIL.Image.new('RGBA', (w, h)) image = PIL.Image.new('RGBA', (w, h))
for iy in range(yc, hc + 1): for iy in range(yc, hc + 1):
for ix in range(xc, wc + 1): for ix in range(xc, wc + 1):
url = 'https://storage.pixelplanet.fun/%s/%s/%s/%s/tiles/%s/%s.png' % (iter_date[0:4], iter_date[4:6] , iter_date[6:], canvas_id, ix, iy) url = '%s/%s/%s/%s/%s/tiles/%s/%s.png' % (PPFUN_STORAGE_URL, iter_date[0:4], iter_date[4:6] , iter_date[6:], canvas_id, ix, iy)
offx = ix * 256 + offset - x offx = ix * 256 + offset - x
offy = iy * 256 + offset - y offy = iy * 256 + offset - y
tasks.append(fetch(session, url, offx, offy, image, bkg, True)) tasks.append(fetch(session, url, offx, offy, image, bkg, True))
@ -143,10 +117,13 @@ async def get_area(canvas, x, y, w, h, start_date, end_date):
cnt += 1 cnt += 1
#frames.append(image.copy()) #frames.append(image.copy())
image.save('./timelapse/t%s.png' % (cnt)) image.save('./timelapse/t%s.png' % (cnt))
headers = {
'User-Agent': USER_AGENT
}
while True: while True:
async with session.get('https://pixelplanet.fun/history?day=%s&id=%s' % (iter_date, canvas_id)) as resp: async with session.get('%s/history?day=%s&id=%s' % (PPFUN_URL, iter_date, canvas_id), headers=headers) as resp:
try: try:
time_list = json.loads(await resp.text()) time_list = await resp.json()
break break
except: except:
print('Couldn\'t decode json for day %s, trying again' % (iter_date)) print('Couldn\'t decode json for day %s, trying again' % (iter_date))
@ -162,7 +139,7 @@ async def get_area(canvas, x, y, w, h, start_date, end_date):
image_rel = image.copy() image_rel = image.copy()
for iy in range(yc, hc + 1): for iy in range(yc, hc + 1):
for ix in range(xc, wc + 1): for ix in range(xc, wc + 1):
url = 'https://storage.pixelplanet.fun/%s/%s/%s/%s/%s/%s/%s.png' % (iter_date[0:4], iter_date[4:6] , iter_date[6:], canvas_id, time, ix, iy) url = '%s/%s/%s/%s/%s/%s/%s/%s.png' % (PPFUN_STORAGE_URL, iter_date[0:4], iter_date[4:6] , iter_date[6:], canvas_id, time, ix, iy)
offx = ix * 256 + offset - x offx = ix * 256 + offset - x
offy = iy * 256 + offset - y offy = iy * 256 + offset - y
tasks.append(fetch(session, url, offx, offy, image_rel, bkg)) tasks.append(fetch(session, url, offx, offy, image_rel, bkg))
@ -183,41 +160,63 @@ async def get_area(canvas, x, y, w, h, start_date, end_date):
#frames[0].save('timelapse.png', save_all=True, append_images=frames[1:], duration=100, loop=0, default_image=False, blend=1) #frames[0].save('timelapse.png', save_all=True, append_images=frames[1:], duration=100, loop=0, default_image=False, blend=1)
if __name__ == "__main__": async def main():
apime = await fetchMe()
if len(sys.argv) != 5 and len(sys.argv) != 6: if len(sys.argv) != 5 and len(sys.argv) != 6:
print("Download history of an area of pixelplanet - useful for timelapses") print("Download history of an area of pixelplanet - useful for timelapses")
print("") print("")
print("Usage: historyDownload.py canvasId startX_startY endX_endY start_date [end_date]") print("Usage: historyDownload.py canvasID startX_startY endX_endY start_date [end_date]")
print("") print("")
print("→start_date and end_date are in YYYY-MM-dd formate") print("→start_date and end_date are in YYYY-MM-dd formate")
print("→user R key on pixelplanet to copy coordinates)") print("→user R key on pixelplanet to copy coordinates)")
print("→images will be saved into timelapse folder)") print("→images will be saved into timelapse folder)")
print("canvasID: ", end='')
for canvas_id, canvas in apime['canvases'].items():
if 'v' in canvas and canvas['v']:
continue
print(f"{canvas_id} = {canvas['title']}", end=', ')
print()
print("-----------") print("-----------")
print("You can create a timelapse from the resulting files with ffmpeg like that:") print("You can create a timelapse from the resulting files with ffmpeg like that:")
print("ffmpeg -framerate 15 -f image2 -i timelapse/t%d.png -c:v libvpx-vp9 -pix_fmt yuva420p output.webm") print("ffmpeg -framerate 15 -f image2 -i timelapse/t%d.png -c:v libvpx-vp9 -pix_fmt yuva420p output.webm")
print("or lossless example:") print("or lossless example:")
print("ffmpeg -framerate 15 -f image2 -i timelapse/t%d.png -c:v libvpx-vp9 -pix_fmt yuv444p -qmin 0 -qmax 0 -lossless 1 -an output.webm") print("ffmpeg -framerate 15 -f image2 -i timelapse/t%d.png -c:v libvpx-vp9 -pix_fmt yuv444p -qmin 0 -qmax 0 -lossless 1 -an output.webm")
return
canvas_id = sys.argv[1]
if canvas_id not in apime['canvases']:
print("Invalid canvas selected")
return
canvas = apime['canvases'][canvas_id]
if 'v' in canvas and canvas['v']:
print("Can\'t get area for 3D canvas")
return
start = sys.argv[2].split('_')
end = sys.argv[3].split('_')
start_date = datetime.date.fromisoformat(sys.argv[4])
if len(sys.argv) == 6:
end_date = datetime.date.fromisoformat(sys.argv[5])
else: else:
canvas = int(sys.argv[1]) end_date = datetime.date.today()
start = sys.argv[2].split('_') x = int(start[0])
end = sys.argv[3].split('_') y = int(start[1])
start_date = datetime.date.fromisoformat(sys.argv[4]) w = int(end[0]) - x + 1
if len(sys.argv) == 6: h = int( end[1]) - y + 1
end_date = datetime.date.fromisoformat(sys.argv[5]) if not os.path.exists('./timelapse'):
else: os.mkdir('./timelapse')
end_date = datetime.date.today() await get_area(canvas_id, canvas, x, y, w, h, start_date, end_date)
x = int(start[0]) print("Done!")
y = int(start[1]) print("to create a timelapse from it:")
w = int(end[0]) - x + 1 print("ffmpeg -framerate 15 -f image2 -i timelapse/t%d.png -c:v libvpx-vp9 -pix_fmt yuva420p output.webm")
h = int( end[1]) - y + 1 print("example with scaling *3 and audio track:")
loop = asyncio.get_event_loop() print("ffmpeg -i ./audio.mp3 -framerate 8 -f image2 -i timelapse/t%d.png -map 0:a -map 1:v -vf scale=iw*3:-1 -shortest -c:v libvpx-vp9 -c:a libvorbis -pix_fmt yuva420p output.webm")
if not os.path.exists('./timelapse'): print("lossless example:")
os.mkdir('./timelapse') print("ffmpeg -framerate 15 -f image2 -i timelapse/t%d.png -c:v libvpx-vp9 -pix_fmt yuv444p -qmin 0 -qmax 0 -lossless 1 -an output.webm")
loop.run_until_complete(get_area(canvas, x, y, w, h, start_date, end_date))
print("Done!") if __name__ == "__main__":
print("to create a timelapse from it:") asyncio.run(main())
print("ffmpeg -framerate 15 -f image2 -i timelapse/t%d.png -c:v libvpx-vp9 -pix_fmt yuva420p output.webm")
print("example with scaling *3 and audio track:")
print("ffmpeg -i ./audio.mp3 -framerate 8 -f image2 -i timelapse/t%d.png -map 0:a -map 1:v -vf scale=iw*3:-1 -shortest -c:v libvpx-vp9 -c:a libvorbis -pix_fmt yuva420p output.webm")
print("lossless example:")
print("ffmpeg -framerate 15 -f image2 -i timelapse/t%d.png -c:v libvpx-vp9 -pix_fmt yuv444p -qmin 0 -qmax 0 -lossless 1 -an output.webm")