分类: 代码收藏

经常一些经常用到收藏的代码如:CMD,Linux,Python,JavaScript,PHP,HTML等一些Shell脚本。省得用到的时候又不知道在哪找了

  • 淘宝天猫 PC 端 CSS 隐藏技巧:高效实现元素隐形方案

    淘宝天猫 PC 端 CSS 隐藏技巧:高效实现元素隐形方案

    核心实现思路

    元素隐藏的核心需求是让目标元素在视觉上不可见,且不影响页面其他元素的正常布局。本次方案通过定位偏移、背景设置与可见性控制的组合方式,既避免了display: none可能引发的布局塌陷问题,也解决了单纯visibility: hidden占用页面空间的弊端,适配淘宝天猫 PC 端的渲染环境。

    优化后 CSS 代码

    /* 全品类弹窗容器隐藏样式 */
    .all-cats-popup {
      position: absolute;
      top: -49999px; /* 向上偏移,脱离可视区域 */
      left: 0;
      width: 10000px;
      height: 100000px;
      display: block;
      background: #ffffff; /* 保持背景一致性,避免透明导致的异常显示 */
    }
    
    /* 弹窗内容区域定位优化 */
    .popup-content {
      position: relative;
      width: 100%;
      float: left;
      clear: both;
      left: 99999px; /* 向右偏移,进一步确保不可见 */
      top: 99490px;
      height: 100%;
      background: #ffffff;
      background-image: url(//gdp.alicdn.com/imgextra/i1/752188877/O1CN013sFHB32FRikpKiLy4_!!75218877.gif);
      background-position: top center;
      background-attachment: fixed;
      background-repeat: no-repeat;
    }
    
    /* 强制显示控制(兼容特殊场景) */
    .popup-hidden {
      visibility: visible; /* 覆盖默认隐藏状态,确保元素可正常渲染 */
    }

    代码解析与使用说明

    1. 容器隐藏逻辑

    .all-cats-popup 类通过 position: absolute 脱离文档流,再利用超大负值 top: -49999px 将元素移出页面可视区域。宽高设置为超大值(width: 10000pxheight: 100000px)是为了适配不同页面布局,避免元素部分暴露,背景色设置为白色可与页面背景融合,减少视觉冲突。

    2. 内容区域定位

    .popup-content 作为子容器,通过 float: left 和 clear: both 确保布局不错乱,left 和 top 的超大正值偏移与父容器配合,双重保障元素不可见。背景图相关属性保留了原始需求,适用于需要加载背景资源但不展示元素的场景,background-attachment: fixed 可固定背景位置,提升显示一致性。

    3. 兼容场景控制

    .popup-hidden 类使用 visibility: visible 强制元素可见,该类可根据业务需求动态添加或移除,适用于 “默认隐藏,特定条件下显示” 的交互场景,相比 display 属性切换,visibility 不会破坏元素的布局结构,适配淘宝天猫的组件渲染机制。

    注意事项

    1. 兼容性适配:该方案兼容主流浏览器及淘宝天猫 PC 端的内置渲染引擎,无需额外添加浏览器前缀。
    2. 性能优化:超大宽高设置可能影响页面渲染性能,若无需适配特殊布局,可适当减小宽高值(如 width: 100vwheight: 100vh)。
    3. 背景资源:背景图 URL 为示例地址,实际使用时需替换为自身项目的资源链接,确保资源可正常访问。
    4. 交互配合:若需通过 JS 控制元素显示 / 隐藏,可结合 classList.add()/classList.remove() 操作 .popup-hidden 类,避免直接修改样式属性。

    通过以上优化后的 CSS 代码,可高效实现淘宝天猫 PC 端元素的隐藏需求,同时兼顾布局稳定性和场景兼容性,适用于店铺装修、活动页面开发等多种场景。

  • WEBP/PNG/HEIC批量转JPG:李哥的一键式图片格式转换神器

    WEBP/PNG/HEIC批量转JPG:李哥的一键式图片格式转换神器

    兄弟们,是不是经常遇到这些头疼事?

    • 从网站扒下来的图片全是 WEBP​ 格式,编辑软件打不开?
    • PNG​ 图片虽然清晰,但体积太大,上传发布总受限制?
    • 用苹果设备拍的照片是 HEIC​ 格式,在Windows电脑上就成了“天书”?

    别慌!李哥出手,必属精品!今天给大家带来的这款 「批量图片格式转换JPG工具」,就是专门治这些“格式不服”的!它就像你图片库里的“格式统一大师”,管你什么WEBP、PNG还是HEIC,统统给咱变成最通用、最省心的 JPG​ 格式!

    真正的“傻瓜式”操作:把脚本和图片放一个文件夹,双击运行,剩下的交给程序。自动安装环境、自动转换、自动整理文件,你只管喝杯茶等着收JPG就行!特别加入了 HEIC 格式支持,再也不用为苹果照片在电脑上打不开而发愁了。转换后的JPG、原始文件、转换失败的图片,会自动分门别类存到 convert/source/failed/三个文件夹里,井井有条,绝不乱套。万一有同名文件?不存在的!程序会自动给你加上序号,保证一个文件都不会被覆盖。

    下载脚本 -> 双击运行 -> 收获一文件夹整齐的JPG图片!

    李哥已经把代码和详细的使用说明都准备好了,就等你来取。赶紧下载试试,从此告别图片格式转换的烦恼!做人呢,最重要的就是开心!用李哥的工具,让你的图片处理也开心起来!

    核心解读:

    作用:自动检查并安装必要的Python库(Pillow和pillow-heif)启用HEIC文件格式支持(苹果设备照片格式)

    创建虚拟环境并安装python库

    # 退出当前环境
    deactivate
    
    # 删除损坏的虚拟环境
    cd ~/Documents/env
    rm -rf myenv
    
    # 重新创建虚拟环境
    python3 -m venv myenv
    
    # 激活新环境
    source myenv/bin/activate
    
    # 检查pip是否正常
    pip --version
    
    # 安装Pillow
    pip install Pillow
    
    # 检查安装是否成功
    python3 -c "from PIL import Image; print('Pillow安装成功!')"

    创建三个目录:

    • convert/– 存放转换后的JPG文件
    • source/– 存放原始图片文件
    • failed/– 存放转换失败的文件

    智能移动文件到指定目录,自动处理重名文件(添加序号)输出格式JPG (.jpg) – 通用的有损压缩图片格式

    文件整理逻辑

    转换前目录结构:
    当前目录/
    ├── image1.webp
    ├── image2.png
    ├── image3.heic
    └── convert_images.py
    
    转换后目录结构:
    当前目录/
    ├── convert/           # 转换后的JPG文件
    │   ├── image1.jpg
    │   ├── image2.jpg
    │   └── image3.jpg
    ├── source/            # 原始文件(已移动)
    │   ├── image1.webp
    │   ├── image2.png
    │   └── image3.heic
    ├── failed/            # 转换失败的文件
    └── convert_images.py

    实现代码:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import os
    import glob
    import shutil
    import sys
    import subprocess
    
    def check_and_install_dependencies():
        """检查并安装必要的依赖"""
        dependencies = ['Pillow', 'pillow-heif']
        missing_deps = []
        
        # 检查Pillow
        try:
            from PIL import Image
            print("✓ Pillow 已安装")
        except ImportError:
            missing_deps.append('Pillow')
        
        # 检查pillow-heif
        try:
            import pillow_heif
            print("✓ pillow-heif 已安装")
        except ImportError:
            missing_deps.append('pillow-heif')
        
        # 安装缺失的依赖
        if missing_deps:
            print(f"❌ 缺少依赖: {', '.join(missing_deps)}")
            print("正在安装依赖...")
            
            for dep in missing_deps:
                try:
                    if dep == 'Pillow':
                        subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'Pillow'])
                    elif dep == 'pillow-heif':
                        subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pillow-heif'])
                    print(f"✓ {dep} 安装成功")
                except subprocess.CalledProcessError:
                    print(f"❌ {dep} 安装失败,尝试使用镜像源...")
                    try:
                        subprocess.check_call([sys.executable, '-m', 'pip', 'install', dep, 
                                             '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple/'])
                        print(f"✓ {dep} 安装成功(使用镜像源)")
                    except:
                        print(f"❌ {dep} 安装失败,请手动安装: pip install {dep}")
                        return False
            # 重新检查
            try:
                from PIL import Image
                import pillow_heif
                print("✓ 所有依赖安装成功")
                return True
            except ImportError as e:
                print(f"❌ 依赖安装后仍然失败: {e}")
                return False
        return True
    
    def setup_heic_support():
        """设置HEIC支持"""
        try:
            import pillow_heif
            pillow_heif.register_heif_opener()
            print("✓ HEIC格式支持已启用")
            return True
        except Exception as e:
            print(f"❌ HEIC支持初始化失败: {e}")
            return False
    
    def create_directories():
        """创建必要的目录"""
        directories = ['convert', 'source', 'failed']
        for directory in directories:
            if not os.path.exists(directory):
                os.makedirs(directory)
                print(f"✓ 创建目录: {directory}/")
    
    def move_file_to_directory(original_file, directory):
        """移动文件到指定目录"""
        try:
            filename = os.path.basename(original_file)
            destination = os.path.join(directory, filename)
            
            # 如果目标文件已存在,添加序号
            counter = 1
            base_name, ext = os.path.splitext(filename)
            while os.path.exists(destination):
                new_filename = f"{base_name}_{counter}{ext}"
                destination = os.path.join(directory, new_filename)
                counter += 1
            
            shutil.move(original_file, destination)
            return True
        except Exception as e:
            print(f"⚠ 移动文件失败 {original_file}: {e}")
            return False
    
    def convert_image_file(input_file, temp_jpg_file, is_heic=False):
        """转换图片文件"""
        try:
            from PIL import Image
            
            if is_heic:
                # HEIC文件特殊处理
                try:
                    import pillow_heif
                    heif_file = pillow_heif.open_heif(input_file)
                    image = Image.frombytes(
                        heif_file.mode, 
                        heif_file.size, 
                        heif_file.data,
                        "raw",
                        heif_file.mode,
                        heif_file.stride,
                    )
                except:
                    # 如果直接读取失败,尝试通过PIL打开
                    pillow_heif.register_heif_opener()
                    image = Image.open(input_file)
            else:
                # 其他格式文件
                image = Image.open(input_file)
            
            # 处理图片模式
            if image.mode in ('RGBA', 'LA', 'P'):
                background = Image.new('RGB', image.size, (255, 255, 255))
                if image.mode == 'P':
                    image = image.convert('RGBA')
                if image.mode == 'RGBA':
                    background.paste(image, mask=image.split()[-1])
                else:
                    background.paste(image)
                image = background
            elif image.mode != 'RGB':
                image = image.convert('RGB')
            
            # 保存为JPG
            image.save(temp_jpg_file, "JPEG", quality=85, optimize=True)
            return True, "成功"
            
        except Exception as e:
            return False, str(e)
    
    def batch_convert_images():
        """批量转换图片"""
        print("=== 图片格式批量转换工具 ===")
        
        # 检查并安装依赖
        if not check_and_install_dependencies():
            print("❌ 依赖安装失败,无法继续")
            return
        
        # 设置HEIC支持
        heic_supported = setup_heic_support()
        
        # 创建目录
        create_directories()
        
        # 收集文件
        files_to_convert = []
        for pattern in ['*.webp', '*.WEBP', '*.png', '*.PNG', '*.heic', '*.HEIC']:
            files_to_convert.extend(glob.glob(pattern))
        
        files_to_convert = sorted(list(set(files_to_convert)))
        files_to_convert = [f for f in files_to_convert if not any(f.startswith(d) for d in ['convert/', 'source/', 'failed/'])]
        
        if not files_to_convert:
            print("❌ 未找到可转换的图片文件")
            return
        
        # 分类统计
        webp_files = [f for f in files_to_convert if f.lower().endswith('.webp')]
        png_files = [f for f in files_to_convert if f.lower().endswith('.png')]
        heic_files = [f for f in files_to_convert if f.lower().endswith('.heic')]
        
        print(f"找到 {len(files_to_convert)} 个文件:")
        print(f"  WEBP: {len(webp_files)} 个, PNG: {len(png_files)} 个, HEIC: {len(heic_files)} 个")
        
        if heic_files and not heic_supported:
            print("⚠ HEIC文件将无法转换")
        
        # 转换统计
        results = {'success': 0, 'failed': 0, 'skipped': 0}
        
        for i, input_file in enumerate(files_to_convert, 1):
            filename_without_ext = os.path.splitext(os.path.basename(input_file))[0]
            temp_jpg_file = filename_without_ext + ".jpg"
            final_jpg_path = os.path.join('convert', temp_jpg_file)
            
            # 跳过已存在
            if os.path.exists(final_jpg_path):
                print(f"{i}/{len(files_to_convert)} ⚡ 跳过已存在: {final_jpg_path}")
                results['skipped'] += 1
                continue
            
            file_size = os.path.getsize(input_file) / 1024
            file_ext = os.path.splitext(input_file)[1].upper()
            is_heic = input_file.lower().endswith('.heic')
            
            print(f"{i}/{len(files_to_convert)} 🔄 转换: {os.path.basename(input_file)} ({file_size:.1f} KB)", end="")
            
            try:
                if is_heic and not heic_supported:
                    success, message = False, "HEIC支持未启用"
                else:
                    success, message = convert_image_file(input_file, temp_jpg_file, is_heic)
                
                if success:
                    # 移动成功文件
                    if os.path.exists(temp_jpg_file):
                        move_file_to_directory(temp_jpg_file, 'convert')
                    move_file_to_directory(input_file, 'source')
                    results['success'] += 1
                    print(" -> ✅ 完成")
                else:
                    # 移动失败文件
                    move_file_to_directory(input_file, 'failed')
                    results['failed'] += 1
                    print(f" -> ❌ 失败: {message}")
                    
            except Exception as e:
                move_file_to_directory(input_file, 'failed')
                results['failed'] += 1
                print(f" -> 💥 异常: {str(e)}")
        
        # 输出结果
        print(f"\n=== 转换完成 ===")
        print(f"✅ 成功: {results['success']}, ❌ 失败: {results['failed']}, ⚡ 跳过: {results['skipped']}")
    
    if __name__ == "__main__":
        batch_convert_images()
        input("\n按Enter键退出...")

  • 立省万元!李哥教你如何使用translate.js实现WP菜单的JavaScript翻译

    立省万元!李哥教你如何使用translate.js实现WP菜单的JavaScript翻译

    你是不是也在为WordPress网站加个多语言菜单而发愁?一想到那些名声在外的翻译插件,脑海里

    是不是立刻浮现出每年上千元的续费账单?

    是不是受够了那个一旦启用就让网站速度变慢的“庞然大物”?

    是不是在面对复杂的设置界面时,感觉像是在操作一架航天飞机,而你只是想骑个自行车出门买个菜?

    兄弟,我懂你。这种感觉,就像是只想拧一颗螺丝,却被迫买下整个五金店。别再忍受了!今天,李哥(LeePoet.cn)就带你彻底摆脱这种“高消费、低体验”的困境。这篇文章,将为你揭开一条“技术平权”之路。

    我们不用求助于任何重型插件,不花一分钱授权费,仅凭几行简洁的JavaScript代码,就能为你的WordPress菜单实现流畅、优雅的多语言切换功能。我们要用的神器,就是轻量级前端翻译库——translate.js

    学完这一招,你不仅能立刻省下未来几年上万元的插件费用,更能收获一个速度更快、完全受你掌控的网站。从此,插件更新、兼容性冲突、账单提醒,这些都与你无关。这不仅是省钱的技巧,更是一种技术的自由。跟着我的步骤,让我们一起对臃肿的翻译插件说“不”,亲手打造属于你自己的极速多语言方案!

    接下来,我们将从第一步“准备translate.js库文件”开始……

    1.先把translate.js上传到服务器,本地调用比https://cdn.staticfile.net/translate.js/3.18.66/translate.js速度更快。

    2.安装插入代码插件,如 “Header and Footer Scripts” 或 “Insert Headers and Footers”。把translate.js的JavaScript代码放到footer或才head里。

    <script src="https://www.你的域名及JS路径.cn/leepoetjs/translate.js"></script> 
    
    <script>
    translate.selectLanguageTag.languages = 'english,chinese_simplified,japanese,spanish,deutsch,french,korean';
    translate.request.listener.delayExecuteTime = 500;
    translate.service.use('client.edge'); //设置机器翻译服务通道
    translate.listener.start(); //开启页面元素动态监控
    translate.selectLanguageTag.show = false;//false隐藏选择框,true打开
    translate.execute();//完成翻译初始化,进行翻译
    </script>

    3.通过函数文件添加需要调用的translate.js,在主题的functions.php文件中添加:

    //调用翻译translate.js
    function add_language_switcher_script() {
        ?>
        <script>
    //添加switchToEnglish()英文函数
        function switchToEnglish() {
            if (typeof translate !== 'undefined' && typeof translate.changeLanguage === 'function') {
                translate.changeLanguage('english');
            }
        }
    //添加switchToChineseSimplified()中文函数
        function switchTochinese_simplified() {
            if (typeof translate !== 'undefined' && typeof translate.changeLanguage === 'function') {
                translate.changeLanguage('chinese_simplified');
            }
        }		
        </script>
        <?php
    }
    add_action('wp_head', 'add_language_switcher_script');

    2.进入WordPress后台 → 外观​ → 菜单,点击创建新菜单或选择现有菜单,在左侧自定义链接部分添加:

    点击添加到菜单,在菜单编辑器中,点击该菜单项展开设置

    • URL:#
    • 链接文字:English或您想要的文字
    • URL字段中替换为:javascript:translate.changeLanguage(‘english’);
    #导航标签字段
    <li href="#" onclick="javascript:switchToEnglish(); return false;">English</li>
    <li href="#" onclick="javascript:switchTochinese_simplified(); return false;">简体中文</li>

    然后保存菜单。*如果需要其它语言,可以继续在主题文件functions.php里继续填加调用。

    然后刷新前台基本搞定。

    相关文章:translate.js:两行代码实现网页全自动多语言内容动态翻译

    现在的WordPress多语言解决方案,尤其是主流插件,确实让人又爱又恨,痛苦主要集中在以下几点:

    沉重的年度费用,如同“数字税”,像WPML、Polylang Premium这类插件,需要每年支付高昂的授权费来获得更新和支持。对于一个长期运营的网站来说,这成了一笔沉重的、持续的固定支出。网站不赚钱时,这笔钱尤其肉疼;网站赚钱了,又会觉得为什么我要一直为这个“基础设施”付钱?感觉就像被“套牢”了。

    “全家桶”式捆绑,资源浪费严重,大型插件功能大而全,但你可能只需要其中最核心的菜单和静态内容翻译功能。它却强行塞给你一整套复杂的翻译管理系统、字符串翻译、媒体翻译等。这导致插件异常臃肿,严重拖慢网站速度,为了一个“点”的需求,背上了整个“面”的负担。

    架构复杂,学习成本高,配置过程繁琐,需要在不同标签页之间来回切换,理解“字符串”、“翻译编辑器”等专业概念。对于只是想给网站加个中英文菜单的博主来说,学习成本太高,一不小心就配错了。

    与主题/插件兼容性噩梦,一旦主题更新或更换,或者安装了新的插件,兼容性问题就可能出现,导致翻译失效或页面错乱。排查问题非常困难,往往需要深度技术知识。

    机器翻译API的隐藏成本,一些方案鼓励你接入Google Translate或DeepL的API来自动翻译。初期感觉方便,但随着内容增长,API调用的费用会悄无声息地累积,成为一个不可预测的成本黑洞。

    总结来说,当下的痛苦是:我们只是想要一个“轻量、快速、便宜、能控制”的翻译方案,尤其是针对菜单和前端静态内容。但市场给出的答案往往是“沉重、昂贵、复杂、受制于人”的庞然大物。

  • translate.js:两行代码实现网页全自动多语言内容动态翻译

    translate.js:两行代码实现网页全自动多语言内容动态翻译

    在全球化日益深入的今天,为网站提供多语言支持已成为提升用户体验和扩大受众范围的关键。传统多语言解决方案通常需要复杂的配置、大量的翻译文件以及繁琐的代码修改,而translate.js的出现彻底改变了这一现状。

    寻找简单高效的网站翻译方案?translate.js 仅用两行JavaScript代码,即可为你的网站添加全自动多语言翻译功能,支持动态内容翻译,是WordPress插件和Google API的轻量级替代方案。

    什么是translate.js?

    translate.js是一款创新的开源JavaScript库,专注于网页多语言切换。它采用MIT开源协议,完全免费商用,只需两行核心代码即可实现HTML页面的全自动翻译,无需修改页面结构,无需语言配置文件,无需API Key,同时对SEO友好。

    核心优势

    1. 极简接入:无需复杂配置,快速集成
    2. 全自动翻译:智能识别页面内容并自动翻译
    3. 无侵入设计:对现有代码几乎零影响
    4. SEO友好:保持搜索引擎优化效果
    5. 开源免费:MIT协议,商业应用无忧

    translate.js是一个免费、开源的翻译工具库,支持多种语言之间的互译,如中英文、法文、日语、韩语、德语等。它避免了API调用次数的限制和费用问题,且使用方法简单,方便快捷。

    普通网页快速测试示例

    1. 随便打开一个网页
    2. F12(审查元素)
    3. 在控制台页签下粘贴入以下代码: 
      var head= document.getElementsByTagName('head')[0];
     var script= document.createElement('script');
     script.type= 'text/javascript';
     script.src= 'https://res.zvo.cn/translate/inspector_v2.js';
     head.appendChild(script);

    普通网页快速接入示例

    <script src="https://cdn.staticfile.net/translate.js/3.18.66/translate.js"></script>
    <script>
    translate.service.use('client.edge'); //设置机器翻译服务通道,相关说明参考 http://translate.zvo.cn/545867.html
    translate.listener.start(); //开启页面元素动态监控,js改变的内容也会被翻译,参考文档: http://translate.zvo.cn/4067.html
    translate.execute();//完成翻译初始化,进行翻译
    </script>

    在网页最末尾, </html> 之前,加入以下代码,一般在页面的最底部,就会出现选择语言的 select 切换标签。添加上述代码后,页面底部将自动出现语言选择下拉框,用户可以轻松切换界面语言。    详细解说

    工作原理

    translate.js的工作原理十分巧妙:

    1. 内容扫描:对页面所有DOM元素进行扫描,识别可翻译文本
    2. 文本抽离:提取需要翻译的文本内容
    3. API翻译:通过配置的翻译服务通道进行翻译
    4. 结果渲染:将翻译结果重新赋予对应元素

    整个过程自动完成,无需人工干预。

    高级功能与微调

    虽然基础使用极其简单,但translate.js提供了丰富的微调指令,满足各种复杂需求:

    语言控制

    translate.changeLanguage('english'); // 主动切换语言
    translate.language.setLocal('chinese_simplified'); // 设置本地语种
    translate.language.getCurrent(); // 获取当前显示语种

    内容过滤

    translate.ignore.text.push('你好'); // 忽略特定文本
    translate.ignore.id.push('test'); // 忽略特定ID元素
    translate.ignore.class.push('test'); // 忽略特定class元素

    高级配置

    translate.setAutoDiscriminateLocalLanguage(); // 自动识别用户语种
    translate.language.setUrlParamControl(); // URL参数控制显示语种
    translate.selectionTranslate.start(); // 启用划词翻译

    除了基础翻译功能,translate.js还提供了一系列高级特性,例如自动识别并翻译图片中的文字内容,监控AJAX请求,实时翻译动态加载的内容,自定义翻译术语,确保专业词汇准确一致,且监控翻译性能,优化用户体验。

    最佳实践建议

    1. 自托管JS文件:将translate.js下载到自己的服务器,确保稳定加载
    2. 合理配置缓存:根据业务特点设置合适的缓存策略
    3. 选择性翻译:对不需要翻译的内容进行排除,提升性能
    4. 渐进式实施:先在小范围测试,再全面推广

    translate.js重新定义了网页多语言实现的范式,将复杂的技术难题简化为几行优雅的代码。无论是个人项目还是企业级应用,它都能提供高效、稳定、易用的多语言解决方案。其开源免费的特性更是降低了技术门槛,让更多开发者能够轻松实现产品的国际化。随着人工智能技术的不断发展,translate.js也在持续进化,集成更先进的翻译引擎,提供更精准的翻译结果。未来,它将继续致力于降低多语言实现的复杂度,助力更多产品走向全球市场。


    DEMO:

    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>多语言网站示例</title>
        <!-- 引入本地的 translate.js -->
        <script src="./translate.js"></script>
        <style>
            body {
                font-family: Arial, sans-serif;
                max-width: 800px;
                margin: 0 auto;
                padding: 20px;
            }
            .language-switcher {
                margin: 20px 0;
                padding: 10px;
                background: #f5f5f5;
                border-radius: 5px;
            }
            .language-btn {
                padding: 8px 16px;
                margin: 0 5px;
                border: 1px solid #ddd;
                background: white;
                cursor: pointer;
                border-radius: 3px;
            }
            .language-btn.active {
                background: #007bff;
                color: white;
                border-color: #007bff;
            }
            .content {
                margin-top: 20px;
                padding: 20px;
                border: 1px solid #eee;
                border-radius: 5px;
            }
        </style>
    </head>
    <body>
        <div class="language-switcher">
            <h3>选择语言 / Select Language:</h3>
            <button class="language-btn active" onclick="switchLanguage('chinese_simplified')">中文</button>
            <button class="language-btn" onclick="switchLanguage('english')">English</button>
            <button class="language-btn" onclick="switchLanguage('japanese')">日本語</button>
            <button class="language-btn" onclick="switchLanguage('korean')">한국어</button>
            <button class="language-btn" onclick="switchLanguage('french')">Français</button>
            <button class="language-btn" onclick="switchLanguage('german')">Deutsch</button>
        </div>
    
        <div class="content" id="translatable-content">
            <h1>欢迎来到我的多语言网站</h1>
            <p>这是一个演示如何使用 translate.js 实现多语言切换的示例。</p>
            
            <h2>功能特点</h2>
            <ul>
                <li>支持多种语言实时切换</li>
                <li>无需刷新页面</li>
                <li>自动翻译页面内容</li>
                <li>简单易用的API</li>
            </ul>
            
            <h2>联系我们</h2>
            <p>电子邮件:contact@example.com</p>
            <p>电话:+86 123-4567-8900</p>
            
            <div class="no-translate">
                <p><em>这个区域的内容不会被翻译(class="no-translate")</em></p>
            </div>
        </div>
    
        <script>
            // 页面加载完成后初始化翻译功能
            document.addEventListener('DOMContentLoaded', function() {
                // 初始化翻译配置
                translate.service.use('client.edge'); // 使用浏览器内置翻译(免费)
                // 或者使用自有翻译服务:translate.service.use('translate.service');
                
                // 设置页面默认语言
                translate.language.setLocal('chinese_simplified');
                
                // 设置忽略翻译的元素(可选)
                translate.ignore.class.push('no-translate');
                
                // 启动监听器,自动检测页面变化
                translate.listener.start();
                
                // 根据浏览器语言自动切换(可选)
                autoDetectLanguage();
                
                console.log('translate.js 初始化完成!');
            });
    
            // 语言切换函数
            function switchLanguage(lang) {
                // 更新按钮状态
                document.querySelectorAll('.language-btn').forEach(btn => {
                    btn.classList.remove('active');
                });
                event.target.classList.add('active');
                
                // 切换语言并执行翻译
                translate.changeLanguage(lang);
                translate.execute();
                
                // 保存语言偏好到本地存储
                localStorage.setItem('preferred-language', lang);
                
                console.log('切换到语言:', lang);
            }
    
            // 自动检测浏览器语言
            function autoDetectLanguage() {
                const savedLang = localStorage.getItem('preferred-language');
                if (savedLang) {
                    // 使用用户之前选择的语言
                    setActiveButton(savedLang);
                    return;
                }
                
                // 检测浏览器语言
                const browserLang = navigator.language.toLowerCase();
                let detectedLang = 'chinese_simplified'; // 默认中文
                
                if (browserLang.includes('en')) {
                    detectedLang = 'english';
                } else if (browserLang.includes('ja')) {
                    detectedLang = 'japanese';
                } else if (browserLang.includes('ko')) {
                    detectedLang = 'korean';
                } else if (browserLang.includes('fr')) {
                    detectedLang = 'french';
                } else if (browserLang.includes('de')) {
                    detectedLang = 'german';
                }
                
                // 如果检测到的语言不是中文,自动切换
                if (detectedLang !== 'chinese_simplified') {
                    setTimeout(() => {
                        switchLanguage(detectedLang);
                    }, 1000);
                }
            }
    
            // 设置活动按钮样式
            function setActiveButton(lang) {
                document.querySelectorAll('.language-btn').forEach(btn => {
                    btn.classList.remove('active');
                    if (btn.textContent.toLowerCase().includes(getLanguageText(lang).toLowerCase())) {
                        btn.classList.add('active');
                    }
                });
            }
    
            // 获取语言显示文本
            function getLanguageText(lang) {
                const langMap = {
                    'chinese_simplified': '中文',
                    'english': 'English',
                    'japanese': '日本語',
                    'korean': '한국어',
                    'french': 'Français',
                    'german': 'Deutsch'
                };
                return langMap[lang] || lang;
            }
    
            // 手动触发翻译函数(如果需要)
            function manualTranslate() {
                translate.execute();
            }
    
            // 重置翻译(恢复原始语言)
            function resetTranslation() {
                translate.reset();
            }
        </script>
    </body>
    </html>

    [members_only]

    <div style="text-align: center;">
        <span id="timeDate"></span><span id="times"></span> 
    </div>
    
    <script language="javascript"> 
    var now = new Date();
    function createtime(){
        var grt= new Date("01/01/2024 00:00:00");
        now.setTime(now.getTime()+250);
        days = (now - grt ) / 1000 / 60 / 60 / 24;
        dnum = Math.floor(days);
        hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum);
        hnum = Math.floor(hours);
        if(String(hnum).length ==1 ){hnum = "0" + hnum;}
        minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum);
        mnum = Math.floor(minutes);
        if(String(mnum).length ==1 ){mnum = "0" + mnum;}
        seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
        snum = Math.round(seconds);
        if(String(snum).length ==1 ){snum = "0" + snum;}
        document.getElementById("timeDate").innerHTML = "本网站己运行"+dnum+"天";
        document.getElementById("times").innerHTML = hnum + "小时" + mnum + "分" + snum + "秒";
    }
    setInterval("createtime()",250); 
    </script>
    
    <div style="text-align: center;"><strong>
    	切换语言:</strong>
    	<a class="ignore" href="javascript:translate.changeLanguage('english');">English</a> | 
    	<a class="ignore" href="javascript:translate.changeLanguage('chinese_simplified');">简体中文</a>
    </div>
    <script src="http://naver.19901117.xyz/translate.js/translate.js"></script>
    
    <script>
    translate.selectLanguageTag.languages = 'english,chinese_simplified,japanese,spanish,deutsch,french,korean';
    translate.request.listener.delayExecuteTime = 500;
    translate.service.use('client.edge'); //设置机器翻译服务通道
    translate.listener.start(); //开启页面元素动态监控
    translate.selectLanguageTag.show = false;//false隐藏选择框,true打开
    translate.execute();//完成翻译初始化,进行翻译
    </script>

    支持的语种表 – translate.service通道

    corsican:科西嘉语
    guarani:瓜拉尼语
    kinyarwanda:卢旺达语
    hausa:豪萨语
    norwegian:挪威语
    dutch:荷兰语
    yoruba:约鲁巴语
    english:英语
    gongen:贡根语
    latin:拉丁语
    nepali:尼泊尔语
    french:法语
    czech:捷克语
    hawaiian:夏威夷语
    georgian:格鲁吉亚语
    russian:俄语
    chinese_simplified:简体中文
    persian:波斯语
    bhojpuri:博杰普尔语
    hindi:印地语
    belarusian:白俄罗斯语
    swahili:斯瓦希里语
    icelandic:冰岛语
    yiddish:意第绪语
    twi:契维语
    irish:爱尔兰语
    gujarati:古吉拉特语
    khmer:高棉语
    slovak:斯洛伐克语
    hebrew:希伯来语
    kannada:卡纳达语
    hungarian:匈牙利语
    tamil:泰米尔语
    arabic:阿拉伯语
    bengali:孟加拉语
    azerbaijani:阿塞拜疆语
    samoan:萨摩亚语
    afrikaans:南非荷兰语
    indonesian:印尼语
    danish:丹麦语
    shona:修纳语
    bambara:班巴拉语
    lithuanian:立陶宛语
    vietnamese:越南语
    maltese:马耳他语
    turkmen:土库曼语
    assamese:阿萨姆语
    catalan:加泰罗尼亚语
    singapore:僧伽罗语
    cebuano:宿务语
    scottish_gaelic:苏格兰盖尔语
    sanskrit:梵语
    polish:波兰语
    galician:加利西亚语
    latvian:拉脱维亚语
    ukrainian:乌克兰语
    tatar:鞑靼语
    welsh:威尔士语
    japanese:日语
    filipino:菲律宾语
    aymara:艾马拉语
    lao:老挝语
    telugu:泰卢固语
    romanian:罗马尼亚语
    haitian_creole:海地克里奥尔语
    dogrid:多格来语
    swedish:瑞典语
    maithili:迈蒂利语
    thai:泰语
    armenian:亚美尼亚语
    burmese:缅甸语
    pashto:普什图语
    hmong:苗语
    dhivehi:迪维希语
    chinese_traditional:繁體中文
    luxembourgish:卢森堡语
    sindhi:信德语
    kurdish:库尔德语(库尔曼吉语)
    turkish:土耳其语
    macedonian:马其顿语
    bulgarian:保加利亚语
    malay:马来语
    luganda:卢干达语
    marathi:马拉地语
    estonian:爱沙尼亚语
    malayalam:马拉雅拉姆语
    deutsch:德语
    slovene:斯洛文尼亚语
    urdu:乌尔都语
    portuguese:葡萄牙语
    igbo:伊博语
    kurdish_sorani:库尔德语(索拉尼)
    oromo:奥罗莫语
    greek:希腊语
    spanish:西班牙语
    frisian:弗里西语
    somali:索马里语
    amharic:阿姆哈拉语
    nyanja:齐切瓦语
    punjabi:旁遮普语
    basque:巴斯克语
    italian:意大利语
    albanian:阿尔巴尼亚语
    korean:韩语
    tajik:塔吉克语
    finnish:芬兰语
    kyrgyz:吉尔吉斯语
    ewe:埃维语
    croatian:克罗地亚语
    creole:克里奥尔语
    quechua:克丘亚语
    bosnian:波斯尼亚语
    maori:毛利语

    [/members_only]

    相关文章:立省万元!李哥教你如何使用translate.js实现WP菜单的JavaScript翻译

  • 数字囤积症救星!LeePoet教你用AI智能整理海量图片

    数字囤积症救星!LeePoet教你用AI智能整理海量图片

    图片太多了怎么办?LeePoet一站式智能整理方案

    💡 LeePoet技术理念:复杂的科技,应该以最简单的方式服务每个普通人。

    你是否也曾在数千张照片中翻找一张重要合影?是否因为图片太多而放弃整理?本文是数字时代每个人的“图片救星”。无论你是拥有上万张照片的摄影爱好者,还是被工作图片淹没的职场人,LeePoet将用AI技术为你提供从简单到专业的全系列解决方案。

    从人物识别到内容分类,Python自动化搞定图片管理,每个人手机里几千张照片的普遍现象,手动整理的痛苦:耗时、低效、容易遗漏,LeePoet的解决方案理念:技术让生活更简单。”隐私保护+内容管理,一键分类敏感图片”,多层级风险评估。

    包含开箱即用的Python脚本、详细配置教程和常见问题解决方案。LeePoet用实际案例证明,技术不应该高高在上,而要真正服务于生活。

    UBUNTU创建虚拟环境操作

    1.创建虚拟环境
    # 进入你的项目文件夹
    cd /path/to/your/project
    
    # 创建虚拟环境(会在当前文件夹创建 venv 目录)
    python3 -m venv myenv
    
    2.激活虚拟环境
    source myenv/bin/activate
    
    3.安装依赖
    python -m pip install opencv-python
    

    如果要使用增强版本,还需要安装:

    python -m pip install torch ultralytics
    
    4.基本完成。

    初级检测:

    创建一个名为 extract_people_images.py的文件完整代码:

    import os
    import shutil
    import cv2
    from pathlib import Path
    
    def detect_people_in_image(image_path, face_cascade=None):
        """
        检测图片中是否包含人物
        """
        if face_cascade is None:
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        
        try:
            img = cv2.imread(image_path)
            if img is None:
                return False
            
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            
            faces = face_cascade.detectMultiScale(
                gray,
                scaleFactor=1.1,
                minNeighbors=5,
                minSize=(30, 30)
            )
            
            return len(faces) > 0
            
        except Exception as e:
            print(f"处理图片 {image_path} 时出错: {e}")
            return False
    
    def extract_images_with_people(source_dir, target_dir):
        """
        从源文件夹提取带人物的图片到目标文件夹
        """
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 加载人脸检测器
        face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        
        print("开始扫描图片...")
        
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            
            # 检查文件格式
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                total_images += 1
                print(f"处理第 {total_images} 张图片: {filename}")
                
                # 检测是否包含人物
                if detect_people_in_image(file_path, face_cascade):
                    images_with_people += 1
                    
                    # 构建目标路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 复制文件
                    shutil.copy2(file_path, target_path)
                    print(f"✓ 检测到人物: {filename}")
                else:
                    print(f"✗ 未检测到人物: {filename}")
        
        print("\n" + "="*50)
        print("处理完成!")
        print(f"总共处理图片: {total_images}张")
        print(f"检测到包含人物的图片: {images_with_people}张")
        print(f"图片已保存到: {target_dir}")
    
    def main():
        # 设置路径
        current_dir = os.getcwd()
        target_dir = os.path.join(current_dir, "images_with_people")
        
        print(f"当前文件夹: {current_dir}")
        print(f"目标文件夹: {target_dir}")
        print("-" * 50)
        
        # 执行提取
        extract_images_with_people(current_dir, target_dir)
    
    if __name__ == "__main__":
        main()
    
    5. 运行脚本
    python extract_people_images.py
    
    6. 退出虚拟环境

    完成后,可以退出虚拟环境:

    其它说明:安装所需库(上面装完了可以不看这)
    # 升级pip(可选)
    python -m pip install --upgrade pip
    
    # 安装OpenCV(基础版本)
    python -m pip install opencv-python
    
    # 或者安装增强版本所需的库
    python -m pip install opencv-python torch ultralytics
    
    创建 requirements.txt 文件(可选)

    你可以创建一个依赖文件,方便以后重新安装:

    # 生成requirements.txt
    python -m pip freeze requirements.txt
    

    requirements.txt 内容示例:

    opencv-python==4.8.1.78
    numpy==1.24.3
    

    以后重新安装依赖:

    python -m pip install -r requirements.txt
    
    完整的项目结构建议
    your_project/
    ├── venv/                    # 虚拟环境(不要提交到版本控制)
    ├── extract_people_images.py # 主程序
    ├── requirements.txt         # 依赖列表
    └── images_with_people/      # 输出文件夹(程序自动创建)
    

    库装不上的其它操作

    python -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple –verbose

    中级检测:

    正常激活虚拟环境

    cd myenv  #即虚拟环境目录
    source myenv/bin/activate   # 进入虚拟环境(如果还没激活)
    pip install opencv-python    # 确保已安装所需库
    

    安装依赖的完整步骤

    # 1. 激活虚拟环境
    source myenv/bin/activate
    
    # 2. 安装依赖(如果网络慢可以使用清华镜像)
    python -m pip install torch torchvision ultralytics opencv-python
    
    # 或者使用国内镜像加速安装
    python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python
    
    # 直接使用python命令运行,不需要执行权限
    python extract_people_images.py
    
    # 给脚本执行权限:
    chmod +x extract_people_images.py
    

    ##

    一、增强检测人物图片:

    使用YOLOv8模型进行更准确的人物检测,增强版人物图片检测

    模型说明

    • yolov8n.pt:最小最快,适合快速检测
    • yolov8s.pt:平衡速度和精度
    • yolov8m.pt:中等精度
    • yolov8l.pt:高精度
    • yolov8x.pt:最高精度,最慢

    特性

    1. 更准确的人物检测:YOLO可以检测各种姿势、大小的人物
    2. 可调置信度:根据需求调整检测敏感度
    3. 检测预览:可选保存带检测框的图片
    4. 详细统计:显示检测数量、置信度、处理时间等
    5. 错误处理:完善的异常处理,不会因为单张图片失败而停止
    6. 进度显示:实时显示处理进度

    这个增强版本比基础版本准确得多,特别是对于侧面、远处、遮挡的人物检测效果更好!

    完整的Python代码

    #!/usr/bin/env python3
    """
    增强版人物图片检测程序
    使用YOLOv8模型进行更准确的人物检测
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            print("\n如果安装缓慢,可以使用清华镜像:")
            print("pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python")
            return None, None
    
    def extract_images_with_people_enhanced(source_dir, target_dir, confidence_threshold=0.3, 
                                          model_size='yolov8n.pt', device='cpu', 
                                          save_detection_preview=False):
        """
        使用YOLO模型检测并提取包含人物的图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值(0.0-1.0),值越小检测越敏感
        model_size: 模型大小 ('yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt')
        device: 运行设备 ('cpu' 或 'cuda')
        save_detection_preview: 是否保存带检测框的预览图
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp', '.JPG', '.JPEG', '.PNG']
        
        print("=" * 60)
        print("增强版人物图片检测程序")
        print("=" * 60)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print(f"设备: {device}")
        print(f"保存检测预览: {save_detection_preview}")
        print("-" * 60)
        
        try:
            # 加载YOLO模型(会自动下载如果不存在)
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            print("请检查网络连接或手动下载模型")
            return
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 处理: {filename}")
            total_images += 1
            
            try:
                # 记录开始时间
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检查是否检测到人物(YOLO中person类的ID是0)
                has_people = False
                people_count = 0
                max_confidence = 0.0
                
                for result in results:
                    if result.boxes is not None and len(result.boxes) > 0:
                        for box in result.boxes:
                            class_id = int(box.cls)
                            confidence = float(box.conf)
                            
                            # class_id 0 对应 'person'
                            if class_id == 0:
                                has_people = True
                                people_count += 1
                                max_confidence = max(max_confidence, confidence)
                
                if has_people:
                    images_with_people += 1
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    base_target_path = target_path
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 复制原图到目标文件夹
                    shutil.copy2(file_path, target_path)
                    
                    # 如果启用预览,保存带检测框的图片
                    if save_detection_preview and has_people:
                        try:
                            # 绘制检测结果
                            plotted_image = results[0].plot()
                            preview_filename = f"preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    print(f"  ✓ 检测到 {people_count} 个人物 (最高置信度: {max_confidence:.3f})")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已复制到: {os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'people_count': people_count,
                        'max_confidence': max_confidence,
                        'detection_time': detection_time
                    })
                    
                else:
                    print(f"  ✗ 未检测到人物 (检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 60)
        print("处理完成!")
        print("=" * 60)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到包含人物的图片: {images_with_people}张")
            print(f"检测率: {(images_with_people/total_images*100):.1f}%")
            
            if detection_times:
                avg_detection_time = sum(detection_times) / len(detection_times)
                print(f"平均检测时间: {avg_detection_time:.2f}秒/张")
                print(f"总检测时间: {sum(detection_times):.2f}秒")
            
            if images_with_people > 0:
                print(f"\n包含人物的图片已保存到: {target_dir}")
                if save_detection_preview:
                    print(f"检测预览图已保存到: {preview_dir}")
                
                # 显示检测到最多人物的前几张图片
                if processed_files:
                    processed_files.sort(key=lambda x: x['people_count'], reverse=True)
                    print(f"\n检测结果最好的图片:")
                    for i, file_info in enumerate(processed_files[:3]):
                        print(f"  {i+1}. {file_info['filename']} - {file_info['people_count']}人 "
                              f"(置信度: {file_info['max_confidence']:.3f})")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='增强版人物图片检测程序')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='images_with_people',
                           help='目标文件夹路径 (默认: images_with_people)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        
        args = parser.parse_args()
        
        # 检查源文件夹是否存在
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        # 运行检测程序
        extract_images_with_people_enhanced(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview
        )
    
    # 简化版本函数(不需要命令行参数)
    def simple_extract():
        """简化版本,使用默认参数"""
        source_dir = os.getcwd()  # 当前文件夹
        target_dir = os.path.join(source_dir, "images_with_people")
        
        print("使用简化模式运行...")
        extract_images_with_people_enhanced(source_dir, target_dir)
    
    if __name__ == "__main__":
        # 如果没有命令行参数,使用简化版本
        import sys
        if len(sys.argv) == 1:
            simple_extract()
        else:
            main()
    

    步骤1:保存文件

    在nano编辑器中:

    • Ctrl+X退出
    • Y确认保存
    • Enter确认文件名

    步骤2:运行程序

    python extract_people_images_enhanced_copy.py
    

    方法2:使用命令行参数

    # 基本使用
    python extract_people_images_enhanced_copy.py --source /path/to/images --target ./output
    
    # 调整检测敏感度(值越小越敏感)
    python extract_people_images_enhanced_copy.py --confidence 0.2
    
    # 使用更大的模型(更准确但更慢)
    python extract_people_images_enhanced_copy.py --model yolov8s.pt
    
    # 保存检测预览图
    python extract_people_images_enhanced_copy.py --preview
    
    # 使用GPU加速(如果有NVIDIA显卡)
    python extract_people_images_enhanced_copy.py --device cuda
    
    # 查看所有选项
    python extract_people_images_enhanced_copy.py --help
    

    如果还是有问题,使用这个简单版本:

    # 先删除所有有问题的文件
    rm -f *.py
    
    # 创建简单版本
    cat > simple_detection.py << 'EOF'
    import os
    import shutil
    import cv2
    from pathlib import Path
    
    def detect_people():
        print("开始检测人物图片...")
        
        # 检查OpenCV
        try:
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        except:
            print("请先安装OpenCV: pip install opencv-python")
            return
        
        # 创建目标文件夹
        target_dir = "images_with_people"
        Path(target_dir).mkdir(exist_ok=True)
        
        # 支持的图片格式
        formats = ['.jpg', '.jpeg', '.png']
        count = 0
        
        for filename in os.listdir('.'):
            if any(filename.lower().endswith(fmt) for fmt in formats):
                print(f"处理: {filename}")
                img = cv2.imread(filename)
                if img is not None:
                    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                    faces = face_cascade.detectMultiScale(gray, 1.1, 5)
                    if len(faces) > 0:
                        shutil.copy2(filename, os.path.join(target_dir, filename))
                        print(f"✓ 检测到人物")
                        count += 1
                    else:
                        print(f"✗ 未检测到人物")
        
        print(f"\n完成! 找到 {count} 张包含人物的图片")
    
    if __name__ == "__main__":
        detect_people()
    EOF
    
    # 运行简单版本
    python simple_detection.py
    

    请按照步骤1-4操作,应该能解决问题!

    二、增强检测人物图片(自定义文件夹):

    这个版本实现了把检测到的图片直接移动到新的文件夹而不是复制,也可以通过后面的加参数定义移动或者复制。

    主要修改 shutil.copy2()shutil.move()

    #!/usr/bin/env python3
    """
    增强版人物图片检测程序(移动版本)
    使用YOLOv8模型进行更准确的人物检测,并将图片移动到新文件夹
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            print("\n如果安装缓慢,可以使用清华镜像:")
            print("pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python")
            return None, None
    
    def extract_images_with_people_enhanced(source_dir, target_dir, confidence_threshold=0.3, 
                                          model_size='yolov8n.pt', device='cpu', 
                                          save_detection_preview=False, move_instead_of_copy=True):
        """
        使用YOLO模型检测并移动包含人物的图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值(0.0-1.0),值越小检测越敏感
        model_size: 模型大小 ('yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt')
        device: 运行设备 ('cpu' 或 'cuda')
        save_detection_preview: 是否保存带检测框的预览图
        move_instead_of_copy: 是否移动而不是复制图片
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp', '.JPG', '.JPEG', '.PNG']
        
        print("=" * 60)
        print("增强版人物图片检测程序(移动版本)")
        print("=" * 60)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"操作模式: {'移动' if move_instead_of_copy else '复制'}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print(f"设备: {device}")
        print(f"保存检测预览: {save_detection_preview}")
        print("-" * 60)
        
        # 警告信息
        if move_instead_of_copy:
            print("⚠️  警告: 此操作将移动图片文件,原文件夹中的图片将被删除!")
            response = input("是否继续?(y/N): ")
            if response.lower() != 'y':
                print("操作已取消")
                return
        
        try:
            # 加载YOLO模型(会自动下载如果不存在)
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            print("请检查网络连接或手动下载模型")
            return
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 处理: {filename}")
            total_images += 1
            
            try:
                # 记录开始时间
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检查是否检测到人物(YOLO中person类的ID是0)
                has_people = False
                people_count = 0
                max_confidence = 0.0
                
                for result in results:
                    if result.boxes is not None and len(result.boxes) > 0:
                        for box in result.boxes:
                            class_id = int(box.cls)
                            confidence = float(box.conf)
                            
                            # class_id 0 对应 'person'
                            if class_id == 0:
                                has_people = True
                                people_count += 1
                                max_confidence = max(max_confidence, confidence)
                
                if has_people:
                    images_with_people += 1
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    base_target_path = target_path
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 移动或复制文件到目标文件夹
                    if move_instead_of_copy:
                        shutil.move(file_path, target_path)
                        operation_text = "移动"
                    else:
                        shutil.copy2(file_path, target_path)
                        operation_text = "复制"
                    
                    # 如果启用预览,保存带检测框的图片
                    if save_detection_preview and has_people:
                        try:
                            # 重新读取图片用于预览(如果是移动操作,需要重新加载)
                            if move_instead_of_copy:
                                preview_source_path = target_path
                            else:
                                preview_source_path = file_path
                                
                            preview_results = model(preview_source_path, conf=confidence_threshold, device=device, verbose=False)
                            plotted_image = preview_results[0].plot()
                            preview_filename = f"preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    print(f"  ✓ 检测到 {people_count} 个人物 (最高置信度: {max_confidence:.3f})")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已{operation_text}到: {os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'people_count': people_count,
                        'max_confidence': max_confidence,
                        'detection_time': detection_time,
                        'operation': operation_text
                    })
                    
                else:
                    print(f"  ✗ 未检测到人物 (检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 60)
        print("处理完成!")
        print("=" * 60)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到包含人物的图片: {images_with_people}张")
            print(f"检测率: {(images_with_people/total_images*100):.1f}%")
            
            if detection_times:
                avg_detection_time = sum(detection_times) / len(detection_times)
                print(f"平均检测时间: {avg_detection_time:.2f}秒/张")
                print(f"总检测时间: {sum(detection_times):.2f}秒")
            
            if images_with_people > 0:
                operation_mode = "移动" if move_instead_of_copy else "复制"
                print(f"\n包含人物的图片已{operation_mode}到: {target_dir}")
                if save_detection_preview:
                    print(f"检测预览图已保存到: {preview_dir}")
                
                # 显示检测到最多人物的前几张图片
                if processed_files:
                    processed_files.sort(key=lambda x: x['people_count'], reverse=True)
                    print(f"\n检测结果最好的图片:")
                    for i, file_info in enumerate(processed_files[:3]):
                        print(f"  {i+1}. {file_info['filename']} - {file_info['people_count']}人 "
                              f"(置信度: {file_info['max_confidence']:.3f})")
                    
                # 安全提示
                if move_instead_of_copy:
                    remaining_files = len([f for f in os.listdir(source_dir) 
                                         if any(f.lower().endswith(fmt) for fmt in supported_formats)])
                    print(f"\n⚠️  原文件夹剩余图片: {remaining_files}张")
                    print("⚠️  检测到的图片已被移动到目标文件夹,原文件已删除")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='增强版人物图片检测程序(移动版本)')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='images_with_people',
                           help='目标文件夹路径 (默认: images_with_people)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        parser.add_argument('--copy', action='store_true',
                           help='使用复制模式而不是移动模式')
        
        args = parser.parse_args()
        
        # 检查源文件夹是否存在
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        # 运行检测程序
        extract_images_with_people_enhanced(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview,
            move_instead_of_copy=not args.copy  # 如果指定--copy则使用复制模式
        )
    
    # 简化版本函数(不需要命令行参数)
    def simple_extract():
        """简化版本,使用默认参数(移动模式)"""
        source_dir = os.getcwd()  # 当前文件夹
        target_dir = os.path.join(source_dir, "images_with_people")
        
        print("使用简化模式运行(移动模式)...")
        print("此操作将把检测到人物的图片移动到新文件夹!")
        
        response = input("是否继续?(y/N): ")
        if response.lower() != 'y':
            print("操作已取消")
            return
        
        extract_images_with_people_enhanced(source_dir, target_dir, move_instead_of_copy=True)
    
    if __name__ == "__main__":
        # 如果没有命令行参数,使用简化版本
        import sys
        if len(sys.argv) == 1:
            simple_extract()
        else:
            main()
    

    主要修改内容:

    1. shutil.copy2()改为 shutil.move()
    2. 添加了移动模式的安全确认,避免误操作
    3. 增加了 move_instead_of_copy参数,可以控制是移动还是复制
    4. 添加了 --copy命令行参数,如果需要复制模式可以加上这个参数
    5. 改进了预览图生成逻辑,适应移动操作
    6. 增加了操作完成后的统计信息,显示剩余文件数量

    使用方法:

    移动模式(默认):

    # 简单使用(移动图片)
    python extract_people_images_enhanced_move.py
    
    # 带参数使用
    python extract_people_images_enhanced_move.py --source ./图片文件夹 --target ./人物图片
    

    复制模式(如果需要保留原文件):

    # 使用复制模式
    python extract_people_images_enhanced_move.py --copy
    
    # 带预览的复制模式
    python extract_people_images_enhanced_move.py --copy --preview
    

    其他参数:

    # 调整检测敏感度
    python extract_people_images_enhanced_move.py --confidence 0.2
    
    # 使用更大的模型
    python extract_people_images_enhanced_move.py --model yolov8s.pt
    
    # 保存检测预览图
    python extract_people_images_enhanced_move.py --preview
    

    安全特性:

    1. 运行前确认:移动模式会要求用户确认
    2. 进度显示:实时显示处理进度
    3. 结果统计:完成后显示移动/复制的文件数量
    4. 剩余文件提示:显示原文件夹剩余图片数量

    这样修改后,检测到人物的图片会被直接移动到目标文件夹,原文件会被删除,节省磁盘空间。如果你需要保留原文件,使用 --copy参数即可。

    高级检测:

    方案1:基于YOLO的人体部位检测

    专门检测女性人体暴露或色情内容。这里有几个不同级别的实现方案:

    #!/usr/bin/env python3
    """
    女性人体暴露/色情图片检测程序
    使用YOLO模型检测暴露的身体部位
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            return None, None
    
    class NudityDetector:
        """暴露内容检测器"""
        
        def __init__(self, confidence_threshold=0.3):
            self.confidence_threshold = confidence_threshold
            # 定义敏感部位类别(基于COCO数据集)
            self.sensitive_parts = {
                'person': 0,      # 人物
                'face': 1,        # 脸部(某些数据集有)
            }
            
            # 定义暴露风险等级的关键词(用于文件名和路径分析)
            self.risky_keywords = [
                'nude', 'naked', 'bikini', 'swimsuit', 'lingerie', 'sexy', 'hot',
                '暴露', '性感', '内衣', '比基尼', '泳装', '裸体', '色情'
            ]
        
        def detect_exposure_level(self, results, filename=""):
            """
            检测图片的暴露等级
            返回: (暴露等级, 置信度, 检测到的部位)
            """
            exposure_level = 0  # 0: 安全, 1: 轻度, 2: 中度, 3: 高度暴露
            max_confidence = 0
            detected_parts = []
            
            for result in results:
                if result.boxes is not None and len(result.boxes) > 0:
                    for box in result.boxes:
                        class_id = int(box.cls)
                        confidence = float(box.conf)
                        
                        # 检测人物
                        if class_id == 0:  # person
                            detected_parts.append('person')
                            max_confidence = max(max_confidence, confidence)
                            
                            # 如果有高置信度的人物检测,基础暴露等级为1
                            if confidence > 0.5:
                                exposure_level = max(exposure_level, 1)
            
            # 基于文件名分析
            filename_risk = self.analyze_filename_risk(filename.lower())
            exposure_level = max(exposure_level, filename_risk)
            
            return exposure_level, max_confidence, detected_parts
        
        def analyze_filename_risk(self, filename):
            """分析文件名的风险等级"""
            risk_level = 0
            for keyword in self.risky_keywords:
                if keyword in filename:
                    if keyword in ['nude', 'naked', '裸体', '色情']:
                        risk_level = max(risk_level, 3)
                    elif keyword in ['bikini', 'swimsuit', 'lingerie', '比基尼', '泳装', '内衣']:
                        risk_level = max(risk_level, 2)
                    else:
                        risk_level = max(risk_level, 1)
            return risk_level
        
        def analyze_skin_ratio(self, image_path):
            """简单的肤色比例分析(基础版本)"""
            try:
                import cv2
                import numpy as np
                
                # 读取图片
                img = cv2.imread(image_path)
                if img is None:
                    return 0
                    
                # 转换到HSV颜色空间进行肤色检测
                hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
                
                # 定义肤色范围(需要根据实际情况调整)
                lower_skin = np.array([0, 20, 70], dtype=np.uint8)
                upper_skin = np.array([20, 255, 255], dtype=np.uint8)
                
                # 创建肤色掩码
                mask = cv2.inRange(hsv, lower_skin, upper_skin)
                
                # 计算肤色像素比例
                skin_ratio = np.sum(mask > 0) / (img.shape[0] * img.shape[1])
                
                return skin_ratio
                
            except Exception as e:
                print(f"肤色分析错误: {e}")
                return 0
    
    def extract_sensitive_images(source_dir, target_dir, confidence_threshold=0.3, 
                               model_size='yolov8n.pt', device='cpu', 
                               save_detection_preview=False, move_instead_of_copy=True,
                               min_exposure_level=1):
        """
        检测并提取敏感图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值
        model_size: 模型大小
        device: 运行设备
        save_detection_preview: 是否保存检测预览
        move_instead_of_copy: 是否移动文件
        min_exposure_level: 最小暴露等级 (1-3)
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 按暴露等级创建子文件夹
        level_folders = {
            1: os.path.join(target_dir, "level1_mild"),
            2: os.path.join(target_dir, "level2_moderate"),
            3: os.path.join(target_dir, "level3_high")
        }
        
        for folder in level_folders.values():
            Path(folder).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
        
        print("=" * 70)
        print("女性人体暴露/色情图片检测程序")
        print("=" * 70)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"操作模式: {'移动' if move_instead_of_copy else '复制'}")
        print(f"最小暴露等级: {min_exposure_level}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print("-" * 70)
        
        # 警告信息
        if move_instead_of_copy:
            print("⚠️  警告: 此操作将移动图片文件!")
            response = input("是否继续?(y/N): ")
            if response.lower() != 'y':
                print("操作已取消")
                return
        
        # 初始化检测器
        detector = NudityDetector(confidence_threshold)
        
        try:
            # 加载YOLO模型
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            return
        
        # 统计信息
        total_images = 0
        detected_images = 0
        level_stats = {1: 0, 2: 0, 3: 0}
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 分析: {filename}")
            total_images += 1
            
            try:
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检测暴露等级
                exposure_level, max_confidence, detected_parts = detector.detect_exposure_level(results, filename)
                
                # 简单的肤色比例分析
                skin_ratio = detector.analyze_skin_ratio(file_path)
                if skin_ratio > 0.3:  # 如果肤色比例较高,提高暴露等级
                    exposure_level = max(exposure_level, 2)
                
                if exposure_level >= min_exposure_level:
                    detected_images += 1
                    level_stats[exposure_level] = level_stats.get(exposure_level, 0) + 1
                    
                    # 确定目标文件夹
                    target_level_folder = level_folders.get(exposure_level, target_dir)
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_level_folder, filename)
                    
                    # 处理重名文件
                    counter = 1
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_level_folder, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 移动或复制文件
                    if move_instead_of_copy:
                        shutil.move(file_path, target_path)
                        operation_text = "移动"
                    else:
                        shutil.copy2(file_path, target_path)
                        operation_text = "复制"
                    
                    # 保存检测预览
                    if save_detection_preview:
                        try:
                            preview_results = model(target_path if move_instead_of_copy else file_path, 
                                                  conf=confidence_threshold, device=device, verbose=False)
                            plotted_image = preview_results[0].plot()
                            preview_filename = f"L{exposure_level}_preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    # 暴露等级描述
                    level_descriptions = {
                        1: "轻度暴露",
                        2: "中度暴露", 
                        3: "高度暴露"
                    }
                    
                    print(f"  ✓ 检测结果: {level_descriptions.get(exposure_level, '未知')} (等级{exposure_level})")
                    print(f"  ✓ 肤色比例: {skin_ratio:.3f}")
                    print(f"  ✓ 检测部位: {', '.join(detected_parts) if detected_parts else '无'}")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已{operation_text}到: level{exposure_level}/{os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'exposure_level': exposure_level,
                        'skin_ratio': skin_ratio,
                        'detected_parts': detected_parts,
                        'detection_time': detection_time,
                        'operation': operation_text
                    })
                    
                else:
                    print(f"  ✗ 安全图片 (暴露等级: {exposure_level}, 检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 70)
        print("检测完成!")
        print("=" * 70)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到敏感图片: {detected_images}张")
            print(f"检测率: {(detected_images/total_images*100):.1f}%")
            
            print(f"\n暴露等级分布:")
            for level, count in level_stats.items():
                if count > 0:
                    level_desc = {1: "轻度暴露", 2: "中度暴露", 3: "高度暴露"}.get(level, "未知")
                    print(f"  等级{level} ({level_desc}): {count}张")
            
            if detected_images > 0:
                operation_mode = "移动" if move_instead_of_copy else "复制"
                print(f"\n敏感图片已{operation_mode}到对应等级的文件夹")
                
                # 显示检测结果
                if processed_files:
                    processed_files.sort(key=lambda x: x['exposure_level'], reverse=True)
                    print(f"\n风险最高的图片:")
                    for i, file_info in enumerate(processed_files[:5]):
                        print(f"  {i+1}. {file_info['filename']} - 等级{file_info['exposure_level']} "
                              f"(肤色比例: {file_info['skin_ratio']:.3f})")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='女性人体暴露/色情图片检测程序')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='sensitive_images',
                           help='目标文件夹路径 (默认: sensitive_images)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        parser.add_argument('--copy', action='store_true',
                           help='使用复制模式而不是移动模式')
        parser.add_argument('--level', type=int, default=1, choices=[1, 2, 3],
                           help='最小暴露等级 (1:轻度, 2:中度, 3:高度, 默认: 1)')
        
        args = parser.parse_args()
        
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        extract_sensitive_images(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview,
            move_instead_of_copy=not args.copy,
            min_exposure_level=args.level
        )
    
    if __name__ == "__main__":
        import sys
        if len(sys.argv) == 1:
            # 简化模式运行
            source_dir = os.getcwd()
            target_dir = os.path.join(source_dir, "sensitive_images")
            
            print("女性人体暴露图片检测程序")
            print("此操作将检测并分类暴露程度的图片!")
            
            response = input("是否继续?(y/N): ")
            if response.lower() == 'y':
                extract_sensitive_images(source_dir, target_dir, move_instead_of_copy=True)
            else:
                print("操作已取消")
        else:
            main()
    

    方案2:使用专门的NSFW检测模型

    如果需要更准确的结果,可以使用专门的NSFW检测模型:

    # 需要额外安装的库
    # pip install tensorflow keras
    
    def setup_nsfw_detector():
        """设置专门的NSFW检测器"""
        try:
            # 这里可以使用预训练的NSFW检测模型
            # 例如: https://github.com/rockyzhengwu/nsfw
            print("正在加载NSFW检测模型...")
            # 实际实现需要下载预训练模型
            return None
        except ImportError:
            print("请安装TensorFlow: pip install tensorflow")
            return None
    

    使用方法:

    # 基本使用(移动模式,检测所有暴露等级)
    python sensitive_detector.py
    
    # 只检测高度暴露的图片
    python sensitive_detector.py --level 3
    
    # 复制模式(保留原文件)
    python sensitive_detector.py --copy
    
    # 指定源文件夹和目标文件夹
    python sensitive_detector.py --source ./图片库 --target ./敏感图片
    
    # 保存检测预览
    python sensitive_detector.py --preview
    
    # 使用更准确的模型
    python sensitive_detector.py --model yolov8s.pt
    

    暴露等级说明:

    • 等级1(轻度): 检测到人物,可能有轻微暴露
    • 等级2(中度): 检测到较多肤色区域或敏感关键词
    • 等级3(高度): 高度暴露内容,包含大量肤色区域或明确敏感内容

    注意事项:

    1. 准确率限制: 这种检测方法有一定误判率
    2. 隐私保护: 请确保合法使用,尊重他人隐私
    3. 法律合规: 在不同地区使用此类工具可能受到法律限制
    4. 人工审核: 建议最终结果由人工审核确认

    这个程序会按暴露程度将图片分类到不同的文件夹,方便你进一步处理。

    正确的运行方法:

    方法1:直接运行Python脚本

    # 进入脚本所在目录
    cd /home/leepoet/Documents/env/myenv/甜心
    
    # 直接运行Python脚本
    python 女性人体暴露.py
    

    方法2:给脚本添加执行权限后直接运行

    # 进入脚本所在目录
    cd /home/leepoet/Documents/env/myenv/甜心
    
    # 给脚本添加执行权限
    chmod +x 女性人体暴露.py
    
    # 直接运行脚本
    ./女性人体暴露.py
    

    设置自定义检测路径

    你可以通过命令行参数灵活指定源文件夹和目标文件夹:

    # 检测指定文件夹,结果保存到自定义目录
    python your_script.py --source /path/to/your/images --target /path/to/output

    # 完整参数示例
    python your_script.py --source /home/user/photos --target /home/user/sorted_photos --confidence 0.5 --model yolov8s.pt --preview --copy

    4. 关键参数说明

    • --source: 指定需要检测的图片文件夹路径
    • --target: 指定结果输出文件夹路径
    • --confidence: 调整检测灵敏度(0.1-1.0)
    • --model: 选择不同的YOLO模型(影响精度和速度)
    • --preview: 保存带检测框的预览图
    • --copy: 使用复制模式(默认是移动文件)
  • hexo生成博客的文章数量过多耗尽所有内存资源后出现out of memory的解决方法

    hexo生成博客的文章数量过多耗尽所有内存资源后出现out of memory的解决方法

    Hexo博客文章数量积累到上千篇时,很可能会在生成静态文件(hexo generate)时遭遇令人头疼的“JavaScript heap out of memory”错误。这主要是因为Node.js默认的内存限制无法处理海量文章生成所需的内存开销。

    文章数量很多时,会出现生成不了的情况,具体的错误是out of memory,具体的错误如下:

    hexo生成博客的文章数量过多耗尽所有内存资源后出现out of memory的解决方法

    这个错误让我一度想要放弃hexo,因为真的太糟心了,试了很多网上的方法都没有用。

    原因
    这个问题出现的主要原始还是在于hexo项目本身的问题,太耗资源了,虽说hexo一直在改进这方面的问题,但是,还是很慢,而且耗费资源很大,导致出现内存溢出。

    解决方法
    最后,分享一些解决方法,网上的那些增大nodejs的内存限制,这些都是没有用的,因为根本原因不在这里,就算你改了,还是可能报错,运气好可能ok,但是希望不大。

    解决办法其实很简单,我查看hexo项目的时候发现,hexo在5.0之后就这个问题做了一些改进,在生成的时候采用限制并行执行数量的方法,避免出现内存溢出。

    命令:在生成博客的时候,使用参数-c,代表生成博客时线程的数量吧,例如:

    hexo -g -c 8
    

    执行这个命令后,跟以往的输出有所不同,会实时的显示正在生成的静态文件,同时,不会出现内存溢出的问题。


    💻 启动本地服务器的基本命令

    最基础的启动命令是:

    hexo clean #清理缓存和旧文件,这是一个好习惯,可以避免某些更新未能生效的问题。简写hexo cl
    hexo generate #这个命令会将你的Markdown文章等源文件转换成浏览器可以解析的静态网页,简写:hexo g
    hexo server #启动服务器,简写hexo s


    💡 可能遇到的问题

    • ​端口被占用​​:如果默认的4000端口已被其他程序使用,启动时会报错。使用 hexo s -p 5000命令换一个端口即可。
    • ​更改未生效​​:如果你修改了博客配置或文章内容,但在浏览器中刷新后看不到变化,可以尝试按 Ctrl + C停止服务器,然后按“清理 -> 生成 -> 启动”的完整流程重新操作一遍。

    启动Hexo本地服务器非常简单,通过几个命令就能在浏览器中预览你的博客。下面是一个快速指南,帮你启动和运行Hexo。

    🛠️ Hexo 内存溢出解决方案

    清理缓存并重新生成

    首先尝试最基本的清理操作,这能解决很多因缓存引起的问题:hexo clean

    增加 Node.js 内存限制,直接在执行命令时增加内存限制,这是最直接的解决方法:

    node --max-old-space-size=16384 ./node_modules/hexo/bin/hexo generate

    或者如果全局安装了 hexo-cli:

    node --max-old-space-size=16384 hexo generate

    这里的 16384表示 16GB 内存,你可以根据需要调整为 8192(8GB)或其他值。

    永久性配置方案

    修改 package.json 中的脚本在 package.json文件的 scripts部分添加内存限制:

    "scripts": {
      "build": "node --max-old-space-size=16384 ./node_modules/hexo/bin/hexo generate --concurrency 8",
      "serve": "node --max-old-space-size=16384 ./node_modules/hexo/bin/hexo server",
      "clean": "hexo clean"
    }

    你的脚本配置详解

    脚本命令功能说明优势
    "build": "node --max-old-space-size=4096 ./node_modules/hexo/bin/hexo generate --concurrency 8"增加内存至4GB,并限制生成线程为8个。--max-old-space-size=4096有效防止生成大量文章时的内存溢出错误。--concurrency 8限制并行处理文件的数量,降低内存峰值,提高大博客生成的稳定性。
    "serve": "node --max-old-space-size=4096 ./node_modules/hexo/bin/hexo server"增加内存至4GB后启动本地服务器。确保本地预览 (hexo s) 时也拥有足够内存,与生成环境一致。
    "clean": "hexo clean"清除缓存和已生成的静态文件。保持简洁,因为清理操作通常不需要额外内存。

    配置好后,你就不再需要直接输入 hexo g或 hexo s了,而是使用更强大的 npm run命令:

    # 1. 清除旧文件
    npm run clean
    
    # 2. 重新生成静态文件(使用了你配置的内存和线程优化)
    npm run build
    
    # 3. 启动服务器进行预览
    npm run serve

    你也可以将命令组合起来,实现一键清理和生成:npm run clean && npm run build

    "scripts": {
      "build": "node --max-old-space-size=4096 ./node_modules/hexo/bin/hexo generate --concurrency 8",
      "serve": "node --max-old-space-size=4096 ./node_modules/hexo/bin/hexo server",
      "clean": "hexo clean",
      "rebuild": "npm run clean && npm run build" // 新增的组合命令
    }


    之后,只需运行 npm run rebuild就会先执行清理,再重新生成网站。

    • 组合命令​​:你可以添加一个组合命令,让你一键完成清理、生成和启动服务器,虽然这需要借助如 npm-run-all的工具,但你可以简单地使用 npm run clean && npm run build && npm run serve
    • ​部署命令​​:如果你使用 hexo-deployer-git等工具自动部署到GitHub Pages或服务器,可以添加一个部署脚本,例如:”deploy”: “npm run clean && npm run build && hexo deploy”

    自定义服务器端口

    如果你的4000端口被其他程序占用,可以直接在 serve脚本中指定新端口。这是比修改配置文件更工程化的做法。

    "serve": "node --max-old-space-size=16384 ./node_modules/hexo/bin/hexo server -p 4001"

    配置好后,使用以下命令来操作博客:

    • ​清理并重新生成​​:npm run clean→ npm run build
    • ​启动本地服务器预览​​:npm run serve
    • 一键清理和生成​​(如果配置了 rebuild脚本):npm run rebuild

    修改 Windows 系统中的 hexo.cmd

    对于 Windows 系统,可以直接修改 hexo 的可执行文件:找到 ./node_modules/.bin/hexo.cmd文件,将其内容修改为:

    @IF EXIST "%~dp0\node.exe" (
      "%~dp0\node.exe" --max-old-space-size=16384 "%~dp0\..\hexo\bin\hexo" %*
    ) ELSE (
      @SETLOCAL
      @SET PATHEXT=%PATHEXT:;.JS;=;%
      node --max-old-space-size=16384 "%~dp0\..\hexo\bin\hexo" %*
    )

    如果上方的配置没用可以用下面的:

    @ECHO off
    GOTO start
    :find_dp0
    SET dp0=%~dp0
    EXIT /b
    :start
    SETLOCAL
    CALL :find_dp0
    
    IF EXIST "%dp0%\node.exe" (
      SET "_prog=%dp0%\node.exe"
    ) ELSE (
      SET "_prog=node"
      SET PATHEXT=%PATHEXT:;.JS;=;%
    )
    
    ENDLOCAL & GOTO :EOF
    
    "%~dp0\node.exe" --max-old-space-size=16384 "%~dp0\..\hexo\bin\hexo" %*
    goto :eof

    ⚙️ 修改系统级的启动文件(针对全局命令)

    如果你希望在任何地方运行 hexo generate这样的全局命令时都生效,可以修改系统环境变量。这通常不推荐作为首选,因为它会影响所有项目,但可以作为备选方案。

    ​•Windows系统​​:可以创建一个或修改一个名为 HEXO_NODE_OPTIONS的系统环境变量,将其值设置为 --max-old-space-size=16384。或者如果你想永久设置,可以使用 setx命令,但设置后需要重新打开终端:setx NODE_OPTIONS --max_old_space_size=16384

    •​​Linux/macOS系统​​:可以在你的 shell 配置文件(如 ~/.bashrc~/.zshrc等)中添加一行:

    export NODE_OPTIONS="--max-old-space-size=16384"

    然后执行 source ~/.zshrc(根据你使用的配置文件)使其立即生效。

    设置后,任何新启动的命令行窗口中运行的 Node.js 程序都会继承这个内存限制。

    针对大型博客的优化方案

    限制生成线程数

    如果您的博客文章数量很多(超过1000篇),可以使用 Hexo 5.0+ 提供的并发控制功能:

    hexo generate --concurrency 8   #简写:hexo -g -c 8

    这个参数会限制并行生成的文件数量,显著降低内存使用量。

    使用 increase-memory-limit 工具

    安装专门的内存限制提升工具:

    # 全局安装
    npm install -g increase-memory-limit
    
    # 进入项目目录执行
    increase-memory-limit


    ⚙️ 常用参数与组合用法

    除了基本命令,还有一些有用的参数和组合命令可以提升效率:

    用途命令说明
    ​调试模式​hexo s --debug方便排查问题,会在控制台输出详细日志。
    ​指定端口​hexo s -p 5000当4000端口被占用时,可以用 -p参数指定其他端口(如5000)。
    ​启动前生成​hexo s -g在启动服务器前,自动执行 hexo generate生成最新的静态文件,确保你看到的是最新改动。
    设置 Node.js 可使用的最大内存空间–max-old-space-size=16384设置 Node.js 可使用的最大老生代内存空间为 ​​16GB​​。这主要用于避免生成大量页面时出现内存溢出(OOM)错误
    指定要执行的 Hexo 核心位置./node_modules/hexo/bin/hexo指定要执行的 Hexo 核心程序文件的位置。
    设置最大并发数​​-c 100指定生成静态页面时的​​最大并发数​​为 100,旨在提升生成过程的效率

    除了在命令中直接指定,你还可以通过以下方式设置内存限制,以避免每次手动输入长命令:

    • ​修改 package.json中的 npm 脚本​​:在你的 Hexo 博客目录下,找到 package.json文件,在 "scripts"部分添加或修改命令。
    • 例如,将 “generate”: hexo generate改为 “generate”: node --max-old-space-size=8192 ./node_modules/hexo/bin/hexo generate
    • 之后,你只需要运行 npm run generate即可
    • 设置环境变量​​:你可以通过设置 NODE_OPTIONS环境变量来全局提升 Node.js 的内存限制。
    • 在 Linux 或 macOS 的终端中执行:export NODE_OPTIONS="--max-old-space-size=16384"
    • 在 Windows 的命令提示符(CMD)中执行:set NODE_OPTIONS="--max-old-space-size=16384"设置后,在同一终端会话中直接运行 hexo generate就会生效

    ⚠️ 注意事项

    • ​合理设置内存大小​​:请根据你电脑的实际物理内存来设置 --max-old-space-size的值。通常建议设置为系统总内存的 50%-70%,以确保系统本身和其他程序有足够的内存运行,避免因系统内存耗尽导致卡顿或崩溃。
    • ​并发数不是越高越好​​:-c参数也并非设置得越高越好,过高的并发数可能会过度消耗 CPU 资源。如果设置后生成过程不稳定,可以尝试适当调低该数值

    报错解决:定位问题文件

    首先需要确定是哪个文件导致了这个问题。错误信息显示 (unknown path),这意味着Hexo无法准确指出问题文件。建议:

    # 使用调试模式获取更详细的信息
    hexo generate --debug

    检查注释语法

    如果在文章或模板中使用了以下特殊字符,可能需要转义:

    • ​大括号​​ {和 }
    • ​注释标签​​ {#和 #}
    • ​其他模板语法字符​

    1.TypeError: logger.info is not a function

    将 themes/Acrylic/scripts/event/welcome.js文件中的代码修改为以下两种方案之一:

    ​方案一:直接使用导入的logger对象(推荐)​

    const logger = require('hexo-log'); // 关键修改:去掉调用括号

    hexo.on('ready', () => {
    const { version } = require('../../package.json')
    logger.info(`
    ===================================================================

    █████╗ ██████╗██████╗ ██╗ ██╗██╗ ██╗ ██████╗
    ██╔══██╗██╔════╝██╔══██╗╚██╗ ██╔╝██║ ██║██╔════╝
    ███████║██║ ██████╔╝ ╚████╔╝ ██║ ██║██║
    ██╔══██║██║ ██╔══██╗ ╚██╔╝ ██║ ██║██║
    ██║ ██║╚██████╗██║ ██║ ██║ ███████╗██║╚██████╗
    ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═════╝

    Next-${version}
    ===================================================================`)
    })

    ​方案二:使用Hexo内置的日志功能(备选)​

    hexo.on('ready', () => {
    const { version } = require('../../package.json')
    // 使用hexo自带的log方法
    hexo.log.info(`
    ===================================================================

    █████╗ ██████╗██████╗ ██╗ ██╗██╗ ██╗ ██████╗
    ██╔══██╗██╔════╝██╔══██╗╚██╗ ██╔╝██║ ██║██╔════╝
    ███████║██║ ██████╔╝ ╚████╔╝ ██║ ██║██║
    ██╔══██║██║ ██╔══██╗ ╚██╔╝ ██║ ██║██║
    ██║ ██║╚██████╗██║ ██║ ██║ ███████╗██║╚██████╗
    ╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚══════╝╚═╝ ╚═════╝

    Next-${version}
    ===================================================================`)
    })

  • Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    Discuz! X3.5的正式版,X3.5正式版发布距今已有一年,它是Discuz! X系列的最新版本,也是目前最稳定和最受欢迎的版本之一。它在前一版本的基础上进行了优化和改进,提供了更多的功能和更好的用户体验。

    正式版提供了从X3.5以下版本的升级

    X3.5运行环境要求:
    安全提示:我们强烈建议您使用仍在开发团队支持期内的操作系统、Web服务器、PHP、数据库、内存缓存等软件,超出支持期的软件可能会对您的站点带来未知的安全隐患。 性能提示:当 MySQL < 5.7 或 MariaDB < 10.2 时, InnoDB 性能下降较为严重,因此在生产系统上运行的站点应升级版本至 MySQL >= 5.7 或 MariaDB >= 10.2 以避免此问题。

    软件名称最低要求推荐版本其他事项
    PHP>= 5.6.07.4 – 8.2依赖 XML 扩展、 JSON 扩展、 GD 扩展 >= 1.0
    MySQL>= 5.5.38.0如使用 MariaDB ,推荐版本为 >= 10.2

    X3.5核心亮点:
    1、支持PHP8
    2、支持MYSQL8
    3、支持IPV6,支持多IP库、支持CDN不同模式真实IP获取,且支持扩展获取模式
    4、支持UTF8MB4(支持emoji表情、更多字符的支持)
    5、支持InnoDB(云数据库已普遍推荐使用)
    6、支持全模块开关(包括论坛,从此Discuz!X不只是论坛,而是全方案的建站系统)
    7、全新的支付系统,自带微信支付、支付宝支付、QQ钱包支付,支持扩展接入更多支付体系,支持第三方调用支付
    8、内置安全手机底层,支持第三方SMS接口接入
    9、更完善、现代化的手机版
    10、全新的后台风格
    11、更安全的密码加密方式
    12、更完善的HTTPS支持
    13、HTML5全面取代Flash

    另有数百项功能改进……

    完整安装包下载

    简体中文

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    Discuz_X3.5_SC_UTF8_20250901.zip

    繁体中文

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    Discuz_X3.5_TC_UTF8_20250901.zip

    Discuz! X3.5 手机版微信小程序包
    https://www.dismall.com/thread-18478-1-1.html

    全新安装教程

    https://www.dismall.com/thread-15912-1-1.html

    宝塔面板安装Discuz! X3.5教程

    https://www.dismall.com/thread-19028-1-1.html

    老版本升级

    从 X3.5 老版本升级
    https://www.dismall.com/thread-15913-1-1.html

    从 Discuz! X3.2 – X3.4 升级
    https://www.dismall.com/thread-15914-1-1.html


    1、打开自己的宝塔面板,在软件商店安装 php 和 mysql

    软件名称最低要求推荐版本其他事项
    PHP>= 5.6.07.4 – 8.2依赖 XML 扩展、 JSON 扩展、 GD 扩展 >= 1.0
    MySQL>= 5.5.38.0如使用 MariaDB ,推荐版本为 >= 10.2

    2、在软件商店选择“一键部署”分类,再搜索 discuz ,再点击一键部署Discuz! X3.5

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    或者

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    3、填上自己的域名,点击提交

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    discuz下载中

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    4、下载完成,这里的数据库信息后边安装Discuz! X3.5 时会用到,点击提示里的网站链接,进入安装界面

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    5、阅读授权协议后点击“我同意”

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    6、系统会自动检查环境及文件目录权限检测成功,点击“下一步”

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    7、保持默认的
    “全新安装 Discuz! X3.5 (含 UCenter Server)”,点击“下一步”

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    7、点击“下一步”,进入安装数据库的界面,如下图所示:

    填写前边宝塔生成的数据库信息,并设置管理员账号和密码。
    点击“下一步”,系统会自动安装数据库直至完毕,如下图所示:

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    安装中界面:

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    安装成功后,会出现如下的界面:

    Linux宝塔面板全新安装Discuz! X3.5官方教程,详细Discuz!安装图文教程 

    至此,Discuz! X3.5 已经成功地安装完毕!您可以登录 Discuz! X3.5 站点并开始设置了。

  • Discuz! X3.4 Tools论坛急诊箱 (2015-04-13版)

    Discuz! X3.4 Tools论坛急诊箱 (2015-04-13版)

    对于使用Discuz! X3.4及相近版本的站长来说,最令人头疼的莫过于网站突然出现故障却无法进入后台管理。此时,一个名为 “Tools论坛急诊箱”​ 的神器就显得至关重要。本文将为您详细介绍这款经典工具的功能、使用方法及至关重要的安全注意事项。

    Tools急诊箱是什么?

    Tools急诊箱是一个独立运行的PHP脚本文件(tools.php)。当您的Discuz!论坛后台因各种原因无法登录时,可以通过直接访问这个脚本来执行一系列紧急恢复操作。它相当于一个 bypass 后台的紧急管理入口,是站长必备的救命工具。

    Tools急诊箱主要功能:

    1、重置管理员账号:将把您指定的会员设置为管理员,重新设置创始人密码。
    2、开启关闭站点: 此处可以进行站点“关闭/打开”的操作。
    3、一键关闭插件:一键关闭应用中心开启的所有插件。
    4、修复数据库: 对所有数据表进行检查修复工作。
    5、恢复数据库: 一次性导入论坛数据备份。
    6、更新缓存: 一键更新论坛的数据缓存与模板缓存。

    Tools工具 安装方法:

    1、下载Tools急诊箱tools.zip文件后;
    2、解压tools.zip文件;
    3、将 tools.php上传到网站根目录中;
    4、访问 网站域名/tools.php 即可进行相关操作。

    Tools急诊箱下载地址: 

    Discuz! X3.4 Tools论坛急诊箱 (2015-04-13版)

    地址一、tools2015.zip(22.12 KB, 下载次数: 3962) 地址二、tools2015.zip
    默认密码:  admin

    使用完一定要删除,否则有安全风险

  • discuz全局变量保存起来以备需要时使用

    discuz全局变量保存起来以备需要时使用

    Discuz! 是一个著名的基于 PHP 和 MySQL 的开源论坛系统,它的模板和插件开发中常常会使用到一系列预定义的全局变量,即“Discuz! $G 全局变量”。这些变量提供了论坛的状态、用户信息、设置参数等数据,使得开发者可以在模板文件中轻松访问并使用这些信息。

    discuz全局变量保存起来以备需要时使用
    $_G[‘uid’] => 当前登录UID
    $_G[‘username’] => 当前登录用户名
    $_G[‘adminid’] => 当前登录ID管理组ID
    $_G[‘groupid’] => 当前登录ID用户组ID
    $_G[‘cookie’] => 客户端cookie
    $_G[‘formhash’] => 当前登录ID的【FORMHASH】 主要用于表单提交
    $_G[‘timestamp’] => 当前活动时间
    $_G[‘starttime’] => 1317042440.3242
    $_G[‘clientip’] => 当前访问者IP地址
    $_G[‘referer’] => 当前请求的地址,主要用户表单提交
    $_G[‘charset’] => 程序编码
    $_G[‘PHP_SELF’] => 当前访问页面的相对地址
    $_G[‘siteurl’] => 程序访问地址
    $_G[‘siteroot’] => 程序所在域名的相对目录
    $_G[‘fid’] => 当前版块id【主题列表页、帖子页】出现
    $_G[‘tid’] => 当前帖子ID【帖子页】出现
    $_G[‘basescript’] => 当前页面所在频道
    $_G[‘basefilename’] => 当前页面php文件名
    $_G[‘staticurl’] => 程序附件目录
    $_G[‘mod’] => 当前页面的MOD值【例如:forum.php?mod=xxx】
    $_G[‘inajax’] => 当前ajax请求的值【无-0 有-1】
    $_G[‘page’] => 当前分页ID
    $_G[‘tpp’] => 当前分页每页显示数量
    $_G[‘seokeywords’] => 当前页面seo关键词
    $_G[‘seodescription’] => 当前页面seo介绍
    $_G[‘timenow’] => Array
    (
    [time] => 2011-9-26 21:07 当前服务器时间
    [offset] => +8 当前服务器时区
    )
    $_G[‘config’] => Array(
        $_G[‘config’][db] =>Array(
          $_G[‘config’][db][1] => Array(
              $_G[‘config’][db][1][dbhost] => localhost 数据库连接地址
              $_G[‘config’][db][1][dbuser]=> root 数据库用户名
              $_G[‘config’][db][1][dbpw]=> 123456 数据库密码
              $_G[‘config’][db][1][dbcharset]=> utf8 数据库编码
              $_G[‘config’][db][1][pconnect]=> 0
              $_G[‘config’][db][1][dbname]=> dxutf 数据库名
              $_G[‘config’][db][1][tablepre]=> pre_ 数据表前缀
           )
        )
    )
    $_G[‘setting’][sitename] => 全局-站点信息-网站名称
    $_G[‘setting’][siteurl] => 全局-站点信息-网站URL
    $_G[‘setting’][regname] => 全局-注册访问-注册-注册地址
    $_G[‘setting’][reglinkname] => 全局-注册访问-注册-注册链接文字
    $_G[‘setting’][regverify] => 全局-注册访问-注册-新用户注册验证
    $_G[‘setting’][icp] => 全局-站点信息-网站备案信息代码
    $_G[‘setting’][imagelib] => 全局-上传设置-基本设置-图片处理库类型
    $_G[‘setting’][extcredits] => 积分情况 自行打印
    $_G[‘setting’][creditsformula] => 全局-积分设置-基本设置-总积分计算公式
    $_G[‘setting’][cacheindexlife] => 全局-性能优化-论坛页面缓存设置-缓存论坛首页有效期
    $_G[‘setting’][cachethreaddir] => 全局-性能优化-论坛页面缓存设置-缓存目录
    $_G[‘setting’][cachethreadlife] => 全局-性能优化-论坛页面缓存设置-缓存帖子有效期
    $_G[‘setting’][bbrulestxt] => 全局-注册访问-注册-网站服务条款
    $_G[‘setting’][bbname] => 全局-站点信息-站点名称
    $_G[‘setting’][attachurl] => 全局-上传设置-基本设置-本地附件URL地址
    $_G[‘setting’][attachdir] => 全局-上传设置-基本设置-本地附件保存位置
    $_G[‘setting’][anonymoustext] => 界面-界面设置-全局-匿名用户的昵称
    $_G[‘setting’][threadsticky] => 界面-界面设置-主题列表-置顶主题的标识
    $_G[‘setting’][defaultindex] => 默认首页文件名forum.php
    $_G[‘setting’][verify] => 用户-认证设置
    $_G[‘setting’][rewriterule] => 后台伪静态规则情况
    $_G[‘setting’][ucenterurl] => UCenter地址
    $_G[‘setting’][plugins] => 后台插件设置与启用情况
    $_G[‘setting’][navlogos] => 后台界面设置-导航设置-内置导航的logo组
    $_G[‘setting’][navmn] => 后台设置的导航情况,主要用于导航判断
    $_G[‘setting’][navs] => 页头导航数组,可参考此数组进行页头导航重写
    $_G[‘setting’][footernavs] => 页尾导航
    $_G[‘setting’][spacenavs] => 家园模块左侧导航
    $_G[‘setting’][mynavs] => 页头导航右边快捷导航按钮内容
    $_G[‘setting’][topnavs] => 页头顶部导航内容
    $_G[‘setting’][forumpicstyle] => Array 版块主题封面
    $_G[‘setting’][forumpicstyle][thumbwidth] => 主题封面宽度
    $_G[‘setting’][forumpicstyle][thumbheight] => 主题封面高度
    $_G[‘setting’][activityfield] => 全局-站点功能-活动主题-发起者必填信息
    $_G[‘setting’][activityextnum] => 全局-站点功能-活动主题-扩展资料项数量
    $_G[‘setting’][activitypp] => 全局-站点功能-活动主题-用户列表每页显示参与活动的人数
    $_G[‘setting’][activitycredit] => 全局-站点功能-活动主题-使用积分
    $_G[‘setting’][activitytype] => 全局-站点功能-活动主题-内置类型
    $_G[‘setting’][adminemail] => 全局-站点信息-管理员邮箱
    $_G[‘member’] =>  Array 当前登录用户个人信息
    $_G[‘member’][uid] => UID
    $_G[‘member’][email] => 邮箱地址
    $_G[‘member’][username] => 用户名
    $_G[‘member’][password] =>经过MD5后的密码(别乱输出!!!切记)
    $_G[‘member’][status] => 用户是否已经删除
    $_G[‘member’][emailstatus] => 邮箱验证状态 0未验证 1验证通过
    $_G[‘member’][avatarstatus] => 头像上传状态 0未上传 1已上传
    $_G[‘member’][videophotostatus] => 视频认证 0未认证 1已认证
    $_G[‘member’][adminid] => 所在管理组ID
    $_G[‘member’][groupid] => 所在用户组ID
    $_G[‘member’][groupexpiry] => 所在用户组有效期
    $_G[‘member’][extgroupids] => 扩展用户组
    $_G[‘member’][regdate] => 注册时间
    $_G[‘member’][credits] => 214 现有总积分
    $_G[‘member’][notifysound] => 短消息声音
    $_G[‘member’][timeoffset] => 所在时区
    $_G[‘member’][newpm] => 新短消息数量
    $_G[‘member’][newprompt] => 新提醒数量
    $_G[‘member’][accessmasks] => 这个貌似访问权限,不确定
    $_G[‘member’][allowadmincp] => 是否拥有管理面板权限 0否 1是
    $_G[‘member’][onlyacceptfriendpm] => 是否只接受好友短消息 0否 1是
    $_G[‘member’][conisbind] => 是否绑定QQ 0否 1是
    $_G[‘member’][lastvisit] => 上次访问时间
    $_G[‘style’] => Array(
    $_G[‘style’][styleid] =>当前风格ID
    $_G[‘style’][name] =>当前风格名
    $_G[‘style’][templateid] => 当前模板体系
    $_G[‘style’][tpldir] => 当前模板目录
    $_G[‘style’][menuhoverbgcolor] => 导航菜单高亮背景颜色
    $_G[‘style’][lightlink] => 浅色链接颜色
    $_G[‘style’][floatbgcolor] => 弹出窗口背景属性
    $_G[‘style’][dropmenubgcolor] =>下拉菜单背景属性$_G[‘style’][floatmaskbgcolor] => 弹出窗口边框颜色属性
    $_G[‘style’][dropmenuborder] => 下拉菜单边框色
    $_G[‘style’][specialbg] => 彩色区域背景色(帖子用户信息栏、需强调的表头等)
    $_G[‘style’][specialborder] => 彩色区域边框
    $_G[‘style’][commonbg] => 通用显示区域背景颜色
    $_G[‘style’][commonborder] => 通用边框颜色
    $_G[‘style’][inputbg] => 输入框背景色
    $_G[‘style’][inputborderdarkcolor] => 输入框边框深色
    $_G[‘style’][headerbgcolor] => 页头背景
    $_G[‘style’][headerborder] => 页头分割线高度
    $_G[‘style’][sidebgcolor] => 家园侧边背景
    $_G[‘style’][msgfontsize] => 帖子内容字号
    $_G[‘style’][bgcolor] => 页面背景
    $_G[‘style’][noticetext] => 提示信息颜色
    $_G[‘style’][highlightlink] => 高亮链接颜色
    $_G[‘style’][link] => 链接文字颜色
    $_G[‘style’][lighttext] => 浅色文字
    $_G[‘style’][midtext] => 中等文本颜色
    $_G[‘style’][tabletext] => 普通文本颜色
    $_G[‘style’][smfontsize] => 小号字体大小
    $_G[‘style’][threadtitlefont] => 主题列表字体
    $_G[‘style’][threadtitlefontsize] => 主题列表字体大小
    $_G[‘style’][smfont] => 小号字体
    $_G[‘style’][titlebgcolor] => 版块列表标题字体颜色$_G[‘style’][fontsize]=> 正常字体大小
    $_G[‘style’][font] => 正常字体
    $_G[‘style’][styleimgdir] => 扩展图片目录
    $_G[‘style’][imgdir] => 界面基础图片目录
    $_G[‘style’][boardimg] => logo所在路径
    $_G[‘style’][headertext] => 页头文字颜色
    $_G[‘style’][footertext] => 页脚文字颜色
    $_G[‘style’][menubgcolor] => 导航菜单背景颜色
    $_G[‘style’][menutext] => 导航菜单文字颜色
    $_G[‘style’][menuhovertext] => 导航菜单高亮文字颜色
    $_G[‘style’][wrapbg] => 主体表格背景色
    $_G[‘style’][wrapbordercolor] => 主体表格边框色
    $_G[‘style’][contentwidth] => 阅读区域宽度
    $_G[‘style’][contentseparate] => 帖子间隔颜色
    $_G[‘style’][inputborder] => 输入框边框浅色
    $_G[‘style’][menuhoverbgcode] => 导航菜单高亮背景
    $_G[‘style’][floatbgcode] => 弹出窗口背景色
    $_G[‘style’][dropmenubgcode] => 下拉菜单背景色
    $_G[‘style’][floatmaskbgcode] => 弹出窗口边框颜色
    $_G[‘style’][headerbgcode] => 页头背景
    $_G[‘style’][sidebgcode] => 家园侧边栏背景属性
    $_G[‘style’][bgcode] => 全局背景属性属性
    $_G[‘style’][titlebgcode] => 版块列表标题背景$_G[‘style’][menubgcode]=> 导航菜单背景属性
    $_G[‘style’][boardlogo] => LOGO img代码
  • 开源神器Copyparty告别U盘、网盘限速!:轻量级自托管文件共享解决方案

    开源神器Copyparty告别U盘、网盘限速!:轻量级自托管文件共享解决方案

    Copyparty 是一个用 Python 编写的便携式文件服务器,它将众多功能(如加速可续传的上传、文件去重、WebDAV、FTP、TFTP、媒体索引、缩略图等)集成到了一个文件中,并且几乎没有强制性依赖。你可以直接运行它,将任何设备变成一个文件服务器,并通过网页浏览器进行访问。

     

    它能让你轻松拥有一个功能强大的私人文件服务器,告别所有烦恼!

    开源神器Copyparty告别U盘、网盘限速!:轻量级自托管文件共享解决方案

    一、Copyparty 是何方神圣?你的数据“瑞士军刀”!

    Copyparty,用大白话说,就是一个多功能、跨平台的文件服务器软件。它就像你私人数据的“瑞士军刀”,集成了文件共享、传输、管理、媒体播放等N多功能于一身。你不需要是技术大神,只需要一点点折腾精神,就能用它搭建一个属于自己的云盘、媒体库,甚至是一个轻量级的团队协作平台。

    核心功能一览:

    • • 协议大满贯: 不止是HTTP网页访问,它还支持WebDAV、FTP、TFTP、SMB/CIFS!这意味着你的文件可以通过各种你熟悉的客户端访问,无论是Windows文件管理器、macOS Finder、iOS文件App,还是各种专业的同步工具,都能无缝连接。
    • • 全平台通吃: Windows、Linux、macOS这些桌面系统就不说了,连Android和iOS都有专门的客户端或通过通用协议访问,真正实现设备无缝切换。
    • • 文件传输优化: 支持加速可恢复的上传/下载,大文件传输再也不怕断网。
    • • 智能文件管理: 自动检测并处理文件去重,为你节省宝贵的硬盘空间;还能进行文件搜索、批量重命名等。
    • • 媒体播放神器: 自动索引媒体文件、生成缩略图,甚至支持在线音频播放,自带均衡器!
    • • 权限管理到位: 可以设置用户账号密码,分配不同的读写权限,甚至基于IP限制访问,安全又省心。

    二、三步上手 Copyparty:简单到你不敢相信!

    Copyparty的安装和使用非常傻瓜式,因为它主要基于Python运行,而Python在很多系统上都是默认安装的,或者安装起来也非常简单。

    Step 1: 确保你有Python环境

    大部分Linux、macOS系统都自带Python。Windows用户如果没安装,可以去Python官网下载安装包,勾选“Add Python to PATH”选项。

    ![图片:Python安装截图或官网链接]

    Step 2: 一行代码安装 Copyparty

    打开你的终端(Windows是CMD或PowerShell,macOS/Linux是Terminal),输入:

    pip install copyparty

    然后回车,稍等片刻,Copyparty就安装好了,是不是比你想象的要简单得多?

    ![图片:pip install copyparty的命令行截图]

    Step 3: 启动你的专属文件服务器

    选择一个你想要共享的文件夹,比如你的D:/我的文件(Windows)或者~/MyShare(macOS/Linux),然后在终端中输入:

    copyparty -p 8000 ./my_files
    • • -p 8000:指定服务运行在8000端口,你可以改成其他未被占用的端口,比如8888。
    • • ./my_files:这里你需要替换成你实际想共享的文件夹路径。比如在D盘的MyShare文件夹,你就写 D:/MyShare。如果是当前目录,直接写 . 就行。

    回车后,你会看到类似这样的信息:

    Listening on http://0.0.0.0:8000/
    Serving: /path/to/your/my_files

    现在,打开你的浏览器,输入 http://localhost:8000 (如果不是本机,把localhost换成你的电脑IP地址),你就能看到你的文件服务器界面啦!

    开源神器Copyparty告别U盘、网盘限速!:轻量级自托管文件共享解决方案

    常见用法举例:

    • • 上传文件: 在网页界面点击上传按钮,或者直接拖拽文件到浏览器窗口。
    • • 下载文件: 点击文件名即可下载,支持断点续传。
    • • 分享链接: 复制文件或文件夹的链接,发给朋友就能访问(如果你的服务器能外网访问)。
    • • WebDAV挂载: 在Windows、macOS或手机上,使用WebDAV协议将你的Copyparty服务器像本地硬盘一样挂载,直接在文件管理器里操作文件。

    三、Copyparty 的魔幻实用场景:不止共享那么简单!

    Copyparty的强大之处在于它的多协议支持和丰富的功能,能够覆盖你日常工作生活的方方面面。

    1. 1. 团队协作的文件共享中心:
    • • 痛点: 团队内部共享大文件(设计稿、视频素材、代码包)总遇到网盘限速、版本混乱。
    • • 解决方案: 搭建一个Copyparty服务器,团队成员通过WebDAV协议挂载,就像操作本地文件一样,实时同步更新。你可以给不同成员设置不同的读写权限,确保文件安全。
    • • 示例: 设计师把最新图稿上传到服务器,文案直接在本地修改文档并保存,改动立刻同步到服务器,方便快捷。
    • 2. 你的专属私人云盘,告别隐私焦虑:
    • • 痛点: 免费网盘空间小、有广告,重要文件担心隐私泄露。
    • • 解决方案: 把Copyparty部署在你的闲置电脑或NAS上,手机照片自动备份,电脑文件随时同步。所有数据都存放在你自己的硬盘里,安全可控,无限空间!
    • • 示例: 手机上的照片和视频自动备份到Copyparty,随时随地通过浏览器或文件App查看,不占用手机存储。
    • 3. 内容创作者的素材管理利器:
    • • 痛点: 视频素材、图片素材堆积如山,重复文件占据大量空间,后期查找困难。
    • • 解决方案: 利用Copyparty的文件去重功能,自动清理重复文件;批量重命名功能帮助你整理命名混乱的素材;媒体索引和缩略图功能让你快速预览和查找所需素材。
    • • 示例: 摄影师拍摄的几百张照片,上传到Copyparty后自动生成缩略图,一眼就能找到需要的照片,还能一键删除拍废的重复照片。
    • 4. 打造家庭影音娱乐中心:
    • • 痛点: 电视盒子播放本地视频麻烦,音乐文件无法统一管理。
    • • 解决方案: 把所有电影、电视剧、音乐文件放到Copyparty共享目录,然后用智能电视、平板、手机通过浏览器或媒体播放器(支持WebDAV/SMB)直接访问,在线观看高清电影,收听无损音乐。Copyparty还能自动索引媒体元数据,让你的影库井井有条。
    • • 示例: 晚上躺在沙发上,用电视打开浏览器访问Copyparty地址,直接点播硬盘里的电影,流畅不卡顿。
    • 5. 跨设备文件传输站,比微信传输更高效:
    • • 痛点: 手机往电脑传文件,电脑往手机传文件,要么数据线,要么微信/QQ限速。
    • • 解决方案: 电脑开启Copyparty,手机通过App或浏览器访问,直接上传下载,速度飞快,文件大小无限制。
    • • 示例: 手机拍完的几十张高清照片,直接通过Copyparty的App上传到电脑,秒传完成,比用数据线还方便。

    四、Copyparty 凭啥脱颖而出?这几点让你爱不释手!

    市面上文件服务器工具不少,但Copyparty能让你眼前一亮,它的独特优势在于:

    • • 🚀 协议全能王,兼容性爆表: 这是Copyparty最杀手锏的优势!HTTP、WebDAV、FTP、TFTP、SMB/CIFS,几乎涵盖了所有主流文件传输协议。这意味着无论你的客户端是什么,都能找到最适合的方式连接,免去了各种转换和兼容烦恼。
    • • 🆓 开源免费,安全放心: Copyparty是完全开源的(基于Python),你无需支付任何费用,可以自由使用和修改。更重要的是,数据完全掌握在你自己手里,没有第三方插手,隐私安全更有保障。
    • • 💡 智能媒体处理,影音体验升级: 自动生成缩略图、媒体元数据索引、在线音频播放(甚至有均衡器和动态范围压缩),这些功能让它不仅仅是文件服务器,更是一个轻量级的媒体中心,非常适合家庭用户。
    • • 💾 硬盘空间管理大师: 文件的自动去重功能,能有效帮你清理重复文件,释放硬盘空间。对于大文件收集爱好者来说,这简直是福音!
    • • ⚡ 轻量高效,部署灵活: 纯Python编写,对系统资源占用极低,运行流畅。而且可以轻松与Nginx、Caddy等反向代理配合,部署在Docker里更是方便快捷。
    • • 🔒 权限管理精细,安全可控: 支持用户账号密码、不同读写权限设置,甚至可以基于IP限制访问。无论是个人使用还是团队协作,都能保证文件的安全性。
    开源神器Copyparty告别U盘、网盘限速!:轻量级自托管文件共享解决方案

    五、扩展推荐:搭配使用,效率翻倍!

    1. 1. 同类工具横向对比:
    • • Filebrowser/HFS: 更轻量级的HTTP文件服务器,通常只有HTTP协议,功能相对简单。适合只需要简单网页分享的场景。
    • • Nextcloud/Seafile: 功能更强大的私有云盘解决方案,集成了文档协作、日历、通讯录等,但部署和维护相对复杂,资源占用也更大。适合对功能集成度要求更高的专业用户或企业。
    • • 总结: Copyparty介于两者之间,它比Filebrowser/HFS功能更丰富(多协议、媒体、去重),比Nextcloud/Seafile更轻量、部署更简单,更专注于文件服务器的“核心业务”。
    • 2. 提升使用效率小技巧:
    • • Docker部署: 如果你熟悉Docker,强烈推荐使用Docker来部署Copyparty,不仅环境隔离,配置和管理也更加方便。
    • • 配合反向代理: 如果你需要通过域名访问你的Copyparty服务器(而不是IP地址+端口),或者需要更高级的HTTPS加密,可以配合Nginx、Caddy等反向代理软件使用。
    • • 内网穿透(公网访问): 如果想让家人或朋友在外网也能访问你的Copyparty服务器,可以考虑使用Frp、Nps等内网穿透工具。
    • • 设置自启动: 将Copyparty设置为系统服务或开机自启动,省去每次手动启动的麻烦。

    总结语

    Copyparty 就像是你的私人数据管家,功能强大又易于上手,无论你是想搭建一个私人网盘,还是一个团队协作的文件中心,它都能完美胜任。让你的数据真正掌握在自己手中,告别限速和隐私担忧!

    强烈推荐收藏!越早用上越早受益!

    开源地址: https://github.com/9001/copyparty