코드 설명
원하는 갯수만큼 엔트리 작품을 자동 생성 후 공개하는 스트립트입니다.
다만 429땜에 한번에 5개가 한계...
코드
더보기
(async () => {
/* ===== 토큰 추출 ===== */
function extractTokens() {
try {
const meta = document.querySelector('meta[name="csrf-token"]');
const el = document.getElementById('__NEXT_DATA__');
if (!meta || !el) return null;
const data = JSON.parse(el.textContent);
const find = (o) => {
if (!o || typeof o !== 'object') return null;
if (o.xToken) return o.xToken;
for (const k in o) {
const r = find(o[k]);
if (r) return r;
}
return null;
};
const xToken = find(data);
if (!xToken) return null;
return { csrfToken: meta.content, xToken };
} catch {
return null;
}
}
const count = parseInt(prompt('생성할 작품 개수', '5'), 10);
if (!Number.isInteger(count) || count <= 0) return;
const gen = (n = 8) => {
const c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let r = '';
for (let i = 0; i < n; i++) r += c[Math.random() * c.length | 0];
return r;
};
const categories = ["game", "arts", "knowledge", "storytelling", "living", "etc"];
/* ===== 동시성 풀 ===== */
async function runPool(tasks, limit = 4) {
const running = [];
for (const task of tasks) {
const p = task().finally(() => running.splice(running.indexOf(p), 1));
running.push(p);
if (running.length >= limit) await Promise.race(running);
}
await Promise.allSettled(running);
}
const tasks = Array.from({ length: count }, (_, i) => async () => {
const tokens = extractTokens();
if (!tokens) throw 'TOKEN_FAIL';
/* ===== CREATE ===== */
const createRes = await fetch("https://playentry.org/graphql/CREATE_PROJECT", {
method: "POST",
mode: "cors",
credentials: "include",
headers: {
"accept": "*/*",
"accept-language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
"content-type": "application/json",
"csrf-token": tokens.csrfToken,
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-client-type": "Client",
"x-token": tokens.xToken
},
referrer: "https://playentry.org/ws/new?type=normal&mode=block&lang=ko",
body: "{\"query\":\"\\n mutation CREATE_PROJECT(\\n \\n $name: String\\n $speed: Int\\n $objects: JSON\\n $variables: JSON\\n $messages: JSON\\n $functions: JSON\\n $tables: JSON\\n $scenes: JSON\\n $blockLog: JSON\\n $lecture:ID\\n $study:ID\\n $discovery: ID\\n $isForLecture:Boolean\\n $isForStudy:Boolean\\n $isForSubmit: Boolean\\n $isPracticalCourse: Boolean\\n $interface: JSON\\n $aiUtilizeBlocks: JSON\\n $expansionBlocks: JSON\\n $hardwareLiteBlocks: JSON\\n $description: String\\n $description2: String\\n $description3: String\\n $thumb: String\\n $isopen: Boolean\\n $showComment: Boolean\\n $categoryCode: String\\n $parent: ID\\n $learning: String\\n\\n ) {\\n createProject(\\n \\n name: $name\\n speed: $speed\\n objects: $objects\\n variables: $variables\\n messages: $messages\\n functions: $functions\\n tables: $tables\\n scenes: $scenes\\n blockLog: $blockLog\\n lecture: $lecture\\n study: $study\\n discovery: $discovery\\n isForLecture: $isForLecture\\n isForStudy: $isForStudy\\n isForSubmit: $isForSubmit\\n isPracticalCourse: $isPracticalCourse\\n interface: $interface\\n aiUtilizeBlocks: $aiUtilizeBlocks\\n expansionBlocks: $expansionBlocks\\n hardwareLiteBlocks: $hardwareLiteBlocks\\n description: $description\\n description2: $description2\\n description3: $description3\\n thumb: $thumb\\n isopen: $isopen\\n showComment: $showComment\\n categoryCode: $categoryCode\\n parent: $parent\\n learning: $learning\\n\\n ) {\\n \\n status\\n result\\n\\n }\\n }\\n\",\"variables\":{\"category\":\"기타\",\"scenes\":[{\"id\":\"7dwq\",\"name\":\"장면 1\"}],\"variables\":[{\"name\":\"초시계\",\"id\":\"brih\",\"visible\":false,\"value\":\"0\",\"variableType\":\"timer\",\"isCloud\":false,\"isRealTime\":false,\"cloudDate\":false,\"object\":null,\"x\":134,\"y\":-70},{\"name\":\"대답\",\"id\":\"1vu8\",\"visible\":false,\"value\":\"0\",\"variableType\":\"answer\",\"isCloud\":false,\"isRealTime\":false,\"cloudDate\":false,\"object\":null,\"x\":150,\"y\":-100}],\"objects\":[{\"id\":\"7y0y\",\"name\":\"엔트리봇\",\"script\":\"[[{\\\"id\\\":\\\"j3fs\\\",\\\"x\\\":21.5,\\\"y\\\":30,\\\"type\\\":\\\"when_run_button_click\\\",\\\"params\\\":[null],\\\"statements\\\":[],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]},{\\\"id\\\":\\\"f36a\\\",\\\"x\\\":0,\\\"y\\\":0,\\\"type\\\":\\\"repeat_basic\\\",\\\"params\\\":[{\\\"id\\\":\\\"515i\\\",\\\"x\\\":0,\\\"y\\\":0,\\\"type\\\":\\\"number\\\",\\\"params\\\":[10],\\\"statements\\\":[],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]},null],\\\"statements\\\":[[{\\\"id\\\":\\\"cl28\\\",\\\"x\\\":0,\\\"y\\\":0,\\\"type\\\":\\\"move_direction\\\",\\\"params\\\":[{\\\"id\\\":\\\"9op9\\\",\\\"x\\\":0,\\\"y\\\":0,\\\"type\\\":\\\"number\\\",\\\"params\\\":[10],\\\"statements\\\":[],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]},null],\\\"statements\\\":[],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]}]],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]}]]\",\"objectType\":\"sprite\",\"rotateMethod\":\"free\",\"scene\":\"7dwq\",\"sprite\":{\"pictures\":[{\"id\":\"vx80\",\"dimension\":{\"width\":144,\"height\":246},\"fileurl\":\"/lib/entry-js/images/media/entrybot1.svg\",\"thumbUrl\":\"/lib/entry-js/images/media/entrybot1.svg\",\"name\":\"엔트리봇_걷기1\",\"imageType\":\"svg\"},{\"id\":\"4t48\",\"dimension\":{\"width\":144,\"height\":246},\"fileurl\":\"/lib/entry-js/images/media/entrybot2.svg\",\"thumbUrl\":\"/lib/entry-js/images/media/entrybot2.svg\",\"name\":\"엔트리봇_걷기2\",\"imageType\":\"svg\"}],\"sounds\":[{\"duration\":1.3,\"ext\":\".mp3\",\"id\":\"8el5\",\"fileurl\":\"/lib/entry-js/images/media/bark.mp3\",\"name\":\"강아지 짖는 소리\"}]},\"selectedPictureId\":\"vx80\",\"lock\":false,\"entity\":{\"x\":0,\"y\":0,\"regX\":72,\"regY\":123,\"scaleX\":0.5128205128205128,\"scaleY\":0.5128205128205128,\"rotation\":0,\"direction\":90,\"width\":144,\"height\":246,\"font\":\"undefinedpx \",\"visible\":true}}],\"expansionBlocks\":[],\"aiUtilizeBlocks\":[],\"speed\":60,\"name\":\"260127_코딩_연구소 작품\",\"likeCnt\":0,\"visit\":0,\"isopen\":false,\"user\":\"62595ee73ad54503da9eef61\",\"messages\":[],\"functions\":[],\"tables\":[],\"interface\":{\"menuWidth\":280,\"canvasWidth\":480,\"object\":\"7y0y\"},\"hardwareLiteBlocks\":[],\"externalModules\":[],\"externalModulesLite\":[],\"isPracticalCourse\":false,\"blockLog\":{\"categories\":[\"event\",\"repeat\",\"walk\"],\"when_run_button_click\":1,\"repeat_basic\":1,\"number\":2,\"move_direction\":1}}}"
}).then(r => r.json());
const projectId = createRes?.data?.createProject?.result?.id;
if (!projectId) throw 'CREATE_FAIL';
/* ===== UPDATE ===== */
const tags = Array.from({ length: 5 }, () => gen(4));
const category = categories[Math.random() * categories.length | 0];
const title = `랜덤 작품 - ${gen(5)}`;
const description = `자동 생성\n${gen(16)}`;
const instructions = `사용법\n1.${gen(8)}\n2.${gen(8)}`;
const remarks = `비고 ${gen(10)}`;
await fetch("https://playentry.org/graphql/UPDATE_PROJECT", {
method: "POST",
mode: "cors",
credentials: "include",
headers: {
"content-type": "application/json",
"csrf-token": tokens.csrfToken,
"x-token": tokens.xToken,
"x-client-type": "Client"
},
body: `{\"query\":\"\\n mutation UPDATE_PROJECT(\\n \\n $id: ID!\\n $name: String\\n $speed: Int\\n $objects: JSON\\n $variables: JSON\\n $messages: JSON\\n $functions: JSON\\n $tables: JSON\\n $scenes: JSON\\n $blockLog: JSON\\n $interface: JSON\\n $aiUtilizeBlocks: JSON\\n $expansionBlocks: JSON\\n $hardwareLiteBlocks: JSON\\n $thumb: String\\n $categoryCode: String\\n $description: String\\n $description2: String\\n $description3: String\\n $isopen: Boolean\\n $showComment: Boolean\\n $isPracticalCourse: Boolean\\n $group: ID\\n $learning: String\\n $tags: [String]\\n\\n ) {\\n updateProject(\\n \\n id: $id\\n name: $name\\n speed: $speed\\n objects: $objects\\n variables: $variables\\n messages: $messages\\n functions: $functions\\n tables: $tables\\n scenes: $scenes\\n blockLog: $blockLog\\n interface: $interface\\n aiUtilizeBlocks: $aiUtilizeBlocks\\n expansionBlocks: $expansionBlocks\\n hardwareLiteBlocks: $hardwareLiteBlocks\\n thumb: $thumb\\n categoryCode: $categoryCode\\n description: $description\\n description2: $description2\\n description3: $description3\\n isopen: $isopen\\n showComment: $showComment\\n isPracticalCourse: $isPracticalCourse\\n group: $group\\n learning: $learning\\n tags: $tags\\n\\n ) {\\n \\n status\\n result\\n\\n }\\n }\\n\",\"variables\":{\"id\":\"${projectId}\",\"name\":\"${title}\",\"categoryCode\":\"${category}\",\"description\":\"${description}\",\"description2\":\"${instructions}\",\"description3\":\"${remarks}\",\"isopen\":true,\"tags\":[\"${tags[0]}\",\"${tags[1]}\",\"${tags[2]}\",\"${tags[3]}\",\"${tags[4]}\"],\"showComment\":false}}`
});
console.log(`✅ ${i + 1}/${count} 완료`);
});
await runPool(tasks, 4);
console.log('🎉 전체 완료');
})();
(async () => {
/* ===== 토큰 추출 ===== */
function extractTokens() {
try {
const meta = document.querySelector('meta[name="csrf-token"]');
const el = document.getElementById('__NEXT_DATA__');
if (!meta || !el) return null;
const data = JSON.parse(el.textContent);
const find = (o) => {
if (!o || typeof o !== 'object') return null;
if (o.xToken) return o.xToken;
for (const k in o) {
const r = find(o[k]);
if (r) return r;
}
return null;
};
const xToken = find(data);
if (!xToken) return null;
return { csrfToken: meta.content, xToken };
} catch {
return null;
}
}
const count = parseInt(prompt('생성할 작품 개수', '5'), 10);
if (!Number.isInteger(count) || count <= 0) return;
const gen = (n = 8) => {
const c = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let r = '';
for (let i = 0; i < n; i++) r += c[Math.random() * c.length | 0];
return r;
};
const categories = ["game", "arts", "knowledge", "storytelling", "living", "etc"];
/* ===== 동시성 풀 ===== */
async function runPool(tasks, limit = 4) {
const running = [];
for (const task of tasks) {
const p = task().finally(() => running.splice(running.indexOf(p), 1));
running.push(p);
if (running.length >= limit) await Promise.race(running);
}
await Promise.allSettled(running);
}
const tasks = Array.from({ length: count }, (_, i) => async () => {
const tokens = extractTokens();
if (!tokens) throw 'TOKEN_FAIL';
/* ===== CREATE ===== */
const createRes = await fetch("https://playentry.org/graphql/CREATE_PROJECT", {
method: "POST",
mode: "cors",
credentials: "include",
headers: {
"content-type": "application/json",
"csrf-token": tokens.csrfToken,
"x-token": tokens.xToken,
"x-client-type": "Client"
},
body: "{\"query\":\"\\n mutation CREATE_PROJECT(\\n \\n $name: String\\n $speed: Int\\n $objects: JSON\\n $variables: JSON\\n $messages: JSON\\n $functions: JSON\\n $tables: JSON\\n $scenes: JSON\\n $blockLog: JSON\\n $lecture:ID\\n $study:ID\\n $discovery: ID\\n $isForLecture:Boolean\\n $isForStudy:Boolean\\n $isForSubmit: Boolean\\n $isPracticalCourse: Boolean\\n $interface: JSON\\n $aiUtilizeBlocks: JSON\\n $expansionBlocks: JSON\\n $hardwareLiteBlocks: JSON\\n $description: String\\n $description2: String\\n $description3: String\\n $thumb: String\\n $isopen: Boolean\\n $showComment: Boolean\\n $categoryCode: String\\n $parent: ID\\n $learning: String\\n\\n ) {\\n createProject(\\n \\n name: $name\\n speed: $speed\\n objects: $objects\\n variables: $variables\\n messages: $messages\\n functions: $functions\\n tables: $tables\\n scenes: $scenes\\n blockLog: $blockLog\\n lecture: $lecture\\n study: $study\\n discovery: $discovery\\n isForLecture: $isForLecture\\n isForStudy: $isForStudy\\n isForSubmit: $isForSubmit\\n isPracticalCourse: $isPracticalCourse\\n interface: $interface\\n aiUtilizeBlocks: $aiUtilizeBlocks\\n expansionBlocks: $expansionBlocks\\n hardwareLiteBlocks: $hardwareLiteBlocks\\n description: $description\\n description2: $description2\\n description3: $description3\\n thumb: $thumb\\n isopen: $isopen\\n showComment: $showComment\\n categoryCode: $categoryCode\\n parent: $parent\\n learning: $learning\\n\\n ) {\\n \\n status\\n result\\n\\n }\\n }\\n\",\"variables\":{\"category\":\"기타\",\"scenes\":[{\"id\":\"7dwq\",\"name\":\"장면 1\"}],\"variables\":[{\"name\":\"초시계\",\"id\":\"brih\",\"visible\":false,\"value\":\"0\",\"variableType\":\"timer\",\"isCloud\":false,\"isRealTime\":false,\"cloudDate\":false,\"object\":null,\"x\":134,\"y\":-70},{\"name\":\"대답\",\"id\":\"1vu8\",\"visible\":false,\"value\":\"0\",\"variableType\":\"answer\",\"isCloud\":false,\"isRealTime\":false,\"cloudDate\":false,\"object\":null,\"x\":150,\"y\":-100}],\"objects\":[{\"id\":\"7y0y\",\"name\":\"엔트리봇\",\"script\":\"[[{\\\"id\\\":\\\"j3fs\\\",\\\"x\\\":21.5,\\\"y\\\":30,\\\"type\\\":\\\"when_run_button_click\\\",\\\"params\\\":[null],\\\"statements\\\":[],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]},{\\\"id\\\":\\\"f36a\\\",\\\"x\\\":0,\\\"y\\\":0,\\\"type\\\":\\\"repeat_basic\\\",\\\"params\\\":[{\\\"id\\\":\\\"515i\\\",\\\"x\\\":0,\\\"y\\\":0,\\\"type\\\":\\\"number\\\",\\\"params\\\":[10],\\\"statements\\\":[],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]},null],\\\"statements\\\":[[{\\\"id\\\":\\\"cl28\\\",\\\"x\\\":0,\\\"y\\\":0,\\\"type\\\":\\\"move_direction\\\",\\\"params\\\":[{\\\"id\\\":\\\"9op9\\\",\\\"x\\\":0,\\\"y\\\":0,\\\"type\\\":\\\"number\\\",\\\"params\\\":[10],\\\"statements\\\":[],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]},null],\\\"statements\\\":[],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]}]],\\\"movable\\\":null,\\\"deletable\\\":1,\\\"emphasized\\\":false,\\\"readOnly\\\":null,\\\"copyable\\\":true,\\\"assemble\\\":true,\\\"extensions\\\":[]}]]\",\"objectType\":\"sprite\",\"rotateMethod\":\"free\",\"scene\":\"7dwq\",\"sprite\":{\"pictures\":[{\"id\":\"vx80\",\"dimension\":{\"width\":144,\"height\":246},\"fileurl\":\"/lib/entry-js/images/media/entrybot1.svg\",\"thumbUrl\":\"/lib/entry-js/images/media/entrybot1.svg\",\"name\":\"엔트리봇_걷기1\",\"imageType\":\"svg\"},{\"id\":\"4t48\",\"dimension\":{\"width\":144,\"height\":246},\"fileurl\":\"/lib/entry-js/images/media/entrybot2.svg\",\"thumbUrl\":\"/lib/entry-js/images/media/entrybot2.svg\",\"name\":\"엔트리봇_걷기2\",\"imageType\":\"svg\"}],\"sounds\":[{\"duration\":1.3,\"ext\":\".mp3\",\"id\":\"8el5\",\"fileurl\":\"/lib/entry-js/images/media/bark.mp3\",\"name\":\"강아지 짖는 소리\"}]},\"selectedPictureId\":\"vx80\",\"lock\":false,\"entity\":{\"x\":0,\"y\":0,\"regX\":72,\"regY\":123,\"scaleX\":0.5128205128205128,\"scaleY\":0.5128205128205128,\"rotation\":0,\"direction\":90,\"width\":144,\"height\":246,\"font\":\"undefinedpx \",\"visible\":true}}],\"expansionBlocks\":[],\"aiUtilizeBlocks\":[],\"speed\":60,\"name\":\"260127_코딩_연구소 작품\",\"likeCnt\":0,\"visit\":0,\"isopen\":false,\"user\":\"62595ee73ad54503da9eef61\",\"messages\":[],\"functions\":[],\"tables\":[],\"interface\":{\"menuWidth\":280,\"canvasWidth\":480,\"object\":\"7y0y\"},\"hardwareLiteBlocks\":[],\"externalModules\":[],\"externalModulesLite\":[],\"isPracticalCourse\":false,\"blockLog\":{\"categories\":[\"event\",\"repeat\",\"walk\"],\"when_run_button_click\":1,\"repeat_basic\":1,\"number\":2,\"move_direction\":1}}}"
}).then(r => r.json());
const projectId = createRes?.data?.createProject?.result?.id;
if (!projectId) throw 'CREATE_FAIL';
/* ===== UPDATE (공식 공개 API 방식) ===== */
const tags = Array.from({ length: 5 }, () => gen(4));
const category = categories[Math.random() * categories.length | 0];
const title = `랜덤 작품 - ${gen(5)}`;
const description = `자동 생성\n${gen(16)}`;
const description2 = `사용법\n1.${gen(8)}\n2.${gen(8)}`;
const description3 = `비고 ${gen(10)}`;
const updateRes = await fetch("https://playentry.org/graphql/UPDATE_PROJECT", {
method: "POST",
mode: "cors",
credentials: "include",
headers: {
"accept": "*/*",
"content-type": "application/json",
"csrf-token": tokens.csrfToken,
"x-token": tokens.xToken,
"x-client-type": "Client"
},
referrer: "https://playentry.org/ws/new?type=normal&mode=block&lang=ko",
body: JSON.stringify({
query: `
mutation UPDATE_PROJECT(
$id: ID!
$name: String
$categoryCode: String
$description: String
$description2: String
$description3: String
$isopen: Boolean
$showComment: Boolean
$tags: [String]
) {
updateProject(
id: $id
name: $name
categoryCode: $categoryCode
description: $description
description2: $description2
description3: $description3
isopen: $isopen
showComment: $showComment
tags: $tags
) {
status
result
}
}
`,
variables: {
id: projectId,
name: title,
categoryCode: category,
description,
description2,
description3,
isopen: true,
showComment: true,
tags
}
})
}).then(r => r.json());
console.log(`✅ ${i + 1}/${count} 완료`, updateRes?.data?.updateProject);
});
await runPool(tasks, 4);
console.log('🎉 전체 완료');
})();
코드 사용법
콘솔에다가 입력
참고 사항
더보기
이 코드를 사용해 일어나는 피해와 책임은 모두 사용자에게 있습니다.
또한 엔트리는 커뮤니티 가이드라인 개정을 통해 자동화된 수단 사용을 지양하고 있으니 연구 목적으로 참고바랍니다.
기타 코드 문의는 댓글로 해주세요.
'엔트리' 카테고리의 다른 글
| 엔트리 자동 홍보 코드 (0) | 2026.03.30 |
|---|---|
| 엔트리 움직이는 썸네일 원터치 코드 (1) | 2024.08.03 |
| 엔트리 작품 악플 댓글 아이디 자동 차단 코드 (0) | 2024.08.03 |
| 엔트리 이야기 홍보 코드 (0) | 2024.08.03 |
| 엔트리 유저 찾기 코드 (0) | 2024.08.02 |