django manage 啓動任務,初始化PyQT5搭建的服務平臺前端
class Command(BaseCommand):
def handle(self, *args, **options):
app = QApplication(sys.argv)
win = MainWindow()
app.exit(app.exec_())
參數(init_arguments)、搭載gearmanworker的(init_worker),WebDriver(init_driver),任務加載定時器(init_timer)python
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.root_path = Path(__file__).parent
self.setWindowTitle('易哈佛')
self.init_arguments()
self.init_driver()
self.init_worker()
self.init_timer()
QThread中註冊gearmanworker到gearman服務器,接收到的任務都存入任務池中數據庫
class WebWorker(QThread):
def __init__(self):
super().__init__()
self.worker = None
self.task_pool = []
def run(self):
self.worker = self.init_worker()
self.worker.work()
def init_worker(self):
convert_worker = JsonWorker(['c.ehafolive.com:4730', ])
convert_worker.set_client_id('capture')
convert_worker.register_task('screencapture', self.task_listener)
return convert_worker
@property
def worker_(self) -> JsonWorker:
return self.worker
def task_listener(self, gearman_worker, request):
self.task_pool.append(request.data)
任務加載定時器會每五秒調起一次任務加載功能。任務加載功能必須在任務池存在任務,而且當前平臺沒有任務時纔會執行任務加載,爲了不併發致使任務衝突,因此任務加載功能單線程執行。django
def load_url(self):
# 接受視頻錄製任務
self.lock.acquire()
if self.WebWorker.task_pool and self.usable:
self.usable = False
info = self.WebWorker.task_pool.pop(0)
self.video_layout = info.get('layout')
self.h_id = int(info.get('pk'))
print(self.video_layout, self.h_id)
self.driver_load()
self.lock.release()
一但容許任務加載從任務池中提取一個任務,提取出數據,調用瀏覽器加載功能,瀏覽器加載功能是經過加載定製的頁面,並經過設置瀏覽器的位置和寬高來大體肯定後續須要錄製的區域,在頁面加載完畢後,須要初始化錄製動做監控定時器,並初始化一個視頻對象,後續的進度實時更新依賴於初始化的視頻對象後端
def driver_load(self):
# 設置瀏覽器位置及窗口大小,加載url
url = "https://xxxx?pk=%s" % self.h_id
if self.video_layout == 'vertical':
width, height = 1000, 1446
else:
width, height = 1373, 800
self.set_driver(width, height)
self.driver.get(url)
self.init_cmd_timer()
self.init_video_instance()
經過對任務的橫版和豎版的斷定,將瀏覽器位置調整到合適的區域,並設置相應的寬高瀏覽器
def set_driver(self, width, height):
if self.video_layout == 'vertical':
left, top = self.chose_screen(768, 1366)
else:
left, top = self.chose_screen(1366, 768)
self.screen_width = width - self.window_offset_x
self.screen_height = height - self.window_offset_y
self.driver.set_window_position(left - self.window_offset_x, top)
self.driver.set_window_size(width, height)
由於任務可能重複下發,所以視頻對象可能早有存在,因此對於已存在的對象只需局部更新數據,不須要另外建立ruby
def init_video_instance(self):
from article.models import Article
from points.models import Video
queryset = Article.objects.filter(id=self.h_id)
if not queryset.exists():
return
article = queryset.first()
data = {
'size': 0,
'process': 0,
'course': self.h_id,
'user': article.user,
'layout': article.layout,
'duration': article.duration,
}
video, _ = Video.objects.update_or_create(
defaults=data,
course=self.h_id,
)
self.video_id = video.id
在上述任務加載完畢,而且初始化完成後,錄製動做監控定時器將迎來第一次的超時事件,超時事件將檢測相應的標籤值,在肯定標籤值已經改變並由後端完成修改後,將調起相應的功能服務器
#錄製動做監控定時器超時調起事件
def monitor_cmd(self):
if self.set_monitor_tag_value('click'):
self.mouse_click_event()
if self.set_monitor_tag_value('start'):
self.start_capture()
if self.set_monitor_tag_value('stop'):
self.stop_capture()
#監測動做對應的標籤文本值,發生變化則進行修改
def set_monitor_tag_value(self, tag):
lock = Lock()
lock.acquire()
_, value = self.get_monitor_tag_value(tag)
if value == 'false':
lock.release()
return False
attributeName = 'textContent'
js = "{}.{}={}".format(tag, attributeName, 'false')
self.driver.execute_script(js)
print('set element value %s' % tag)
lock.release()
return True
由後端在前端肯定url加載完畢後調起,實現模擬點擊事件,通知前端開始播放動畫和音頻架構
def mouse_click_event(self):
# 點擊命令執行,開始播放
self.driver.find_element_by_id('click-element').click()
start標籤值的改變在前端肯定動畫和音頻已經開始播放後修改,當後端檢測到文本值發生改變後,檢測錄製區域是否超出屏幕、初始化錄製視頻進程、初始化錄製進度更新定時器,開始屏幕錄製併發
def start_capture(self):
# 開始錄製視頻
if not self.verify_capture_size():
return self.unlocked()
capture_cmd = self.init_capture_cmd()
self.process = RecordProcess()
self.process.start(capture_cmd)
self.init_process_timer()
print(capture_cmd)
start標籤值的改變在前端肯定動畫和音頻已經播放完畢後修改,當後端檢測到文本值發生改變後,調起中止視頻錄製功能,關閉錄製動做監控定時器,關閉進度更新定時器,待錄製視頻進程徹底結束,視頻文件生成後調起上傳視頻
def stop_capture(self):
# 中止錄製視頻
if not hasattr(self, 'process'): return
self.process.quit()
self.process_timer.stop()
self.monitor_timer.stop()
self.process.finished.connect(self.upload_video)
上傳視頻到cos,上傳完成後,解除任務正在執行的標誌,等待下一次任務加載,同時調起頂頂發送消息通知任務已經完成
def upload_video(self):
# 上傳視頻到數據庫
url = save_video(self.video_path, self.video_id)
self.usable = True
task_success(TASK, "path:%s" % url)
若是已經錄製過視頻,原視頻從cos刪除
def save_video(video_path, pk):
if not os.path.exists(video_path):
print('視頻轉錄異常', video_path)
return
f = open(video_path, 'rb')
url = upload_video(f.name, f)
f.seek(0)
size = len(f.read())
instance = Video.objects.get(id=pk)
if instance.url:
delete_from_cos(instance.url.url)
instance.url = url
instance.size = size
instance.process = 100
instance.save()
print(url, pk)
print('*' * 100)
f.close()
return url