isaikr 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +35 -0
  2. package/cdn/api.js +19 -0
  3. package/cdn/character.js +254 -0
  4. package/cdn/chat.js +33 -0
  5. package/cdn/code-editor.js +1131 -0
  6. package/cdn/community-compose.js +270 -0
  7. package/cdn/games/2048/index.html +12 -0
  8. package/cdn/games/breakout/index.html +13 -0
  9. package/cdn/games/clicker/index.html +26 -0
  10. package/cdn/games/flappy/index.html +11 -0
  11. package/cdn/games/memory/index.html +34 -0
  12. package/cdn/games/pong/index.html +13 -0
  13. package/cdn/games/reaction/index.html +38 -0
  14. package/cdn/games/runner/index.html +11 -0
  15. package/cdn/games/snake/index.html +11 -0
  16. package/cdn/games/tetris/index.html +14 -0
  17. package/cdn/games/whack/index.html +8 -0
  18. package/cdn/go.js +126 -0
  19. package/cdn/go2.js +127 -0
  20. package/cdn/header3_behavior.js +1167 -0
  21. package/cdn/header3_layout.js +1004 -0
  22. package/cdn/header3_layout.js.bak +1004 -0
  23. package/cdn/header3_style.css +3524 -0
  24. package/cdn/header3_style.css.bak +3514 -0
  25. package/cdn/lang.js +198 -0
  26. package/cdn/loading.js +143 -0
  27. package/cdn/loading2.js +144 -0
  28. package/cdn/local-model.js +2941 -0
  29. package/cdn/main.js +4 -0
  30. package/cdn/main_asset.js +1849 -0
  31. package/cdn/main_asset.js.bak +6999 -0
  32. package/cdn/main_index.css +287 -0
  33. package/cdn/re_board3.css +733 -0
  34. package/cdn/re_board3.js +734 -0
  35. package/cdn/re_chat_tts.js +652 -0
  36. package/cdn/re_local_runtime.js +2246 -0
  37. package/cdn/re_local_runtime.js.bak +2246 -0
  38. package/cdn/re_share.js +577 -0
  39. package/cdn/re_voice.js +542 -0
  40. package/cdn/utils.js +36 -0
  41. package/cdn/view.js +321 -0
  42. package/header3_behavior.js +804 -0
  43. package/header3_layout.js +998 -0
  44. package/header3_style.css +2740 -0
  45. package/index.js +0 -0
  46. package/lang.js +179 -0
  47. package/main_asset.js +2416 -0
  48. package/main_index.css +274 -0
  49. package/package.json +14 -0
  50. package/re_chat_tts.js +1419 -0
  51. package/re_voice.js +430 -0
@@ -0,0 +1,577 @@
1
+ const reShareConfig = window.__ISAI_RE_SHARE_CONFIG__ || {};
2
+ window.savedPrompt = String(reShareConfig.savedPrompt || '').trim();
3
+ const isSharedView = String(reShareConfig.viewId || '');
4
+
5
+ window.addEventListener('load', () => {
6
+ const sharedImg = String(reShareConfig.ogImage || '');
7
+ if (isSharedView && sharedImg && !sharedImg.includes('isailogo2.png')) {
8
+ setTimeout(() => {
9
+ if (typeof setMode === 'function') setMode('image');
10
+ const img = document.getElementById('preview-img');
11
+ const container = document.getElementById('img-preview-container');
12
+ if (img) img.src = sharedImg;
13
+ if (container) {
14
+ container.classList.add('active');
15
+ container.style.setProperty('display', 'block', 'important');
16
+ }
17
+ const appGrid = document.getElementById('app-container');
18
+ if (appGrid) appGrid.style.setProperty('display', 'none', 'important');
19
+ }, 100);
20
+ }
21
+ });
22
+
23
+ window.currentShareCache = {};
24
+ window.ISAI_TEMP_SOCIAL_EXPIRE_MINUTES = Math.max(3, Math.min(60, Number(window.ISAI_TEMP_SOCIAL_EXPIRE_MINUTES || 10) || 10));
25
+
26
+ function getCharacterShareI18n() {
27
+ return (window.__ISAI_CHARACTER_SHARE_I18N__ && typeof window.__ISAI_CHARACTER_SHARE_I18N__ === 'object')
28
+ ? window.__ISAI_CHARACTER_SHARE_I18N__
29
+ : {};
30
+ }
31
+
32
+ function getImageReportI18n() {
33
+ return (window.__ISAI_IMAGE_REPORT_I18N__ && typeof window.__ISAI_IMAGE_REPORT_I18N__ === 'object')
34
+ ? window.__ISAI_IMAGE_REPORT_I18N__
35
+ : {};
36
+ }
37
+
38
+ function getSharePromptText() {
39
+ const inputElement = document.getElementById('prompt-input');
40
+ let promptText = inputElement ? String(inputElement.value || '').trim() : '';
41
+ if (!promptText || promptText === '...') {
42
+ promptText = window.currentImagePrompt || window.savedPrompt || 'AI Generated Art';
43
+ }
44
+ return promptText.replace(/\s-\s\d{4}-\d{2}-\d{2}.*$/, '').trim();
45
+ }
46
+
47
+ function buildShareCacheKey(currentSrc, promptText, options = {}) {
48
+ const persona = (options && typeof options.persona === 'object' && options.persona) ? options.persona : {};
49
+ return [
50
+ String(options.storageMode || 'imgur_if_needed'),
51
+ String(options.shareKind || 'gallery'),
52
+ options.reuseExistingPage === false ? 'new' : 'reuse',
53
+ String(currentSrc || ''),
54
+ String(promptText || ''),
55
+ String(persona.name || ''),
56
+ String(persona.age || ''),
57
+ String(persona.personality || ''),
58
+ String(persona.speech_style || persona.speechStyle || '')
59
+ ].join('||');
60
+ }
61
+
62
+ function getShareCacheEntry(cacheKey) {
63
+ if (!cacheKey) return null;
64
+ return window.currentShareCache[cacheKey] || null;
65
+ }
66
+
67
+ function setShareCacheEntry(cacheKey, value) {
68
+ if (!cacheKey) return;
69
+ window.currentShareCache[cacheKey] = value;
70
+ }
71
+
72
+ function getCurrentShareContext() {
73
+ const base = (window.__ISAI_SHARE_CONTEXT__ && typeof window.__ISAI_SHARE_CONTEXT__ === 'object')
74
+ ? window.__ISAI_SHARE_CONTEXT__
75
+ : {};
76
+ const params = new URLSearchParams(window.location.search);
77
+ return {
78
+ id: Number(base.id || 0) || 0,
79
+ shareId: String(base.shareId || params.get('v') || '').trim(),
80
+ shareKind: String(base.shareKind || '').trim(),
81
+ isShared: !!(base.isShared || params.get('v')),
82
+ hasPersona: !!base.hasPersona
83
+ };
84
+ }
85
+
86
+ function isExistingImageSharePost() {
87
+ return !!getCurrentShareContext().isShared;
88
+ }
89
+
90
+ function syncImageModalActionButtons() {
91
+ const isShared = isExistingImageSharePost();
92
+ const characterBtn = document.getElementById('image-modal-character-share-btn');
93
+ const reportBtn = document.getElementById('image-modal-report-btn');
94
+ if (characterBtn) characterBtn.classList.toggle('hidden', isShared);
95
+ if (reportBtn) reportBtn.classList.toggle('hidden', !isShared);
96
+ }
97
+
98
+ async function getProcessedBlob(imageUrl, maxWidth = 1200) {
99
+ const response = await fetch(imageUrl);
100
+ const originalBlob = await response.blob();
101
+ const mimeType = originalBlob.type || 'image/png';
102
+
103
+ if (mimeType === 'image/gif') {
104
+ return originalBlob;
105
+ }
106
+
107
+ return new Promise((resolve, reject) => {
108
+ const img = new Image();
109
+ img.crossOrigin = 'Anonymous';
110
+ img.src = URL.createObjectURL(originalBlob);
111
+ img.onload = () => {
112
+ const canvas = document.createElement('canvas');
113
+ let width = img.width;
114
+ let height = img.height;
115
+ if (width > maxWidth) {
116
+ height = Math.round((height * maxWidth) / width);
117
+ width = maxWidth;
118
+ }
119
+ canvas.width = width;
120
+ canvas.height = height;
121
+ const ctx = canvas.getContext('2d');
122
+ if (mimeType === 'image/jpeg') {
123
+ ctx.fillStyle = '#fff';
124
+ ctx.fillRect(0, 0, width, height);
125
+ }
126
+ ctx.drawImage(img, 0, 0, width, height);
127
+ canvas.toBlob((blob) => {
128
+ if (blob) resolve(blob);
129
+ else reject(new Error('Canvas failed'));
130
+ }, mimeType, 0.95);
131
+ };
132
+ img.onerror = () => reject(new Error('Image Load Failed'));
133
+ });
134
+ }
135
+
136
+ function getImageUploadFilename(prefix, blob) {
137
+ const mime = String(blob && blob.type ? blob.type : '').toLowerCase();
138
+ const extMap = {
139
+ 'image/jpeg': 'jpg',
140
+ 'image/jpg': 'jpg',
141
+ 'image/png': 'png',
142
+ 'image/webp': 'webp',
143
+ 'image/gif': 'gif'
144
+ };
145
+ return `${prefix}.${extMap[mime] || 'png'}`;
146
+ }
147
+
148
+ async function uploadImageToImgur(currentSrc) {
149
+ const processedBlob = await getProcessedBlob(currentSrc, 1200);
150
+ const formData = new FormData();
151
+ formData.append('image', processedBlob, getImageUploadFilename('isai-share-upload', processedBlob));
152
+
153
+ const keyRes = await fetch('get_key.php');
154
+ const keyData = await keyRes.json();
155
+ const myClientId = keyData.clientId;
156
+
157
+ const imgurRes = await fetch('https://api.imgur.com/3/image', {
158
+ method: 'POST',
159
+ headers: { 'Authorization': 'Client-ID ' + myClientId },
160
+ body: formData
161
+ });
162
+ const imgurData = await imgurRes.json();
163
+
164
+ if (!imgurData.success || !imgurData.data || !imgurData.data.link) {
165
+ throw new Error('Imgur Upload Failed');
166
+ }
167
+
168
+ return {
169
+ finalImageUrl: imgurData.data.link,
170
+ tempImageExpiresAt: ''
171
+ };
172
+ }
173
+
174
+ async function uploadImageToTemporaryShare(currentSrc, expiresMinutes = window.ISAI_TEMP_SOCIAL_EXPIRE_MINUTES) {
175
+ const processedBlob = await getProcessedBlob(currentSrc, 1200);
176
+ const formData = new FormData();
177
+ formData.append('image', processedBlob, getImageUploadFilename('isai-social-temp', processedBlob));
178
+ formData.append('expires_minutes', String(expiresMinutes));
179
+
180
+ const uploadRes = await fetch('re_store.php?action=upload_temp_share_image', {
181
+ method: 'POST',
182
+ body: formData
183
+ });
184
+ const uploadData = await uploadRes.json();
185
+
186
+ if (!uploadData || !uploadData.success || !uploadData.url) {
187
+ throw new Error((uploadData && uploadData.error) || 'Temporary Upload Failed');
188
+ }
189
+
190
+ return {
191
+ finalImageUrl: uploadData.url,
192
+ tempImageExpiresAt: uploadData.expires_at || ''
193
+ };
194
+ }
195
+
196
+ function normalizeCharacterPersonaForShare(rawPersona, promptText) {
197
+ const source = (rawPersona && typeof rawPersona === 'object') ? rawPersona : {};
198
+ const clampText = (value, maxLen) => {
199
+ const text = String(value || '').replace(/\r/g, '').trim();
200
+ if (!text) return '';
201
+ return text.length > maxLen ? text.slice(0, maxLen) : text;
202
+ };
203
+ const ageRaw = Number(source.age || 0);
204
+ const age = Number.isFinite(ageRaw) && ageRaw >= 19 && ageRaw <= 120 ? Math.floor(ageRaw) : 0;
205
+ return {
206
+ name: clampText(source.name, 80),
207
+ age,
208
+ personality: clampText(source.personality, 300),
209
+ speech_style: clampText(source.speech_style || source.speechStyle, 300),
210
+ background: clampText(source.background || promptText, 420),
211
+ opening_line: clampText(source.opening_line || source.openingLine, 320),
212
+ locale: clampText(source.locale || '', 10)
213
+ };
214
+ }
215
+
216
+ async function uploadAndSaveImage(currentSrc, promptText, options = {}) {
217
+ const storageMode = String(options.storageMode || 'imgur_if_needed').toLowerCase();
218
+ const shareKind = String(options.shareKind || 'gallery').toLowerCase();
219
+ const reuseExistingPage = options.reuseExistingPage !== false;
220
+ const persona = normalizeCharacterPersonaForShare(options.persona, promptText);
221
+ const hasPersona = !!(persona.name || persona.personality || persona.age >= 19);
222
+ const cacheKey = buildShareCacheKey(currentSrc, promptText, { storageMode, shareKind, reuseExistingPage, persona });
223
+
224
+ const urlParams = new URLSearchParams(window.location.search);
225
+ const existingV = urlParams.get('v');
226
+ if (existingV && reuseExistingPage) {
227
+ return {
228
+ shareId: existingV,
229
+ finalImageUrl: currentSrc,
230
+ shareKind
231
+ };
232
+ }
233
+
234
+ const cached = getShareCacheEntry(cacheKey);
235
+ if (cached && cached.shareId) {
236
+ return cached;
237
+ }
238
+
239
+ let finalImageUrl = currentSrc;
240
+ let tempImageExpiresAt = '';
241
+ if (storageMode === 'temporary') {
242
+ const tempResult = await uploadImageToTemporaryShare(finalImageUrl, window.ISAI_TEMP_SOCIAL_EXPIRE_MINUTES);
243
+ finalImageUrl = tempResult.finalImageUrl;
244
+ tempImageExpiresAt = tempResult.tempImageExpiresAt || '';
245
+ } else if (storageMode === 'imgur') {
246
+ const imgurResult = await uploadImageToImgur(finalImageUrl);
247
+ finalImageUrl = imgurResult.finalImageUrl;
248
+ } else if (storageMode === 'imgur_if_needed' && (finalImageUrl.startsWith('blob:') || finalImageUrl.startsWith('data:'))) {
249
+ const imgurResult = await uploadImageToImgur(finalImageUrl);
250
+ finalImageUrl = imgurResult.finalImageUrl;
251
+ }
252
+
253
+ const dbRes = await fetch('re_store.php?action=save_share', {
254
+ method: 'POST',
255
+ headers: { 'Content-Type': 'application/json' },
256
+ body: JSON.stringify({
257
+ prompt: promptText,
258
+ image_url: finalImageUrl,
259
+ share_kind: shareKind,
260
+ temp_image_expires_at: tempImageExpiresAt,
261
+ persona: hasPersona ? persona : null
262
+ })
263
+ });
264
+ const data = await dbRes.json();
265
+
266
+ if (!data || !data.success) {
267
+ throw new Error((data && data.error) || 'DB Save Failed');
268
+ }
269
+
270
+ const result = {
271
+ dbId: Number(data.id || 0) || 0,
272
+ shareId: data.share_id,
273
+ finalImageUrl,
274
+ shareKind,
275
+ tempImageExpiresAt
276
+ };
277
+ setShareCacheEntry(cacheKey, result);
278
+ return result;
279
+ }
280
+
281
+ async function shareCurrentResult() {
282
+ const urlParams = new URLSearchParams(window.location.search);
283
+ const currentV = urlParams.get('v');
284
+
285
+ if (currentV) {
286
+ const shareUrl = window.location.origin + window.location.pathname + '?v=' + currentV;
287
+ navigator.clipboard.writeText(shareUrl);
288
+ if (typeof showToast === 'function') showToast('留곹겕媛€ 蹂듭궗?섏뿀?듬땲??');
289
+ else alert('留곹겕媛€ 蹂듭궗?섏뿀?듬땲??');
290
+ return;
291
+ }
292
+
293
+ const imgElement = document.getElementById('preview-img');
294
+ if (!imgElement || !imgElement.src || imgElement.src.includes('isailogo2.png')) {
295
+ if (typeof showToast === 'function') showToast('No image to save.');
296
+ else alert('?대?吏€媛€ ?놁뒿?덈떎.');
297
+ return;
298
+ }
299
+
300
+ const promptText = getSharePromptText();
301
+ if (typeof showLoader === 'function') showLoader(true);
302
+ if (typeof showToast === 'function') showToast('Saving to Gallery...');
303
+
304
+ try {
305
+ const result = await uploadAndSaveImage(imgElement.src, promptText, {
306
+ storageMode: 'imgur_if_needed',
307
+ shareKind: 'gallery',
308
+ reuseExistingPage: true
309
+ });
310
+ const shareUrl = window.location.origin + window.location.pathname + '?v=' + result.shareId;
311
+ navigator.clipboard.writeText(shareUrl);
312
+ const newUrl = window.location.pathname + '?v=' + result.shareId;
313
+ window.history.pushState({ path: newUrl }, '', newUrl);
314
+ if (window.__ISAI_SHARE_CONTEXT__) {
315
+ window.__ISAI_SHARE_CONTEXT__.id = Number(result.dbId || window.__ISAI_SHARE_CONTEXT__.id || 0) || 0;
316
+ window.__ISAI_SHARE_CONTEXT__.shareId = result.shareId;
317
+ window.__ISAI_SHARE_CONTEXT__.shareKind = 'gallery';
318
+ window.__ISAI_SHARE_CONTEXT__.isShared = true;
319
+ }
320
+ syncImageModalActionButtons();
321
+ if (typeof showToast === 'function') showToast('Saved Successfully!');
322
+ } catch (e) {
323
+ console.error(e);
324
+ if (typeof showToast === 'function') showToast('Error: ' + e.message);
325
+ else alert('Error: ' + e.message);
326
+ } finally {
327
+ if (typeof showLoader === 'function') showLoader(false);
328
+ }
329
+ }
330
+
331
+ async function shareToSocial(platform) {
332
+ const imgElement = document.getElementById('preview-img');
333
+ if (!imgElement || !imgElement.src || imgElement.src.includes('isailogo2.png')) {
334
+ alert('怨듭쑀??肄섑뀗痢좉? ?놁뒿?덈떎.');
335
+ return;
336
+ }
337
+
338
+ const promptText = getSharePromptText();
339
+ const shareWindow = window.open('about:blank', '_blank', 'width=600,height=600');
340
+
341
+ try {
342
+ const result = await uploadAndSaveImage(imgElement.src, promptText, {
343
+ storageMode: 'temporary',
344
+ shareKind: 'social_temp',
345
+ reuseExistingPage: false
346
+ });
347
+
348
+ const baseUrl = window.location.origin + window.location.pathname;
349
+ const shareUrl = baseUrl + '?v=' + result.shareId;
350
+ const proxiedImgUrl = window.location.origin + '/proxy_img.php?url=' + encodeURIComponent(result.finalImageUrl);
351
+
352
+ const encodedUrl = encodeURIComponent(shareUrl);
353
+ const encodedText = encodeURIComponent(promptText);
354
+ const encodedImg = encodeURIComponent(proxiedImgUrl);
355
+
356
+ let snsUrl = '';
357
+ switch (platform) {
358
+ case 'pinterest': snsUrl = `https://www.pinterest.com/pin/create/button/?url=${encodedUrl}&media=${encodedImg}&description=${encodedText}`; break;
359
+ case 'x': snsUrl = `https://twitter.com/intent/tweet?text=${encodedText}&url=${encodedUrl}`; break;
360
+ case 'threads': snsUrl = `https://www.threads.net/intent/post?text=${encodedText}%20${encodedUrl}`; break;
361
+ case 'facebook': snsUrl = `https://www.facebook.com/sharer/sharer.php?u=${encodedUrl}`; break;
362
+ case 'tumblr': snsUrl = `https://www.tumblr.com/widgets/share/tool?posttype=link&title=${encodedText}&canonicalUrl=${encodedUrl}`; break;
363
+ }
364
+
365
+ if (snsUrl) shareWindow.location.href = snsUrl;
366
+ else shareWindow.close();
367
+ } catch (e) {
368
+ console.error(e);
369
+ if (shareWindow) shareWindow.close();
370
+ alert('怨듭쑀 以??ㅻ쪟媛€ 諛쒖깮?덉뒿?덈떎: ' + e.message);
371
+ }
372
+ }
373
+
374
+ async function saveCurrentResultToGallery() {
375
+ const urlParams = new URLSearchParams(window.location.search);
376
+ const currentV = urlParams.get('v');
377
+
378
+ if (currentV) {
379
+ if (typeof showToast === 'function') showToast('Already saved as a post.');
380
+ else alert('Already saved as a post.');
381
+ return { shareId: currentV, alreadySaved: true };
382
+ }
383
+
384
+ const imgElement = document.getElementById('preview-img');
385
+ if (!imgElement || !imgElement.src || imgElement.src.includes('isailogo2.png')) {
386
+ if (typeof showToast === 'function') showToast('No image to save.');
387
+ else alert('No image available.');
388
+ return null;
389
+ }
390
+
391
+ const promptText = getSharePromptText();
392
+ if (typeof showLoader === 'function') showLoader(true);
393
+ if (typeof showToast === 'function') showToast('Saving post...');
394
+
395
+ try {
396
+ const result = await uploadAndSaveImage(imgElement.src, promptText, {
397
+ storageMode: 'imgur_if_needed',
398
+ shareKind: 'gallery',
399
+ reuseExistingPage: true
400
+ });
401
+ const newUrl = window.location.pathname + '?v=' + result.shareId;
402
+ window.history.pushState({ path: newUrl }, '', newUrl);
403
+ if (window.__ISAI_SHARE_CONTEXT__) {
404
+ window.__ISAI_SHARE_CONTEXT__.id = Number(result.dbId || window.__ISAI_SHARE_CONTEXT__.id || 0) || 0;
405
+ window.__ISAI_SHARE_CONTEXT__.shareId = result.shareId;
406
+ window.__ISAI_SHARE_CONTEXT__.shareKind = 'gallery';
407
+ window.__ISAI_SHARE_CONTEXT__.isShared = true;
408
+ }
409
+ syncImageModalActionButtons();
410
+ if (typeof showToast === 'function') showToast('Post created successfully!');
411
+ return { ...result, alreadySaved: false };
412
+ } catch (e) {
413
+ console.error(e);
414
+ if (typeof showToast === 'function') showToast('Error: ' + e.message);
415
+ else alert('Error: ' + e.message);
416
+ throw e;
417
+ } finally {
418
+ if (typeof showLoader === 'function') showLoader(false);
419
+ }
420
+ }
421
+
422
+ function openCharacterShareModal() {
423
+ const i18n = getCharacterShareI18n();
424
+ if (isExistingImageSharePost()) {
425
+ if (typeof showToast === 'function') showToast('Already posted image. Use report instead.');
426
+ return;
427
+ }
428
+ const modal = document.getElementById('character-share-modal');
429
+ const imgElement = document.getElementById('preview-img');
430
+ if (!modal || !imgElement || !imgElement.src || imgElement.src.includes('isailogo2.png')) {
431
+ if (typeof showToast === 'function') showToast('No image available.');
432
+ return;
433
+ }
434
+ const preview = document.getElementById('character-share-preview');
435
+ const promptView = document.getElementById('character-share-prompt');
436
+ const nameField = document.getElementById('character-share-name');
437
+ const ageField = document.getElementById('character-share-age');
438
+ const personalityField = document.getElementById('character-share-personality');
439
+ const speechField = document.getElementById('character-share-speech');
440
+ const promptText = getSharePromptText();
441
+ if (preview) preview.src = imgElement.src;
442
+ if (promptView) promptView.textContent = promptText || i18n.noPrompt || 'No prompt';
443
+ if (nameField) nameField.value = '';
444
+ if (ageField) ageField.value = '19';
445
+ if (personalityField) personalityField.value = '';
446
+ if (speechField) speechField.value = '';
447
+ modal.classList.remove('hidden');
448
+ }
449
+
450
+ function closeCharacterShareModal() {
451
+ const modal = document.getElementById('character-share-modal');
452
+ if (modal) modal.classList.add('hidden');
453
+ }
454
+
455
+ async function createCharacterSharePost() {
456
+ const i18n = getCharacterShareI18n();
457
+ const imgElement = document.getElementById('preview-img');
458
+ if (!imgElement || !imgElement.src || imgElement.src.includes('isailogo2.png')) {
459
+ if (typeof showToast === 'function') showToast('No image available.');
460
+ return;
461
+ }
462
+ const promptText = getSharePromptText();
463
+ const name = String(document.getElementById('character-share-name')?.value || '').trim();
464
+ const age = Number(document.getElementById('character-share-age')?.value || 0);
465
+ const personality = String(document.getElementById('character-share-personality')?.value || '').trim();
466
+ const speechStyle = String(document.getElementById('character-share-speech')?.value || '').trim();
467
+ if (!name) {
468
+ if (typeof showToast === 'function') showToast(i18n.nameRequired || 'Please enter a character name.');
469
+ return;
470
+ }
471
+ if (!Number.isFinite(age) || age < 19) {
472
+ if (typeof showToast === 'function') showToast(i18n.ageRequired || 'Character age must be 19 or older.');
473
+ return;
474
+ }
475
+ if (!personality) {
476
+ if (typeof showToast === 'function') showToast(i18n.personalityRequired || 'Please enter the character personality.');
477
+ return;
478
+ }
479
+ if (typeof showLoader === 'function') showLoader(true);
480
+ if (typeof showToast === 'function') showToast(i18n.creating || 'Character post is being created...');
481
+ try {
482
+ const result = await uploadAndSaveImage(imgElement.src, promptText, {
483
+ storageMode: 'imgur',
484
+ shareKind: 'character',
485
+ reuseExistingPage: false,
486
+ persona: {
487
+ name,
488
+ age,
489
+ personality,
490
+ speech_style: speechStyle,
491
+ background: promptText
492
+ }
493
+ });
494
+ const newUrl = window.location.pathname + '?v=' + result.shareId;
495
+ window.history.pushState({ path: newUrl }, '', newUrl);
496
+ if (window.__ISAI_SHARE_CONTEXT__) {
497
+ window.__ISAI_SHARE_CONTEXT__.id = Number(result.dbId || window.__ISAI_SHARE_CONTEXT__.id || 0) || 0;
498
+ window.__ISAI_SHARE_CONTEXT__.shareId = result.shareId;
499
+ window.__ISAI_SHARE_CONTEXT__.shareKind = 'character';
500
+ window.__ISAI_SHARE_CONTEXT__.isShared = true;
501
+ window.__ISAI_SHARE_CONTEXT__.hasPersona = true;
502
+ }
503
+ syncImageModalActionButtons();
504
+ closeCharacterShareModal();
505
+ if (typeof showToast === 'function') showToast(i18n.created || 'Character post created successfully!');
506
+ } catch (e) {
507
+ console.error(e);
508
+ if (typeof showToast === 'function') showToast('Error: ' + e.message);
509
+ else alert('Error: ' + e.message);
510
+ } finally {
511
+ if (typeof showLoader === 'function') showLoader(false);
512
+ }
513
+ }
514
+
515
+ function openImageShareReportModal() {
516
+ const context = getCurrentShareContext();
517
+ if (!context.isShared || !context.id) {
518
+ if (typeof showToast === 'function') showToast('Saved image post not found.');
519
+ return;
520
+ }
521
+ const modal = document.getElementById('image-report-modal');
522
+ const textarea = document.getElementById('image-report-reason');
523
+ if (textarea) textarea.value = '';
524
+ if (modal) modal.classList.remove('hidden');
525
+ }
526
+
527
+ function closeImageShareReportModal() {
528
+ const modal = document.getElementById('image-report-modal');
529
+ if (modal) modal.classList.add('hidden');
530
+ }
531
+
532
+ async function submitImageShareReport() {
533
+ const i18n = getImageReportI18n();
534
+ const context = getCurrentShareContext();
535
+ const textarea = document.getElementById('image-report-reason');
536
+ const reason = String(textarea?.value || '').trim();
537
+ if (!context.isShared || !context.id) {
538
+ if (typeof showToast === 'function') showToast('Saved image post not found.');
539
+ return;
540
+ }
541
+ if (!reason) {
542
+ if (typeof showToast === 'function') showToast(i18n.placeholder || 'Write the reason for this report');
543
+ return;
544
+ }
545
+ try {
546
+ const res = await fetch('re_store.php?action=submit_content_report', {
547
+ method: 'POST',
548
+ headers: { 'Content-Type': 'application/json' },
549
+ body: JSON.stringify({
550
+ target_type: 'gallery',
551
+ target_id: context.id,
552
+ reason
553
+ })
554
+ });
555
+ const data = await res.json();
556
+ if (!data || !data.success) {
557
+ throw new Error((data && data.error) || 'REPORT_FAILED');
558
+ }
559
+ closeImageShareReportModal();
560
+ if (data.deleted) {
561
+ if (typeof showToast === 'function') showToast(i18n.deleted || 'The post was removed after repeated reports.');
562
+ window.setTimeout(() => {
563
+ window.location.href = '/';
564
+ }, 700);
565
+ return;
566
+ }
567
+ if (typeof showToast === 'function') {
568
+ showToast(data.reported ? (i18n.reported || 'Report submitted.') : (i18n.duplicate || 'You already reported this post this month.'));
569
+ }
570
+ } catch (error) {
571
+ console.error(error);
572
+ if (typeof showToast === 'function') showToast(i18n.error || 'An error occurred while submitting the report.');
573
+ }
574
+ }
575
+
576
+ window.addEventListener('DOMContentLoaded', syncImageModalActionButtons);
577
+ window.addEventListener('popstate', syncImageModalActionButtons);