232 lines
6.5 KiB
Python
232 lines
6.5 KiB
Python
import json
|
|
import os
|
|
from aiohttp import request, web
|
|
from typing import TypedDict, List
|
|
import shutil
|
|
|
|
import server
|
|
import folder_paths
|
|
|
|
class FileInfoDict(TypedDict):
|
|
type: str
|
|
name: str
|
|
bytes: int
|
|
created_at: float
|
|
folder_path: str
|
|
notes: str
|
|
|
|
routes = server.PromptServer.instance.routes
|
|
|
|
comfy_path = os.path.dirname(folder_paths.__file__)
|
|
output_path = os.path.join(comfy_path, 'output')
|
|
browser_path = os.path.dirname(__file__)
|
|
collections_path = os.path.join(browser_path, 'collections')
|
|
|
|
image_extensions = ['.jpg', '.jpeg', '.png', '.gif', '.webp']
|
|
video_extensions = ['.mp4', '.mov', '.avi', '.webm', '.mkv']
|
|
|
|
# type = 'output' or 'collections'
|
|
def get_target_folder_files(folder_path: str, type: str = 'output'):
|
|
if '..' in folder_path:
|
|
return None
|
|
|
|
parent_path = output_path
|
|
if type == 'collections':
|
|
parent_path = collections_path
|
|
|
|
files: List[FileInfoDict] = []
|
|
target_path = os.path.join(parent_path, folder_path)
|
|
|
|
if not os.path.exists(target_path):
|
|
return None
|
|
|
|
folder_listing = os.scandir(target_path)
|
|
folder_listing = sorted(folder_listing, key=lambda f: f.stat().st_ctime, reverse=True)
|
|
for item in folder_listing:
|
|
if not os.path.exists(item.path):
|
|
continue
|
|
name = os.path.basename(item.path)
|
|
ext = os.path.splitext(name)[1].lower()
|
|
if not (item.is_dir() or ext in image_extensions or ext in video_extensions):
|
|
continue
|
|
|
|
created_at = item.stat().st_ctime
|
|
if item.is_file():
|
|
info_file_path = get_info_filename(item.path)
|
|
info_data = {}
|
|
if os.path.exists(info_file_path):
|
|
with open(info_file_path, 'r') as f:
|
|
info_data = json.load(f)
|
|
|
|
bytes = item.stat().st_size
|
|
files.append({
|
|
"type": "file",
|
|
"name": name,
|
|
"bytes": bytes,
|
|
"created_at": created_at,
|
|
"folder_path": folder_path,
|
|
"notes": info_data.get("notes", "")
|
|
})
|
|
elif item.is_dir():
|
|
files.append({
|
|
"type": "dir",
|
|
"name": name,
|
|
"bytes": 0,
|
|
"created_at": created_at,
|
|
"folder_path": folder_path,
|
|
"notes": ""
|
|
})
|
|
|
|
return files
|
|
|
|
|
|
def get_info_filename(filename):
|
|
return os.path.splitext(filename)[0] + "_info.json"
|
|
|
|
|
|
# folder_path
|
|
@routes.get("/browser/files")
|
|
async def api_get_files_root(request):
|
|
folder_path = request.query.get('folder_path', '')
|
|
files = get_target_folder_files(folder_path)
|
|
|
|
if files == None:
|
|
return web.Response(status=404)
|
|
|
|
return web.json_response({
|
|
'files': files
|
|
})
|
|
|
|
|
|
# filename, folder_path, type
|
|
@routes.delete("/browser/files")
|
|
async def api_delete_file(request):
|
|
json_data = await request.json()
|
|
filename = json_data['filename']
|
|
folder_path = json_data['folder_path'] or ''
|
|
parent_path = output_path
|
|
if json_data['type'] == 'collections':
|
|
parent_path = collections_path
|
|
|
|
target_path = os.path.join(parent_path, folder_path, filename)
|
|
if not os.path.exists(target_path):
|
|
return web.json_response(status=404)
|
|
|
|
os.remove(target_path)
|
|
info_file_path = get_info_filename(target_path)
|
|
if os.path.exists(info_file_path):
|
|
os.remove(info_file_path)
|
|
|
|
info_filename = get_info_filename(target_path)
|
|
if os.path.exists(info_filename):
|
|
os.remove(info_filename)
|
|
|
|
return web.Response(status=201)
|
|
|
|
|
|
@routes.put("/browser/collections/{filename}")
|
|
async def api_update_collection(request):
|
|
json_data = await request.json()
|
|
filename = request.match_info.get("filename", None)
|
|
folder_path = json_data['folder_path'] or ''
|
|
|
|
new_filename = json_data['filename'] or filename
|
|
notes = json_data['notes']
|
|
|
|
old_file_path = os.path.join(collections_path, folder_path, filename)
|
|
new_file_path = os.path.join(collections_path, folder_path, new_filename)
|
|
|
|
if not os.path.exists(old_file_path):
|
|
return web.Response(status=404)
|
|
|
|
if filename != new_filename:
|
|
shutil.move(
|
|
old_file_path,
|
|
new_file_path
|
|
)
|
|
old_info_file_path = get_info_filename(old_file_path)
|
|
if os.path.exists(old_info_file_path):
|
|
new_info_file_path = get_info_filename(new_file_path)
|
|
shutil.move(
|
|
old_info_file_path,
|
|
new_info_file_path
|
|
)
|
|
|
|
if notes:
|
|
extra = {
|
|
"notes": notes
|
|
}
|
|
info_file_path = get_info_filename(new_file_path)
|
|
with open(info_file_path, "w") as outfile:
|
|
json.dump(extra, outfile)
|
|
|
|
return web.Response(status=201)
|
|
|
|
|
|
@routes.get("/browser/collections")
|
|
async def api_get_collections(_):
|
|
files = get_target_folder_files('', 'collections')
|
|
|
|
if files == None:
|
|
return web.Response(status=404)
|
|
|
|
return web.json_response({
|
|
'files': files
|
|
})
|
|
|
|
# filename, folder_path
|
|
@routes.get("/browser/collections/view")
|
|
async def api_view_collection(request):
|
|
folder_path = request.query.get("folder_path", '')
|
|
filename = request.query.get("filename", None)
|
|
if not filename:
|
|
return web.Response(status=404)
|
|
|
|
file_path = os.path.join(collections_path, folder_path, filename)
|
|
|
|
if not os.path.exists(file_path):
|
|
return web.Response(status=404)
|
|
|
|
with open(file_path, 'rb') as f:
|
|
media_file = f.read()
|
|
|
|
content_type = 'application/json'
|
|
file_extension = os.path.splitext(filename)[1].lower()
|
|
if file_extension in image_extensions:
|
|
content_type = f'image/{file_extension[1:]}'
|
|
if file_extension in video_extensions:
|
|
content_type = f'video/{file_extension[1:]}'
|
|
|
|
return web.Response(
|
|
body=media_file,
|
|
content_type=content_type,
|
|
headers={"Content-Disposition": f"filename=\"{filename}\""}
|
|
)
|
|
|
|
# filename, folder_path
|
|
@routes.post("/browser/collections")
|
|
async def api_add_to_collections(request):
|
|
json_data = await request.json()
|
|
filename = json_data['filename']
|
|
folder_path = json_data['folder_path'] or ''
|
|
|
|
if not os.path.exists(collections_path):
|
|
os.mkdir(collections_path)
|
|
|
|
source_file_path = os.path.join(output_path, folder_path, filename)
|
|
if not os.path.exists(source_file_path):
|
|
return web.Response(status=404)
|
|
|
|
shutil.copy(source_file_path, collections_path)
|
|
|
|
return web.Response(status=201)
|
|
|
|
|
|
routes.static(
|
|
'/browser/web',
|
|
os.path.join(browser_path, 'web/build')
|
|
)
|
|
|
|
WEB_DIRECTORY = "web"
|
|
NODE_CLASS_MAPPINGS = {}
|