Files
iptv-share/index.html
T
2026-10-02 05:28:37 +08:00

122 lines
8.2 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IPTV直播源免费共享</title>
<style>
*{margin:0;padding:0;box-sizing:border-box;}
body{min-height:100vh;background:linear-gradient(135deg,#0f2027 0%,#203a43 50%,#2c5364 100%);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','PingFang SC','Microsoft YaHei',sans-serif;color:#e8f1f8;}
.wrap{max-width:860px;margin:0 auto;padding:60px 20px 80px;}
header{position:relative;text-align:center;margin-bottom:48px;}
h1{font-size:2.4em;font-weight:800;letter-spacing:2px;background:linear-gradient(90deg,#6dd5ed,#2193b0,#6dd5ed);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;margin-bottom:14px;}
.sub{color:#9fc3d4;font-size:15px;letter-spacing:1px;}
.admin-area{position:absolute;top:0;right:0;}
.admin-btn{background:rgba(255,255,255,0.08);border:1px solid rgba(255,255,255,0.18);color:#bcd9e8;padding:8px 16px;border-radius:20px;font-size:13px;cursor:pointer;transition:all .2s;}
.admin-btn:hover{background:rgba(255,255,255,0.16);}
.admin-btn.unlock{color:#ffd479;border-color:rgba(255,212,121,.4);}
.panel{display:none;background:rgba(255,255,255,0.06);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,0.12);border-radius:14px;padding:20px;margin-bottom:26px;}
.panel.show{display:block;}
.panel input{width:100%;padding:11px 14px;margin:6px 0;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(0,0,0,0.25);color:#e8f1f8;font-size:14px;outline:none;}
.panel input:focus{border-color:#2193b0;}
.panel .row{display:flex;gap:10px;flex-wrap:wrap;}
.panel .row input{flex:1;min-width:200px;}
.btn{padding:11px 22px;border-radius:8px;border:none;font-size:14px;font-weight:600;cursor:pointer;transition:all .2s;}
.btn-p{background:linear-gradient(90deg,#2193b0,#6dd5ed);color:#fff;}
.btn-p:hover{opacity:.88;}
.stats{color:#7ea8bc;font-size:13px;margin-bottom:20px;text-align:center;}
.source{display:flex;align-items:center;gap:14px;background:rgba(255,255,255,0.06);backdrop-filter:blur(10px);border:1px solid rgba(255,255,255,0.10);border-radius:14px;padding:18px 20px;margin-bottom:14px;transition:all .25s;}
.source:hover{transform:translateY(-2px);border-color:rgba(109,213,237,0.4);box-shadow:0 8px 24px rgba(0,0,0,0.3);}
.dot{width:10px;height:10px;border-radius:50%;background:#4ade80;box-shadow:0 0 10px #4ade80;flex-shrink:0;}
.info{flex:1;min-width:0;}
.name{font-size:15px;font-weight:600;margin-bottom:4px;word-break:break-all;}
.url{font-size:12px;color:#8fb5c7;word-break:break-all;}
.acts{display:flex;gap:8px;flex-shrink:0;}
.act{padding:7px 14px;border-radius:8px;border:1px solid rgba(255,255,255,0.15);background:rgba(255,255,255,0.06);color:#bcd9e8;font-size:12px;cursor:pointer;transition:all .2s;text-decoration:none;}
.act:hover{background:rgba(255,255,255,0.14);}
.act.del{color:#ff8a8a;border-color:rgba(255,138,138,0.3);display:none;}
body.admin .act.del{display:inline-block;}
.empty{text-align:center;color:#6f97a9;padding:50px 0;font-size:14px;}
.toast{position:fixed;bottom:30px;left:50%;transform:translateX(-50%);background:rgba(33,147,176,0.95);color:#fff;padding:10px 24px;border-radius:24px;font-size:13px;opacity:0;transition:opacity .3s;pointer-events:none;z-index:99;}
.toast.show{opacity:1;}
.modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.6);z-index:50;align-items:center;justify-content:center;}
.modal.show{display:flex;}
.modal-box{background:#1b3a47;border-radius:14px;padding:28px;width:320px;text-align:center;}
.modal-box h3{font-size:16px;margin-bottom:16px;}
.modal-box input{width:100%;padding:11px 14px;border-radius:8px;border:1px solid rgba(255,255,255,0.2);background:rgba(0,0,0,0.3);color:#fff;font-size:14px;outline:none;margin-bottom:14px;}
footer{text-align:center;color:#5d8496;font-size:12px;margin-top:60px;}
@media (max-width:600px){h1{font-size:1.7em;}.source{flex-wrap:wrap;}.acts{width:100%;justify-content:flex-end;}.admin-area{position:static;margin-top:14px;text-align:right;}}
</style>
</head>
<body>
<div class="wrap">
<header>
<h1>IPTV直播源免费共享</h1>
<p class="sub">免费 · 开放 · 共享 —— 收集与分享可用的 IPTV 直播源</p>
<div class="admin-area"><button class="admin-btn" id="adminBtn" onclick="adminClick()">管理员</button></div>
</header>
<div class="panel" id="addPanel">
<div class="row">
<input id="inName" placeholder="直播源标题,如:某卫视高清">
<input id="inUrl" placeholder="链接地址,如:http://.../xxx.m3u">
<button class="btn btn-p" onclick="addItem()">添加</button>
</div>
</div>
<p class="stats" id="stats"></p>
<div id="list"></div>
<footer>本页面仅作技术交流与源共享用途 · 数据保存在浏览器本地</footer>
</div>
<div class="modal" id="pwdModal">
<div class="modal-box">
<h3>管理员登录</h3>
<input type="password" id="pwd" placeholder="请输入管理密码" onkeydown="if(event.key==='Enter')doLogin()">
<button class="btn btn-p" style="width:100%" onclick="doLogin()">登录</button>
</div>
</div>
<div class="toast" id="toast"></div>
<script>
var ADMIN_PWD='iptv2026';
var KEY='iptv_share_sources';
var DEFAULTS=[
{name:'示例 · 综合直播源(m3u)',url:'https://live.fanmingming.com/tv/m3u/ipv6.m3u'},
{name:'示例 · 央视卫视源(txt)',url:'http://example.com/cctv.txt'}
];
function load(){try{var v=JSON.parse(localStorage.getItem(KEY));if(v&&v.length>=0)return v;}catch(e){}return DEFAULTS.slice();}
function save(v){try{localStorage.setItem(KEY,JSON.stringify(v));}catch(e){}}
var isAdmin=false;
function toast(m){var t=document.getElementById('toast');t.textContent=m;t.classList.add('show');setTimeout(function(){t.classList.remove('show');},1800);}
function esc(s){return String(s).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}
function render(){
var v=load();
document.getElementById('stats').textContent='共 '+v.length+' 个直播源';
var h='';
if(v.length===0){h='<div class="empty">暂无直播源,管理员登录后可添加</div>';}
for(var i=0;i<v.length;i++){
h+='<div class="source"><span class="dot"></span><div class="info"><div class="name">'+esc(v[i].name)+'</div><div class="url">'+esc(v[i].url)+'</div></div><div class="acts"><a class="act" href="javascript:void(0)" onclick="copyUrl('+i+')">复制</a><a class="act del" href="javascript:void(0)" onclick="delItem('+i+')">删除</a></div></div>';
}
document.getElementById('list').innerHTML=h;
}
function copyUrl(i){var v=load()[i].url;navigator.clipboard?navigator.clipboard.writeText(v).then(function(){toast('已复制');},function(){fallback(v);}):fallback(v);}
function fallback(t){var ta=document.createElement('textarea');ta.value=t;document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);toast('已复制');}
function adminClick(){
if(isAdmin){isAdmin=false;document.body.classList.remove('admin');document.getElementById('addPanel').classList.remove('show');document.getElementById('adminBtn').textContent='管理员';document.getElementById('adminBtn').classList.remove('unlock');toast('已退出管理员');}
else{document.getElementById('pwdModal').classList.add('show');document.getElementById('pwd').value='';setTimeout(function(){document.getElementById('pwd').focus();},100);}
}
function doLogin(){
var p=document.getElementById('pwd').value;
if(p===ADMIN_PWD){isAdmin=true;document.body.classList.add('admin');document.getElementById('pwdModal').classList.remove('show');document.getElementById('addPanel').classList.add('show');document.getElementById('adminBtn').textContent='管理员已解锁';document.getElementById('adminBtn').classList.add('unlock');toast('欢迎,管理员');}
else{toast('密码错误');}
}
function addItem(){
var n=document.getElementById('inName').value.trim(),u=document.getElementById('inUrl').value.trim();
if(!n||!u){toast('请填写标题和链接');return;}
var v=load();v.push({name:n,url:u});save(v);render();
document.getElementById('inName').value='';document.getElementById('inUrl').value='';toast('添加成功');
}
function delItem(i){var v=load();v.splice(i,1);save(v);render();toast('已删除');}
document.getElementById('pwdModal').addEventListener('click',function(e){if(e.target===this)this.classList.remove('show');});
render();
</script>
</body>
</html>