142 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import http.server
 | ||
| import socketserver
 | ||
| import os
 | ||
| import argparse
 | ||
| from urllib.parse import unquote
 | ||
| import mimetypes
 | ||
| import logging
 | ||
| 
 | ||
| # 配置日志
 | ||
| logging.basicConfig(
 | ||
|     level=logging.INFO,
 | ||
|     format='%(asctime)s - %(levelname)s - %(message)s'
 | ||
| )
 | ||
| 
 | ||
| class FileHandler(http.server.SimpleHTTPRequestHandler):
 | ||
|     def __init__(self, *args, **kwargs):
 | ||
|         self.base_directory = os.path.abspath(os.path.join(os.getcwd(), 'audio'))
 | ||
|         super().__init__(*args, directory=self.base_directory, **kwargs)
 | ||
| 
 | ||
|     def do_GET(self):
 | ||
|         try:
 | ||
|             # 解码URL路径
 | ||
|             path = unquote(self.path)
 | ||
|             # 获取文件的完整路径
 | ||
|             file_path = os.path.abspath(os.path.join(self.base_directory, path.lstrip('/')))
 | ||
|             
 | ||
|             # 安全检查:确保请求的路径在audio目录下
 | ||
|             if not file_path.startswith(self.base_directory):
 | ||
|                 self.send_error(403, "Access denied")
 | ||
|                 return
 | ||
| 
 | ||
|             # 检查文件是否存在
 | ||
|             if not os.path.exists(file_path):
 | ||
|                 self.send_error(404, "File not found")
 | ||
|                 return
 | ||
| 
 | ||
|             # 如果是目录,显示目录内容
 | ||
|             if os.path.isdir(file_path):
 | ||
|                 self.send_directory_listing(file_path)
 | ||
|                 return
 | ||
| 
 | ||
|             # 只允许访问音频文件
 | ||
|             allowed_extensions = {'.wav', '.mp3', '.ogg', '.m4a', '.flac'}
 | ||
|             if not any(file_path.lower().endswith(ext) for ext in allowed_extensions):
 | ||
|                 self.send_error(403, "File type not allowed")
 | ||
|                 return
 | ||
| 
 | ||
|             # 获取文件的MIME类型
 | ||
|             content_type, _ = mimetypes.guess_type(file_path)
 | ||
|             if content_type is None:
 | ||
|                 content_type = 'application/octet-stream'
 | ||
| 
 | ||
|             # 发送文件
 | ||
|             self.send_file(file_path, content_type)
 | ||
| 
 | ||
|         except Exception as e:
 | ||
|             logging.error(f"Error handling request: {str(e)}")
 | ||
|             self.send_error(500, f"Internal server error: {str(e)}")
 | ||
| 
 | ||
|     def send_file(self, file_path, content_type):
 | ||
|         try:
 | ||
|             with open(file_path, 'rb') as f:
 | ||
|                 self.send_response(200)
 | ||
|                 self.send_header('Content-type', content_type)
 | ||
|                 self.send_header('Content-Disposition', f'attachment; filename="{os.path.basename(file_path)}"')
 | ||
|                 self.end_headers()
 | ||
|                 self.wfile.write(f.read())
 | ||
|         except Exception as e:
 | ||
|             logging.error(f"Error sending file: {str(e)}")
 | ||
|             self.send_error(500, f"Error reading file: {str(e)}")
 | ||
| 
 | ||
|     def send_directory_listing(self, directory):
 | ||
|         try:
 | ||
|             self.send_response(200)
 | ||
|             self.send_header('Content-type', 'text/html; charset=utf-8')
 | ||
|             self.end_headers()
 | ||
| 
 | ||
|             # 生成目录列表HTML
 | ||
|             html = ['<!DOCTYPE html>',
 | ||
|                    '<html><head><title>Audio Files Directory</title>',
 | ||
|                    '<style>',
 | ||
|                    'body { font-family: Arial, sans-serif; margin: 20px; }',
 | ||
|                    'table { border-collapse: collapse; width: 100%; }',
 | ||
|                    'th, td { padding: 8px; text-align: left; border-bottom: 1px solid #ddd; }',
 | ||
|                    'tr:hover { background-color: #f5f5f5; }',
 | ||
|                    '.audio-file { color: #0066cc; }',
 | ||
|                    '</style></head><body>',
 | ||
|                    '<h1>Audio Files Directory</h1>',
 | ||
|                    '<table>',
 | ||
|                    '<tr><th>Name</th><th>Size</th><th>Type</th></tr>']
 | ||
| 
 | ||
|             # 添加父目录链接
 | ||
|             if self.path != '/':
 | ||
|                 html.append('<tr><td><a href="..">..</a></td><td>-</td><td>Directory</td></tr>')
 | ||
| 
 | ||
|             # 列出目录内容
 | ||
|             for item in sorted(os.listdir(directory)):
 | ||
|                 item_path = os.path.join(directory, item)
 | ||
|                 is_dir = os.path.isdir(item_path)
 | ||
|                 
 | ||
|                 # 只显示目录和音频文件
 | ||
|                 if not is_dir and not any(item.lower().endswith(ext) for ext in {'.wav', '.mp3', '.ogg', '.m4a', '.flac'}):
 | ||
|                     continue
 | ||
| 
 | ||
|                 size = '-' if is_dir else f"{os.path.getsize(item_path):,} bytes"
 | ||
|                 item_type = 'Directory' if is_dir else 'Audio File'
 | ||
|                 item_class = 'audio-file' if not is_dir else ''
 | ||
|                 html.append(f'<tr><td><a href="{os.path.join(self.path, item)}" class="{item_class}">{item}</a></td><td>{size}</td><td>{item_type}</td></tr>')
 | ||
| 
 | ||
|             html.append('</table></body></html>')
 | ||
|             self.wfile.write('\n'.join(html).encode('utf-8'))
 | ||
| 
 | ||
|         except Exception as e:
 | ||
|             logging.error(f"Error generating directory listing: {str(e)}")
 | ||
|             self.send_error(500, f"Error generating directory listing: {str(e)}")
 | ||
| 
 | ||
| def run_server(port):
 | ||
|     # 确保audio目录存在
 | ||
|     audio_dir = os.path.join(os.getcwd(), 'audio')
 | ||
|     if not os.path.exists(audio_dir):
 | ||
|         os.makedirs(audio_dir)
 | ||
|         logging.info(f"Created audio directory at: {audio_dir}")
 | ||
|     
 | ||
|     # 创建服务器
 | ||
|     handler = FileHandler
 | ||
|     host = "0.0.0.0"
 | ||
|     with socketserver.TCPServer((host, port), handler) as httpd:
 | ||
|         logging.info(f"Server started at http://{host}:{port}")
 | ||
|         logging.info(f"Local access: http://localhost:{port}")
 | ||
|         logging.info(f"Serving files from: {audio_dir}")
 | ||
|         try:
 | ||
|             httpd.serve_forever()
 | ||
|         except KeyboardInterrupt:
 | ||
|             logging.info("Server stopped by user")
 | ||
|             httpd.server_close()
 | ||
| 
 | ||
| if __name__ == "__main__":
 | ||
|     parser = argparse.ArgumentParser(description='Audio files HTTP server')
 | ||
|     parser.add_argument('-p', '--port', type=int, default=8000, help='Port to run the server on (default: 8000)')
 | ||
|     args = parser.parse_args()
 | ||
| 
 | ||
|     run_server(args.port)  | 
