由于電腦上的短視頻太多了,并且分別存放在各個子目錄下,每次更新后想要整理視頻比較麻煩,因此想用Python編寫程序來輔助管理視頻文件。其實寫個Python腳本程序即可實現(xiàn)大器的需求,但為了多練習(xí)PyQt和交互的方便,還是編寫個桌面程序更易于使用。
主要的功能代碼
本程序的主要功能代碼實際上是比較少的,大部分代碼都是輔助界面設(shè)計和控件交互邏輯的。
def playVideo(self):
'''查找符合條件的視頻并播放'''
day_secs = 24*60*60
NOW = time.time() # 當(dāng)前時間戳
# 掃描指定目錄的視頻文件
files = []
for d in self.dirs:
if d[-1] not in ('\', '/'):
d += '/'
files += glob(d + '**/*.mp4', recursive=True)
# 過濾指定時間范圍內(nèi)的文件
recent = {}
for file in files:
if '創(chuàng)建時間' 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
# 文件按創(chuàng)建時間倒序排序
files = [recent[k] for k in sorted(recent, reverse=True)]
# 創(chuàng)建播放列表
if not files:
return
with open(self.listFile, 'w', encoding='utf-8') as fp:
fp.write('n'.join(files))
# 調(diào)用外部播放器打開播放列表
subprocess.Popen([self.player.text(), self.listFile])
值得一提的是,這里調(diào)用外部程序用的是subprocess.Popen(),也可以用os.system()代替。通常在執(zhí)行os.system()函數(shù)時會阻塞它的調(diào)用者,直到所啟動的命令行程序退出,此問題可以通過以下方式解決。
在linux平臺上需要在命令末尾加上shell后臺運算符&:
os.system('python test.py &')
在windows中用DOS的start命令使命令并行啟動:
os.system('start python test.py')
設(shè)置窗口居中
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))
如果需要將窗口設(shè)置稍微偏上一點,可以修改y的計算值,比如將2修改為3,根據(jù)自己的偏好進(jìn)行調(diào)整。
關(guān)閉程序前保存數(shù)據(jù)
在關(guān)閉程序前,有時需要對設(shè)置數(shù)據(jù)進(jìn)行保存或者對臨時文件進(jìn)行清理。PyQt5雖然內(nèi)置了很多信號,但對于此需求卻愛莫能助,需要我們自定義信號。可以使用pyqtSignal()方法定義新的信號,信號的定義需要放在__init__()之前作為類的屬性。
在界面類中重載closeEvent事件,發(fā)射自定義的退出信號,然后將此信號連接到槽函數(shù)(自定義的處理方法)。
class View(QWidget):
'''應(yīng)用圖形界面'''
closing = pyqtSignal() # 窗口關(guān)閉信號
def __init__(self):
super(View, self).__init__()
self.setWindowTitle('最新短視頻查看器')
# 省略部分代碼
def closeEvent(self, event):
'''關(guān)閉前發(fā)送信號清理臨時文件'''
self.closing.emit()
event.accept()
窗口控件布局
Qt的布局管理器非常的強(qiáng)大和方便,各種布局都可以相互嵌套。如果指定了stretch=1,那么此控件會根據(jù)布局的空間進(jìn)行自動調(diào)整長度或者高度(取決于是橫向布局還是縱向布局)。以下控件定義和布局是通過代碼實現(xiàn),未使用Qt界面設(shè)計工具,簡單的界面推薦直接用代碼定義。
def _createWidgets(self):
'''創(chuàng)建窗口部件'''
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('排序依據(jù)')
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)
連接信號和槽函數(shù)
PyQt的信號和槽函數(shù)的連接非常簡潔方便,不同于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)
讀取配置文件
根據(jù)指定路徑和文件讀取配置,如果文件不存在則創(chuàng)建新的配置文件,用于記錄當(dāng)前使用的掃描目錄和播放器的路徑,這樣下次運行程序時無需重新添加路徑。
def loadConfig(self):
'''導(dǎo)入配置數(shù)據(jù)'''
self.config = ConfigObj(self.configFile, encoding='utf-8')
try:
self.dirs = self.config['程序設(shè)置']['掃描路徑']
self.dirList.addItems(self.dirs)
self.player.setText(self.config['程序設(shè)置']['播放器路徑'])
except KeyError:
self.config['程序設(shè)置'] = {}
self.config['程序設(shè)置']['掃描路徑'] = []
self.config['程序設(shè)置']['播放器路徑'] = ''
self.dirs = self.config['程序設(shè)置']['掃描路徑']
總體而言,本程序還是比較簡單的,基本實現(xiàn)了大器的需求。還有一點可以改進(jìn)的是,由于掃描文件比較多時可能耗時比較長,程序界面會有幾秒時間顯示程序無響應(yīng),影響使用體驗。可以將這部分另開一個線程處理,處理完再觸發(fā)信號通知播放器播放文件。由于文章篇幅有限,未貼出全部代碼,需要完整代碼的可以關(guān)注后私信大器。
我是大器,正在建立自己的知識庫,并將這些經(jīng)驗分享給你,請關(guān)注我,一起交流學(xué)習(xí)。