有245人阅读过
一个TXT和M3U格式互转的工具
发布于2025/07/29 更新于2025/07/29
[ 教程仅保证更新时有效,请自行测试。]
发布于2025/07/29 更新于2025/07/29
[ 教程仅保证更新时有效,请自行测试。]
[ 教程仅保证更新时有效,请自行测试。]
快速实现TXT转M3U,或M3U转TXT格式直播源,支持DIYP分组格式
在线测试:IPTV-M3U转换工具
代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IPTV-M3U转换工具</title>
<style>
:root {
--primary-color: #3498db;
--secondary-color: #2ecc71;
--danger-color: #e74c3c;
--dark-color: #2c3e50;
--light-color: #ecf0f1;
--border-radius: 6px;
--box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--transition: all 0.3s ease;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f7fa;
color: #333;
line-height: 1.6;
min-height: 100vh;
display: flex;
flex-direction: column;
}
.header {
background: linear-gradient(135deg, var(--primary-color), var(--secondary-color));
color: white;
padding: 1.5rem 0;
text-align: center;
box-shadow: var(--box-shadow);
margin-bottom: 2rem;
}
.header h1 {
font-size: 2rem;
font-weight: 600;
margin-bottom: 0.5rem;
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 0 1.5rem;
flex: 1;
width: 100%;
}
.card {
background: white;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
padding: 1.5rem;
margin-bottom: 2rem;
}
.card-title {
font-size: 1.25rem;
margin-bottom: 1rem;
color: var(--dark-color);
font-weight: 600;
border-bottom: 1px solid #eee;
padding-bottom: 0.5rem;
}
.button-group {
display: flex;
gap: 0.75rem;
flex-wrap: wrap;
margin-bottom: 1.5rem;
}
.button {
padding: 0.75rem 1.25rem;
border: none;
border-radius: var(--border-radius);
font-size: 0.95rem;
font-weight: 500;
cursor: pointer;
transition: var(--transition);
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.button-primary {
background-color: var(--primary-color);
color: white;
}
.button-secondary {
background-color: var(--secondary-color);
color: white;
}
.button-danger {
background-color: var(--danger-color);
color: white;
}
.button-outline {
background-color: transparent;
border: 1px solid var(--primary-color);
color: var(--primary-color);
}
.button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.1);
}
.file-input {
margin-bottom: 1.5rem;
}
.file-input label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
color: var(--dark-color);
}
.file-input input[type="file"] {
width: 100%;
padding: 0.75rem;
border: 1px solid #ddd;
border-radius: var(--border-radius);
background-color: white;
}
.preview-container {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
margin-top: 1.5rem;
}
.preview-column {
flex: 1;
min-width: 300px;
}
.preview-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.75rem;
}
.preview-title {
font-weight: 600;
color: var(--dark-color);
}
.preview-content {
width: 100%;
height: 400px;
padding: 1rem;
border: 1px solid #ddd;
border-radius: var(--border-radius);
background-color: white;
font-family: 'Courier New', Courier, monospace;
font-size: 0.9rem;
resize: none;
overflow-y: auto;
}
.footer {
text-align: center;
padding: 1.5rem;
margin-top: 2rem;
background-color: var(--dark-color);
color: white;
}
.footer .copyright {
font-size: 0.9rem;
}
@media (max-width: 768px) {
.preview-container {
flex-direction: column;
}
.preview-column {
width: 100%;
}
.button-group {
flex-direction: column;
}
}
/* 动画效果 */
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.card {
animation: fadeIn 0.5s ease-out;
}
/* 工具提示 */
.tooltip {
position: relative;
display: inline-block;
}
.tooltip .tooltiptext {
visibility: hidden;
width: 200px;
background-color: #333;
color: #fff;
text-align: center;
border-radius: 6px;
padding: 5px;
position: absolute;
z-index: 1;
bottom: 125%;
left: 50%;
transform: translateX(-50%);
opacity: 0;
transition: opacity 0.3s;
font-size: 0.8rem;
}
.tooltip:hover .tooltiptext {
visibility: visible;
opacity: 1;
}
</style>
</head>
<body>
<header>
<h1>IPTV格式转换工具</h1>
<p>M3U/TXT/DIYP格式互转</p>
</header>
<div>
<div>
<h2>转换操作</h2>
<div>
<button class="button button-primary" onclick="convertToM3U()">
<span>转换为M3U</span>
<span>
<span>将TXT/DIYP格式转换为M3U格式</span>
</span>
</button>
<button class="button button-secondary" onclick="convertToDiyp()">
<span>转换为DIYP(带分组)</span>
<span>
<span>将M3U格式转换为DIYP格式</span>
</span>
</button>
<button class="button button-outline" onclick="convertToTXT()">
<span>转换为TXT(不带分组)</span>
<span>
<span>将M3U格式转换为简单TXT格式</span>
</span>
</button>
</div>
<div>
<label for="fileInput">选择文件 (支持.txt, .m3u, .m3u8)</label>
<input type="file" id="fileInput" accept=".txt,.m3u,.m3u8" onchange="updatePreview('fileInput', 'previewBefore')">
</div>
</div>
<div>
<div id="container">
<div>
<h3>原始内容</h3>
<button class="button button-danger" onclick="clearBefore()">清空</button>
</div>
<textarea id="previewBefore" placeholder="请上传文件或拖拽文件到此处..."></textarea>
</div>
<div>
<div>
<h3>转换结果</h3>
<div>
<button class="button button-danger" onclick="clearAfter()">清空</button>
<button class="button button-primary" onclick="copyContent()">复制</button>
<button class="button button-secondary" onclick="exportConvertedFile()">导出</button>
</div>
</div>
<textarea id="previewAfter" placeholder="转换结果将显示在这里..."></textarea>
</div>
</div>
</div>
<footer>
<div>© 2024 群晖直播 Rights Reserved.</div>
</footer>
<script>
// 保持原有的JavaScript功能不变
function findLineNumber(text, searchText) {
var regex = new RegExp(searchText, 'g');
var lines = text.split('\n');
var lineNumber = 0;
for (var i = 0; i < lines.length; i++) {
if (lines[i].match(regex)) {
return lineNumber;
}
lineNumber++;
}
return -1;
}
function TxtToM3U(txtPreview) {
var m3uContent='';
if(txtPreview == null || txtPreview=='') return '';
var lines = txtPreview.split("\n");
if (txtPreview.includes("#EXTM3U") || txtPreview.includes("#EXTINF")) {
var errline=findLineNumber(txtPreview,"#EXTM3U");
if(errline==-1){
errline=findLineNumber(txtPreview,"#EXTINF");
}
m3uContent = "检测到"+ (errline+1) + "行包含特定字符EXTM3U或者EXTINF,请检查文本内容,可能已经是m3u格式";
return m3uContent;
}
if(!txtPreview.includes(",")) {
m3uContent = "文本内容不包含分隔','字符,无法转换";
return m3uContent;
}
m3uContent = "#EXTM3U x-tvg-url=\"http://epg.51zmt.top:8000/e.xml,https://epg.112114.xyz/pp.xml\"\n";
var tempUrls = [];
var lastGroupName = '';
lines.forEach(function(line) {
if (line.trim() !== "") {
if (line.includes("#genre#")) {
var groupName = line.split(",")[0].trim();
groupName = groupName.replace(/^\s*|\s*$/g, '');
if (groupName != null && groupName !== "") {
lastGroupName = groupName;
}
} else {
if(line.includes(",")){
var channelName = line.split(",")[0].trim();
var channelUrl = line.split(",")[1].trim();
if (channelName != '' && channelUrl != '' && !tempUrls.includes(channelUrl)) {
if (lastGroupName !== "") {
m3uContent += "#EXTINF:-1 group-title=\"" + lastGroupName + "\"," + channelName + "\n";
} else {
m3uContent += "#EXTINF:-1," + channelName + "\n";
}
m3uContent += channelUrl + "\n";
tempUrls.push(channelUrl);
}
}
}
}
});
return m3uContent;
}
function convertToM3U() {
var txtPreview = document.getElementById("previewBefore");
var m3uPreview = document.getElementById("previewAfter");
m3uPreview.value=TxtToM3U(txtPreview.value);
convertedData = m3uPreview.value;
}
function M3uToDiyp(m3uPreview) {
var txtContent = "";
if(m3uPreview == null || m3uPreview=='') return '';
var lines = m3uPreview.split("\n");
if (!m3uPreview.includes("#EXTM3U") && !m3uPreview.includes("#EXTINF")) {
txtContent = "不是M3U格式,可能已经是DIYP/TXT格式,无法转换";
return txtContent;
}
var lastgroupName = "";
for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim();
if (line.startsWith("#EXTINF")) {
var groupName = getGroupName(line);
if (groupName != null && groupName != '' && groupName != lastgroupName) {
txtContent += groupName + ",#genre#\n";
lastgroupName = groupName;
}
var name='频道名解析错误';
var match = line.match(/tvg-name=\"([^\"]+)\"/);
if (match) {
name=match[1];
} else {
var count = (line.match(/,/g) || []).length;
if(count>1){
name = line.split(",")[count].trim();
}
else{
name = line.split(",")[1].trim();
}
}
name=name.replace(/\s*/g, '');
var url = lines[i + 1].trim();
if(name!=''&&url!=''){
txtContent += name + "," + url + "\n";
}
}
}
if (txtContent != '' && lastgroupName == '') {
txtContent = "国际,#genre#\n" + txtContent;
}
return txtContent;
}
function convertToDiyp() {
var m3uPreview = document.getElementById("previewBefore");
var txtPreview = document.getElementById("previewAfter");
txtPreview.value = M3uToDiyp(m3uPreview.value);
convertedData = txtPreview.value;
}
function M3uToTXT(m3uPreview) {
var txtContent = "";
if(m3uPreview == null || m3uPreview=='') return '';
var lines = m3uPreview.split("\n");
if (!m3uPreview.includes("#EXTM3U") && !m3uPreview.includes("#EXTINF")) {
txtContent = "不是M3U格式,可能已经是DIYP/TXT格式,无法转换";
return txtContent;
}
for (var i = 0; i < lines.length; i++) {
var line = lines[i].trim();
if (line.startsWith("#EXTINF")) {
var name='频道名解析错误';
var count = (line.match(/,/g) || []).length;
if(count>1){
name = line.split(",")[count].trim();
}
else{
name = line.split(",")[1].trim();
}
var url = lines[i + 1].trim();
if(name!=''&&url!=''){
txtContent += name + "," + url + "\n";
}
}
}
return txtContent;
}
function convertToTXT() {
var m3uPreview = document.getElementById("previewBefore");
var txtPreview = document.getElementById("previewAfter");
txtPreview.value = M3uToTXT(m3uPreview.value);
convertedData = txtPreview.value;
}
function updatePreview(inputId, previewId) {
var fileInput = document.getElementById(inputId);
var file = fileInput.files[0];
var reader = new FileReader();
reader.onload = function(e) {
var contents = e.target.result;
var preview = document.getElementById(previewId);
preview.value = contents;
};
reader.readAsText(file);
}
function exportConvertedFile() {
if (typeof convertedData == 'undefined' || convertedData == null || convertedData == '') {
alert('没有可导出的内容!');
return;
}
const blob = new Blob([convertedData], { type: 'text/plain' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
// 根据内容自动判断文件类型
if (convertedData.includes("#EXTM3U")) {
link.download = 'iptv_playlist.m3u';
} else {
link.download = 'iptv_channels.txt';
}
link.click();
URL.revokeObjectURL(url);
}
function getGroupName(str) {
const regex = /group-title\s*=\s*"(.*?)"/;
const result = str.match(regex);
if (result && result.length > 1) {
const groupTitle = result[1];
return groupTitle.replace(/^\s*|\s*$/g, '');
}
}
function clearBefore() {
var m3uPreview = document.getElementById("previewBefore");
m3uPreview.value = '';
var fileInput = document.getElementById("fileInput");
fileInput.value = '';
}
function clearAfter() {
var txtPreview = document.getElementById("previewAfter");
txtPreview.value = '';
convertedData = '';
}
function copyContent() {
const m3uOutput = document.getElementById('previewAfter');
m3uOutput.select();
if(m3uOutput.value == '') {
alert('没有内容可复制!');
return;
}
document.execCommand('copy');
alert('内容已复制到剪贴板!');
}
// 拖拽功能
var box = document.getElementById('container');
document.ondrop = function(e){
e.preventDefault();
}
document.ondragover = function(e){
e.preventDefault();
}
box.ondrop = function(e){
var dataFile = e.dataTransfer.files[0];
var fr = new FileReader();
fr.readAsText(dataFile);
fr.onload = function(){
var data = fr.result;
var ta = document.getElementById('previewBefore');
ta.value = data;
}
}
// Ctrl+S 快捷键保存
window.addEventListener("keydown", function(e) {
if((e.key=='s'||e.key=='S')&&(navigator.platform.match("Mac") ? e.metaKey : e.ctrlKey)){
e.preventDefault();
exportConvertedFile();
}
}, false);
</script>
</body>
</html>文章对你有帮助吗?
- 一般[0]

- 很赞[0]

- 没用[0]

- 垃圾[0]

- 无语[0]



