My Computer · 2024/10/04 6

苹果cmsV10增加影片网盘下载分享功能

让苹果cms集在线播放、网盘资源分享于一身:支持百度网盘、夸克网盘、迅雷云盘、阿里云盘、天翼云盘、UC网盘、115网盘

效果:没有下载链接的页面

发布页弹窗

发布链接后

整理以下大概过程:

设置数据库编码、mac_vod表vod_down_url为utf8mb4,支持标题输入emoji表情。

增加前台下载页面downlist,苹果cms后台,视频,下载器,增加需要支持的网盘。

直接在downlist里写了php代码,使用后台控制器安全处理数据,前端纯静态不含任何代码,不会暴露数据库。主要的处理逻辑:
免登录游客可发布;
每用户可以发布多种网盘类型的下载链接;
每用户同类型网盘链接只允许有一条数据记录;
先根据用户提交url判定网盘类型,将数据写入vod_down_from;
根据vod_down_from的排序,按照展示格式重新组合内容,将数据写入vod_down_url;

后台新建控制器 application/api/controller/Downlist.php

<?php
namespace app\api\controller;

use think\Controller;
use think\Db;
use think\Request;

class Downlist extends Controller
{
    // 推荐方法名 index 或 share,根据你的实际需求路由即可
    public function share()
    {
        if (!request()->isPost()) {
            return json(['message' => '非法请求'], 400);
        }

        $vod_id = input('post.vod_id/s', '', 'trim');
        $vod_down_title = input('post.vod_down_title/s', '', 'trim');
        $vod_down_url = input('post.vod_down_url/s', '', 'trim');
        $user_name = input('post.user_name/s', '', 'trim');
        $maccms_date = input('post.maccms_date/s', '', 'trim');

        if (!$vod_id || !$vod_down_title || !$vod_down_url || !$user_name || !$maccms_date) {
            return json(['message' => '参数不全'], 422);
        }

        // 网盘类型自动判断(含主流和特殊协议),要对应苹果cms后台视频-下载器-编码
        $platform_mapping = [
            'magnet:'         => '磁力下载',
            'baidu.com'       => '百度网盘',
            'pan.baidu.com'   => '百度网盘',
            'alipan.com'      => '阿里云盘',
            'aliyundrive.com' => '阿里云盘',
            'quark.cn'        => '夸克网盘',
            'xunlei.com'      => '迅雷云盘',
            'uc.cn'           => 'UC网盘',
            '189.cn'          => '天翼云盘',
            '115.com'         => '115网盘',
            'anxia.com'       => '115网盘',
            '115cdn.com'      => '115网盘',
            'znas.cn'         => '私有云盘',
            '123684.com'      => '123云盘'
        ];

        $vod_down_from = '';
        foreach ($platform_mapping as $domain => $platform) {
            if (strpos($vod_down_url, $domain) !== false) {
                $vod_down_from = $platform;
                break;
            }
        }
        if (!$vod_down_from) {
            return json(['message' => '不支持的网盘类型'], 400);
        }

        $row = Db::name('vod')->where('vod_id', $vod_id)->field('vod_down_from, vod_down_url')->find();
        if ($row) {
            $existing_from = $row['vod_down_from'] ?? '';
            $existing_url = $row['vod_down_url'] ?? '';
            if (strpos($existing_from, $vod_down_from) === false) {
                $existing_from .= ($existing_from ? '$$$' : '') . $vod_down_from;
                $new_entry = "{$vod_down_title}@{$user_name}-{$maccms_date}\${$vod_down_url}";
                $existing_url .= ($existing_url ? '$$$' : '') . $new_entry;
                Db::name('vod')->where('vod_id', $vod_id)->update([
                    'vod_down_from' => $existing_from,
                    'vod_down_url' => $existing_url
                ]);
            } else {
                $from_types = explode('$$$', $existing_from);
                $existing_urls = explode('$$$', $existing_url);
                $idx = array_search($vod_down_from, $from_types);
                if ($idx !== false) {
                    $entries = explode('#', $existing_urls[$idx]);
                    foreach ($entries as $i => $entry) {
                        if (strpos($entry, $user_name) !== false) {
                            unset($entries[$i]);
                        }
                    }
                    $new_entry = "{$vod_down_title}@{$user_name}-{$maccms_date}\${$vod_down_url}";
                    array_unshift($entries, $new_entry);
                    $existing_urls[$idx] = implode('#', $entries);
                    $existing_url = implode('$$$', $existing_urls);
                    Db::name('vod')->where('vod_id', $vod_id)->update([
                        'vod_down_url' => $existing_url
                    ]);
                }
            }
        } else {
            $new_from = $vod_down_from;
            $new_url = "{$vod_down_title}@{$user_name}-{$maccms_date}\${$vod_down_url}";
            Db::name('vod')->insert([
                'vod_id' => $vod_id,
                'vod_down_from' => $new_from,
                'vod_down_url' => $new_url
            ]);
        }

        return json(['message' => '已受理。']);
    }

    // 接口测试
    public function index()
    {
        return json(['message' => 'Downlist接口正常']);
    }
}

前端增加下载链接弹窗核心代码,供参考

function showPopup() {
    var popup = `
        <div class="tanc-popup-overlay"></div>
        <div class="tanc-popup-content">
            <div class="tanc-popup-header">
                <h4>分享 {$obj.vod_name} 下载链接 - 建议注册并登录后发布</h4>
                <div class="tanc-popup-close">✖</div>
            </div>
            <div class="tanc-popup-body">
                <div id="panvalue">
                    <div style="margin-bottom: 20px;color: red;">每用户同种类型仅允许且只保留最新发布的1条链接<br>支持百度网盘、夸克网盘、迅雷云盘、阿里云盘、天翼云盘、UC网盘、115网盘、磁力链接、极空间私有云盘<br></div>
                    <form id="link-form">
                        <label for="vod_down_title">名称:</label>
                        <div id="length_counter">0/100</div>
                        <input type="text" id="vod_down_title" name="vod_down_title" placeholder="100字以内,建议包含分辨率、字幕相关信息" required>
                        <label for="vod_down_url">链接:</label>
                        <input type="text" id="vod_down_url" name="vod_down_url" placeholder="建议包含提取码" required pattern="^(https?|ftp|magnet):\/\/[^\s/$.?#].[^\s]*$">
                        <input type="hidden" name="user_name" value="{$user.user_name}" readonly>
                        <input type="hidden" name="maccms_date" value="{$maccms.date} " readonly>
                        <input type="hidden" id="vod_id" name="vod_id" value="{$obj.vod_id}" autocomplete="on" readonly>
                        <div class="tanc-popup-footer">
                            <button type="submit">发布</button>
                            <button type="button" id="closeBtn">关闭</button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
        <div id="msg-tip" style="display:none;position:fixed;top:40%;left:50%;transform:translate(-50%,-50%);z-index:99999;background:rgba(0,0,0,0.85);color:#fff;padding:24px 40px;font-size:18px;border-radius:8px;text-align:center;"></div>
    `;
    var div = document.createElement('div');
    div.innerHTML = popup;
    document.body.appendChild(div);

    // 实时更新长度提示
    document.getElementById('vod_down_title').addEventListener('input', function() {
        var maxLength = 100;
        var currentLength = this.value.length;
        var lengthCounter = document.getElementById('length_counter');
        if (currentLength > maxLength) {
            this.value = this.value.substring(0, maxLength);
            currentLength = maxLength;
            showMsgTip('名称输入长度不能超过100字!');
        }
        lengthCounter.textContent = currentLength + '/200';
    });

    // 验证下载链接
    const urlInput = document.getElementById('vod_down_url');
    urlInput.addEventListener('input', function() {
      const url = this.value;
      if (!/^(https?|ftp|magnet):\/\/[^\s/$.?#].[^\s]*$/.test(url)) {
        // 这里可以添加提示用户输入无效的代码
        // showMsgTip('输入不是有效的 URL 或磁力链接');
      }
    });

    // 关闭按钮功能
    document.getElementById('closeBtn').addEventListener('click', closePopup);
    div.querySelector('.tanc-popup-close').addEventListener('click', closePopup);
    div.querySelector('.tanc-popup-overlay').addEventListener('click', closePopup);

    // 表单提交
    document.getElementById('link-form').onsubmit = function(e) {
        e.preventDefault();
        var formData = new FormData(this);
        var submitButton = document.querySelector('.tanc-popup-footer button[type="submit"]');

        // 禁用按钮并显示倒计时
        submitButton.disabled = true;
        var countdown = 10;
        submitButton.textContent = `发布 (${countdown})`;

        var interval = setInterval(() => {
            countdown--;
            submitButton.textContent = `发布 (${countdown})`;
            if (countdown <= 0) {
                clearInterval(interval);
                submitButton.disabled = false;
                submitButton.textContent = '发布';
            }
        }, 1000);

        //使用控制器处理数据操作
        fetch('/api.php/downlist/share', {
            method: 'POST',
            body: formData
        })
        .then(response => {
            if (!response.ok) {
                throw new Error('网络响应不是 ok');
            }
            return response.json();
        })
        .then(data => {
            showMsgTip(data.message); // 只显示提示,不自动关闭弹窗
            // closePopup(); // 注释掉或删除
        })
        .catch(error => {
            showMsgTip("已受理");
        });
    };

    // 自定义消息提示,不影响主弹窗
    function showMsgTip(text, delay) {
        delay = delay || 1500;
        var el = document.getElementById('msg-tip');
        el.innerText = text;
        el.style.display = 'block';
        setTimeout(function(){
            el.style.display = 'none';
        }, delay);
    }
}

从写需求到最终实现用了三天时间,我一个二把刀是不可能写代码的,基本都是交给chatGPT来搞定 😂