<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="description" property="og:description"
        content="文件列表服务器 - 提供文件下载服务" />
    <meta name="twitter:description"
        content="文件列表服务器 - 提供文件下载服务" />
    <meta name="author" content="文件服务器" />
    <meta name="copyright" content="文件服务器" />
    <meta property="og:url" name="twitter:url" content="/" />
    <meta name="keywords" content="文件, 下载, 文件列表, mirror, 文件服务器" />
    <meta name="robots" content="index" />
    <meta property="og:site_name" content="文件列表服务器" />
    <meta property="og:title" content="文件列表服务器" />
    <meta property="twitter:title" content="文件列表服务器" />
    <meta property="og:image" content="/img/logo.png" />
    <meta property="twitter:card" content="/img/logo.png" />
    <meta property="og:type" content="site" />

    <title>文件列表服务器</title>

    <link rel="apple-touch-icon" sizes="180x180" href="https://almalinux.org/fav/apple-touch-icon.png" />
    <link rel="icon" type="image/png" sizes="32x32" href="https://almalinux.org/fav/favicon-32x32.png" />
    <link rel="icon" type="image/png" sizes="16x16" href="https://almalinux.org/fav/favicon-16x16.png" />
    <link rel="mask-icon" href="https://almalinux.org/fav/safari-pinned-tab.svg" color="#1A1135" />
    <link rel="shortcut icon" href="https://almalinux.org/fav/favicon.ico" />
    <meta name="msapplication-TileColor" content="#1A1135" />

    <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" crossorigin="anonymous">
    <link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css" as="style"
        crossorigin="anonymous">
    <link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css" as="style"
        crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css"
        crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css"
        crossorigin="anonymous">
    <link rel="stylesheet" media="bogus">
    <script>
        window.$ = document.querySelector.bind(document);
        window.$$ = document.querySelectorAll.bind(document);
        Node.prototype.on = window.on = function (name, fn) {
            this.addEventListener(name, fn);
        }
        NodeList.prototype.__proto__ = Array.prototype;
        NodeList.prototype.on = NodeList.prototype.addEventListener = function (name, fn) {
            this.forEach(function (elem, i) {
                elem.on(name, fn);
            });
        }

        function humanFileSize(bytes, si = false, dp = 1) {
            const thresh = si ? 1000 : 1024;

            if (Math.abs(bytes) < thresh) {
                return bytes + ' B';
            }

            const units = si
                ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
                : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
            let u = -1;
            const r = 10 ** dp;

            do {
                bytes /= thresh;
                ++u;
            } while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);

            return bytes.toFixed(dp) + ' ' + units[u];
        }

        function setSortable(c = 'th') {
            const getCellValue = function (tr, idx) {
                return tr.children[idx].innerText || tr.children[idx].textContent;
            }

            const comparer = function (idx, asc) {
                return function (a, b) {
                    return (function (v1, v2) {
                        return v1 !== '' && v2 !== '' && !isNaN(v1) && !isNaN(v2) ? v1 - v2 : v1.toString().localeCompare(v2)
                    })(getCellValue(asc ? a : b, idx), getCellValue(asc ? b : a, idx));
                }
            }

            $$(c).forEach(function (th) {
                th.addEventListener('click', (function (e) {
                    let i = (e.target.tagName == 'SPAN' ? e.target : e.target.querySelector('span'));
                    const table = th.closest('table');
                    const tbody = table.querySelector('tbody');

                    if (table) {
                        const is = table.querySelectorAll('th span');
                        if (is) {
                            is.forEach(s => s.style.transform = 'scaleY(1)');
                            is.forEach(s => s.textContent = 'filter_list');
                        }
                        if (i) {
                            i.textContent = 'sort';
                            i.style.transform = this.asc ? 'scaleY(-1)' : 'scaleY(1)';
                        }
                        Array.from(tbody.querySelectorAll('tr'))
                            .sort(comparer(Array.from(th.parentNode.children).indexOf(th), this.asc = !this.asc))
                            .forEach(tr => tbody.appendChild(tr));
                    }
                }
                ))
            });
        }

        function filterTable(v = '', l = 0, c = 'table tbody tr', e = 'td') {
            const tr = $$(c);
            let cc = 0;
            v = v.toLowerCase();

            if (l && v && v.length < l) { return; }

            while (cc < tr.length) {
                let td = tr[cc].getElementsByTagName(e),
                    dpl = 'none';
                ccc = 0;

                while (ccc < td.length) {
                    let txt = (td[ccc].textContent || td[ccc].innerText).toLowerCase();
                    if (txt.indexOf(v) > -1) {
                        dpl = '';
                    }
                    ++ccc;
                }
                tr[cc].style.display = dpl;
                ++cc;
            }
        }

        function getData(c = '#idx-json') {
            const cdom = $(c);
            if (cdom.textContent.indexOf('[') >= 0) {
                return JSON.parse(cdom.textContent);
            }
        }

        function getHref(u = '') {
            return u + window.location.search;
        }

        function setEnv(s = '#idx-filter', t = '#idx-stheme') {
            const pathname = window.location.pathname,
                prm = new URLSearchParams(window.location.search);

            document.removeEventListener('DOMContentLoaded', main);

            window.language = prm.has('l') || 'sv-SE';

            if (prm.has('b')) {
                $('section').style.backgroundImage = `url("${decodeURIComponent(prm.get('b'))}")`;
            }

            if (prm.has('t')) {
                setTheme($(t).value = prm.get('t'));
            }

            $(s).addEventListener('keyup', function (e) { filterTable(e.target.value, 3); });

            setSortable();

            $('#idx-path').innerHTML = '<small>' +
                pathname.split('/').reduce(function (a, v, i, o) {
                    return a += ` / <a href="#" style="color:#FFF; font-weight: bold;" onclick="window.open(getHref('/${o.slice(1, i + 1).join('/')}'),'_self')">${v}</a> `;
                }) +
                `<a title="返回" href="#" onclick="window.open(getHref('${pathname.substring(0, pathname.slice(0, -1).lastIndexOf('/'))}'),'_self')"><span class="material-icons">arrow_back_ios_new</span></a>` +
                '</small>'
        }

        function setData(a = [], n = [0, 0, 0, 0], p = 15000, m = 1, c = 'table tbody', f = 'footer') {
            const pathname = window.location.pathname;
            let tblHtm = '';

            while (n[0] < a.length) {
                let entry = a[n[0]];
                mtime = new Date(entry.mtime),
                    entry.mtime = mtime.toLocaleString(window.language),  //`${mtime.toLocaleDateString()}  ${mtime.toLocaleTimeString()}`,
                    entry.ext = entry.name.substr(entry.name.lastIndexOf('.') + 1).toUpperCase(),
                    url = `${pathname}${entry.name}`;

                if (entry.type == 'directory') {
                    ++n[1];
                    tblHtm += `<tr>
                            <td><span class="material-icons" title="文件夹">folder</span><span class="dn">${entry.type}</span></td>
                            <td><div title="...${entry.name.substr(-10)}"><a href="#" style="color:#FFF; font-weight: bold;" onclick="window.open(getHref('${url}'),'_self')">${entry.name}</a></div></td>
                            <td>${entry.mtime}</td>
                            <td></td>
                        </tr>`;
                } else {
                    ++n[2];
                    n[3] += entry.size;
                    tblHtm += `<tr>
                            <td><span class="material-icons" title="${entry.ext} 文件">insert_drive_file</span><span class="dn">${entry.type}</span></td>
                            <td><div title="...${entry.name.substr(-10)}"><a download="${entry.name}" style="color:#FFF" href="${url}">${entry.name}</a></div>
                                    <span class="fr"><a download="${entry.name}" href="${url}"><span class="material-icons" title="保存 ${entry.ext}">download</span></a>
                                    <a href="${url}" target="_blank"><span class="material-icons" title="在新窗口打开 ${entry.ext}">open_in_browser</span></a></span>
                            </td>
                            <td>${entry.mtime}</td>
                            <td>${humanFileSize(entry.size, true, 2)}</td>
                        </tr>`;
                }

                if (n[0] && n[0] != a.length - 1 && n[0] % p === 0) {
                    $(c).innerHTML += tblHtm;
                    if (a.length >= p && n[0] == p) { $('.load').remove(); }
                    ++n[0];
                    setTimeout(function () {
                        setData(a, n);
                    }, m);
                    return;
                }

                ++n[0];
                if (a.length < p && n[0] == a.length) { $('.load').remove(); }
            }

            $(c).innerHTML += tblHtm;
            if (n[0] == a.length) {
                $(f).innerHTML = `
                        <span class="material-icons">folder_open</span><span>${n[1]}</span><span>个文件夹</span>
                        <span class="material-icons">description</span><span>${n[2]}</span><span>个文件</span>
                        <span class="material-icons">account_tree</span><span>${(n[1] + n[2])}</span><span>总计  </span>
                        <span class="material-icons">storage</span><span>${humanFileSize(n[3], true, 3)}</span>
                        <div class="beian">
                            <a href="https://beian.miit.gov.cn/" rel="noopener" target="_blank" data-pjax-state="">豫ICP备2022001119号 </a>
                            <img src="/.autoindex/img/beian.png" alt="">
                            <a href="https://beian.mps.gov.cn/#/query/webSearch?code=41150302000200" rel="noopener" target="_blank" data-pjax-state="">豫公网安备 41150302000200号</a>
                        </div>`;
                a = null;
            }
        }

        function main() {
            const jsn = getData();
            setEnv();
            if (jsn) {
                setData(jsn);
            } else if (window.location.pathname.endsWith('.html')) {
                alert('请确认是否已启用NGINX自动索引功能？');
            }
        }

        document.addEventListener('wheel', function (e) {
            document.querySelector('main').scrollTop += e.deltaY;
            e.preventDefault();
        }, { passive: false });

        document.addEventListener('DOMContentLoaded', main);
    </script>
    <style>
        html,
        body {
            text-align: left;
            overflow: hidden;
            height: 100%;
            margin: 0;
            display: flex;
            flex-direction: column;
            flex-wrap: nowrap;
            flex-direction: column;
            background: #1A1135;
            color: #FFF;
        }

        header {
            flex-shrink: 0;
        }

        header ul {
            margin: 7px;
            display: flex;
            align-items: stretch;
            justify-content: space-between;
        }

        header li {
            display: inline;
            margin: 0 20px;
            white-space: nowrap;
        }

        main {
            overflow: auto scroll;
            flex-grow: 1;
            padding: 8px 10px;
            display: flex;
            justify-content: center;
            align-items: flex-start;
            scroll-snap-type: y mandatory;
        }

        footer {
            flex-shrink: 0;
            text-align: left;
            margin: 0;
            border-top: solid 1px #bd3f9c;
            z-index: 4;
            padding: 8px 15px;
            display: flex;
            align-items: center;
            justify-content: flex-start;
            flex-wrap: wrap;
            gap: 5px;
        }

        table {
            width: calc(100vw / 1.618);
        }

        th {
            position: sticky;
            top: 0px;
            z-index: 2;
            white-space: nowrap;
            cursor: pointer;
        }

        th span.material-icons {
            vertical-align: top;
            padding: 0 0 0 1em;
        }

        .material-icons {
            color: #bd3f9c;
        }

        th:first-child {
            padding: unset;
        }

        td:first-child {
            width: 32px;
        }

        td:nth-child(n+3) {
            width: 1%;
            white-space: nowrap;
        }

        td:nth-child(2) {
            display: grid;
            grid-template-columns: 1fr auto;
        }

        td:nth-child(2) div {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        tr {
            transition: all 0.2s ease 0s;
            scroll-snap-align: start;
        }

        tr:hover {
            box-shadow: 0px 5px 40px -10px rgba(0, 0, 0, 0.2);
        }

        span.material-icons+span {
            vertical-align: middle;
            padding: 0 2em 0 1em;
        }

        section {
            width: 99%;
            height: 99%;
            position: fixed;
            left: 0;
            right: 0;
            z-index: 1;
            background-size: cover;
            background-repeat: no-repeat;
            background-attachment: fixed;
            background-position: center;
            filter: blur(3px);
            opacity: 0.13
        }

        article {
            z-index: 3;
        }

        #idx-filter {
            width: unset;
        }

        #idx-path {
            vertical-align: text-top;
        }

        #idx-path span {
            font-size: 16px;
            vertical-align: text-bottom;
            padding: 0 1em;
        }

        #idx-json {
            display: none;
        }

        #idx-stheme {
            width: auto;
        }

        .header {
            background-color: #1A1135;
        }

        .material-icons {
            vertical-align: middle;
        }

        .fs36 {
            font-size: 36px;
        }

        .dn {
            display: none;
        }

        .fr {
            float: right;
        }

        .load {
            position: fixed;
            left: 0px;
            top: 0px;
            width: 100%;
            height: 100%;
            background: #1A1135;
            z-index: 9999
        }

        .lds {
            display: inline-block;
            width: 80px;
            height: 80px;
            position: fixed;
            left: 47.5%;
            top: 47.5%;
        }

        .lds:after {
            content: " ";
            display: block;
            width: 64px;
            height: 64px;
            margin: 8px;
            border-radius: 50%;
            border: 6px solid #bd3f9c;
            border-color: #bd3f9c transparent;
            animation: lds 1.2s linear infinite;
        }

        @keyframes lds {
            0% {
                transform: rotate(0deg);
            }

            100% {
                transform: rotate(360deg);
            }
        }

        .beian {
            margin-left: auto;
            display: flex;
            align-items: center;
            gap: 5px;
            font-size: 13px;
        }

        .beian a {
            color: #FFF;
            text-decoration: none;
            transition: color 0.2s ease;
        }

        .beian a:hover {
            color: #bd3f9c;
            text-decoration: none;
        }

        .beian img {
            height: 16px;
            vertical-align: middle;
        }

        footer .material-icons {
            font-size: 18px;
        }

        footer span:not(.beian-info):not(.beian-separator) {
            margin-right: 15px;
            font-size: 14px;
        }
    </style>
</head>

<body>
    <div class="load">
        <div class="lds"></div>
    </div>
    <header>
        <ul>
            <li>
                <span class="material-icons fs36" style="color: #bd3f9c;">folder_shared</span>
                <span style="font-size: 24px; font-weight: bold; color: #FFF; margin-left: 10px;">文件列表</span>
            </li>
            <li style="margin: auto; margin-left: 0;">
                <span class="material-icons fs36">drive_file_move</span>
                <span id="idx-path"></span>
            </li>
            <li></li>
            <li></li>
            <li></li>
            <li style="margin: auto;">
                <span class="material-icons">filter_alt</span>
                <input id="idx-filter" type="text" placeholder="搜索文件...">
            </li>
            <li></li>
        </ul>
    </header>
    <main>
        <section></section>
        <article>
            <table>
                <thead>
                    <tr>
                        <th class="header"><span class="material-icons">filter_list</span></th>
                        <th class="header">文件名<span class="material-icons">filter_list</span></th>
                        <th class="header">修改时间<span class="material-icons">filter_list</span></th>
                        <th class="header">大小<span class="material-icons">filter_list</span></th>
                    </tr>
                </thead>
                <tbody></tbody>
            </table>
        </article>


        <div id="idx-json">[
{ "name":"驱动", "type":"directory", "mtime":"Wed, 27 May 2026 09:23:06 GMT" },
{ "name":"HEU_KMS_Activator_v63.3.4.rar", "type":"file", "mtime":"Fri, 29 May 2026 00:17:24 GMT", "size":5110529 }
]        </div>
    </main>
    <footer>
    </footer>
</body>
</html>
