diff --git a/core/dlna_controller.py b/core/dlna_controller.py
index 900f40c..3f87fc3 100644
--- a/core/dlna_controller.py
+++ b/core/dlna_controller.py
@@ -132,12 +132,13 @@ class DLNAController:
# ================== AVTransport 服务方法 ==================
- def set_av_transport_uri(self, media_url, metadata=""):
+ def set_av_transport_uri(self, media_url, title = "", metadata=""):
"""
设置播放URI
Args:
media_url: 媒体文件的URL
+ title: 媒体文件名称
metadata: 媒体元数据(可选)
Returns:
@@ -146,16 +147,27 @@ class DLNAController:
if not self.av_transport_url:
return False
+ if title and not metadata:
+ # 转义title中的XML特殊字符
+ title_escaped = title.replace('&', '&').replace('<', '<').replace('>', '>').replace('"', '"')
+ # 构建简单的DIDL-Lite元数据
+ metadata = f"""
+ -
+ {title_escaped}
+
+ """
+
# 转义XML特殊字符
media_url_escaped = media_url.replace('&', '&').replace('<', '<').replace('>', '>')
media_url_escaped = urllib.parse.quote(media_url_escaped,safe=':/')
metadata_escaped = metadata.replace('&', '&').replace('<', '<').replace('>', '>')
soap_body = f"""
- 0
- {media_url_escaped}
- {metadata_escaped}
-"""
+ 0
+ {media_url_escaped}
+ {metadata_escaped}
+ """
action = "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"
success, response = self._send_soap_request(self.av_transport_url, action, soap_body)
@@ -178,9 +190,9 @@ class DLNAController:
return False
soap_body = f"""
- 0
- {speed}
-"""
+ 0
+ {speed}
+ """
action = "urn:schemas-upnp-org:service:AVTransport:1#Play"
success, response = self._send_soap_request(self.av_transport_url, action, soap_body)
@@ -198,8 +210,8 @@ class DLNAController:
return False
soap_body = """
- 0
-"""
+ 0
+ """
action = "urn:schemas-upnp-org:service:AVTransport:1#Pause"
success, response = self._send_soap_request(self.av_transport_url, action, soap_body)
@@ -217,8 +229,8 @@ class DLNAController:
return False
soap_body = """
- 0
-"""
+ 0
+ """
action = "urn:schemas-upnp-org:service:AVTransport:1#Stop"
success, response = self._send_soap_request(self.av_transport_url, action, soap_body)
@@ -242,10 +254,10 @@ class DLNAController:
target_escaped = target.replace('&', '&').replace('<', '<').replace('>', '>')
soap_body = f"""
- 0
- {unit}
- {target_escaped}
-"""
+ 0
+ {unit}
+ {target_escaped}
+ """
action = "urn:schemas-upnp-org:service:AVTransport:1#Seek"
success, response = self._send_soap_request(self.av_transport_url, action, soap_body)
@@ -267,8 +279,8 @@ class DLNAController:
return None
soap_body = """
- 0
-"""
+ 0
+ """
action = "urn:schemas-upnp-org:service:AVTransport:1#GetTransportInfo"
success, response = self._send_soap_request(self.av_transport_url, action, soap_body)
@@ -321,8 +333,8 @@ class DLNAController:
return None
soap_body = """
- 0
-"""
+ 0
+ """
action = "urn:schemas-upnp-org:service:AVTransport:1#GetPositionInfo"
success, response = self._send_soap_request(self.av_transport_url, action, soap_body)
@@ -375,10 +387,10 @@ class DLNAController:
volume = max(0, min(100, int(volume)))
soap_body = f"""
- 0
- {channel}
- {volume}
-"""
+ 0
+ {channel}
+ {volume}
+ """
action = "urn:schemas-upnp-org:service:RenderingControl:1#SetVolume"
success, response = self._send_soap_request(self.rendering_control_url, action, soap_body)
@@ -399,9 +411,9 @@ class DLNAController:
return None
soap_body = f"""
- 0
- {channel}
-"""
+ 0
+ {channel}
+ """
action = "urn:schemas-upnp-org:service:RenderingControl:1#GetVolume"
success, response = self._send_soap_request(self.rendering_control_url, action, soap_body)
@@ -444,10 +456,10 @@ class DLNAController:
desired_mute = "1" if mute else "0"
soap_body = f"""
- 0
- {channel}
- {desired_mute}
-"""
+ 0
+ {channel}
+ {desired_mute}
+ """
action = "urn:schemas-upnp-org:service:RenderingControl:1#SetMute"
success, response = self._send_soap_request(self.rendering_control_url, action, soap_body)
@@ -468,9 +480,9 @@ class DLNAController:
return None
soap_body = f"""
- 0
- {channel}
-"""
+ 0
+ {channel}
+ """
action = "urn:schemas-upnp-org:service:RenderingControl:1#GetMute"
success, response = self._send_soap_request(self.rendering_control_url, action, soap_body)
@@ -512,7 +524,7 @@ class DLNAController:
return None
soap_body = """
-"""
+ """
action = "urn:schemas-upnp-org:service:ConnectionManager:1#GetProtocolInfo"
success, response = self._send_soap_request(self.connection_manager_url, action, soap_body)
@@ -540,119 +552,3 @@ class DLNAController:
except ET.ParseError:
return None
- # ================== 高级方法 ==================
-
- def play_media(self, media_url, metadata="", wait=1):
- """
- 播放媒体文件(组合操作)
-
- Args:
- media_url: 媒体文件URL
- metadata: 媒体元数据
- wait: 设置URI后的等待时间(秒)
-
- Returns:
- bool: 是否成功
- """
- import time
-
- if self.set_av_transport_uri(media_url, metadata):
- time.sleep(wait)
- return self.play()
- return False
-
- def get_device_status(self):
- """
- 获取设备完整状态
-
- Returns:
- dict: 设备状态信息
- """
- status = {
- 'device_info': {
- 'friendly_name': self.device_info.get('friendly_name', '未知'),
- 'ip': self.device_info.get('ip', '未知'),
- 'location': self.device_info.get('location', '未知')
- },
- 'transport_info': self.get_transport_info(),
- 'position_info': self.get_position_info(),
- 'volume': self.get_volume(),
- 'mute': self.get_mute(),
- 'protocol_info': self.get_protocol_info(),
- 'services': {
- 'av_transport': self.av_transport_url is not None,
- 'rendering_control': self.rendering_control_url is not None,
- 'connection_manager': self.connection_manager_url is not None
- }
- }
-
- return status
-
- def get_supported_formats(self):
- """
- 获取设备支持的媒体格式
-
- Returns:
- list: 支持的格式列表
- """
- protocol_info = self.get_protocol_info()
- if not protocol_info or 'sink' not in protocol_info:
- return []
-
- # 解析sink字段,提取支持的格式
- sink_info = protocol_info['sink']
- formats = []
-
- # DLNA格式通常是逗号分隔的
- for fmt in sink_info.split(','):
- fmt = fmt.strip()
- if fmt:
- formats.append(fmt)
-
- return formats
-
- def can_play_format(self, media_url):
- """
- 检查设备是否可能支持指定格式
-
- Args:
- media_url: 媒体URL
-
- Returns:
- bool: 是否可能支持
- """
- import mimetypes
-
- # 获取文件扩展名
- if '.' in media_url:
- ext = media_url.split('.')[-1].lower()
-
- # 常见扩展名到MIME类型的映射
- ext_to_mime = {
- 'mp4': 'video/mp4',
- 'mp3': 'audio/mp3',
- 'm4a': 'audio/mp4',
- 'wav': 'audio/wav',
- 'flac': 'audio/flac',
- 'mkv': 'video/x-matroska',
- 'avi': 'video/x-msvideo',
- 'mov': 'video/quicktime',
- 'wmv': 'video/x-ms-wmv',
- 'flv': 'video/x-flv',
- 'webm': 'video/webm',
- 'ogg': 'audio/ogg',
- 'oga': 'audio/ogg',
- 'ogv': 'video/ogg',
- 'm3u8': 'application/x-mpegURL',
- 'mpd': 'application/dash+xml'
- }
-
- mime_type = ext_to_mime.get(ext)
- if mime_type:
- # 检查设备是否支持该MIME类型
- supported_formats = self.get_supported_formats()
- for fmt in supported_formats:
- if mime_type in fmt:
- return True
-
- return False
\ No newline at end of file
diff --git a/ui/main_window.py b/ui/main_window.py
index e3e49ec..b11b8b9 100644
--- a/ui/main_window.py
+++ b/ui/main_window.py
@@ -43,8 +43,10 @@ class MainWindow(QMainWindow):
# 获取图标路径(支持打包和开发环境)
if getattr(sys, 'frozen', False):
- # 打包后的exe环境
- base_path = sys._MEIPASS
+ # pyInstaller打包后的exe环境
+ # base_path = sys._MEIPASS
+ # Nuitka打包后
+ base_path = os.path.dirname(sys.executable)
else:
# 开发环境
base_path = os.path.abspath(".")
@@ -707,7 +709,7 @@ class MainWindow(QMainWindow):
self.log_message("设置播放地址", file_url)
# 设置播放URI并开始播放
- if self.dlna_controller.set_av_transport_uri(file_url):
+ if self.dlna_controller.set_av_transport_uri(file_url, file_name):
self.dlna_controller.play()
self.start_btn.setEnabled(False)
self.pause_btn.setEnabled(True)
@@ -740,7 +742,7 @@ class MainWindow(QMainWindow):
self.log_message("设置服务路径", "成功" if dir_bool else "失败")
file_url = f"http://{ip_text}/{file_name}"
- if self.dlna_controller.set_av_transport_uri(file_url):
+ if self.dlna_controller.set_av_transport_uri(file_url, file_name):
self.dlna_controller.play()
self.start_btn.setEnabled(False)
self.pause_btn.setEnabled(True)
@@ -758,27 +760,27 @@ class MainWindow(QMainWindow):
def pause_casting(self):
"""暂停投屏"""
if self.dlna_controller:
- if self.dlna_controller.pause():
- self.is_paused = True # 标记为暂停状态
+ self.dlna_controller.pause()
+ self.is_paused = True # 标记为暂停状态
- self.start_btn.setText("继续播放")
- self.start_btn.setEnabled(True)
- self.pause_btn.setEnabled(False)
+ self.start_btn.setText("继续播放")
+ self.start_btn.setEnabled(True)
+ self.pause_btn.setEnabled(False)
- self.log_message("投屏", "已暂停播放")
+ self.log_message("投屏", "已暂停播放")
def stop_casting(self):
"""停止投屏"""
if self.dlna_controller:
- if self.dlna_controller.stop():
- self.is_paused = False # 重置暂停状态
+ self.dlna_controller.stop()
+ self.is_paused = False # 重置暂停状态
- self.start_btn.setText("开始投屏")
- self.start_btn.setEnabled(True)
- self.pause_btn.setEnabled(False)
- self.stop_btn.setEnabled(False)
+ self.start_btn.setText("开始投屏")
+ self.start_btn.setEnabled(True)
+ self.pause_btn.setEnabled(False)
+ self.stop_btn.setEnabled(False)
- self.log_message("投屏", "已停止播放")
+ self.log_message("投屏", "已停止播放")
def volume_changed(self, value):
"""音量改变"""