Guest User

Untitled

a guest
Feb 5th, 2025
370
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 10.96 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="ru">
  3. <head>
  4.   <meta charset="UTF-8">
  5.   <title>Просмотрщик JSON диалогов</title>
  6.   <style>
  7.     body {
  8.       font-family: Arial, sans-serif;
  9.       margin: 20px;
  10.     }
  11.     h1 {
  12.       font-size: 24px;
  13.     }
  14.     #conversation {
  15.       margin-top: 20px;
  16.     }
  17.     .message {
  18.       border: 1px solid #ccc;
  19.       border-radius: 5px;
  20.       padding: 10px;
  21.       margin-bottom: 10px;
  22.       display: flex; /* Включаем флекс‑раскладку, чтобы разместить аватар и контент в одной строке */
  23.       align-items: flex-start; /* Аватар и текст выравниваем по верхнему краю */
  24.     }
  25.     .message-avatar {
  26.       margin-right: 10px;
  27.     }
  28.     .message-avatar img {
  29.       width: 40px;
  30.       height: 40px;
  31.       border-radius: 50%;
  32.       object-fit: cover;
  33.     }
  34.     .message-content {
  35.       flex: 1; /* Заставляем контент занимать оставшееся пространство */
  36.     }
  37.     .message-header {
  38.       font-weight: bold;
  39.       margin-bottom: 5px;
  40.     }
  41.     .message-text {
  42.       margin-bottom: 5px;
  43.       white-space: pre-wrap;
  44.     }
  45.     .attachments img {
  46.       max-width: 300px;
  47.       display: block;
  48.       margin-bottom: 5px;
  49.       cursor: pointer;
  50.     }
  51.     .attachments a {
  52.       text-decoration: none;
  53.       color: #0066cc;
  54.     }
  55.     .forwards {
  56.       border-left: 2px solid #999;
  57.       margin-left: 10px;
  58.       padding-left: 10px;
  59.       margin-top: 10px;
  60.     }
  61.  
  62.     /* Кнопки навигации */
  63.     #navButtons {
  64.       position: fixed;
  65.       top: 20px;
  66.       right: 20px;
  67.       z-index: 999; /* чтобы кнопки были поверх контента */
  68.     }
  69.     #navButtons button {
  70.       margin-right: 5px;
  71.       padding: 8px 12px;
  72.       cursor: pointer;
  73.     }
  74.   </style>
  75. </head>
  76. <body>
  77.   <h1>Просмотрщик JSON диалогов</h1>
  78.   <p>Выберите JSON‑файл с диалогом (например, 397536668.json):</p>
  79.   <input type="file" id="fileInput" accept=".json">
  80.  
  81.   <!-- Кнопки навигации -->
  82.   <div id="navButtons">
  83.     <button id="prevButton">Назад</button>
  84.     <button id="nextButton">Вперёд</button>
  85.   </div>
  86.  
  87.   <div id="conversation"></div>
  88.  
  89.   <script>
  90.     // Глобальные переменные для работы с фото
  91.     let photoMessages = []; // массив индексов сообщений, где есть хотя бы одно фото
  92.     let currentPhotoIndex = 0; // индекс в массиве photoMessages
  93.  
  94.     /**
  95.      * Рекурсивная функция для создания DOM‑элемента для одного сообщения.
  96.      * Если у сообщения есть вложенные пересылаемые сообщения (fwd), они также обрабатываются.
  97.      */
  98.     function createMessageElement(message, profiles) {
  99.       const messageDiv = document.createElement('div');
  100.       messageDiv.className = 'message';
  101.  
  102.       // Определяем имя отправителя по полю from через массив profiles
  103.       const sender = profiles.find(p => p.id === message.from);
  104.       const senderName = sender ? `${sender.firstName} ${sender.lastName}` : 'Неизвестно';
  105.       const senderPhoto = sender && sender.photo ? sender.photo : ''; // ссылка на фото отправителя
  106.  
  107.       // Создаем блок для аватарки
  108.       const avatarDiv = document.createElement('div');
  109.       avatarDiv.className = 'message-avatar';
  110.       const avatarImg = document.createElement('img');
  111.       avatarImg.src = senderPhoto;
  112.       avatarImg.alt = senderName;
  113.       avatarDiv.appendChild(avatarImg);
  114.  
  115.       // Создаем блок для контента (заголовок, текст, вложения)
  116.       const contentDiv = document.createElement('div');
  117.       contentDiv.className = 'message-content';
  118.  
  119.       // Форматируем дату (в JSON время задано в формате Unix timestamp)
  120.       const date = new Date(message.time * 1000);
  121.       const header = document.createElement('div');
  122.       header.className = 'message-header';
  123.       header.textContent = `${senderName} — ${date.toLocaleString()}`;
  124.       contentDiv.appendChild(header);
  125.  
  126.       // Текст сообщения
  127.       const textDiv = document.createElement('div');
  128.       textDiv.className = 'message-text';
  129.       textDiv.textContent = message.text || '';
  130.       contentDiv.appendChild(textDiv);
  131.  
  132.       // Если есть attachments (например, фото или документы)
  133.       if (message.attachments && Array.isArray(message.attachments)) {
  134.        const attachmentsDiv = document.createElement('div');
  135.         attachmentsDiv.className = 'attachments';
  136.         message.attachments.forEach(attachment => {
  137.           if (attachment.type === 'photo') {
  138.             // Для фото выводим изображение, обёрнутое в ссылку,
  139.             // которая открывает полную версию (hd) или превью, если hd отсутствует
  140.             const a = document.createElement('a');
  141.             a.href = attachment.hd || attachment.preview;
  142.             a.target = '_blank';
  143.             const img = document.createElement('img');
  144.             img.src = attachment.preview;
  145.             img.alt = 'Фото';
  146.             a.appendChild(img);
  147.             attachmentsDiv.appendChild(a);
  148.           } else if (attachment.type === 'doc') {
  149.             // Для документов выводим ссылку с названием файла
  150.             const docLink = document.createElement('a');
  151.             docLink.href = attachment.link;
  152.             docLink.textContent = attachment.title;
  153.             docLink.target = '_blank';
  154.             attachmentsDiv.appendChild(docLink);
  155.           }
  156.           // Если нужны другие типы вложений – можно добавить обработку здесь
  157.         });
  158.         contentDiv.appendChild(attachmentsDiv);
  159.       }
  160.  
  161.       // Если сообщение содержит пересланные (fwd) сообщения, обрабатываем их рекурсивно
  162.       if (message.fwd && Array.isArray(message.fwd)) {
  163.        const fwdDiv = document.createElement('div');
  164.         fwdDiv.className = 'forwards';
  165.         message.fwd.forEach(fwdMsg => {
  166.           const fwdMessageElement = createMessageElement(fwdMsg, profiles);
  167.           fwdDiv.appendChild(fwdMessageElement);
  168.         });
  169.         contentDiv.appendChild(fwdDiv);
  170.       }
  171.  
  172.       // Добавляем блоки на общую обёртку сообщения
  173.       messageDiv.appendChild(avatarDiv);
  174.       messageDiv.appendChild(contentDiv);
  175.  
  176.       return messageDiv;
  177.     }
  178.  
  179.     // Функция для прокрутки к сообщению с фото по индексу в photoMessages
  180.     function scrollToPhotoMessage(index) {
  181.       const conversationDiv = document.getElementById('conversation');
  182.       if (photoMessages.length === 0) return; // Если вообще нет сообщений с фото
  183.       if (index < 0 || index >= photoMessages.length) return; // Вне диапазона
  184.  
  185.       const messageIndex = photoMessages[index];
  186.       const messageElement = conversationDiv.children[messageIndex];
  187.       if (messageElement) {
  188.         messageElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
  189.       }
  190.     }
  191.  
  192.     // Обработчик нажатия кнопки "Назад"
  193.     function goPrevPhoto() {
  194.       if (photoMessages.length === 0) return;
  195.       currentPhotoIndex = (currentPhotoIndex - 1 + photoMessages.length) % photoMessages.length;
  196.       scrollToPhotoMessage(currentPhotoIndex);
  197.     }
  198.  
  199.     // Обработчик нажатия кнопки "Вперёд"
  200.     function goNextPhoto() {
  201.       if (photoMessages.length === 0) return;
  202.       currentPhotoIndex = (currentPhotoIndex + 1) % photoMessages.length;
  203.       scrollToPhotoMessage(currentPhotoIndex);
  204.     }
  205.  
  206.     // Обработчик выбора файла
  207.     document.getElementById('fileInput').addEventListener('change', function(event) {
  208.       const file = event.target.files[0];
  209.       if (!file) return;
  210.  
  211.       const reader = new FileReader();
  212.       reader.onload = function(e) {
  213.         try {
  214.           let content = e.target.result;
  215.  
  216.           // Если файл начинается с "let dialogjson =", удаляем эту часть
  217.           if (content.trim().startsWith('let dialogjson')) {
  218.             const index = content.indexOf('{');
  219.             if (index !== -1) {
  220.               content = content.substring(index);
  221.             }
  222.           }
  223.  
  224.           const data = JSON.parse(content);
  225.  
  226.           // Проверяем наличие необходимых полей messages и profiles
  227.           if (!data.messages || !data.profiles) {
  228.             alert('Неверный формат JSON: отсутствуют поля messages или profiles');
  229.             return;
  230.           }
  231.  
  232.           // Сортируем сообщения по времени (от старых к новым)
  233.           data.messages.sort((a, b) => a.time - b.time);
  234.  
  235.           // Очищаем контейнер для переписки
  236.           const conversationDiv = document.getElementById('conversation');
  237.           conversationDiv.innerHTML = '';
  238.  
  239.           // Сбрасываем массив фото и индекс
  240.           photoMessages = [];
  241.           currentPhotoIndex = 0;
  242.  
  243.           // Выводим каждое сообщение и попутно собираем индексы, где есть фото
  244.           data.messages.forEach((message, index) => {
  245.             const messageElement = createMessageElement(message, data.profiles);
  246.             conversationDiv.appendChild(messageElement);
  247.  
  248.             // Проверяем, есть ли хотя бы одна фотография в attachments
  249.             if (message.attachments && message.attachments.some(a => a.type === 'photo')) {
  250.              photoMessages.push(index);
  251.             }
  252.           });
  253.         } catch (error) {
  254.           alert('Ошибка при чтении JSON: ' + error.message);
  255.         }
  256.       };
  257.       reader.readAsText(file);
  258.     });
  259.  
  260.     // Слушатели для кнопок "Назад" / "Вперёд"
  261.     document.getElementById('prevButton').addEventListener('click', goPrevPhoto);
  262.     document.getElementById('nextButton').addEventListener('click', goNextPhoto);
  263.  
  264.     // Слушатель нажатий на клавиши (стрелки влево / вправо)
  265.     document.addEventListener('keydown', (e) => {
  266.       if (e.key === 'ArrowLeft') {
  267.         goPrevPhoto();
  268.       } else if (e.key === 'ArrowRight') {
  269.         goNextPhoto();
  270.       }
  271.     });
  272.   </script>
  273. </body>
  274. </html>
  275.  
Advertisement
Add Comment
Please, Sign In to add comment