本文目录导读:

我来帮你编写一个监控数据归档进度的脚本,我会提供几种不同场景的示例,你可以根据实际需要选择使用。
通用文件归档监控脚本
#!/usr/bin/env python3
"""
数据归档进度监控脚本
支持监控文件复制、压缩、传输等归档操作
"""
import os
import time
import psutil
import json
from datetime import datetime
from pathlib import Path
class ArchiveMonitor:
def __init__(self, source_dir, target_dir, check_interval=5):
self.source_dir = Path(source_dir)
self.target_dir = Path(target_dir)
self.check_interval = check_interval # 检查间隔(秒)
self.start_time = None
self.total_files = 0
self.total_size = 0
self.processed_files = 0
self.processed_size = 0
def scan_source(self):
"""扫描源目录,获取总文件数和总大小"""
print(f"正在扫描源目录: {self.source_dir}")
for file_path in self.source_dir.rglob('*'):
if file_path.is_file():
self.total_files += 1
self.total_size += file_path.stat().st_size
print(f"发现 {self.total_files} 个文件,总大小: {self.format_size(self.total_size)}")
def check_progress(self):
"""检查当前归档进度"""
current_files = 0
current_size = 0
if self.target_dir.exists():
for file_path in self.target_dir.rglob('*'):
if file_path.is_file():
current_files += 1
current_size += file_path.stat().st_size
return current_files, current_size
def calculate_speed(self, size, elapsed):
"""计算传输速度"""
if elapsed > 0:
return size / elapsed
return 0
def format_size(self, bytes):
"""格式化文件大小显示"""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes < 1024.0:
return f"{bytes:.2f} {unit}"
bytes /= 1024.0
return f"{bytes:.2f} PB"
def estimate_time(self, processed, total, speed):
"""预估剩余时间"""
if speed > 0 and processed < total:
remaining = (total - processed) / speed
return remaining
return 0
def monitor(self):
"""主监控循环"""
print(f"开始监控归档进度...")
print(f"源目录: {self.source_dir}")
print(f"目标目录: {self.target_dir}")
print("-" * 60)
self.start_time = time.time()
self.scan_source()
try:
while True:
time.sleep(self.check_interval)
elapsed = time.time() - self.start_time
# 获取当前进度
self.processed_files, self.processed_size = self.check_progress()
# 计算指标
file_percent = (self.processed_files / self.total_files * 100) if self.total_files > 0 else 0
size_percent = (self.processed_size / self.total_size * 100) if self.total_size > 0 else 0
speed = self.calculate_speed(self.processed_size, elapsed)
eta = self.estimate_time(self.processed_size, self.total_size, speed)
# 显示进度
os.system('clear' if os.name == 'posix' else 'cls') # 清屏
print(f"数据归档进度监控 - {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 60)
print(f"文件进度: {self.processed_files}/{self.total_files} ({file_percent:.2f}%)")
print(f"大小进度: {self.format_size(self.processed_size)}/{self.format_size(self.total_size)} ({size_percent:.2f}%)")
print(f"传输速度: {self.format_size(speed)}/s")
print(f"已用时间: {self.format_time(elapsed)}")
print(f"预计剩余: {self.format_time(eta)}")
print("-" * 60)
# 进度条
bar_length = 50
filled = int(bar_length * size_percent / 100)
bar = '█' * filled + '░' * (bar_length - filled)
print(f"进度: |{bar}| {size_percent:.1f}%")
# 检查是否完成
if size_percent >= 100:
print("\n✅ 归档完成!")
break
except KeyboardInterrupt:
print("\n\n监控已停止")
def format_time(self, seconds):
"""格式化时间显示"""
if seconds <= 0:
return "0秒"
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
parts = []
if hours > 0:
parts.append(f"{hours}小时")
if minutes > 0:
parts.append(f"{minutes}分")
parts.append(f"{secs}秒")
return "".join(parts)
# 使用示例
if __name__ == "__main__":
# 配置路径
SOURCE_DIR = "/path/to/source" # 源数据目录
TARGET_DIR = "/path/to/archive" # 归档目标目录
# 创建监控器并开始监控
monitor = ArchiveMonitor(SOURCE_DIR, TARGET_DIR, check_interval=2)
monitor.monitor()
数据库归档监控脚本
#!/usr/bin/env python3
"""
数据库归档进度监控脚本
支持MySQL/PostgreSQL数据库备份进度监控
"""
import subprocess
import re
import time
from datetime import datetime
class DatabaseArchiveMonitor:
def __init__(self, db_type='mysql', host='localhost', port=3306,
user='root', password='', database=''):
self.db_type = db_type
self.host = host
self.port = port
self.user = user
self.password = password
self.database = database
def monitor_mysql_dump(self, output_file):
"""监控MySQL数据库导出进度"""
print(f"开始监控MySQL数据库归档: {self.database}")
print(f"输出文件: {output_file}")
print("-" * 60)
start_time = time.time()
last_size = 0
# 执行mysqldump命令
cmd = f"mysqldump -h{self.host} -P{self.port} -u{self.user}"
if self.password:
cmd += f" -p{self.password}"
cmd += f" {self.database} > {output_file}"
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
try:
while process.poll() is None:
time.sleep(2)
elapsed = time.time() - start_time
# 检查输出文件大小
try:
current_size = os.path.getsize(output_file)
speed = (current_size - last_size) / 2 # 每秒速度
# 显示进度
print(f"\r时间: {self.format_time(elapsed)} | "
f"大小: {self.format_size(current_size)} | "
f"速度: {self.format_size(speed)}/s", end='')
last_size = current_size
except FileNotFoundError:
print("\r等待文件创建...", end='')
# 检查是否成功
if process.returncode == 0:
total_size = os.path.getsize(output_file)
print(f"\n✅ MySQL数据库归档完成!")
print(f"最终大小: {self.format_size(total_size)}")
print(f"总用时: {self.format_time(time.time() - start_time)}")
else:
error = process.stderr.read().decode()
print(f"\n❌ 归档失败: {error}")
except KeyboardInterrupt:
process.terminate()
print("\n监控已停止")
def monitor_postgresql_dump(self, output_file):
"""监控PostgreSQL数据库导出进度"""
print(f"开始监控PostgreSQL数据库归档: {self.database}")
print(f"输出文件: {output_file}")
print("-" * 60)
start_time = time.time()
# 使用pg_dump并获取进度
cmd = f"pg_dump -h{self.host} -p{self.port} -U{self.user}"
if self.password:
os.environ['PGPASSWORD'] = self.password
cmd += f" {self.database} > {output_file}"
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
# 监控进度
while process.poll() is None:
time.sleep(2)
elapsed = time.time() - start_time
try:
current_size = os.path.getsize(output_file)
print(f"\r时间: {self.format_time(elapsed)} | "
f"已备份: {self.format_size(current_size)}", end='')
except FileNotFoundError:
print("\r等待备份开始...", end='')
if process.returncode == 0:
total_size = os.path.getsize(output_file)
print(f"\n✅ PostgresQL数据库归档完成!")
print(f"最终大小: {self.format_size(total_size)}")
print(f"总用时: {self.format_time(time.time() - start_time)}")
else:
error = process.stderr.read().decode()
print(f"\n❌ 归档失败: {error}")
def format_size(self, bytes):
"""格式化文件大小"""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes < 1024.0:
return f"{bytes:.2f} {unit}"
bytes /= 1024.0
return f"{bytes:.2f} PB"
def format_time(self, seconds):
"""格式化时间"""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
# 使用示例
if __name__ == "__main__":
# MySQL监控示例
mysql_monitor = DatabaseArchiveMonitor(
db_type='mysql',
host='localhost',
user='root',
password='password',
database='mydatabase'
)
mysql_monitor.monitor_mysql_dump("backup.sql")
# PostgreSQL监控示例
pg_monitor = DatabaseArchiveMonitor(
db_type='postgresql',
host='localhost',
port=5432,
user='postgres',
password='password',
database='mydb'
)
pg_monitor.monitor_postgresql_dump("pg_backup.sql")
压缩归档进度监控
#!/usr/bin/env python3
"""
压缩归档进度监控脚本
监控tar/zip等压缩操作进度
"""
import os
import time
import threading
from pathlib import Path
class CompressionMonitor:
def __init__(self, source_dir, archive_file, archive_type='tar.gz'):
self.source_dir = Path(source_dir)
self.archive_file = Path(archive_file)
self.archive_type = archive_type
self.total_size = 0
self.monitoring = False
def get_total_size(self):
"""计算源目录总大小"""
total = 0
for file_path in self.source_dir.rglob('*'):
if file_path.is_file():
total += file_path.stat().st_size
return total
def monitor(self):
"""启动监控"""
print(f"开始监控压缩归档: {self.source_dir} -> {self.archive_file}")
print("-" * 60)
self.total_size = self.get_total_size()
start_time = time.time()
self.monitoring = True
# 在后台启动压缩进程
compress_thread = threading.Thread(target=self.compress_files)
compress_thread.start()
try:
while compress_thread.is_alive():
time.sleep(2)
elapsed = time.time() - start_time
if self.archive_file.exists():
current_size = self.archive_file.stat().st_size
# 压缩比大约在2-5倍之间,这里估算为3倍
estimated_progress = min((current_size * 3) / self.total_size * 100, 99)
speed = current_size / elapsed if elapsed > 0 else 0
print(f"\r进度: {self.format_size(current_size)}/{self.format_size(self.total_size)} | "
f"耗时: {self.format_time(elapsed)} | "
f"速度: {self.format_size(speed)}/s", end='')
# 压缩完成
final_size = self.archive_file.stat().st_size if self.archive_file.exists() else 0
total_time = time.time() - start_time
compression_ratio = self.total_size / final_size if final_size > 0 else 0
print(f"\n✅ 压缩归档完成!")
print(f"原始大小: {self.format_size(self.total_size)}")
print(f"压缩大小: {self.format_size(final_size)}")
print(f"压缩比: {compression_ratio:.2f}:1")
print(f"总用时: {self.format_time(total_time)}")
except KeyboardInterrupt:
print("\n监控已停止")
self.monitoring = False
def compress_files(self):
"""执行文件压缩"""
import tarfile
import gzip
if self.archive_type == 'tar.gz':
with tarfile.open(self.archive_file, "w:gz") as tar:
tar.add(self.source_dir, arcname=self.source_dir.name)
elif self.archive_type == 'zip':
import zipfile
with zipfile.ZipFile(self.archive_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
for file_path in self.source_dir.rglob('*'):
if file_path.is_file():
zipf.write(file_path, file_path.relative_to(self.source_dir.parent))
def format_size(self, bytes):
"""格式化文件大小"""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes < 1024.0:
return f"{bytes:.2f} {unit}"
bytes /= 1024.0
return f"{bytes:.2f} PB"
def format_time(self, seconds):
"""格式化时间"""
hours = int(seconds // 3600)
minutes = int((seconds % 3600) // 60)
secs = int(seconds % 60)
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
# 使用示例
if __name__ == "__main__":
source = "/path/to/data" # 要压缩的数据目录
archive = "/path/to/archive.tar.gz" # 输出的归档文件
monitor = CompressionMonitor(source, archive, 'tar.gz')
monitor.monitor()
Web界面监控(使用Flask)
#!/usr/bin/env python3
"""
Web版归档监控界面
提供实时进度显示
"""
from flask import Flask, jsonify, render_template_string
import os
import time
import threading
from pathlib import Path
app = Flask(__name__)
# 全局状态
archive_status = {
'total_files': 0,
'processed_files': 0,
'total_size': 0,
'processed_size': 0,
'speed': 0,
'start_time': None,
'is_running': False,
'percentage': 0
}
HTML_TEMPLATE = '''
<!DOCTYPE html>
<html>
<head>数据归档监控</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 40px;
background: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 30px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
}
h1 {
color: #333;
text-align: center;
}
.progress-bar {
width: 100%;
height: 30px;
background: #e0e0e0;
border-radius: 15px;
overflow: hidden;
margin: 20px 0;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #4CAF50, #45a049);
transition: width 1s ease;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
}
.stats {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin: 20px 0;
}
.stat-item {
background: #f9f9f9;
padding: 15px;
border-radius: 5px;
text-align: center;
}
.stat-label {
color: #666;
font-size: 14px;
}
.stat-value {
color: #333;
font-size: 24px;
font-weight: bold;
margin-top: 5px;
}
.status {
text-align: center;
padding: 10px;
border-radius: 5px;
margin: 20px 0;
}
.running {
background: #e3f2fd;
color: #1976D2;
}
.completed {
background: #e8f5e9;
color: #388E3C;
}
</style>
</head>
<body>
<div class="container">
<h1>📊 数据归档监控</h1>
<div class="progress-bar">
<div class="progress-fill" style="width: {{ status.percentage }}%">
{{ "%.1f"|format(status.percentage) }}%
</div>
</div>
<div class="stats">
<div class="stat-item">
<div class="stat-label">文件进度</div>
<div class="stat-value">{{ status.processed_files }}/{{ status.total_files }}</div>
</div>
<div class="stat-item">
<div class="stat-label">大小进度</div>
<div class="stat-value">{{ format_size(status.processed_size) }}/{{ format_size(status.total_size) }}</div>
</div>
<div class="stat-item">
<div class="stat-label">传输速度</div>
<div class="stat-value">{{ format_size(status.speed) }}/s</div>
</div>
<div class="stat-item">
<div class="stat-label">运行时间</div>
<div class="stat-value">{{ format_time(status.elapsed) }}</div>
</div>
</div>
<div class="status {{ 'running' if status.is_running else 'completed' }}">
{{ '🔄 归档进行中...' if status.is_running else '✅ 归档完成!' }}
</div>
</div>
<script>
function updateStatus() {
fetch('/status')
.then(response => response.json())
.then(data => {
document.querySelector('.progress-fill').style.width = data.percentage + '%';
document.querySelector('.progress-fill').textContent = data.percentage.toFixed(1) + '%';
// 更新其他统计信息
document.querySelectorAll('.stat-value')[0].textContent =
data.processed_files + '/' + data.total_files;
document.querySelectorAll('.stat-value')[1].textContent =
formatBytes(data.processed_size) + '/' + formatBytes(data.total_size);
document.querySelectorAll('.stat-value')[2].textContent =
formatBytes(data.speed) + '/s';
if (data.percentage >= 100) {
document.querySelector('.status').className = 'status completed';
document.querySelector('.status').textContent = '✅ 归档完成!';
}
});
}
function formatBytes(bytes) {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
// 每2秒更新一次
setInterval(updateStatus, 2000);
</script>
</body>
</html>
'''
@app.route('/')
def index():
"""主页面"""
return render_template_string(HTML_TEMPLATE, status=archive_status)
@app.route('/status')
def status():
"""返回JSON状态"""
if archive_status['start_time']:
elapsed = time.time() - archive_status['start_time']
else:
elapsed = 0
return jsonify({
'total_files': archive_status['total_files'],
'processed_files': archive_status['processed_files'],
'total_size': archive_status['total_size'],
'processed_size': archive_status['processed_size'],
'speed': archive_status['speed'],
'percentage': archive_status['percentage'],
'elapsed': elapsed,
'is_running': archive_status['is_running']
})
def update_status():
"""更新归档状态(示例)"""
# 这里应该实现实际的归档进度检查逻辑
# 以下为模拟数据
while archive_status['is_running']:
time.sleep(2)
if archive_status['processed_size'] < archive_status['total_size']:
# 模拟进度增加
increase = min(1024*1024*100, archive_status['total_size'] - archive_status['processed_size'])
archive_status['processed_size'] += increase
archive_status['percentage'] = (archive_status['processed_size'] / archive_status['total_size']) * 100
else:
archive_status['is_running'] = False
archive_status['percentage'] = 100
break
if __name__ == '__main__':
# 初始化示例数据
archive_status['total_files'] = 1000
archive_status['total_size'] = 1024 * 1024 * 1024 * 10 # 10GB
archive_status['start_time'] = time.time()
archive_status['is_running'] = True
# 启动后台更新线程
update_thread = threading.Thread(target=update_status, daemon=True)
update_thread.start()
# 启动Web服务器
app.run(host='0.0.0.0', port=5000, debug=True)
日志文件归档监控
#!/usr/bin/env python3
"""
日志归档监控脚本
适合监控日志文件的轮转和归档
"""
import time
import os
from datetime import datetime, timedelta
from pathlib import Path
class LogArchiveMonitor:
def __init__(self, log_dir, archive_dir, rotation_size='100M'):
self.log_dir = Path(log_dir)
self.archive_dir = Path(archive_dir)
self.rotation_size = self.parse_size(rotation_size)
# 确保目录存在
self.archive_dir.mkdir(parents=True, exist_ok=True)
def parse_size(self, size_str):
"""解析大小字符串"""
size_str = size_str.upper()
if size_str.endswith('K'):
return int(float(size_str[:-1]) * 1024)
elif size_str.endswith('M'):
return int(float(size_str[:-1]) * 1024 * 1024)
elif size_str.endswith('G'):
return int(float(size_str[:-1]) * 1024 * 1024 * 1024)
else:
return int(size_str)
def format_size(self, bytes):
"""格式化大小"""
for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
if bytes < 1024.0:
return f"{bytes:.2f} {unit}"
bytes /= 1024.0
return f"{bytes:.2f} PB"
def get_log_files(self):
"""获取所有日志文件"""
log_files = []
for file_path in self.log_dir.glob('*.log'):
if file_path.is_file():
log_files.append(file_path)
return log_files
def check_rotation_needed(self, file_path):
"""检查是否需要轮转"""
if file_path.exists():
size = file_path.stat().st_size
return size >= self.rotation_size
return False
def rotate_log(self, file_path):
"""轮转日志文件"""
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
archive_name = f"{file_path.stem}_{timestamp}{file_path.suffix}.gz"
archive_path = self.archive_dir / archive_name
# 压缩并归档
import gzip
import shutil
with open(file_path, 'rb') as f_in:
with gzip.open(archive_path, 'wb') as f_out:
shutil.copyfileobj(f_in, f_out)
# 清空原日志文件
file_path.write_text('')
return archive_path
def monitor(self):
"""启动监控循环"""
print(f"开始监控日志归档...")
print(f"日志目录: {self.log_dir}")
print(f"归档目录: {self.archive_dir}")
print(f"轮转阈值: {self.format_size(self.rotation_size)}")
print("-" * 60)
stats = {
'rotated_files': 0,
'total_size': 0,
'start_time': time.time()
}
try:
while True:
time.sleep(10) # 每10秒检查一次
log_files = self.get_log_files()
for log_file in log_files:
if self.check_rotation_needed(log_file):
archived = self.rotate_log(log_file)
stats['rotated_files'] += 1
stats['total_size'] += archived.stat().st_size
print(f"[{datetime.now().strftime('%H:%M:%S')}] "
f"轮转: {log_file.name} -> {archived.name} "
f"({self.format_size(archived.stat().st_size)})")
# 显示汇总信息
elapsed = time.time() - stats['start_time']
sys.stdout.write(f"\r运行时间: {self.format_time(int(elapsed))} | "
f"已轮转: {stats['rotated_files']} 个文件 | "
f"总归档大小: {self.format_size(stats['total_size'])}")
sys.stdout.flush()
except KeyboardInterrupt:
print("\n\n监控已停止")
print(f"总计轮转: {stats['rotated_files']} 个文件")
print(f"总归档大小: {self.format_size(stats['total_size'])}")
def format_time(self, seconds):
"""格式化时间"""
hours = seconds // 3600
minutes = (seconds % 3600) // 60
secs = seconds % 60
return f"{hours:02d}:{minutes:02d}:{secs:02d}"
# 使用示例
if __name__ == "__main__":
monitor = LogArchiveMonitor(
log_dir="/var/log/myapp",
archive_dir="/data/logs/archive",
rotation_size="100M" # 100MB触发轮转
)
monitor.monitor()
使用方法
-
通用文件归档监控
python file_archive_monitor.py
-
数据库归档监控
python db_archive_monitor.py
-
压缩归档监控
python compression_monitor.py
-
Web监控界面
pip install flask python web_monitor.py # 打开浏览器访问 http://localhost:5000
注意事项
- 权限问题:确保脚本有足够的权限访问源和目标目录
- 性能影响:监控间隔不要太短,避免影响归档性能
- 错误处理:建议添加重试机制和错误日志
- 资源清理:长时间运行的监控要注意内存使用
- 安全考虑:不要在脚本中硬编码密码
根据你的具体需求选择合适的脚本,或组合使用多个脚本来满足复杂场景。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播