# DLNAPlay

扫描局域网中的DLNA设备，并按名称匹配，将本地音乐或视频投送到设备上进行播放。
Github源码地址：[sffzh/dlnaPlay](https://github.com/sffzh/dlnaPlay)

## 特点：
1. 可以按列表播放媒体文件，或者指定多个文件按序或随机播放；
2. 扫描局域网设备后保存临时文件，下次可以快速开始投放；
3. 局域网设备扫描时，采用异步扫描机制，只要发现指定设备立即开始投放，无须等待扫描达到超时时长。

## 依赖说明

本程序中控制upnp设备的功能（查看设备信息、播放、暂停、调节音量等）依赖于项目[flyte/upnpclient](https://github.com/flyte/upnpclient)

## Install

```sh
pip install dlnaPlay
```
### 特殊情况：Termux 等无法安装 lxml4 的环境

在Termux中安装失败，提示是 `lxml:4.9.4` 依赖编译安装失败。 
这是因为`upnpclient`要求依赖lxml版本低于5.0.0。
解决办法如下：
```sh
# 更新系统软件：
pkg update
pkg upgrade
# 先安装高版本lxml:
pkg install build-essential libxml2 libxslt
pip install lxml # 或者用pip install lxml==6.0.2 指定版本号
# 安装`upnpclient`的其他依赖
pip install requests python-dateutil six ifaddr
# 安装`dlnaPlay`的其他依赖
pip install argparse twisted
# 不检查依赖直接安装 upnpclient
pip install upnpclient==1.0.3 --no-deps
# 不检查依赖直接安装 dlnaPlay
pip install dlnaPlay --no-deps
```

## Usage

use `dlnaPlay -h` to show all param options
```sh
dlnaPlay -h
```

## 使用示例

### 列出可用设备

```sh
dlnaPlay -w list_devices
```
`-w` 参数表示 `watch`，用来查看设备状态而不进行控制操作。后续再详细说明。

` -w list_devices`会在扫描局域网的upnp设备后列出支持DLNA投放的设备。扫描时长达到定义的超时时间后会结束程序。
超时时间秒数可用参数 `-t` 设置，默认为5秒。

注意，网络扫描的结果具有不确定性。如果扫描没有发现设备，可增加超时时间再试一次。
通常情况下家用局域网的设备能在5秒内被扫描到，如果超过20秒没发现设备，则需要检查设备自身的网络问题。
将扫描时间增加到30秒以上通常是没有任何意义的。


### 播放m3u歌单列表到指定设备

假设我的局域网中有一台支持DLNA播放的音箱，其upnp名称为`SUPER Sound X9-9527`

```sh
dlnaPlay -d "X9-9527" -f ~/music/playlist/favorite.m3u -s -v 30 -M 15
```

> 说明：
> `-d` 指定设备名称，只需要包含在完整名称中的一小段即可。会采用第一个扫描到可匹配上名称的设备。
  设备名称为其upnp描述文件中的“frendly_name”字段的值。
> `-f` 指定m3u歌单文件。文件内容为纯文本，每行对应一个歌曲文件。可使用当对路径或绝对路径。相对路径为媒体文件相对m3u文件的路径。媒体文件支持`mp3`、`flac`、`ogg`、`m4a`、`mp4`等常见格式，视频或音乐均可。视频投屏需要设备支持。
> `-s` 小写`s`，表示 `shuffle`随机播放, 会对歌曲随机排序后播放。
> `-v` 小写，设置播放音量。
> `-M` 大写，设置播放歌曲数量。注意如果设置了`-s`随机播放，会先打乱顺序再截取曲目数量，因此不用担心歌单尾部的歌曲无法随机播放到。

设备名称选择名称中的一小段即可，但需要自行确保不会匹配到多个不同设备。如果多个设备都能匹配到，将会自动选择首个被扫描到的设备。

### 指定媒体文件进行播放

使用`-m`参数可直接指定媒体文件。可以多次使用此参数以选择多个文件。文件路径无效会自动跳过。

```sh
dlnaPlay -d "-TV" -m "../videos/Love Harder(part 1).mp4" -m "../videos/Love Harder(part 2).mp4" -v 30
```

### 停止播放

对于命令行执行的播放任务，使用`Ctrl+C`或杀死进程的方式结束命令，会在命令行退出前发送信号使DLNA播放设备停止播放。

但如果使用`kill -9`强制结束任务，则程序会强行中断，DLNA设备不会收到停止播放信号，会继续播放，直到所有缓存数据播放完。（通常在数秒钟时间，缓存较大的设备可能可以直接播放完一整首歌。

如果使用此程序播放多首歌曲，中途直接操作DLNA播放设备停止播放，则程序会在少许延迟后自动开始播放下一首。这是因为程序是通过轮询设备状态，以设备停止播放来判断一首歌放完、该放下一首了的。

如果命令行在后台运行，想要停止播放，有以下两种方法：

* 一、直接`ps`查看进程，然后杀死进程。
* 二、使用程序指定设备名称停止播放，命令类似：

  ```sh
  dlnaPlay -d X9-9527 -S
  ```
  > `-d X9-9527` 指定需要停止播放的设备，`-S`为大写字母，表示`Stop`，停止播放。


 
