由于電腦上的短視頻太多了,并且分別存放在各個子目錄下,每次更新后想要整理視頻比較麻煩,因此想用Python編寫程序來輔助管理視頻文件。其實寫個Python腳本程序即可實現大器的需求,但為了多練習PyQt和交互的方便,還是編寫個桌面程序更易于使用。

主要的功能代碼
本程序的主要功能代碼實際上是比較少的,大部分代碼都是輔助界面設計和控件交互邏輯的。
def playVideo(self):
'''查找符合條件的視頻并播放'''
day_secs = 24*60*60
NOW = time.time() # 當前時間戳
# 掃描指定目錄的視頻文件
files = []
for d in self.dirs:
if d[-1] not in ('\', '/'):
d += '/'
files += glob(d + '**/*.mp4', recursive=True)
# 過濾指定時間范圍內的文件
recent = {}
for file in files:
if '創建時間' in self.timeAttr.currentText():
stamp = os.path.getctime(file)
else:
stamp = os.path.getmtime(file)
condition = self.timeRange.currentText()
span = int(condition.strip('過去天')) * day_secs
if stamp > NOW - span:
recent[stamp] = file
# 文件按創建時間倒序排序
files = [recent[k] for k in sorted(recent, reverse=True)]
# 創建播放列表
if not files:
return
with open(self.listFile, 'w', encoding='utf-8') as fp:
fp.write('n'.join(files))
# 調用外部播放器打開播放列表
subprocess.Popen([self.player.text(), self.listFile])
值得一提的是,這里調用外部程序用的是subprocess.Popen(),也可以用os.system()代替。通常在執行os.system()函數時會阻塞它的調用者,直到所啟動的命令行程序退出,此問題可以通過以下方式解決。
在linux平臺上需要在命令末尾加上shell后臺運算符&:
os.system('python test.py &')
在windows中用DOS的start命令使命令并行啟動:
os.system('start python test.py')
設置窗口居中
def _centerOnScreen(self):
'''窗口在屏幕居中'''
screen = QDesktopWidget().screenGeometry()
size = self.geometry()
x = (screen.width() - size.width()) / 2
y = (screen.height() - size.height()) / 2
self.move(int(x), int(y))
如果需要將窗口設置稍微偏上一點,可以修改y的計算值,比如將2修改為3,根據自己的偏好進行調整。
關閉程序前保存數據
在關閉程序前,有時需要對設置數據進行保存或者對臨時文件進行清理。PyQt5雖然內置了很多信號,但對于此需求卻愛莫能助,需要我們自定義信號。可以使用pyqtSignal()方法定義新的信號,信號的定義需要放在__init__()之前作為類的屬性。
在界面類中重載closeEvent事件,發射自定義的退出信號,然后將此信號連接到槽函數(自定義的處理方法)。
class View(QWidget):
'''應用圖形界面'''
closing = pyqtSignal() # 窗口關閉信號
def __init__(self):
super(View, self).__init__()
self.setWindowTitle('最新短視頻查看器')
# 省略部分代碼
def closeEvent(self, event):
'''關閉前發送信號清理臨時文件'''
self.closing.emit()
event.accept()
窗口控件布局
Qt的布局管理器非常的強大和方便,各種布局都可以相互嵌套。如果指定了stretch=1,那么此控件會根據布局的空間進行自動調整長度或者高度(取決于是橫向布局還是縱向布局)。以下控件定義和布局是通過代碼實現,未使用Qt界面設計工具,簡單的界面推薦直接用代碼定義。
def _createWidgets(self):
'''創建窗口部件'''
layout = QHBoxLayout(self) # 全局布局
layout.setContentsMargins(18, 12, 18, 12)
l1 = QVBoxLayout()
self.dirList = QListWidget()
self.player = QLineEdit()
l11 = QHBoxLayout()
self.label1 = QLabel('時間范圍')
self.timeRange = QComboBox()
self.label2 = QLabel('排序依據')
self.timeAttr = QComboBox()
l11.addWidget(self.label1)
l11.addWidget(self.timeRange,stretch=1)
l11.addSpacing(20)
l11.addWidget(self.label2)
l11.addWidget(self.timeAttr, stretch=1)
l1.addWidget(self.dirList)
l1.addWidget(self.player)
l1.addLayout(l11)
l2 = QVBoxLayout()
self.add = QPushButton('添加路徑')
self.remove = QPushButton('移除路徑')
self.openPath = QPushButton('選擇播放器')
self.play = QPushButton('查找并播放')
l2.addWidget(self.add)
l2.addWidget(self.remove)
l2.addStretch()
l2.addWidget(self.openPath)
l2.addWidget(self.play)
layout.addLayout(l1)
layout.addLayout(l2)
連接信號和槽函數
PyQt的信號和槽函數的連接非常簡潔方便,不同于C++的冗長。
def _connectSignals(self):
'''連接信號和槽'''
self.add.clicked.connect(self.addDir)
self.remove.clicked.connect(self.rmDir)
self.openPath.clicked.connect(self.openPlayerPath)
self.play.clicked.connect(self.playVideo)
self.closing.connect(self.saveConfig)
讀取配置文件
根據指定路徑和文件讀取配置,如果文件不存在則創建新的配置文件,用于記錄當前使用的掃描目錄和播放器的路徑,這樣下次運行程序時無需重新添加路徑。
def loadConfig(self):
'''導入配置數據'''
self.config = ConfigObj(self.configFile, encoding='utf-8')
try:
self.dirs = self.config['程序設置']['掃描路徑']
self.dirList.addItems(self.dirs)
self.player.setText(self.config['程序設置']['播放器路徑'])
except KeyError:
self.config['程序設置'] = {}
self.config['程序設置']['掃描路徑'] = []
self.config['程序設置']['播放器路徑'] = ''
self.dirs = self.config['程序設置']['掃描路徑']
總體而言,本程序還是比較簡單的,基本實現了大器的需求。還有一點可以改進的是,由于掃描文件比較多時可能耗時比較長,程序界面會有幾秒時間顯示程序無響應,影響使用體驗。可以將這部分另開一個線程處理,處理完再觸發信號通知播放器播放文件。由于文章篇幅有限,未貼出全部代碼,需要完整代碼的可以關注后私信大器。
我是大器,正在建立自己的知識庫,并將這些經驗分享給你,請關注我,一起交流學習。