dailypromptnode
This commit is contained in:
@@ -21,7 +21,7 @@ A powerful workflow scheduling extension for ComfyUI that enables automated dail
|
||||
## 🚀 Installation 安裝方式
|
||||
|
||||
### Method 1: ComfyUI Manager (Recommended)
|
||||
### 方法 1:ComfyUI 管理器(推薦/稍後可用)
|
||||
### 方法 1:ComfyUI 管理器(推薦)
|
||||
1. Open ComfyUI Manager 開啟 ComfyUI 管理器
|
||||
2. Search for "ComfyUI-ScheduledTask" 搜尋 "ComfyUI-ScheduledTask"
|
||||
3. Click Install 點擊安裝
|
||||
@@ -114,6 +114,65 @@ A special utility node that generates time-based random seeds:
|
||||
- Ensures different results for each scheduled run 確保每次排程運行都有不同結果
|
||||
- Setting this for create large image list and run 在設定時間內進行大規模隨機排程
|
||||
|
||||
### Daily Prompt Scheduler Node / 每日提示詞排程節點
|
||||
|
||||

|
||||
|
||||
A ComfyUI node that provides time-based prompt management with daily rotation capabilities.
|
||||
提供基於時間的提示詞管理和每日輪換功能。
|
||||
|
||||
####Features / 功能特色
|
||||
|
||||
- **Daily Rotation / 每日輪換**: Automatically selects different prompts each day / 每天自動選擇不同的提示詞
|
||||
- **Two Operation Modes / 兩種運作模式**:
|
||||
- **Scheduled Mode / 排程模式**: Sequential selection with time seed (predictable daily progression) / 使用時間種子的順序選擇(可預測的每日進展)
|
||||
- **Random Mode / 隨機模式**: Random selection with daily seed (random but consistent per day) / 使用每日種子的隨機選擇(隨機但每天一致)
|
||||
- **File-based Management / 檔案管理**: Load prompts from text files in the `Prompt` folder / 從Prompt資料夾中的文字檔載入提示詞
|
||||
- **Individual Time Seeds / 獨立時間種子**: Each text file maintains its own scheduling timeline / 每個文字檔維護自己的排程時間線
|
||||
- **List Output / 列表輸出**: Returns prompts as a connectable string list for workflow integration / 返回可連接的字串列表用於工作流程整合
|
||||
- **Loop Integration / 迴圈整合**: Provides count output for easy loop control / 提供計數輸出便於迴圈控制
|
||||
|
||||
#### Setup / 設置
|
||||
|
||||
1. Visit`Prompt` folder in your node directory: `/ComfyUI-ScheduledTask/Prompt/` / 在節點目錄中訪問`Prompt`資料夾:`/ComfyUI-ScheduledTask/Prompt/`
|
||||
2. Place your text files (`.txt`) in this folder / 將文字檔(`.txt`)放置在此資料夾中
|
||||
3. Each line in the text file represents one prompt (empty lines are ignored) / 文字檔中每一行代表一個提示詞(空行會被忽略)
|
||||
|
||||
#### Inputs / 輸入參數
|
||||
|
||||
- **txt_file / 文字檔**: Dropdown selection of available text files in the Prompt folder / 下拉選單選擇Prompt資料夾中的可用文字檔
|
||||
- **daily_count / 每日數量**: Number of prompts to select each day (1-5000) / 每天選擇的提示詞數量(1-5000)
|
||||
- **scheduled / 排程**: Toggle between Scheduled and Random modes (Default is Random Mode)/ 在排程模式和隨機模式之間切換,預設為隨機模式,每天隨機抽選提示組數
|
||||
|
||||
#### Outputs / 輸出參數
|
||||
|
||||
- **daily_prompts / 每日提示詞**: List of selected prompts (STRING list, connectable to other nodes) / 選中的提示詞列表(字串列表,可連接到其他節點)
|
||||
- **total_index / 總數索引**: Number of prompts actually returned (INT, useful for loop control) / 實際返回的提示詞數量(整數,用於迴圈控制)
|
||||
|
||||
#### Operation Modes / 運作模式
|
||||
|
||||
#### Scheduled Mode / 排程模式
|
||||
- **First Run / 首次運行**: Creates a time seed based on current date / 基於當前日期創建時間種子
|
||||
- **Daily Progression / 每日進展**: Selects prompts sequentially / 按順序選擇提示詞
|
||||
- **Example / 範例**: With 12 prompts, selecting 3 per day / 有12個提示詞,每天選擇3個:
|
||||
- Day 1 / 第1天: Prompts 1, 2, 3 / 提示詞1, 2, 3
|
||||
- Day 2 / 第2天: Prompts 4, 5, 6 / 提示詞4, 5, 6
|
||||
- Day 3 / 第3天: Prompts 7, 8, 9 / 提示詞7, 8, 9
|
||||
- Day 4 / 第4天: Prompts 10, 11, 12 / 提示詞10, 11, 12
|
||||
- Day 5 / 第5天: Prompts 1, 2, 3 (cycles back) / 提示詞1, 2, 3(循環回到開頭)
|
||||
|
||||
#### Random Mode / 隨機模式
|
||||
- **Daily Random / 每日隨機**: Uses date-based seed for random selection / 使用基於日期的種子進行隨機選擇
|
||||
- **Consistent / 一致性**: Same random selection throughout the day / 整天保持相同的隨機選擇
|
||||
- **Example / 範例**: Random but fixed selection per day (e.g., prompts 3, 7, 11) / 每天隨機但固定的選擇(例如:提示詞3, 7, 11)
|
||||
|
||||
#### File Management / 檔案管理
|
||||
|
||||
- **Multiple Files / 多檔案**: Each `.txt` file has independent scheduling / 每個`.txt`檔案都有獨立的排程
|
||||
- **Time Seeds / 時間種子**: Stored as `{filename}_time_seed.json` in the Prompt folder(If Scheduled) / 以`{檔名}_time_seed.json`的形式儲存在Prompt資料夾中,假使是使用排程模式
|
||||
- **Auto-wrapping / 自動循環**: Never causes index errors, automatically wraps around (With Time Seed) / 永不會造成索引錯誤,自動循環,但可能會因此採樣到相同的圖片,請配合時間種子使用
|
||||
- **UTF-8 Support / UTF-8支援**: Handles international characters and languages / 支援國際字符和多種語言
|
||||
|
||||
### File Structure 檔案結構
|
||||
|
||||
```
|
||||
@@ -121,12 +180,15 @@ ComfyUI-ScheduledTask/
|
||||
├── __init__.py # Extension entry point 擴展入口點
|
||||
├── scheduler.py # Core scheduling logic & TimeToSeedList node 核心排程邏輯和時間種子節點
|
||||
├── web_handler.py # API endpoints API 端點
|
||||
├── Prompt/ # 提示詞檔案庫
|
||||
│ ├── Example.txt # 範例檔案
|
||||
├── web/
|
||||
│ └── scheduled_task.js # Frontend interface 前端介面
|
||||
├── Workflow/ # Saved workflow files (auto-created) 保存的工作流程檔案(自動創建)
|
||||
│ ├── workflow1.json
|
||||
│ └── workflow2.json
|
||||
└── schedules.json # Schedule configuration (auto-created) 排程配置(自動創建)
|
||||
|
||||
```
|
||||
### Workflow Format 工作流程格式
|
||||
Saved workflows are stored in ComfyUI API format:
|
||||
|
||||
+33
-10
@@ -4,10 +4,20 @@ ComfyUI-ScheduledTask
|
||||
"""
|
||||
|
||||
import os
|
||||
from .scheduler import SchedulerManager, TimeToSeedList
|
||||
from .web_handler import setup_routes
|
||||
import threading
|
||||
import time
|
||||
import atexit
|
||||
|
||||
# 匯入節點類別和排程管理器
|
||||
from .scheduler import SchedulerManager, TimeToSeedList, DailyPromptScheduler
|
||||
|
||||
# 匯入web處理器 (如果存在的話)
|
||||
try:
|
||||
from .web_handler import setup_routes
|
||||
HAS_WEB_HANDLER = True
|
||||
except ImportError:
|
||||
HAS_WEB_HANDLER = False
|
||||
print("Warning: web_handler not found, web interface will be disabled")
|
||||
|
||||
# 全域排程管理器
|
||||
scheduler_manager = None
|
||||
@@ -20,35 +30,48 @@ def get_scheduler():
|
||||
|
||||
# 延遲初始化
|
||||
def delayed_init():
|
||||
time.sleep(3) # 等待ComfyUI完全啟動
|
||||
get_scheduler()
|
||||
try:
|
||||
time.sleep(3) # 等待ComfyUI完全啟動
|
||||
get_scheduler()
|
||||
except Exception as e:
|
||||
print(f"Error in delayed initialization: {e}")
|
||||
|
||||
# 啟動初始化執行緒
|
||||
init_thread = threading.Thread(target=delayed_init, daemon=True)
|
||||
init_thread.start()
|
||||
|
||||
# 設定web路由
|
||||
setup_routes()
|
||||
# 設定web路由 (如果可用)
|
||||
if HAS_WEB_HANDLER:
|
||||
try:
|
||||
setup_routes()
|
||||
except Exception as e:
|
||||
print(f"Error setting up web routes: {e}")
|
||||
|
||||
# 清理函數
|
||||
import atexit
|
||||
def cleanup():
|
||||
global scheduler_manager
|
||||
if scheduler_manager:
|
||||
scheduler_manager.stop()
|
||||
try:
|
||||
scheduler_manager.stop()
|
||||
except Exception as e:
|
||||
print(f"Error during cleanup: {e}")
|
||||
|
||||
atexit.register(cleanup)
|
||||
|
||||
# ComfyUI節點映射
|
||||
# 節點類別映射 - 這是關鍵!
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"TimeToSeedList": TimeToSeedList,
|
||||
"DailyPromptScheduler": DailyPromptScheduler,
|
||||
}
|
||||
|
||||
# 節點顯示名稱映射
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"TimeToSeedList": "Time to Seed List",
|
||||
"DailyPromptScheduler": "Daily Prompt Scheduler",
|
||||
}
|
||||
|
||||
# Web擴展映射 - 這是關鍵!
|
||||
# Web擴展映射
|
||||
WEB_DIRECTORY = "./web"
|
||||
|
||||
# 確保必要的匯出
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS', 'WEB_DIRECTORY']
|
||||
@@ -0,0 +1,12 @@
|
||||
Ancient magical laboratory filled with glowing potions, floating books, crystal orbs, wooden shelves lined with mysterious bottles, candlelight illumination, mystical atmosphere, detailed fantasy art style
|
||||
Wizard's underground laboratory with bubbling cauldrons, spell circles carved in stone floor, hanging herbs and ingredients, magical apparatus, dim torchlight, medieval fantasy setting
|
||||
Modern witch's laboratory combining magical and scientific elements, glass beakers with swirling colorful potions, digital displays showing magical formulas, LED lighting mixed with candles, contemporary fantasy aesthetic
|
||||
Alchemist's tower laboratory with spiral staircases, floating magical instruments, golden light streaming through stained glass windows, ancient tomes, transmutation circles, Renaissance-inspired magical workshop
|
||||
Steampunk magical laboratory with brass pipes, mechanical magical devices, steam-powered cauldrons, copper and bronze equipment, Victorian-era magical engineering, gear-driven spell apparatus
|
||||
Enchanted forest laboratory built inside a giant tree, bioluminescent plants as light sources, natural wooden surfaces, magical mushrooms, fairy lights, organic magical equipment, nature-integrated magic workshop
|
||||
Crystal cave magical laboratory with towering crystal formations, prismatic light effects, levitating gemstones, magical energy coursing through crystal networks, ethereal glow, crystalline magical apparatus
|
||||
Underwater magical laboratory in an air bubble, aquatic magical creatures swimming outside, coral-based equipment, bioluminescent sea plants, magical water manipulation devices, oceanic fantasy setting
|
||||
Celestial magical observatory laboratory on a floating platform, star charts and astronomical instruments, magical telescopes, cosmic energy collectors, nebula views through windows, space-themed magical research facility
|
||||
Miniature magical laboratory inside a snow globe, tiny detailed magical equipment, microscopic potions, doll-house scale magical apparatus, whimsical and intricate design, magical realism aesthetic
|
||||
Dark gothic magical laboratory with ornate iron fixtures, dramatic shadows, purple and green magical flames, ancient grimoires bound in leather, gargoyle statues, gothic arches, ominous magical energy
|
||||
Bright cheerful magical bakery laboratory, pastel-colored potions that look like cupcakes, magical mixing bowls, enchanted ovens, candy-colored magical ingredients, whimsical cartoon style, sweet magical atmosphere
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
+178
@@ -14,6 +14,184 @@ import random
|
||||
from datetime import datetime
|
||||
import hashlib
|
||||
|
||||
class DailyPromptScheduler:
|
||||
def __init__(self):
|
||||
self.node_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
self.prompt_dir = os.path.join(self.node_dir, "Prompt")
|
||||
|
||||
# Ensure Prompt folder exists
|
||||
if not os.path.exists(self.prompt_dir):
|
||||
os.makedirs(self.prompt_dir)
|
||||
|
||||
def get_txt_files(self):
|
||||
"""Get all txt files in the Prompt folder"""
|
||||
if not os.path.exists(self.prompt_dir):
|
||||
return ["Please place txt files in Prompt folder"]
|
||||
|
||||
# Only get .txt files, exclude .json files
|
||||
txt_files = [f for f in os.listdir(self.prompt_dir)
|
||||
if f.endswith('.txt') and not f.endswith('_time_seed.json')]
|
||||
if not txt_files:
|
||||
return ["Please place txt files in Prompt folder"]
|
||||
|
||||
return txt_files
|
||||
|
||||
def get_seed_file_path(self, txt_filename):
|
||||
"""Get the seed file path for specific txt file"""
|
||||
# Remove .txt extension and add _time_seed.json
|
||||
base_name = os.path.splitext(txt_filename)[0]
|
||||
seed_filename = f"{base_name}_time_seed.json"
|
||||
return os.path.join(self.prompt_dir, seed_filename)
|
||||
|
||||
def load_time_seed(self, txt_filename):
|
||||
"""Load time seed for specific txt file"""
|
||||
seed_file = self.get_seed_file_path(txt_filename)
|
||||
if os.path.exists(seed_file):
|
||||
try:
|
||||
with open(seed_file, 'r', encoding='utf-8') as f:
|
||||
seed_data = json.load(f)
|
||||
return seed_data.get('seed_date', None)
|
||||
except:
|
||||
return None
|
||||
return None
|
||||
|
||||
def save_time_seed(self, txt_filename, seed_date):
|
||||
"""Save time seed for specific txt file"""
|
||||
seed_file = self.get_seed_file_path(txt_filename)
|
||||
seed_data = {'seed_date': seed_date}
|
||||
with open(seed_file, 'w', encoding='utf-8') as f:
|
||||
json.dump(seed_data, f, ensure_ascii=False)
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
instance = cls()
|
||||
txt_files = instance.get_txt_files()
|
||||
|
||||
return {
|
||||
"required": {
|
||||
"txt_file": (txt_files, {"default": txt_files[0] if txt_files else ""}),
|
||||
"daily_count": ("INT", {
|
||||
"default": 3,
|
||||
"min": 1,
|
||||
"max": 5000,
|
||||
"step": 1
|
||||
}),
|
||||
"scheduled": ("BOOLEAN", {
|
||||
"default": False,
|
||||
"label_on": "Set Time Seed",
|
||||
"label_off": "Random Mode"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING", "INT")
|
||||
RETURN_NAMES = ("daily_prompts", "total_index")
|
||||
OUTPUT_IS_LIST = (True, False)
|
||||
FUNCTION = "get_daily_prompts"
|
||||
CATEGORY = "text/scheduled"
|
||||
|
||||
def IS_CHANGED(self, txt_file, daily_count, scheduled):
|
||||
"""Ensure node is not cached"""
|
||||
current_time = datetime.now()
|
||||
current_date = current_time.strftime("%Y%m%d")
|
||||
|
||||
# If file doesn't exist, return current timestamp
|
||||
txt_path = os.path.join(self.prompt_dir, txt_file)
|
||||
if not os.path.exists(txt_path):
|
||||
return str(current_time.timestamp())
|
||||
|
||||
# Combine file modification time, current date and settings to generate identifier
|
||||
try:
|
||||
file_mtime = os.path.getmtime(txt_path)
|
||||
unique_id = f"{file_mtime}_{current_date}_{daily_count}_{scheduled}_{txt_file}"
|
||||
return hashlib.md5(unique_id.encode()).hexdigest()
|
||||
except:
|
||||
return str(current_time.timestamp())
|
||||
|
||||
def read_txt_file(self, filename):
|
||||
"""Read and parse txt file"""
|
||||
txt_path = os.path.join(self.prompt_dir, filename)
|
||||
|
||||
if not os.path.exists(txt_path):
|
||||
return []
|
||||
|
||||
try:
|
||||
with open(txt_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Split by newlines, filter empty lines
|
||||
lines = [line.strip() for line in content.split('\n') if line.strip()]
|
||||
return lines
|
||||
except Exception as e:
|
||||
logger.error(f"Error reading file: {e}")
|
||||
return []
|
||||
|
||||
def get_daily_prompts(self, txt_file, daily_count, scheduled):
|
||||
# Check if file exists
|
||||
if txt_file == "Please place txt files in Prompt folder":
|
||||
return (["Error: Please place txt files in Prompt folder"], 0)
|
||||
|
||||
# Read prompt list
|
||||
all_prompts = self.read_txt_file(txt_file)
|
||||
|
||||
if not all_prompts:
|
||||
error_msg = f"Error: Unable to read file {txt_file} or file is empty"
|
||||
return ([error_msg], 0)
|
||||
|
||||
current_time = datetime.now()
|
||||
current_date = current_time.strftime("%Y%m%d")
|
||||
|
||||
# Ensure not exceeding available prompts count
|
||||
actual_count = min(daily_count, len(all_prompts))
|
||||
|
||||
# Handle scheduling logic
|
||||
if scheduled:
|
||||
# Scheduled mode with time seed
|
||||
seed_date = self.load_time_seed(txt_file)
|
||||
|
||||
if seed_date is None:
|
||||
# First time setting seed
|
||||
self.save_time_seed(txt_file, current_date)
|
||||
seed_date = current_date
|
||||
status = f"Time seed set: {seed_date} for {txt_file}"
|
||||
else:
|
||||
status = f"Using time seed: {seed_date} for {txt_file}"
|
||||
|
||||
# Calculate days difference from seed date
|
||||
try:
|
||||
seed_datetime = datetime.strptime(seed_date, "%Y%m%d")
|
||||
current_datetime = datetime.strptime(current_date, "%Y%m%d")
|
||||
days_diff = (current_datetime - seed_datetime).days
|
||||
except:
|
||||
days_diff = 0
|
||||
|
||||
# Calculate starting index for sequential selection
|
||||
total_prompts = len(all_prompts)
|
||||
start_index = (days_diff * actual_count) % total_prompts
|
||||
|
||||
# Sequential selection with wrapping
|
||||
selected_prompts = []
|
||||
for i in range(actual_count):
|
||||
index = (start_index + i) % total_prompts
|
||||
selected_prompts.append(all_prompts[index])
|
||||
|
||||
else:
|
||||
# Random mode: use different random seed each day
|
||||
random_seed = int(current_date) + hash(txt_file)
|
||||
random.seed(random_seed)
|
||||
status = f"Random mode - Date seed: {current_date} for {txt_file}"
|
||||
|
||||
# Randomly select prompts without replacement
|
||||
selected_prompts = random.sample(all_prompts, actual_count)
|
||||
|
||||
# Output debug information
|
||||
logger.info(f"DailyPromptScheduler: {status}")
|
||||
logger.info(f"DailyPromptScheduler: Selected {actual_count} from {len(all_prompts)} prompts")
|
||||
logger.info(f"DailyPromptScheduler: Selected prompts: {selected_prompts}")
|
||||
|
||||
return (selected_prompts, actual_count)
|
||||
|
||||
|
||||
class TimeToSeedList:
|
||||
"""
|
||||
Generate random seed list based on current time
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"schedules": [
|
||||
{
|
||||
"time": "09:09",
|
||||
"workflow": "Exmaple.json",
|
||||
"time": "23:22",
|
||||
"workflow": "ExmapleDailyPrompt.json",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"globalEnabled": true,
|
||||
"updated_at": "2025-06-19T09:07:21.402267"
|
||||
"updated_at": "2025-06-20T23:20:23.382801"
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
{
|
||||
"3": {
|
||||
"inputs": {
|
||||
"seed": [
|
||||
"31",
|
||||
0
|
||||
],
|
||||
"steps": 20,
|
||||
"cfg": 8,
|
||||
"sampler_name": "euler",
|
||||
"scheduler": "normal",
|
||||
"denoise": 1,
|
||||
"model": [
|
||||
"4",
|
||||
0
|
||||
],
|
||||
"positive": [
|
||||
"6",
|
||||
0
|
||||
],
|
||||
"negative": [
|
||||
"7",
|
||||
0
|
||||
],
|
||||
"latent_image": [
|
||||
"5",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "KSampler",
|
||||
"_meta": {
|
||||
"title": "KSampler"
|
||||
}
|
||||
},
|
||||
"4": {
|
||||
"inputs": {
|
||||
"ckpt_name": "dreamshaper_8.safetensors"
|
||||
},
|
||||
"class_type": "CheckpointLoaderSimple",
|
||||
"_meta": {
|
||||
"title": "Load Checkpoint"
|
||||
}
|
||||
},
|
||||
"5": {
|
||||
"inputs": {
|
||||
"width": 512,
|
||||
"height": 512,
|
||||
"batch_size": 1
|
||||
},
|
||||
"class_type": "EmptyLatentImage",
|
||||
"_meta": {
|
||||
"title": "Empty Latent Image"
|
||||
}
|
||||
},
|
||||
"6": {
|
||||
"inputs": {
|
||||
"text": [
|
||||
"30",
|
||||
0
|
||||
],
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Prompt)"
|
||||
}
|
||||
},
|
||||
"7": {
|
||||
"inputs": {
|
||||
"text": "text, watermark",
|
||||
"clip": [
|
||||
"4",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "CLIPTextEncode",
|
||||
"_meta": {
|
||||
"title": "CLIP Text Encode (Prompt)"
|
||||
}
|
||||
},
|
||||
"8": {
|
||||
"inputs": {
|
||||
"samples": [
|
||||
"3",
|
||||
0
|
||||
],
|
||||
"vae": [
|
||||
"4",
|
||||
2
|
||||
]
|
||||
},
|
||||
"class_type": "VAEDecode",
|
||||
"_meta": {
|
||||
"title": "VAE Decode"
|
||||
}
|
||||
},
|
||||
"9": {
|
||||
"inputs": {
|
||||
"filename_prefix": "ComfyUI",
|
||||
"images": [
|
||||
"8",
|
||||
0
|
||||
]
|
||||
},
|
||||
"class_type": "SaveImage",
|
||||
"_meta": {
|
||||
"title": "Save Image"
|
||||
}
|
||||
},
|
||||
"30": {
|
||||
"inputs": {
|
||||
"txt_file": "Example.txt",
|
||||
"daily_count": 3,
|
||||
"scheduled": false
|
||||
},
|
||||
"class_type": "DailyPromptScheduler",
|
||||
"_meta": {
|
||||
"title": "Daily Prompt Scheduler"
|
||||
}
|
||||
},
|
||||
"31": {
|
||||
"inputs": {
|
||||
"count": [
|
||||
"30",
|
||||
1
|
||||
]
|
||||
},
|
||||
"class_type": "TimeToSeedList",
|
||||
"_meta": {
|
||||
"title": "Time to Seed List"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user