# app.py
from flask import Flask, render_template_string, send_from_directory, request
import os
import re
from werkzeug.utils import secure_filename

# --- 配置 ---
# 请在这里修改为你存放图片的文件夹路径
ROOT_IMAGE_FOLDER = r'\\192.168.31.92\ubuntuShare2T\学习资料'  # 使用原始字符串以避免转义问题
PORT = 80  # 你可以修改这个端口号，如果5000被占用了
# --- 配置结束 ---

app = Flask(__name__)


def atoi(text):
    """辅助函数：将文本中的数字部分转换为整数，用于排序"""
    return int(text) if text.isdigit() else text


def natural_keys(text):
    """
    辅助函数：生成用于自然排序的键。
    例如: '1002' -> ['1002'] (其中 '1002' 被转换为整数)
          'img_10' -> ['img_', 10]
    这样可以确保 '1001.jpg' 排在 '1002.png' 之前。
    """
    return [atoi(c) for c in re.split(r'(\d+)', text)]


def find_media_in_folder(folder_path):
    """在指定文件夹中查找所有图片和视频文件"""
    allowed_image_exts = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp'}
    allowed_video_exts = {'.mp4', '.avi', '.mov', '.wmv', '.flv', '.webm', '.m4v', '.mkv', '.mpg', '.mpeg', '.3gp',
                          '.3g2'}

    try:
        files = os.listdir(folder_path)
    except PermissionError:
        print(f"权限不足，无法访问: {folder_path}")
        return [], []

    image_files = [f for f in files if os.path.isfile(os.path.join(folder_path, f)) and os.path.splitext(f)[
        1].lower() in allowed_image_exts]
    video_files = [f for f in files if os.path.isfile(os.path.join(folder_path, f)) and os.path.splitext(f)[
        1].lower() in allowed_video_exts]

    return sorted(image_files, key=natural_keys), sorted(video_files, key=natural_keys)


def get_subfolders(folder_path):
    """获取指定文件夹下的所有子文件夹"""
    try:
        items = os.listdir(folder_path)
    except PermissionError:
        print(f"权限不足，无法访问: {folder_path}")
        return []
    subfolders = [item for item in items if os.path.isdir(os.path.join(folder_path, item))]
    return sorted(subfolders, key=natural_keys)


@app.route('/')
def index():
    # 默认访问根目录，subpath为空字符串
    return list_folder_content('')


@app.route('/browse/')
@app.route('/browse/<path:subpath>')
def list_folder_content(subpath=''):
    """
    递归浏览文件夹内容的主函数
    subpath: URL中传递的子路径
    """
    # 从查询参数获取显示模式，默认为 'list'
    mode = request.args.get('mode', 'list')
    if mode not in ['list', 'grid', 'manga']:
        mode = 'list'

    # 构建当前要浏览的物理路径
    # 注意：这里使用全局变量 ROOT_IMAGE_FOLDER
    current_path = os.path.normpath(os.path.join(ROOT_IMAGE_FOLDER, subpath))

    # 检测是否为漫画路径
    is_manga_path = '漫画' in subpath

    # 安全检查，防止路径穿越
    if not current_path.startswith(os.path.normpath(ROOT_IMAGE_FOLDER)):
        return "Access Denied", 403

    # 查找当前文件夹下的媒体文件和子文件夹
    image_files, video_files = find_media_in_folder(current_path)
    subfolders = get_subfolders(current_path)

    # 构建面包屑导航
    path_parts = [p for p in subpath.split('/') if p]
    breadcrumbs = [{'name': 'Home', 'url': '/'}]
    cumulative_path = ''
    for part in path_parts:
        cumulative_path += part + '/'
        breadcrumbs.append({'name': part, 'url': f'/browse/{cumulative_path.rstrip("/")}'})

    html_template = '''
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>文件浏览器 - {{ current_path_name }}</title>
        <style>
            * { margin: 0; padding: 0; box-sizing: border-box; }
            body {
                font-family: "Segoe UI", "Microsoft YaHei", Arial, sans-serif;
                background-color: #f5f5f5;
                color: #333;
            }
            /* 顶部地址栏 - Windows风格 */
            .address-bar {
                display: flex;
                align-items: center;
                background: #fff;
                border-bottom: 1px solid #ddd;
                padding: 8px 16px;
                gap: 2px;
                flex-wrap: wrap;
            }
            .address-bar a, .address-bar span.current {
                padding: 4px 10px;
                border-radius: 3px;
                font-size: 14px;
                color: #333;
                text-decoration: none;
            }
            .address-bar a:hover {
                background: #e5e5e5;
            }
            .address-bar span.current {
                color: #000;
                font-weight: 600;
            }
            .address-bar .sep {
                color: #999;
                font-size: 14px;
                padding: 0 2px;
                user-select: none;
            }
            .address-bar .home-btn {
                font-size: 16px;
                padding: 4px 8px;
            }
            /* 工具栏 */
            .toolbar {
                display: flex;
                align-items: center;
                padding: 10px 16px;
                background: #fff;
                border-bottom: 1px solid #ddd;
                gap: 12px;
            }
            .mode-btn {
                padding: 5px 14px;
                border: 1px solid #ccc;
                background: #fff;
                border-radius: 3px;
                cursor: pointer;
                font-size: 13px;
                text-decoration: none;
                color: #333;
            }
            .mode-btn:hover {
                background: #f0f0f0;
            }
            .mode-btn.active {
                background: #0078d4;
                color: #fff;
                border-color: #0078d4;
            }
            /* 主内容区 */
            .main-content {
                padding: 16px;
                max-width: 1400px;
                margin: 0 auto;
            }
            .section {
                margin-bottom: 28px;
            }
            .section-title {
                font-size: 14px;
                color: #555;
                margin-bottom: 12px;
                padding-bottom: 6px;
                border-bottom: 1px solid #e0e0e0;
                font-weight: 600;
                display: flex;
                align-items: center;
                gap: 6px;
            }
            /* 网格模式 */
            .grid-container {
                display: grid;
                grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
                gap: 12px;
            }
            .grid-item {
                background: #fff;
                border: 1px solid #e0e0e0;
                border-radius: 6px;
                padding: 12px 8px;
                text-align: center;
                cursor: pointer;
                transition: all 0.2s;
                text-decoration: none;
                color: #333;
                display: flex;
                flex-direction: column;
                align-items: center;
                overflow: hidden;
            }
            .grid-item:hover {
                border-color: #0078d4;
                background: #f0f8ff;
                box-shadow: 0 2px 8px rgba(0,0,0,0.08);
            }
            .grid-item .icon {
                font-size: 48px;
                margin-bottom: 8px;
                line-height: 1;
            }
            .grid-item img.thumb {
                width: 100%;
                height: 100px;
                object-fit: cover;
                border-radius: 4px;
                margin-bottom: 8px;
            }
            .grid-item .name {
                font-size: 12px;
                word-break: break-all;
                line-height: 1.4;
                max-height: 2.8em;
                overflow: hidden;
                display: -webkit-box;
                -webkit-line-clamp: 2;
                -webkit-box-orient: vertical;
            }
            /* 列表模式 */
            .list-container {
                background: #fff;
                border: 1px solid #e0e0e0;
                border-radius: 6px;
                overflow: hidden;
            }
            .list-item {
                display: flex;
                align-items: center;
                padding: 10px 16px;
                border-bottom: 1px solid #f0f0f0;
                text-decoration: none;
                color: #333;
                transition: background 0.15s;
            }
            .list-item:last-child { border-bottom: none; }
            .list-item:hover {
                background: #f5f5f5;
            }
            .list-item .icon {
                font-size: 24px;
                margin-right: 12px;
                width: 28px;
                text-align: center;
                flex-shrink: 0;
            }
            .list-item .thumb {
                width: 40px;
                height: 40px;
                object-fit: cover;
                border-radius: 4px;
                margin-right: 12px;
                flex-shrink: 0;
                border: 1px solid #eee;
            }
            .list-item .info {
                flex: 1;
                min-width: 0;
            }
            .list-item .name {
                font-size: 14px;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            .list-item .type {
                font-size: 12px;
                color: #999;
                margin-top: 2px;
            }
            /* Modal / Lightbox */
            .modal-overlay {
                position: fixed;
                top: 0; left: 0; right: 0; bottom: 0;
                background: rgba(0,0,0,0.85);
                display: flex;
                justify-content: center;
                align-items: center;
                z-index: 9999;
                padding: 20px;
                opacity: 0;
                pointer-events: none;
                transition: opacity 0.25s ease;
            }
            .modal-overlay.active {
                opacity: 1;
                pointer-events: auto;
            }
            .modal-content {
                position: relative;
                max-width: 90vw;
                max-height: 90vh;
                display: flex;
                flex-direction: column;
                align-items: center;
            }
            .modal-content img {
                max-width: 90vw;
                max-height: 85vh;
                object-fit: contain;
                border-radius: 4px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.5);
            }
            .modal-content video {
                max-width: 90vw;
                max-height: 85vh;
                border-radius: 4px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.5);
                background: #000;
            }
            .modal-close {
                position: absolute;
                top: -40px;
                right: 0;
                color: #fff;
                font-size: 32px;
                cursor: pointer;
                width: 36px;
                height: 36px;
                display: flex;
                align-items: center;
                justify-content: center;
                border-radius: 50%;
                transition: background 0.2s;
                user-select: none;
            }
            .modal-close:hover {
                background: rgba(255,255,255,0.2);
            }
            .modal-title {
                color: #fff;
                margin-top: 10px;
                font-size: 14px;
                text-align: center;
                max-width: 80vw;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
            }
            .img-trigger, .video-trigger {
                cursor: pointer;
            }
            /* 漫画模式 */
            .manga-container {
                display: flex;
                flex-direction: column;
                align-items: center;
                background: #1a1a1a;
                padding: 0;
                border-radius: 0;
            }
            .manga-item {
                width: 100%;
                max-width: 900px;
                line-height: 0;
            }
            .manga-item img {
                width: 100%;
                height: auto;
                display: block;
                border: none;
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
        <!-- 地址栏 -->
        <div class="address-bar">
            <a href="/" class="home-btn" title="主页">🏠</a>
            {% for crumb in breadcrumbs %}
                {% if not loop.first %}
                    <span class="sep">›</span>
                    {% if loop.last %}
                        <span class="current">{{ crumb.name }}</span>
                    {% else %}
                        <a href="{{ crumb.url }}">{{ crumb.name }}</a>
                    {% endif %}
                {% endif %}
            {% endfor %}
        </div>

        <!-- 工具栏 -->
        <div class="toolbar">
            <a href="?mode=list" class="mode-btn {% if mode == 'list' %}active{% endif %}">📋 列表</a>
            <a href="?mode=grid" class="mode-btn {% if mode == 'grid' %}active{% endif %}">⊞ 网格</a>
            {% if is_manga_path %}
            <a href="?mode=manga" class="mode-btn {% if mode == 'manga' %}active{% endif %}">📖 漫画</a>
            {% endif %}
        </div>

        <div class="main-content">
            <!-- 文件夹 -->
            {% if subfolders %}
            <div class="section">
                <div class="section-title"><span>📁</span> 文件夹 <span style="color:#999;font-weight:400;">({{ subfolders|length }})</span></div>
                {% if mode == 'grid' %}
                <div class="grid-container">
                    {% for folder in subfolders %}
                    <a href="{{ url_for('list_folder_content', subpath=(current_subpath + folder) if current_subpath else folder) }}?mode={{ mode }}" class="grid-item">
                        <div class="icon">📁</div>
                        <div class="name">{{ folder }}</div>
                    </a>
                    {% endfor %}
                </div>
                {% else %}
                <div class="list-container">
                    {% for folder in subfolders %}
                    <a href="{{ url_for('list_folder_content', subpath=(current_subpath + folder) if current_subpath else folder) }}?mode={{ mode }}" class="list-item">
                        <div class="icon">📁</div>
                        <div class="info">
                            <div class="name">{{ folder }}</div>
                            <div class="type">文件夹</div>
                        </div>
                    </a>
                    {% endfor %}
                </div>
                {% endif %}
            </div>
            {% endif %}

            <!-- 图片 -->
            {% if images %}
            <div class="section">
                <div class="section-title"><span>📷</span> 图片 <span style="color:#999;font-weight:400;">({{ images|length }})</span></div>
                {% if mode == 'manga' %}
                <div class="manga-container">
                    {% for image in images %}
                    <div class="manga-item img-trigger" data-src="{{ url_for('serve_media', full_path=(current_subpath + image) if current_subpath else image) }}" data-name="{{ image }}">
                        <img src="{{ url_for('serve_media', full_path=(current_subpath + image) if current_subpath else image) }}" alt="{{ image }}" loading="lazy">
                    </div>
                    {% endfor %}
                </div>
                {% elif mode == 'grid' %}
                <div class="grid-container">
                    {% for image in images %}
                    <div class="grid-item img-trigger" data-src="{{ url_for('serve_media', full_path=(current_subpath + image) if current_subpath else image) }}" data-name="{{ image }}">
                        <img class="thumb" src="{{ url_for('serve_media', full_path=(current_subpath + image) if current_subpath else image) }}" alt="{{ image }}" loading="lazy">
                        <div class="name">{{ image }}</div>
                    </div>
                    {% endfor %}
                </div>
                {% else %}
                <div class="list-container">
                    {% for image in images %}
                    <div class="list-item img-trigger" data-src="{{ url_for('serve_media', full_path=(current_subpath + image) if current_subpath else image) }}" data-name="{{ image }}">
                        <img class="thumb" src="{{ url_for('serve_media', full_path=(current_subpath + image) if current_subpath else image) }}" alt="" loading="lazy">
                        <div class="info">
                            <div class="name">{{ image }}</div>
                            <div class="type">图片文件</div>
                        </div>
                    </div>
                    {% endfor %}
                </div>
                {% endif %}
            </div>
            {% endif %}

            <!-- 视频 -->
            {% if videos %}
            <div class="section">
                <div class="section-title"><span>🎬</span> 视频 <span style="color:#999;font-weight:400;">({{ videos|length }})</span></div>
                {% if mode == 'grid' %}
                <div class="grid-container">
                    {% for video in videos %}
                    <div class="grid-item video-trigger" data-src="{{ url_for('serve_media', full_path=(current_subpath + video) if current_subpath else video) }}" data-name="{{ video }}">
                        <div class="icon">🎬</div>
                        <div class="name">{{ video }}</div>
                    </div>
                    {% endfor %}
                </div>
                {% else %}
                <div class="list-container">
                    {% for video in videos %}
                    <div class="list-item video-trigger" data-src="{{ url_for('serve_media', full_path=(current_subpath + video) if current_subpath else video) }}" data-name="{{ video }}">
                        <div class="icon">🎬</div>
                        <div class="info">
                            <div class="name">{{ video }}</div>
                            <div class="type">视频文件</div>
                        </div>
                    </div>
                    {% endfor %}
                </div>
                {% endif %}
            </div>
            {% endif %}
        </div>

        <!-- 图片/视频预览弹窗 -->
        <div class="modal-overlay" id="modalOverlay" onclick="closeModal(event)">
            <div class="modal-content" onclick="event.stopPropagation()">
                <div class="modal-close" onclick="closeModal()">&times;</div>
                <img id="modalImg" style="display:none;" alt="">
                <video id="modalVideo" style="display:none;" controls playsinline></video>
                <div class="modal-title" id="modalTitle"></div>
            </div>
        </div>

        <script>
            const overlay = document.getElementById('modalOverlay');
            const modalImg = document.getElementById('modalImg');
            const modalVideo = document.getElementById('modalVideo');
            const modalTitle = document.getElementById('modalTitle');

            function openImage(src, name) {
                modalVideo.style.display = 'none';
                modalVideo.pause();
                modalVideo.src = '';
                modalImg.style.display = 'block';
                modalImg.src = src;
                modalTitle.textContent = name || '';
                overlay.classList.add('active');
                document.body.style.overflow = 'hidden';
            }

            function openVideo(src, name) {
                modalImg.style.display = 'none';
                modalImg.src = '';
                modalVideo.style.display = 'block';
                modalVideo.src = src;
                modalVideo.play();
                modalTitle.textContent = name || '';
                overlay.classList.add('active');
                document.body.style.overflow = 'hidden';
            }

            function closeModal(e) {
                if (e && e.target !== overlay && !e.target.classList.contains('modal-close')) return;
                overlay.classList.remove('active');
                modalVideo.pause();
                modalVideo.src = '';
                modalImg.src = '';
                document.body.style.overflow = '';
            }

            document.querySelectorAll('.img-trigger').forEach(el => {
                el.addEventListener('click', () => openImage(el.dataset.src, el.dataset.name));
            });
            document.querySelectorAll('.video-trigger').forEach(el => {
                el.addEventListener('click', () => openVideo(el.dataset.src, el.dataset.name));
            });
            document.addEventListener('keydown', e => {
                if (e.key === 'Escape') closeModal();
            });
        </script>
    </body>
    </html>
    '''

    # 获取当前路径的名称用于显示
    current_path_name = os.path.basename(current_path) if current_path != ROOT_IMAGE_FOLDER else 'Root Directory'

    return render_template_string(
        html_template,
        images=image_files,
        videos=video_files,
        subfolders=subfolders,
        current_path_name=current_path_name,
        current_subpath=subpath + '/' if subpath else '',  # 传递给模板，用于构建文件路径
        breadcrumbs=breadcrumbs,
        mode=mode,  # 将模式传递给模板
        is_manga_path=is_manga_path
    )


# 新增：用于在新页面播放视频的路由
@app.route('/play_video/<path:full_path>')
def play_video(full_path):
    """
    在新页面播放单个视频
    full_path: 视频文件的完整路径（包含子文件夹）
    """
    # 安全检查
    full_file_path = os.path.normpath(os.path.join(ROOT_IMAGE_FOLDER, full_path))
    if not full_file_path.startswith(os.path.normpath(ROOT_IMAGE_FOLDER)):
        return "Access Denied", 403

    # 获取视频文件名
    video_filename = os.path.basename(full_path)

    # 将 video_url 的生成移到模板内部
    video_player_template = '''
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>正在播放: {{ video_filename }}</title>
        <style>
            body {
                margin: 0;
                padding: 0;
                background-color: #000; /* 黑色背景 */
                display: flex;
                justify-content: center;
                align-items: center;
                height: 100vh; /* 全屏高度 */
            }
            .video-container {
                width: 100%;
                height: 100%;
                max-width: 90%; /* 最大宽度 */
                max-height: 90vh; /* 最大高度 */
            }
            .video-player {
                width: 100%;
                height: 100%;
                object-fit: contain; /* 保持视频比例 */
            }
        </style>
    </head>
    <body>
        <div class="video-container">
            <video class="video-player" controls autoplay playsinline preload="none">
                <!-- 在模板内部使用 url_for -->
                <source src="{{ url_for('serve_media', full_path=full_path) }}" type="video/{{ video_filename.split('.')[-1].lower() }}">
                您的浏览器不支持视频播放。
            </video>
        </div>
    </body>
    </html>
    '''
    # 注意：传递给 render_template_string 的变量，可以在模板内部直接使用
    return render_template_string(
        video_player_template,
        video_filename=video_filename,
        full_path=full_path  # 将 full_path 也传递给模板，以便在模板内使用 url_for
    )


# 统一的媒体文件服务路由，处理图片和视频
@app.route('/media_file/<path:full_path>')
def serve_media(full_path):
    """
    提供媒体文件（图片/视频）服务
    full_path: 包含子文件夹路径和文件名
    """
    # 从完整路径中分离出文件夹和文件名
    folder_path = os.path.dirname(full_path)
    filename = os.path.basename(full_path)

    # 构建完整的物理路径
    base_dir = os.path.join(ROOT_IMAGE_FOLDER, folder_path)

    # 安全检查
    full_file_path = os.path.normpath(os.path.join(base_dir, filename))
    if not full_file_path.startswith(os.path.normpath(ROOT_IMAGE_FOLDER)):
        return "Access Denied", 403

    return send_from_directory(base_dir, filename)


if __name__ == '__main__':
    # 确保根图片文件夹存在
    if not os.path.exists(ROOT_IMAGE_FOLDER):
        print(f"错误：找不到根图片文件夹 '{ROOT_IMAGE_FOLDER}'")
        exit(1)

    print(f"Web服务即将启动，请访问 http://127.0.0.1:{PORT}")
    print(f"根目录路径: {os.path.abspath(ROOT_IMAGE_FOLDER)}")
    app.run(debug=True, host='0.0.0.0', port=PORT)