Surprise! We've been running on hardware provided by BuyVM for a few months and wanted to show them a little appreciation.
Running a paste site comes with unique challenges, ones that aren't always obvious and hard to control. As such, BuyVM offered us a home where we could worry less about the hosting side of things and focus on maintaining a clean and useful service! Go check them out and show them some love!
Submitted on February 2, 2025 at 11:12 PM

New Paste 1 (Python)

import glob, os, sys, time
import cv2, ffmpeg, keyboard, tqdm, numpy as np, pyautogui as pg

map_position_url = "https://satisfactory-calculator.com/en/interactive-map#5.5;284600;-215237|gameLayer|"
saves_path = max(glob.glob(f"{os.getenv('LOCALAPPDATA')}/FactoryGame/Saved/SaveGames/[0-9]*"), key=os.path.getmtime)
count = len([f for f in os.listdir(saves_path) if f.endswith(".sav")])
origin = "https://satisfactory-calculator.com/en/interactive-map#5;0;0|gameLayer|"
width, height = pg.screenshot().width, pg.screenshot().height

should_exit = False

def sleep(t):
    time.sleep(t)
    if should_exit:
        raise KeyboardInterrupt

def await_visibility(img, hidden=False):
    for _ in range(80):
        try:
            pg.locateOnScreen(f"buttons/{img}.png", confidence=0.97)
            if not hidden:
                return
        except pg.ImageNotFoundException:
            if hidden:
                return
        sleep(0.5)
    raise TimeoutError

def wait_until_loaded():
    for _ in range(50):
        sleep(0.5)
        s = pg.screenshot()
        for x, y in np.ndindex((20, 20)):
            if s.getpixel((x * width // 20, y * height // 20)) == (221, 221, 221):
                pass
        else:
            return
    raise TimeoutError

def pan_map(x):
    pg.moveTo(max(0, x), 1)
    pg.mouseDown()
    sleep(0.2)
    pg.moveTo(max(0, -x), 1)
    sleep(0.2)
    pg.mouseUp()
    sleep(0.2)

def set_map_position(pos):
    pg.hotkey("ctrl", "l")
    pg.typewrite(pos)
    pg.press("enter")
    c = pg.pixel(width // 2, height // 2)
    while pg.pixelMatchesColor(width // 2, height // 2, c):
        sleep(0.2)
    wait_until_loaded()

def generate_missing_images(missing):
    for i in tqdm.tqdm(missing, desc="Generating images"):
        while True:
            try:
                await_visibility("upload_icon")
                if i != 0:
                    pg.click(pg.locateCenterOnScreen("buttons/upload_icon.png", confidence=0.97))
                    await_visibility("file_upload_dialog")
                    pg.hotkey("shift", "tab")
                    pg.hotkey("shift", "tab")
                    pg.press(["down"] + (["up"] if i == count else ["down"] * (count - i - 2)) + ["enter"])
                    await_visibility("upload_icon", hidden=True)
                    await_visibility("upload_icon")
                    await_visibility("player_icon")
                set_map_position(origin)
                for button in os.listdir("buttons/visibility_buttons"):
                    try:
                        pg.click(pg.locateCenterOnScreen(f"buttons/visibility_buttons/{button}", confidence=0.97))
                        await_visibility(f"visibility_buttons/{button.split('.')[0]}", hidden=True)
                    except pg.ImageNotFoundException:
                        continue
                set_map_position(map_position_url)
                pg.click("buttons/view_fullscreen.png")
                pg.moveTo(1, 1)
                sleep(4)
                wait_until_loaded()
                pan_map(-60)
                left = cv2.cvtColor(np.array(pg.screenshot()), cv2.COLOR_RGB2BGR)
                pan_map(120)
                right = cv2.cvtColor(np.array(pg.screenshot()), cv2.COLOR_RGB2BGR)
                cv2.imwrite(f"img/{i}.png", np.hstack([left[:, 60:-60], right[:, -180:-60]]))
                pg.hotkey("ctrl", "F5")
                break
            except (TimeoutError, pg.ImageNotFoundException):
                pg.keyDown("ctrl")
                pg.press(["t", "tab", "w", "9"], interval=0.01)
                pg.keyUp("ctrl")
                pg.typewrite(origin)
                pg.press("enter")
            finally:
                time.sleep(1)

def render_video():
    if "timelapse.mp4" in os.listdir():
        os.remove("timelapse.mp4")
    prev_img = cv2.imread(f"img/0.png")
    video = cv2.VideoWriter("temp/timelapse.avi", 0, 30, (width, height))
    mask = np.zeros((height, width))
    frames = []
    for i in tqdm.tqdm(range(count + 1), desc="Processing frames"):
        img = cv2.imread(f"img/{i}.png")
        diff = cv2.cvtColor(cv2.absdiff(prev_img, img), cv2.COLOR_BGR2GRAY) > 10
        for f in range(5 if i < count else 120):
            mask = np.minimum(1, diff + mask * 0.95)
            frame = (img * (mask[..., None] * 0.4 + 0.6)).astype(np.uint8)
            video.write(frame)
            if f % 5 == 0:
                frames.append(frame)
                diff = np.zeros((height, width))
        prev_img = img
    for frame in tqdm.tqdm(frames[::-2], desc="Adding reverse frames"):
        video.write(frame)
    video.release()
    ffmpeg.input("temp/timelapse.avi").output("timelapse.mp4", vcodec="libx264", crf=18).run()

def exit_handler(callback):
    if callback.name == "esc":
        global should_exit
        should_exit = True

def main():
    try:
        pg.PAUSE = 0.01
        keyboard.hook(exit_handler)
        for d in ["buttons/visibility_buttons", "img", "temp"]:
            os.makedirs(d, exist_ok=True)
        missing = [i for i in range(count + 1) if not os.path.exists(f"img/{i}.png")][::-1]
        generate_missing_images(missing)
        render_video()
    except KeyboardInterrupt:
        sys.exit(-1)
    finally:
        for file_name in os.listdir("temp"):
            os.remove(os.path.join("temp", file_name))

if __name__ == "__main__":
    main()