Update app.py
Browse files
app.py
CHANGED
|
@@ -1869,44 +1869,74 @@ def similarity_matching(sprites_data: dict, project_folder: str, top_k: int = 1,
|
|
| 1869 |
matched_indices = sorted({idx for lst in per_sprite_matched_indices for idx in lst})
|
| 1870 |
print("matched_indices------------------>",matched_indices)
|
| 1871 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1872 |
sprite_base_p = Path(sprite_base_path).resolve(strict=False)
|
| 1873 |
backdrop_base_p = Path(backdrop_base_path).resolve(strict=False)
|
| 1874 |
project_folder_p = Path(project_folder)
|
| 1875 |
project_folder_p.mkdir(parents=True, exist_ok=True)
|
| 1876 |
|
|
|
|
|
|
|
|
|
|
| 1877 |
def display_like_windows_no_lead(p: Path) -> str:
|
| 1878 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1879 |
if s.startswith("/"):
|
| 1880 |
s = s[1:]
|
| 1881 |
return s.replace("/", "\\")
|
| 1882 |
|
| 1883 |
def is_subpath(child: Path, parent: Path) -> bool:
|
|
|
|
| 1884 |
try:
|
|
|
|
| 1885 |
child.relative_to(parent)
|
| 1886 |
return True
|
| 1887 |
except Exception:
|
| 1888 |
return False
|
| 1889 |
-
|
| 1890 |
-
#
|
|
|
|
|
|
|
|
|
|
| 1891 |
for matched_idx in matched_indices:
|
|
|
|
| 1892 |
if not (0 <= matched_idx < len(paths_list)):
|
| 1893 |
print(f" β matched_idx {matched_idx} out of range, skipping")
|
| 1894 |
continue
|
|
|
|
| 1895 |
matched_image_path = paths_list[matched_idx]
|
| 1896 |
-
matched_path_p = Path(matched_image_path).resolve(strict=False)
|
| 1897 |
-
matched_folder_p = matched_path_p.parent
|
| 1898 |
matched_filename = matched_path_p.name
|
|
|
|
|
|
|
| 1899 |
matched_folder_display = display_like_windows_no_lead(matched_folder_p)
|
|
|
|
| 1900 |
print(f"Processing matched image: {matched_image_path}")
|
| 1901 |
print(f" - Folder: {matched_folder_display}")
|
| 1902 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1903 |
folder_key = matched_folder_p.as_posix()
|
| 1904 |
-
|
| 1905 |
-
# SPRITE
|
| 1906 |
if is_subpath(matched_folder_p, sprite_base_p) and folder_key not in copied_sprite_folders:
|
| 1907 |
print(f"Processing SPRITE folder: {matched_folder_display}")
|
| 1908 |
copied_sprite_folders.add(folder_key)
|
|
|
|
| 1909 |
sprite_json_path = matched_folder_p / "sprite.json"
|
|
|
|
|
|
|
| 1910 |
if sprite_json_path.exists() and sprite_json_path.is_file():
|
| 1911 |
try:
|
| 1912 |
with sprite_json_path.open("r", encoding="utf-8") as f:
|
|
@@ -1917,15 +1947,19 @@ def similarity_matching(sprites_data: dict, project_folder: str, top_k: int = 1,
|
|
| 1917 |
print(f" β Failed to read sprite.json in {matched_folder_display}: {repr(e)}")
|
| 1918 |
else:
|
| 1919 |
print(f" β No sprite.json in {matched_folder_display}")
|
|
|
|
|
|
|
| 1920 |
try:
|
| 1921 |
sprite_files = list(matched_folder_p.iterdir())
|
| 1922 |
except Exception as e:
|
| 1923 |
sprite_files = []
|
| 1924 |
print(f" β Failed to list files in {matched_folder_display}: {repr(e)}")
|
|
|
|
| 1925 |
print(f" Files in sprite folder: {[p.name for p in sprite_files]}")
|
| 1926 |
for p in sprite_files:
|
| 1927 |
fname = p.name
|
| 1928 |
if fname in (matched_filename, "sprite.json"):
|
|
|
|
| 1929 |
continue
|
| 1930 |
if p.is_file():
|
| 1931 |
dst = project_folder_p / fname
|
|
@@ -1934,11 +1968,17 @@ def similarity_matching(sprites_data: dict, project_folder: str, top_k: int = 1,
|
|
| 1934 |
print(f" β Copied sprite asset: {p} -> {dst}")
|
| 1935 |
except Exception as e:
|
| 1936 |
print(f" β Failed to copy sprite asset {p}: {repr(e)}")
|
| 1937 |
-
|
| 1938 |
-
|
|
|
|
|
|
|
| 1939 |
if is_subpath(matched_folder_p, backdrop_base_p) and folder_key not in copied_backdrop_folders:
|
| 1940 |
print(f"Processing BACKDROP folder: {matched_folder_display}")
|
| 1941 |
copied_backdrop_folders.add(folder_key)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1942 |
backdrop_src = matched_folder_p / matched_filename
|
| 1943 |
backdrop_dst = project_folder_p / matched_filename
|
| 1944 |
if backdrop_src.exists() and backdrop_src.is_file():
|
|
@@ -1949,15 +1989,19 @@ def similarity_matching(sprites_data: dict, project_folder: str, top_k: int = 1,
|
|
| 1949 |
print(f" β Failed to copy matched backdrop image {backdrop_src}: {repr(e)}")
|
| 1950 |
else:
|
| 1951 |
print(f" β Matched backdrop source not found: {backdrop_src}")
|
|
|
|
|
|
|
| 1952 |
try:
|
| 1953 |
backdrop_files = list(matched_folder_p.iterdir())
|
| 1954 |
except Exception as e:
|
| 1955 |
backdrop_files = []
|
| 1956 |
print(f" β Failed to list files in {matched_folder_display}: {repr(e)}")
|
|
|
|
| 1957 |
print(f" Files in backdrop folder: {[p.name for p in backdrop_files]}")
|
| 1958 |
for p in backdrop_files:
|
| 1959 |
fname = p.name
|
| 1960 |
if fname in (matched_filename, "project.json"):
|
|
|
|
| 1961 |
continue
|
| 1962 |
if p.is_file():
|
| 1963 |
dst = project_folder_p / fname
|
|
@@ -1966,18 +2010,28 @@ def similarity_matching(sprites_data: dict, project_folder: str, top_k: int = 1,
|
|
| 1966 |
print(f" β Copied backdrop asset: {p} -> {dst}")
|
| 1967 |
except Exception as e:
|
| 1968 |
print(f" β Failed to copy backdrop asset {p}: {repr(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1969 |
pj = matched_folder_p / "project.json"
|
| 1970 |
if pj.exists() and pj.is_file():
|
| 1971 |
try:
|
| 1972 |
with pj.open("r", encoding="utf-8") as f:
|
| 1973 |
bd_json = json.load(f)
|
|
|
|
| 1974 |
for tgt in bd_json.get("targets", []):
|
| 1975 |
if tgt.get("isStage"):
|
| 1976 |
backdrop_data.append(tgt)
|
|
|
|
|
|
|
| 1977 |
except Exception as e:
|
| 1978 |
print(f" β Failed to read project.json in {matched_folder_display}: {repr(e)}")
|
| 1979 |
-
|
| 1980 |
-
|
|
|
|
|
|
|
|
|
|
| 1981 |
final_project = {
|
| 1982 |
"targets": [], "monitors": [], "extensions": [],
|
| 1983 |
"meta": {
|
|
@@ -1986,9 +2040,13 @@ def similarity_matching(sprites_data: dict, project_folder: str, top_k: int = 1,
|
|
| 1986 |
"agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
|
| 1987 |
}
|
| 1988 |
}
|
|
|
|
|
|
|
|
|
|
| 1989 |
for spr in project_data:
|
| 1990 |
if not spr.get("isStage", False):
|
| 1991 |
final_project["targets"].append(spr)
|
|
|
|
| 1992 |
if backdrop_data:
|
| 1993 |
all_costumes, sounds = [], []
|
| 1994 |
seen_costumes = set()
|
|
@@ -2491,185 +2549,185 @@ def similarity_matching(sprites_data: dict, project_folder: str, top_k: int = 1,
|
|
| 2491 |
|
| 2492 |
# # Flatten unique matched indices to process copying once per folder
|
| 2493 |
# matched_indices = sorted({idx for lst in per_sprite_matched_indices for idx in lst})
|
| 2494 |
-
#
|
| 2495 |
|
| 2496 |
-
#
|
| 2497 |
-
#
|
| 2498 |
-
#
|
| 2499 |
-
#
|
| 2500 |
|
| 2501 |
-
#
|
| 2502 |
-
#
|
| 2503 |
-
#
|
| 2504 |
-
#
|
| 2505 |
-
#
|
| 2506 |
|
| 2507 |
-
#
|
| 2508 |
-
#
|
| 2509 |
|
| 2510 |
-
#
|
| 2511 |
-
#
|
| 2512 |
-
#
|
| 2513 |
-
#
|
| 2514 |
-
#
|
| 2515 |
-
#
|
| 2516 |
-
#
|
| 2517 |
-
#
|
| 2518 |
-
#
|
| 2519 |
|
| 2520 |
-
#
|
| 2521 |
-
#
|
| 2522 |
-
#
|
| 2523 |
-
#
|
| 2524 |
-
#
|
| 2525 |
-
#
|
| 2526 |
-
#
|
| 2527 |
-
#
|
| 2528 |
|
| 2529 |
-
#
|
| 2530 |
-
#
|
| 2531 |
-
#
|
| 2532 |
|
| 2533 |
-
#
|
| 2534 |
-
#
|
| 2535 |
-
#
|
| 2536 |
-
#
|
| 2537 |
-
#
|
| 2538 |
|
| 2539 |
-
#
|
| 2540 |
-
#
|
| 2541 |
-
#
|
| 2542 |
-
#
|
| 2543 |
|
| 2544 |
-
#
|
| 2545 |
-
#
|
| 2546 |
|
| 2547 |
-
#
|
| 2548 |
-
#
|
| 2549 |
-
#
|
| 2550 |
-
#
|
| 2551 |
-
#
|
| 2552 |
|
| 2553 |
-
#
|
| 2554 |
-
#
|
| 2555 |
|
| 2556 |
-
#
|
| 2557 |
-
#
|
| 2558 |
-
#
|
| 2559 |
-
#
|
| 2560 |
|
| 2561 |
-
#
|
| 2562 |
-
#
|
| 2563 |
-
#
|
| 2564 |
-
#
|
| 2565 |
-
#
|
| 2566 |
-
#
|
| 2567 |
-
#
|
| 2568 |
-
#
|
| 2569 |
-
#
|
| 2570 |
-
#
|
| 2571 |
-
#
|
| 2572 |
-
#
|
| 2573 |
-
#
|
| 2574 |
|
| 2575 |
-
#
|
| 2576 |
-
#
|
| 2577 |
-
#
|
| 2578 |
-
#
|
| 2579 |
-
#
|
| 2580 |
-
#
|
| 2581 |
|
| 2582 |
-
#
|
| 2583 |
-
#
|
| 2584 |
-
#
|
| 2585 |
-
#
|
| 2586 |
-
#
|
| 2587 |
-
#
|
| 2588 |
-
#
|
| 2589 |
-
#
|
| 2590 |
-
#
|
| 2591 |
-
#
|
| 2592 |
-
#
|
| 2593 |
-
#
|
| 2594 |
-
#
|
| 2595 |
-
#
|
| 2596 |
-
#
|
| 2597 |
|
| 2598 |
-
#
|
| 2599 |
-
#
|
| 2600 |
-
#
|
| 2601 |
-
#
|
| 2602 |
-
#
|
| 2603 |
-
#
|
| 2604 |
|
| 2605 |
-
#
|
| 2606 |
-
#
|
| 2607 |
-
#
|
| 2608 |
-
#
|
| 2609 |
-
#
|
| 2610 |
-
#
|
| 2611 |
-
#
|
| 2612 |
-
#
|
| 2613 |
-
#
|
| 2614 |
-
#
|
| 2615 |
-
#
|
| 2616 |
|
| 2617 |
-
#
|
| 2618 |
-
#
|
| 2619 |
-
#
|
| 2620 |
-
#
|
| 2621 |
-
#
|
| 2622 |
-
#
|
| 2623 |
|
| 2624 |
-
#
|
| 2625 |
-
#
|
| 2626 |
-
#
|
| 2627 |
-
#
|
| 2628 |
-
#
|
| 2629 |
-
#
|
| 2630 |
-
#
|
| 2631 |
-
#
|
| 2632 |
-
#
|
| 2633 |
-
#
|
| 2634 |
-
#
|
| 2635 |
-
#
|
| 2636 |
-
#
|
| 2637 |
-
#
|
| 2638 |
-
#
|
| 2639 |
|
| 2640 |
-
#
|
| 2641 |
-
#
|
| 2642 |
-
#
|
| 2643 |
-
#
|
| 2644 |
-
#
|
| 2645 |
-
#
|
| 2646 |
-
#
|
| 2647 |
-
#
|
| 2648 |
-
#
|
| 2649 |
-
#
|
| 2650 |
-
#
|
| 2651 |
-
#
|
| 2652 |
-
#
|
| 2653 |
-
#
|
| 2654 |
-
#
|
| 2655 |
-
#
|
| 2656 |
|
| 2657 |
-
#
|
| 2658 |
|
| 2659 |
-
#
|
| 2660 |
-
#
|
| 2661 |
-
#
|
| 2662 |
-
#
|
| 2663 |
-
#
|
| 2664 |
-
#
|
| 2665 |
-
#
|
| 2666 |
-
#
|
| 2667 |
|
| 2668 |
|
| 2669 |
-
#
|
| 2670 |
-
#
|
| 2671 |
-
#
|
| 2672 |
-
#
|
| 2673 |
|
| 2674 |
# # then backdrop as the Stage
|
| 2675 |
# if backdrop_data:
|
|
|
|
| 1869 |
matched_indices = sorted({idx for lst in per_sprite_matched_indices for idx in lst})
|
| 1870 |
print("matched_indices------------------>",matched_indices)
|
| 1871 |
|
| 1872 |
+
import shutil
|
| 1873 |
+
import json
|
| 1874 |
+
import os
|
| 1875 |
+
from pathlib import Path
|
| 1876 |
+
|
| 1877 |
+
# normalize base paths once before the loop
|
| 1878 |
sprite_base_p = Path(sprite_base_path).resolve(strict=False)
|
| 1879 |
backdrop_base_p = Path(backdrop_base_path).resolve(strict=False)
|
| 1880 |
project_folder_p = Path(project_folder)
|
| 1881 |
project_folder_p.mkdir(parents=True, exist_ok=True)
|
| 1882 |
|
| 1883 |
+
copied_sprite_folders = set()
|
| 1884 |
+
copied_backdrop_folders = set()
|
| 1885 |
+
|
| 1886 |
def display_like_windows_no_lead(p: Path) -> str:
|
| 1887 |
+
"""
|
| 1888 |
+
For human-readable logs only β convert Path to a string like:
|
| 1889 |
+
"app\\blocks\\Backdrops\\Castle 2.sb3" (no leading slash).
|
| 1890 |
+
"""
|
| 1891 |
+
s = p.as_posix() # forward-slash string, safe for Path objects
|
| 1892 |
if s.startswith("/"):
|
| 1893 |
s = s[1:]
|
| 1894 |
return s.replace("/", "\\")
|
| 1895 |
|
| 1896 |
def is_subpath(child: Path, parent: Path) -> bool:
|
| 1897 |
+
"""Robust membership test: is child under parent?"""
|
| 1898 |
try:
|
| 1899 |
+
# use non-strict resolve only if needed, but avoid exceptions
|
| 1900 |
child.relative_to(parent)
|
| 1901 |
return True
|
| 1902 |
except Exception:
|
| 1903 |
return False
|
| 1904 |
+
|
| 1905 |
+
# Flatten unique matched indices (if not already)
|
| 1906 |
+
matched_indices = sorted({idx for lst in per_sprite_matched_indices for idx in lst})
|
| 1907 |
+
print("matched_indices------------------>", matched_indices)
|
| 1908 |
+
|
| 1909 |
for matched_idx in matched_indices:
|
| 1910 |
+
# defensive check
|
| 1911 |
if not (0 <= matched_idx < len(paths_list)):
|
| 1912 |
print(f" β matched_idx {matched_idx} out of range, skipping")
|
| 1913 |
continue
|
| 1914 |
+
|
| 1915 |
matched_image_path = paths_list[matched_idx]
|
| 1916 |
+
matched_path_p = Path(matched_image_path).resolve(strict=False) # keep as Path
|
| 1917 |
+
matched_folder_p = matched_path_p.parent # Path object
|
| 1918 |
matched_filename = matched_path_p.name
|
| 1919 |
+
|
| 1920 |
+
# Prepare display-only string (do NOT reassign matched_folder_p)
|
| 1921 |
matched_folder_display = display_like_windows_no_lead(matched_folder_p)
|
| 1922 |
+
|
| 1923 |
print(f"Processing matched image: {matched_image_path}")
|
| 1924 |
print(f" - Folder: {matched_folder_display}")
|
| 1925 |
+
print(f" - Sprite path: {display_like_windows_no_lead(sprite_base_p)}")
|
| 1926 |
+
print(f" - Backdrop path: {display_like_windows_no_lead(backdrop_base_p)}")
|
| 1927 |
+
print(f" - Filename: {matched_filename}")
|
| 1928 |
+
|
| 1929 |
+
# Use a canonical string to store in the copied set (POSIX absolute-ish)
|
| 1930 |
folder_key = matched_folder_p.as_posix()
|
| 1931 |
+
|
| 1932 |
+
# ---------- SPRITE ----------
|
| 1933 |
if is_subpath(matched_folder_p, sprite_base_p) and folder_key not in copied_sprite_folders:
|
| 1934 |
print(f"Processing SPRITE folder: {matched_folder_display}")
|
| 1935 |
copied_sprite_folders.add(folder_key)
|
| 1936 |
+
|
| 1937 |
sprite_json_path = matched_folder_p / "sprite.json"
|
| 1938 |
+
print("sprite_json_path----------------------->", sprite_json_path)
|
| 1939 |
+
print("copied sprite folder----------------------->", copied_sprite_folders)
|
| 1940 |
if sprite_json_path.exists() and sprite_json_path.is_file():
|
| 1941 |
try:
|
| 1942 |
with sprite_json_path.open("r", encoding="utf-8") as f:
|
|
|
|
| 1947 |
print(f" β Failed to read sprite.json in {matched_folder_display}: {repr(e)}")
|
| 1948 |
else:
|
| 1949 |
print(f" β No sprite.json in {matched_folder_display}")
|
| 1950 |
+
|
| 1951 |
+
# copy non-matching files from the sprite folder (except matched image and sprite.json)
|
| 1952 |
try:
|
| 1953 |
sprite_files = list(matched_folder_p.iterdir())
|
| 1954 |
except Exception as e:
|
| 1955 |
sprite_files = []
|
| 1956 |
print(f" β Failed to list files in {matched_folder_display}: {repr(e)}")
|
| 1957 |
+
|
| 1958 |
print(f" Files in sprite folder: {[p.name for p in sprite_files]}")
|
| 1959 |
for p in sprite_files:
|
| 1960 |
fname = p.name
|
| 1961 |
if fname in (matched_filename, "sprite.json"):
|
| 1962 |
+
print(f" Skipping {fname} (matched image or sprite.json)")
|
| 1963 |
continue
|
| 1964 |
if p.is_file():
|
| 1965 |
dst = project_folder_p / fname
|
|
|
|
| 1968 |
print(f" β Copied sprite asset: {p} -> {dst}")
|
| 1969 |
except Exception as e:
|
| 1970 |
print(f" β Failed to copy sprite asset {p}: {repr(e)}")
|
| 1971 |
+
else:
|
| 1972 |
+
print(f" Skipping {fname} (not a file)")
|
| 1973 |
+
|
| 1974 |
+
# ---------- BACKDROP ----------
|
| 1975 |
if is_subpath(matched_folder_p, backdrop_base_p) and folder_key not in copied_backdrop_folders:
|
| 1976 |
print(f"Processing BACKDROP folder: {matched_folder_display}")
|
| 1977 |
copied_backdrop_folders.add(folder_key)
|
| 1978 |
+
print("backdrop_base_path----------------------->", display_like_windows_no_lead(backdrop_base_p))
|
| 1979 |
+
print("copied backdrop folder----------------------->", copied_backdrop_folders)
|
| 1980 |
+
|
| 1981 |
+
# copy matched backdrop image
|
| 1982 |
backdrop_src = matched_folder_p / matched_filename
|
| 1983 |
backdrop_dst = project_folder_p / matched_filename
|
| 1984 |
if backdrop_src.exists() and backdrop_src.is_file():
|
|
|
|
| 1989 |
print(f" β Failed to copy matched backdrop image {backdrop_src}: {repr(e)}")
|
| 1990 |
else:
|
| 1991 |
print(f" β Matched backdrop source not found: {backdrop_src}")
|
| 1992 |
+
|
| 1993 |
+
# copy other files from folder (skip project.json and matched image)
|
| 1994 |
try:
|
| 1995 |
backdrop_files = list(matched_folder_p.iterdir())
|
| 1996 |
except Exception as e:
|
| 1997 |
backdrop_files = []
|
| 1998 |
print(f" β Failed to list files in {matched_folder_display}: {repr(e)}")
|
| 1999 |
+
|
| 2000 |
print(f" Files in backdrop folder: {[p.name for p in backdrop_files]}")
|
| 2001 |
for p in backdrop_files:
|
| 2002 |
fname = p.name
|
| 2003 |
if fname in (matched_filename, "project.json"):
|
| 2004 |
+
print(f" Skipping {fname} (matched image or project.json)")
|
| 2005 |
continue
|
| 2006 |
if p.is_file():
|
| 2007 |
dst = project_folder_p / fname
|
|
|
|
| 2010 |
print(f" β Copied backdrop asset: {p} -> {dst}")
|
| 2011 |
except Exception as e:
|
| 2012 |
print(f" β Failed to copy backdrop asset {p}: {repr(e)}")
|
| 2013 |
+
else:
|
| 2014 |
+
print(f" Skipping {fname} (not a file)")
|
| 2015 |
+
|
| 2016 |
+
# read project.json to extract Stage/targets
|
| 2017 |
pj = matched_folder_p / "project.json"
|
| 2018 |
if pj.exists() and pj.is_file():
|
| 2019 |
try:
|
| 2020 |
with pj.open("r", encoding="utf-8") as f:
|
| 2021 |
bd_json = json.load(f)
|
| 2022 |
+
stage_count = 0
|
| 2023 |
for tgt in bd_json.get("targets", []):
|
| 2024 |
if tgt.get("isStage"):
|
| 2025 |
backdrop_data.append(tgt)
|
| 2026 |
+
stage_count += 1
|
| 2027 |
+
print(f" β Successfully read project.json from {matched_folder_display}, found {stage_count} stage(s)")
|
| 2028 |
except Exception as e:
|
| 2029 |
print(f" β Failed to read project.json in {matched_folder_display}: {repr(e)}")
|
| 2030 |
+
else:
|
| 2031 |
+
print(f" β No project.json in {matched_folder_display}")
|
| 2032 |
+
|
| 2033 |
+
print("---")
|
| 2034 |
+
|
| 2035 |
final_project = {
|
| 2036 |
"targets": [], "monitors": [], "extensions": [],
|
| 2037 |
"meta": {
|
|
|
|
| 2040 |
"agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
|
| 2041 |
}
|
| 2042 |
}
|
| 2043 |
+
|
| 2044 |
+
|
| 2045 |
+
# Add sprite targets (non-stage)
|
| 2046 |
for spr in project_data:
|
| 2047 |
if not spr.get("isStage", False):
|
| 2048 |
final_project["targets"].append(spr)
|
| 2049 |
+
|
| 2050 |
if backdrop_data:
|
| 2051 |
all_costumes, sounds = [], []
|
| 2052 |
seen_costumes = set()
|
|
|
|
| 2549 |
|
| 2550 |
# # Flatten unique matched indices to process copying once per folder
|
| 2551 |
# matched_indices = sorted({idx for lst in per_sprite_matched_indices for idx in lst})
|
| 2552 |
+
# print("matched_indices------------------>",matched_indices)
|
| 2553 |
|
| 2554 |
+
# import shutil
|
| 2555 |
+
# import json
|
| 2556 |
+
# import os
|
| 2557 |
+
# from pathlib import Path
|
| 2558 |
|
| 2559 |
+
# # normalize base paths once before the loop
|
| 2560 |
+
# sprite_base_p = Path(sprite_base_path).resolve(strict=False)
|
| 2561 |
+
# backdrop_base_p = Path(backdrop_base_path).resolve(strict=False)
|
| 2562 |
+
# project_folder_p = Path(project_folder)
|
| 2563 |
+
# project_folder_p.mkdir(parents=True, exist_ok=True)
|
| 2564 |
|
| 2565 |
+
# copied_sprite_folders = set()
|
| 2566 |
+
# copied_backdrop_folders = set()
|
| 2567 |
|
| 2568 |
+
# def display_like_windows_no_lead(p: Path) -> str:
|
| 2569 |
+
# """
|
| 2570 |
+
# For human-readable logs only β convert Path to a string like:
|
| 2571 |
+
# "app\\blocks\\Backdrops\\Castle 2.sb3" (no leading slash).
|
| 2572 |
+
# """
|
| 2573 |
+
# s = p.as_posix() # forward-slash string, safe for Path objects
|
| 2574 |
+
# if s.startswith("/"):
|
| 2575 |
+
# s = s[1:]
|
| 2576 |
+
# return s.replace("/", "\\")
|
| 2577 |
|
| 2578 |
+
# def is_subpath(child: Path, parent: Path) -> bool:
|
| 2579 |
+
# """Robust membership test: is child under parent?"""
|
| 2580 |
+
# try:
|
| 2581 |
+
# # use non-strict resolve only if needed, but avoid exceptions
|
| 2582 |
+
# child.relative_to(parent)
|
| 2583 |
+
# return True
|
| 2584 |
+
# except Exception:
|
| 2585 |
+
# return False
|
| 2586 |
|
| 2587 |
+
# # Flatten unique matched indices (if not already)
|
| 2588 |
+
# matched_indices = sorted({idx for lst in per_sprite_matched_indices for idx in lst})
|
| 2589 |
+
# print("matched_indices------------------>", matched_indices)
|
| 2590 |
|
| 2591 |
+
# for matched_idx in matched_indices:
|
| 2592 |
+
# # defensive check
|
| 2593 |
+
# if not (0 <= matched_idx < len(paths_list)):
|
| 2594 |
+
# print(f" β matched_idx {matched_idx} out of range, skipping")
|
| 2595 |
+
# continue
|
| 2596 |
|
| 2597 |
+
# matched_image_path = paths_list[matched_idx]
|
| 2598 |
+
# matched_path_p = Path(matched_image_path).resolve(strict=False) # keep as Path
|
| 2599 |
+
# matched_folder_p = matched_path_p.parent # Path object
|
| 2600 |
+
# matched_filename = matched_path_p.name
|
| 2601 |
|
| 2602 |
+
# # Prepare display-only string (do NOT reassign matched_folder_p)
|
| 2603 |
+
# matched_folder_display = display_like_windows_no_lead(matched_folder_p)
|
| 2604 |
|
| 2605 |
+
# print(f"Processing matched image: {matched_image_path}")
|
| 2606 |
+
# print(f" - Folder: {matched_folder_display}")
|
| 2607 |
+
# print(f" - Sprite path: {display_like_windows_no_lead(sprite_base_p)}")
|
| 2608 |
+
# print(f" - Backdrop path: {display_like_windows_no_lead(backdrop_base_p)}")
|
| 2609 |
+
# print(f" - Filename: {matched_filename}")
|
| 2610 |
|
| 2611 |
+
# # Use a canonical string to store in the copied set (POSIX absolute-ish)
|
| 2612 |
+
# folder_key = matched_folder_p.as_posix()
|
| 2613 |
|
| 2614 |
+
# # ---------- SPRITE ----------
|
| 2615 |
+
# if is_subpath(matched_folder_p, sprite_base_p) and folder_key not in copied_sprite_folders:
|
| 2616 |
+
# print(f"Processing SPRITE folder: {matched_folder_display}")
|
| 2617 |
+
# copied_sprite_folders.add(folder_key)
|
| 2618 |
|
| 2619 |
+
# sprite_json_path = matched_folder_p / "sprite.json"
|
| 2620 |
+
# print("sprite_json_path----------------------->", sprite_json_path)
|
| 2621 |
+
# print("copied sprite folder----------------------->", copied_sprite_folders)
|
| 2622 |
+
# if sprite_json_path.exists() and sprite_json_path.is_file():
|
| 2623 |
+
# try:
|
| 2624 |
+
# with sprite_json_path.open("r", encoding="utf-8") as f:
|
| 2625 |
+
# sprite_info = json.load(f)
|
| 2626 |
+
# project_data.append(sprite_info)
|
| 2627 |
+
# print(f" β Successfully read sprite.json from {matched_folder_display}")
|
| 2628 |
+
# except Exception as e:
|
| 2629 |
+
# print(f" β Failed to read sprite.json in {matched_folder_display}: {repr(e)}")
|
| 2630 |
+
# else:
|
| 2631 |
+
# print(f" β No sprite.json in {matched_folder_display}")
|
| 2632 |
|
| 2633 |
+
# # copy non-matching files from the sprite folder (except matched image and sprite.json)
|
| 2634 |
+
# try:
|
| 2635 |
+
# sprite_files = list(matched_folder_p.iterdir())
|
| 2636 |
+
# except Exception as e:
|
| 2637 |
+
# sprite_files = []
|
| 2638 |
+
# print(f" β Failed to list files in {matched_folder_display}: {repr(e)}")
|
| 2639 |
|
| 2640 |
+
# print(f" Files in sprite folder: {[p.name for p in sprite_files]}")
|
| 2641 |
+
# for p in sprite_files:
|
| 2642 |
+
# fname = p.name
|
| 2643 |
+
# if fname in (matched_filename, "sprite.json"):
|
| 2644 |
+
# print(f" Skipping {fname} (matched image or sprite.json)")
|
| 2645 |
+
# continue
|
| 2646 |
+
# if p.is_file():
|
| 2647 |
+
# dst = project_folder_p / fname
|
| 2648 |
+
# try:
|
| 2649 |
+
# shutil.copy2(str(p), str(dst))
|
| 2650 |
+
# print(f" β Copied sprite asset: {p} -> {dst}")
|
| 2651 |
+
# except Exception as e:
|
| 2652 |
+
# print(f" β Failed to copy sprite asset {p}: {repr(e)}")
|
| 2653 |
+
# else:
|
| 2654 |
+
# print(f" Skipping {fname} (not a file)")
|
| 2655 |
|
| 2656 |
+
# # ---------- BACKDROP ----------
|
| 2657 |
+
# if is_subpath(matched_folder_p, backdrop_base_p) and folder_key not in copied_backdrop_folders:
|
| 2658 |
+
# print(f"Processing BACKDROP folder: {matched_folder_display}")
|
| 2659 |
+
# copied_backdrop_folders.add(folder_key)
|
| 2660 |
+
# print("backdrop_base_path----------------------->", display_like_windows_no_lead(backdrop_base_p))
|
| 2661 |
+
# print("copied backdrop folder----------------------->", copied_backdrop_folders)
|
| 2662 |
|
| 2663 |
+
# # copy matched backdrop image
|
| 2664 |
+
# backdrop_src = matched_folder_p / matched_filename
|
| 2665 |
+
# backdrop_dst = project_folder_p / matched_filename
|
| 2666 |
+
# if backdrop_src.exists() and backdrop_src.is_file():
|
| 2667 |
+
# try:
|
| 2668 |
+
# shutil.copy2(str(backdrop_src), str(backdrop_dst))
|
| 2669 |
+
# print(f" β Copied matched backdrop image: {backdrop_src} -> {backdrop_dst}")
|
| 2670 |
+
# except Exception as e:
|
| 2671 |
+
# print(f" β Failed to copy matched backdrop image {backdrop_src}: {repr(e)}")
|
| 2672 |
+
# else:
|
| 2673 |
+
# print(f" β Matched backdrop source not found: {backdrop_src}")
|
| 2674 |
|
| 2675 |
+
# # copy other files from folder (skip project.json and matched image)
|
| 2676 |
+
# try:
|
| 2677 |
+
# backdrop_files = list(matched_folder_p.iterdir())
|
| 2678 |
+
# except Exception as e:
|
| 2679 |
+
# backdrop_files = []
|
| 2680 |
+
# print(f" β Failed to list files in {matched_folder_display}: {repr(e)}")
|
| 2681 |
|
| 2682 |
+
# print(f" Files in backdrop folder: {[p.name for p in backdrop_files]}")
|
| 2683 |
+
# for p in backdrop_files:
|
| 2684 |
+
# fname = p.name
|
| 2685 |
+
# if fname in (matched_filename, "project.json"):
|
| 2686 |
+
# print(f" Skipping {fname} (matched image or project.json)")
|
| 2687 |
+
# continue
|
| 2688 |
+
# if p.is_file():
|
| 2689 |
+
# dst = project_folder_p / fname
|
| 2690 |
+
# try:
|
| 2691 |
+
# shutil.copy2(str(p), str(dst))
|
| 2692 |
+
# print(f" β Copied backdrop asset: {p} -> {dst}")
|
| 2693 |
+
# except Exception as e:
|
| 2694 |
+
# print(f" β Failed to copy backdrop asset {p}: {repr(e)}")
|
| 2695 |
+
# else:
|
| 2696 |
+
# print(f" Skipping {fname} (not a file)")
|
| 2697 |
|
| 2698 |
+
# # read project.json to extract Stage/targets
|
| 2699 |
+
# pj = matched_folder_p / "project.json"
|
| 2700 |
+
# if pj.exists() and pj.is_file():
|
| 2701 |
+
# try:
|
| 2702 |
+
# with pj.open("r", encoding="utf-8") as f:
|
| 2703 |
+
# bd_json = json.load(f)
|
| 2704 |
+
# stage_count = 0
|
| 2705 |
+
# for tgt in bd_json.get("targets", []):
|
| 2706 |
+
# if tgt.get("isStage"):
|
| 2707 |
+
# backdrop_data.append(tgt)
|
| 2708 |
+
# stage_count += 1
|
| 2709 |
+
# print(f" β Successfully read project.json from {matched_folder_display}, found {stage_count} stage(s)")
|
| 2710 |
+
# except Exception as e:
|
| 2711 |
+
# print(f" β Failed to read project.json in {matched_folder_display}: {repr(e)}")
|
| 2712 |
+
# else:
|
| 2713 |
+
# print(f" β No project.json in {matched_folder_display}")
|
| 2714 |
|
| 2715 |
+
# print("---")
|
| 2716 |
|
| 2717 |
+
# final_project = {
|
| 2718 |
+
# "targets": [], "monitors": [], "extensions": [],
|
| 2719 |
+
# "meta": {
|
| 2720 |
+
# "semver": "3.0.0",
|
| 2721 |
+
# "vm": "11.3.0",
|
| 2722 |
+
# "agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36"
|
| 2723 |
+
# }
|
| 2724 |
+
# }
|
| 2725 |
|
| 2726 |
|
| 2727 |
+
# # Add sprite targets (non-stage)
|
| 2728 |
+
# for spr in project_data:
|
| 2729 |
+
# if not spr.get("isStage", False):
|
| 2730 |
+
# final_project["targets"].append(spr)
|
| 2731 |
|
| 2732 |
# # then backdrop as the Stage
|
| 2733 |
# if backdrop_data:
|