diff options
author | Minteck <contact@minteck.org> | 2022-11-28 17:30:40 +0100 |
---|---|---|
committer | Minteck <contact@minteck.org> | 2022-11-28 17:30:40 +0100 |
commit | 0beaa17c10bd8fea776adaa08e41c1d543058c03 (patch) | |
tree | ef554bc27470ac257a554d228cfdd656ffb96e18 | |
download | maneplace-timelapse-0beaa17c10bd8fea776adaa08e41c1d543058c03.tar.gz maneplace-timelapse-0beaa17c10bd8fea776adaa08e41c1d543058c03.tar.bz2 maneplace-timelapse-0beaa17c10bd8fea776adaa08e41c1d543058c03.zip |
Initial commit
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | .idea/.gitignore | 8 | ||||
-rw-r--r-- | .idea/deployment.xml | 21 | ||||
-rw-r--r-- | .idea/discord.xml | 7 | ||||
-rw-r--r-- | .idea/inspectionProfiles/profiles_settings.xml | 6 | ||||
-rw-r--r-- | .idea/maneplace-timelapse.iml | 8 | ||||
-rw-r--r-- | .idea/misc.xml | 4 | ||||
-rw-r--r-- | .idea/modules.xml | 8 | ||||
-rw-r--r-- | .idea/sshConfigs.xml | 8 | ||||
-rw-r--r-- | .idea/webServers.xml | 14 | ||||
-rw-r--r-- | initial.png | bin | 0 -> 21716 bytes | |||
-rw-r--r-- | main.py | 186 | ||||
-rw-r--r-- | main2.py | 159 | ||||
-rw-r--r-- | user.py | 43 |
14 files changed, 478 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..50ed299 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +frame.png +data.json +frames +users +out.mp4 +out.webm diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..a3f0ef4 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="PublishConfigData" autoUpload="Always" serverName="zephyrheights" remoteFilesAllowedToDisappearOnAutoupload="false"> + <serverData> + <paths name="zephyrheights"> + <serverdata> + <mappings> + <mapping deploy="/mnt/maneplace-timelapse" local="$PROJECT_DIR$" web="/" /> + </mappings> + <excludedPaths> + <excludedPath local="true" path="$PROJECT_DIR$/frames" /> + <excludedPath local="true" path="$PROJECT_DIR$/data.json" /> + <excludedPath local="true" path="$PROJECT_DIR$/out.webm" /> + <excludedPath local="true" path="$PROJECT_DIR$/out.mp4" /> + </excludedPaths> + </serverdata> + </paths> + </serverData> + <option name="myAutoUpload" value="ALWAYS" /> + </component> +</project>
\ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..d8e9561 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="DiscordProjectSettings"> + <option name="show" value="PROJECT_FILES" /> + <option name="description" value="" /> + </component> +</project>
\ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ +<component name="InspectionProjectProfileManager"> + <settings> + <option name="USE_PROJECT_PROFILE" value="false" /> + <version value="1.0" /> + </settings> +</component>
\ No newline at end of file diff --git a/.idea/maneplace-timelapse.iml b/.idea/maneplace-timelapse.iml new file mode 100644 index 0000000..d0876a7 --- /dev/null +++ b/.idea/maneplace-timelapse.iml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="PYTHON_MODULE" version="4"> + <component name="NewModuleRootManager"> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module>
\ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..dc9ea49 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" /> +</project>
\ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d0ee548 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/maneplace-timelapse.iml" filepath="$PROJECT_DIR$/.idea/maneplace-timelapse.iml" /> + </modules> + </component> +</project>
\ No newline at end of file diff --git a/.idea/sshConfigs.xml b/.idea/sshConfigs.xml new file mode 100644 index 0000000..ebf677e --- /dev/null +++ b/.idea/sshConfigs.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="SshConfigs"> + <configs> + <sshConfig host="zephyrheights.equestria.dev" id="20eb5082-bb4d-4ccb-80b9-d1f885ee9ac8" keyPath="$USER_HOME$/.ssh/id_rsa" port="2222" nameFormat="DESCRIPTIVE" username="root" useOpenSSHConfig="true" /> + </configs> + </component> +</project>
\ No newline at end of file diff --git a/.idea/webServers.xml b/.idea/webServers.xml new file mode 100644 index 0000000..3b5af2a --- /dev/null +++ b/.idea/webServers.xml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="WebServers"> + <option name="servers"> + <webServer id="b1a8137c-ae95-45e8-9689-f27e4b37f34b" name="zephyrheights"> + <fileTransfer accessType="SFTP" host="zephyrheights.equestria.dev" port="2222" sshConfigId="20eb5082-bb4d-4ccb-80b9-d1f885ee9ac8" sshConfig="root@zephyrheights.equestria.dev:2222 key" keyPair="true"> + <advancedOptions> + <advancedOptions dataProtectionLevel="Private" keepAliveTimeout="0" passiveMode="true" shareSSLContext="true" /> + </advancedOptions> + </fileTransfer> + </webServer> + </option> + </component> +</project>
\ No newline at end of file diff --git a/initial.png b/initial.png Binary files differnew file mode 100644 index 0000000..5a7ef95 --- /dev/null +++ b/initial.png @@ -0,0 +1,186 @@ +import json +import time +import shutil +import os +import datetime +from PIL import Image + +divider = 60 +dates = {} + +try: + shutil.rmtree("./frames") +except FileNotFoundError: + pass + +os.mkdir("./frames") + +data = json.load(open('data.json')) +image = Image.open('initial.png') +initial = Image.open('initial.png') +image.save('frames/0000000000000000.png') + +total = len(data) + + +def hex_to_rgb(value): + value = value.lstrip('#') + lv = len(value) + return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)) + + +colors = [ + "#6D001A", + "#BE0039", + "#FF4500", + "#FFA800", + "#FFD635", + "#FFF8B8", + "#00A368", + "#00CC78", + "#7EED56", + "#00756F", + "#009EAA", + "#00CCC0", + "#2450A4", + "#3690EA", + "#51E9F4", + "#493AC1", + "#6A5CFF", + "#94B3FF", + "#811E9F", + "#B44AC0", + "#E4ABFF", + "#DE107F", + "#FF3881", + "#FF99AA", + "#6D482F", + "#9C6926", + "#FFB470", + "#000000", + "#515252", + "#898D90", + "#D4D7D9", + "#FFFFFF", + "#ffff5c", + "#d9d94a", + "#ff7313", + "#fce07c", + "#bdbd3e", + "#c0aa19", + "#8f8fe0", + "#6b6bd1", + "#9efe90", + "#360082", + "#00ccff", + "#44b1ce", + "#4a2157", + "#d676e3", + "#abfbff", + "#a11461", + "#592d1b", + "#914724", + "#cc6d42", + "#ff8559", + "#ffd5ad", + "#d39748", + "#fa74a4", + "#ffd1dc", + "#679112", + "#d39648", + "#9fc455", + "#d5ebad", + "#adafb0", + "#793ccf", + "#a771f7", + "#d3bff5", +] + +frame = 1 +frameFile = 1 +times = [] + +for event in data: + percentage = "%.2f" % ((frame / total) * 100) + remaining = total - frame + + if len(times) > 0: + avg = sum(times) / len(times) + else: + avg = 0 + + eta = None + + if frame > 1000: + eta = avg * remaining + + if eta is not None: + eta_seconds = round(eta / 1000000000) + eta_string = str(eta_seconds) + " seconds remaining" + done_by = datetime.datetime.fromtimestamp(round(time.time() + eta_seconds)).isoformat().split("T")[1] + + if eta_seconds > 60: + if eta_seconds > 3600: + if round(eta_seconds / 3600) > 1: + eta_string = str(round(eta_seconds / 3600)) + " hours remaining" + else: + eta_string = str(round(eta_seconds / 3600)) + " hour remaining" + else: + if round(eta_seconds / 60) > 1: + eta_string = str(round(eta_seconds / 60)) + " minutes remaining" + else: + eta_string = str(round(eta_seconds / 60)) + " minute remaining" + + print(f"\r{frame}/{total} ({percentage}% complete, {eta_string}, done at {done_by})", end="", flush=True) + else: + print(f"\r{frame}/{total} ({percentage}% complete, calculating...)", end="", flush=True) + + start = time.time_ns() + if 'x' in event and 'y' in event: + # Normal pixel placement + if colors[event['color']] is not None and event['userId'] != "591555636505083905": + image.putpixel((event['x'], event['y']), hex_to_rgb(colors[event['color']])) + else: + # Mod tool + if 0 <= event['x1'] <= 1000 and 0 <= event['x2'] <= 1000 \ + and 0 <= event['y1'] <= 1000 and 0 <= event['y2'] <= 1000: + for x in range(event['x1'], event['x2']): + for y in range(event['y1'], event['y2']): + if colors[event['color']] is not None: + image.putpixel((x, y), hex_to_rgb(colors[event['color']])) + else: + print(event) + + if frame % divider == 0: + image.save(f'frames/{str(frameFile).rjust(16, "0")}.png') + dates[str(frameFile / 60)] = event['timestamp'] + frameFile += 1 + + frame += 1 + + end = time.time_ns() + duration = end - start + times.append(duration) + +print("\r\nSaving video...") +os.system("ffmpeg -y -framerate 60 -pattern_type glob -i 'frames/*.png' -c:v libx264 out.pre.mp4") +os.system("ffmpeg -y -i out.pre.mp4 out.pre.webm") + +print("\r\nSaving metadata...") +with open('metadata.json', 'w') as f: + json.dump(dates, f) + +print("\r\nSwitching slots...") +try: + os.remove("out.old.mp4") +except FileNotFoundError: + pass +os.rename("out.mp4", "out.old.mp4") +os.rename("out.pre.mp4", "out.mp4") + +try: + os.remove("out.old.webm") +except FileNotFoundError: + pass +os.rename("out.webm", "out.old.webm") +os.rename("out.pre.webm", "out.webm") diff --git a/main2.py b/main2.py new file mode 100644 index 0000000..9730ba9 --- /dev/null +++ b/main2.py @@ -0,0 +1,159 @@ +import json +import time +import shutil +import os +import datetime +from PIL import Image + +divider = 10 +dates = {} + +data = json.load(open('data.json')) +image = Image.open('initial.png') +initial = Image.open('initial.png') +image.save('frame.png') + +total = len(data) + + +def hex_to_rgb(value): + value = value.lstrip('#') + return int(value[0:2], 16), int(value[2:4], 16), int(value[4:6], 16) + + +""" +def hex_to_rgb(value): + value = value.lstrip('#') + lv = len(value) + return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)) +""" + + +colors = [ + "#6D001A", + "#BE0039", + "#FF4500", + "#FFA800", + "#FFD635", + "#FFF8B8", + "#00A368", + "#00CC78", + "#7EED56", + "#00756F", + "#009EAA", + "#00CCC0", + "#2450A4", + "#3690EA", + "#51E9F4", + "#493AC1", + "#6A5CFF", + "#94B3FF", + "#811E9F", + "#B44AC0", + "#E4ABFF", + "#DE107F", + "#FF3881", + "#FF99AA", + "#6D482F", + "#9C6926", + "#FFB470", + "#000000", + "#515252", + "#898D90", + "#D4D7D9", + "#FFFFFF", + "#ffff5c", + "#d9d94a", + "#ff7313", + "#fce07c", + "#bdbd3e", + "#c0aa19", + "#8f8fe0", + "#6b6bd1", + "#9efe90", + "#360082", + "#00ccff", + "#44b1ce", + "#4a2157", + "#d676e3", + "#abfbff", + "#a11461", + "#592d1b", + "#914724", + "#cc6d42", + "#ff8559", + "#ffd5ad", + "#d39748", + "#fa74a4", + "#ffd1dc", + "#679112", + "#d39648", + "#9fc455", + "#d5ebad", + "#adafb0", + "#793ccf", + "#a771f7", + "#d3bff5", +] + +frame = 1 +frameFile = 1 +times = [] + +for event in data: + percentage = "%.2f" % ((frame / total) * 100) + remaining = total - frame + + if len(times) > 0: + avg = sum(times) / len(times) + else: + avg = 0 + + eta = None + + if frame > 1000: + eta = avg * remaining + + if eta is not None: + eta_seconds = round(eta / 1000000000) + eta_string = str(eta_seconds) + " seconds remaining" + done_by = datetime.datetime.fromtimestamp(round(time.time() + eta_seconds)).isoformat().split("T")[1] + + if eta_seconds > 60: + if eta_seconds > 3600: + if round(eta_seconds / 3600) > 1: + eta_string = str(round(eta_seconds / 3600)) + " hours remaining" + else: + eta_string = str(round(eta_seconds / 3600)) + " hour remaining" + else: + if round(eta_seconds / 60) > 1: + eta_string = str(round(eta_seconds / 60)) + " minutes remaining" + else: + eta_string = str(round(eta_seconds / 60)) + " minute remaining" + + print(f"\r{frame}/{total} ({percentage}% complete, {eta_string}, done at {done_by})", end="", flush=True) + else: + print(f"\r{frame}/{total} ({percentage}% complete, calculating...)", end="", flush=True) + + start = time.time_ns() + if 'x' in event and 'y' in event: + # Normal pixel placement + if colors[event['color']] is not None: + image.putpixel((event['x'], event['y']), hex_to_rgb(colors[event['color']])) + else: + # Mod tool + if 0 <= event['x1'] <= 1000 and 0 <= event['x2'] <= 1000 \ + and 0 <= event['y1'] <= 1000 and 0 <= event['y2'] <= 1000: + for x in range(event['x1'], event['x2']): + for y in range(event['y1'], event['y2']): + if colors[event['color']] is not None: + image.putpixel((x, y), hex_to_rgb(colors[event['color']])) + + frame += 1 + + end = time.time_ns() + duration = end - start + times.append(duration) + +print("\r\nSaving frame to 'frame.png'...") +image.save(f'frame.png') @@ -0,0 +1,43 @@ +import sys + +import json +import time +import os +from PIL import Image + +try: + os.mkdir("./users") +except FileExistsError: + pass + +data = json.load(open('data.json')) +users = [] + +for item in data: + if item['userId'] not in users: + users.append(item['userId']) + + +def hex_to_rgb(value): + value = value.lstrip('#') + lv = len(value) + return tuple(int(value[i:i + lv // 3], 16) for i in range(0, lv, lv // 3)) + + +length = len(users) +index = 1 + +for user in users: + image = Image.new(mode="RGB", size=(1000, 1000)) + + frame = 1 + times = [] + + for event in data: + start = time.time_ns() + if 'x' in event and 'y' in event and event['userId'] == user: + image.putpixel((event['x'], event['y']), (255, 255, 255)) + + print(f"Saving frame for {user} [{index}/{length}, {round((index / length) * 100, 2)}%]...") + image.save(f'users/{user}.png') + index += 1 |