diff options
| author | Mistivia <i@mistivia.com> | 2025-10-24 00:02:08 +0800 |
|---|---|---|
| committer | Mistivia <i@mistivia.com> | 2025-10-24 00:02:08 +0800 |
| commit | 5c71d2a538a93fd4a4fc06cb7941231cc5c0b104 (patch) | |
| tree | eabed03636eb9210234a317751924034d665fef1 | |
| parent | e1b67e5d2e13acbf0bf1673025e129556679e5cf (diff) | |
add irclog
| -rw-r--r-- | irclog/#main/2025/10-31.txt | 3 | ||||
| -rw-r--r-- | irclog/index.html | 0 | ||||
| -rw-r--r-- | irclog/linksub.js | 130 | ||||
| -rw-r--r-- | irclog/nginx.config | 9 | ||||
| -rw-r--r-- | irclog/view.html | 114 |
5 files changed, 256 insertions, 0 deletions
diff --git a/irclog/#main/2025/10-31.txt b/irclog/#main/2025/10-31.txt new file mode 100644 index 0000000..46e1367 --- /dev/null +++ b/irclog/#main/2025/10-31.txt @@ -0,0 +1,3 @@ +[00:00:00] <alice>: hello. +[00:00:01] <bob>: bye. + diff --git a/irclog/index.html b/irclog/index.html new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/irclog/index.html diff --git a/irclog/linksub.js b/irclog/linksub.js new file mode 100644 index 0000000..f855435 --- /dev/null +++ b/irclog/linksub.js @@ -0,0 +1,130 @@ +(function() { + 'use strict'; + + const targetUrlPattern = /https:\/\/raye\.mistivia\.com\/irclog\/([^/]+)\/(\d+)\/$/; + + const currentUrl = window.location.href; + + const match = currentUrl.match(targetUrlPattern); + + if (match) { + let channel = match[1]; + let year = match[2]; + + channel = channel.replace(/%23/g, '#'); + year = year.replace(/%23/g, '#'); + + const links = document.querySelectorAll('a'); + + links.forEach(link => { + const originalHref = link.getAttribute('href'); + + if (originalHref && originalHref.match(/^(\d{2}-\d{2}|\d{4}-\d{2}-\d{2}|[a-zA-Z0-9_-]+)\.txt$/)) { + + let datePart = originalHref.replace(/\.txt$/, ''); + + datePart = datePart.replace(/%23/g, '#'); + const newHref = `https://raye.mistivia.com/irclog/view.html#${channel}/${year}/${datePart}`; + + link.setAttribute('href', newHref); + } + }); + } +})(); + +(function() { + // Check if the title starts with "Index of" + if (document.title.startsWith("Index of")) { + // --- Mobile-Friendly Styles (CSS equivalent) --- + var style = document.createElement('style'); + style.textContent = ` + body { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + margin: 0; + padding: 15px; + background-color: #ffffff; + color: #333; + max-width: 900px; + } + h1 { + font-size: 1.8em; /* 标题稍大 */ + margin-bottom: 15px; + color: #2c3e50; + } + hr { + border: 0; + border-top: 1px solid #ddd; + margin: 10px 0 15px 0; + } + pre { + white-space: pre-wrap; + word-wrap: break-word; + padding: 0; + margin: 0; + } + + /* 列表项链接样式 */ + a { + display: block; + padding: 12px 10px; /* 增加点击区域和间距 */ + font-size: 1.2em; /* 字体大一点 */ + text-decoration: none; + color: #007aff; + border-bottom: 1px solid #eee; + transition: background-color 0.2s ease; /* 添加过渡效果 */ + } + + /* 鼠标悬停变色 (桌面端) */ + a:hover { + background-color: #f0f8ff; /* 浅蓝色背景 */ + color: #005bb5; /* 链接颜色略深 */ + } + + /* 最后一个元素不显示底部分割线 */ + pre a:last-child { + border-bottom: none; + } + + /* 确保只显示文件名 */ + .filename-only { + display: block !important; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + width: 100%; + } + `; + document.head.appendChild(style); + const standardContent = 'width=device-width, initial-scale=1.0, viewport-fit=cover'; + const newViewport = document.createElement('meta'); + newViewport.setAttribute('name', 'viewport'); + newViewport.setAttribute('content', standardContent); + document.head.appendChild(newViewport); + + + // --- Clean up the Listing (JavaScript DOM Manipulation) --- + var pre = document.querySelector('pre'); + if (pre) { + + var links = pre.querySelectorAll('a'); + + // 2. Clear the original <pre> content + pre.textContent = ''; + + links.forEach(function(link) { + // Get the href and the filename text + var filename = link.textContent.trim(); // Trim whitespace + var href = link.getAttribute('href'); + + // Create a new, clean anchor element + var newLink = document.createElement('a'); + newLink.setAttribute('href', href); + newLink.classList.add('filename-only'); + newLink.textContent = filename; // Only the filename + + // Append the clean link to the <pre> block + pre.appendChild(newLink); + }); + } + } +})(); diff --git a/irclog/nginx.config b/irclog/nginx.config new file mode 100644 index 0000000..d00dae1 --- /dev/null +++ b/irclog/nginx.config @@ -0,0 +1,9 @@ +server { + # ... + location /irclog/ { + charset UTF-8; + autoindex on; + sub_filter_types text/html; + sub_filter '</body>' '<script src="/irclog/linksub.js"></script></body>'; + } +} diff --git a/irclog/view.html b/irclog/view.html new file mode 100644 index 0000000..6d8385c --- /dev/null +++ b/irclog/view.html @@ -0,0 +1,114 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <title>IRC Log Viewer</title> + <style> + body { + font-family: Arial, sans-serif; + max-width: 1000px; + margin: 20px; + background-color: #f4f4f4; + } + #log-container { + border: 1px solid #ccc; + padding: 15px; + background-color: #fff; + white-space: pre-wrap; + } + pre { + font-family: Consolas, monospace; + margin: 0; + padding: 0; + overflow-wrap: anywhere; + white-space: pre-wrap; + } + .error { + color: red; + font-weight: bold; + } + .loading { + color: blue; + } + </style> +</head> +<body> + + <h1>IRC Log Viewer</h1> + <div id="status"></div> + <div id="log-container"> + </div> + + <script> + document.addEventListener('DOMContentLoaded', () => { + const statusDiv = document.getElementById('status'); + const logContainer = document.getElementById('log-container'); + + let urlHash = window.location.hash.substring(1); + + if (!urlHash) { + statusDiv.className = 'error'; + statusDiv.textContent = 'Error: No hash fragment found in the URL. Please append a hash (e.g., #2023-01-01) to the URL.'; + return; + } + urlHash = urlHash.replace(/#/g, '%23'); + const logBaseUrl = 'https://raye.mistivia.com/irclog/'; + let targetUrl = `${logBaseUrl}${urlHash}.txt`; // 假设日志文件是 .txt 格式 + + statusDiv.className = 'loading'; + statusDiv.textContent = `Loading log for: ${urlHash} from ${targetUrl} ...`; + logContainer.innerHTML = ''; + + // --- 新增: HTML特殊字符转义函数 --- + function escapeHtml(unsafe) { + if (!unsafe) return ''; + // 替换 <, >, &, " + return unsafe + .replace(/&/g, "&") + .replace(/</g, "<") + .replace(/>/g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); + } + + function ircAction(text) { + const regex = + /^(\[[^\]]+\])(\s*<)([^>]+)(>:\s*)(\u0001ACTION\s+)([^\u0001]+)(\u0001)(.*)$/gm; + const replacement = '$1 * $3 $6$8'; + return text.replace(regex, replacement); + } + + function linkify(text) { + const urlRegex = /(\b(https?):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig; + return text.replace(urlRegex, function(url) { + return `<a href="${url}" target="_blank">${url}</a>`; + }); + } + + fetch(targetUrl) + .then(response => { + if (!response.ok) { + throw new Error(`HTTP Error: ${response.status} ${response.statusText} for hash: ${urlHash}`); + } + return response.text(); + }) + .then(text => { + statusDiv.textContent = '' + statusDiv.className = ''; + text = ircAction(text); + let safeText = escapeHtml(text); + + const finalHtml = linkify(safeText); + logContainer.innerHTML = `<pre>${finalHtml}</pre>`; + }) + .catch(error => { + console.error('Fetch error:', error); + statusDiv.className = 'error'; + statusDiv.textContent = `Failed to load log. ${error.message}`; + logContainer.innerHTML = `<pre class="error">Could not fetch log. Please check the console for details. (CORS or network issue likely).</pre>`; + }); + }); + </script> + +</body> +</html> |
