Add segment_time
This commit is contained in:
1 parent
3e3b35f75c
commit
ea1445befb
5 files changed
+208
-179
No files matched your search
+13
-11
@@ -19,30 +19,32 @@ class DownloadBase:
|
||||
# -c copy -bsf:a aac_adtstoasc -movflags +faststart output.mp4
|
||||
self.raw_stream_url = None
|
||||
self.opt_args = []
|
||||
|
||||
self.default_output_args = [
|
||||
'-bsf:a', 'aac_adtstoasc',
|
||||
]
|
||||
if config.get('segment_time'):
|
||||
self.default_output_args += \
|
||||
['-segment_time', f"{config.get('segment_time') if config.get('segment_time') else '00:50:00'}"]
|
||||
else:
|
||||
self.default_output_args += \
|
||||
['-fs', f"{config.get('file_size') if config.get('file_size') else '2621440000'}"]
|
||||
self.default_input_args = ['-headers', ''.join('%s: %s\r\n' % x for x in fake_headers.items()),
|
||||
'-reconnect_streamed', '1', '-reconnect_delay_max', '20', '-rw_timeout', '20000000']
|
||||
if config.get('file_size'):
|
||||
self.default_type_args = ['-fs', f"{config.get('file_size') if config.get('file_size') else '2621440000'}"]
|
||||
self.default_type_num = 1
|
||||
elif config.get('segment_time'):
|
||||
self.default_type_args = ['-segment_time', f"{config.get('segment_time') if config.get('segment_time') else '00:50:00'}"]
|
||||
self.default_type_num = 2
|
||||
|
||||
def check_stream(self):
|
||||
logger.debug(self.fname)
|
||||
raise NotImplementedError()
|
||||
|
||||
def download(self, filename):
|
||||
if self.default_type_num == 1:
|
||||
typenum = [f'{filename}.part']
|
||||
elif self.default_type_num == 2:
|
||||
typenum = ['-f', 'segment', f'{self.file_name}-%03d.{self.suffix}']
|
||||
args = ['ffmpeg', '-y', *self.default_input_args,
|
||||
'-i', self.raw_stream_url, *self.default_output_args, *self.opt_args,
|
||||
'-c', 'copy', '-f', self.suffix, *self.default_type_args, *typenum]
|
||||
'-c', 'copy', '-f', self.suffix]
|
||||
if config.get('segment_time'):
|
||||
args += ['-f', 'segment', f'{self.fname}-%03d.{self.suffix}']
|
||||
else:
|
||||
args += [f'{filename}.part']
|
||||
|
||||
proc = subprocess.Popen(args, stdin=subprocess.PIPE)
|
||||
try:
|
||||
retval = proc.wait()
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
|
||||
import selenium.common
|
||||
from PIL import Image
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.action_chains import ActionChains
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support import expected_conditions as ec
|
||||
from selenium.webdriver.support.wait import WebDriverWait
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
from biliup import Plugin, config
|
||||
from ..engine.upload import UploadBase, logger
|
||||
from .slider import slider_cracker
|
||||
|
||||
|
||||
@Plugin.upload("bilibili")
|
||||
@@ -201,4 +204,149 @@ class BiliChrome(UploadBase):
|
||||
'//*[@class="upload-v2-container"]/div[2]/div[3]/div[1]/div[12]/div[2]/div/textarea')
|
||||
text_2.send_keys('职业选手直播第一视角录像。这个自动录制上传的小程序开源在Github:'
|
||||
'http://t.cn/RgapTpf(或者在Github搜索ForgQi)\n'
|
||||
'交流群:837362626')
|
||||
'交流群:837362626')
|
||||
|
||||
class slider_cracker(object):
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.driver.maximize_window() # 最大化窗口
|
||||
self.driver.set_window_size(1024, 768)
|
||||
self.fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'true_image.png')
|
||||
|
||||
def get_true_image(self, slider_xpath=r'//*[@id="gc-box"]/div/div[3]/div[1]'):
|
||||
# element = WebDriverWait(self.driver, 50).until(EC.element_to_be_clickable((By.XPATH, slider_xpath)))
|
||||
element = WebDriverWait(self.driver, 50).until(
|
||||
EC.element_to_be_clickable((By.CLASS_NAME, "geetest_slider_button")))
|
||||
ActionChains(self.driver).move_to_element(element).perform() # 鼠标移动到滑动框以显示图片
|
||||
js = 'document.querySelector("body > div.geetest_panel.geetest_wind ' \
|
||||
'> div.geetest_panel_box.geetest_no_logo.geetest_panelshowslide ' \
|
||||
'> div.geetest_panel_next > div > div.geetest_wrap > div.geetest_widget ' \
|
||||
'> div > a > div.geetest_canvas_img.geetest_absolute > canvas").' \
|
||||
'style.display = "%s";'
|
||||
self.driver.execute_script(js % "inline")
|
||||
time.sleep(1)
|
||||
true_image = self.get_img(self.fn)
|
||||
self.driver.execute_script(js % "none")
|
||||
return true_image
|
||||
|
||||
def get_img(self, img_name, img_xpath=r'//*[@id="gc-box"]/div/div[1]/div[2]/div[1]/a[2]'): # 260*116
|
||||
fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'slider_screenshot.png')
|
||||
|
||||
screen_shot = self.driver.save_screenshot(fn)
|
||||
# image_element = self.driver.find_element_by_xpath(img_xpath)
|
||||
image_element = self.driver.find_element_by_class_name(r'geetest_window')
|
||||
left = image_element.location['x']
|
||||
top = image_element.location['y'] # selenium截图并获取验证图片location后将其截出保存
|
||||
right = image_element.location['x'] + image_element.size['width']
|
||||
bottom = image_element.location['y'] + image_element.size['height']
|
||||
image = Image.open(fn)
|
||||
image = image.crop((left, top, right, bottom))
|
||||
image.save(img_name)
|
||||
return image
|
||||
|
||||
def analysis(self, true_image, knob_xpath=r'//*[@id="gc-box"]/div/div[3]/div[2]'):
|
||||
fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img2.png')
|
||||
img1 = Image.open(self.fn)
|
||||
# slider_element = self.driver.find_element_by_xpath(knob_xpath)
|
||||
slider_element = self.driver.find_element_by_class_name("geetest_slider_button")
|
||||
ActionChains(self.driver).click_and_hold(slider_element).perform() # 点击滑块后截取残缺图
|
||||
time.sleep(1)
|
||||
img2 = self.get_img(fn)
|
||||
img1_width, img1_height = img1.size
|
||||
img2_width, img2_height = img2.size
|
||||
left = 0
|
||||
flag = False
|
||||
|
||||
for i in range(69, img1_width): # 遍历x>65的像素点(x<65是拼图块)
|
||||
for j in range(0, img1_height):
|
||||
if not self.is_pixel_equal(img1, img2, i, j):
|
||||
left = i
|
||||
flag = True
|
||||
break
|
||||
if flag:
|
||||
break
|
||||
if left >= 73:
|
||||
left = left - 3 # 误差纠正
|
||||
else:
|
||||
left = left
|
||||
return left
|
||||
|
||||
def is_pixel_equal(self, img1, img2, x, y): # 通过比较俩图片像素点RGB值差值判断是否为缺口
|
||||
pix1 = img1.load()[x, y]
|
||||
pix2 = img2.load()[x, y]
|
||||
if (abs(pix1[0] - pix2[0] < 60) and abs(pix1[1] - pix2[1] < 60) and abs(pix1[2] - pix2[2] < 60)):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_track(self, distance):
|
||||
"""
|
||||
根据偏移量获取移动轨迹
|
||||
:param distance: 偏移量
|
||||
:return: 移动轨迹
|
||||
"""
|
||||
# 移动轨迹
|
||||
track = []
|
||||
# 当前位移
|
||||
current = 0
|
||||
# 减速阈值
|
||||
mid = distance * 4 / 5
|
||||
# 计算间隔
|
||||
t = 0.2
|
||||
# 初速度
|
||||
v = 0
|
||||
|
||||
while current < distance:
|
||||
if current < mid:
|
||||
# 加速度为正2
|
||||
a = 2
|
||||
else:
|
||||
# 加速度为负3
|
||||
a = -3
|
||||
# 初速度v0
|
||||
v0 = v
|
||||
# 当前速度v = v0 + at
|
||||
v = v0 + a * t
|
||||
# 移动距离x = v0t + 1/2 * a * t^2
|
||||
move = v0 * t + 1 / 2 * a * t * t
|
||||
# 当前位移
|
||||
current += move
|
||||
# 加入轨迹
|
||||
track.append(round(move))
|
||||
# print(track)
|
||||
#
|
||||
# print(sum(track))
|
||||
track.append(distance - sum(track))
|
||||
# print(track)
|
||||
# print(sum(track))
|
||||
return track
|
||||
|
||||
def move_to_gap(self, slider, track):
|
||||
"""
|
||||
拖动滑块到缺口处
|
||||
:param slider: 滑块
|
||||
:param track: 轨迹
|
||||
:return:
|
||||
"""
|
||||
ActionChains(self.driver).click_and_hold(slider).perform()
|
||||
for x in track:
|
||||
ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=random.uniform(-5, 2)).perform()
|
||||
time.sleep(0.5)
|
||||
ActionChains(self.driver).release().perform()
|
||||
|
||||
def crack(self):
|
||||
true_image = self.get_true_image()
|
||||
x_offset = self.analysis(true_image)
|
||||
print(x_offset)
|
||||
|
||||
track = self.get_track(x_offset)
|
||||
knob_element = WebDriverWait(self.driver, 50).until(
|
||||
EC.element_to_be_clickable((By.XPATH, r'/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]')))
|
||||
self.move_to_gap(knob_element, track)
|
||||
|
||||
# fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'result0.png')
|
||||
# fn1 = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'result1.png')
|
||||
# time.sleep(0.02)
|
||||
# screen_shot = self.driver.save_screenshot(fn)
|
||||
# time.sleep(2)
|
||||
# screen_shot = self.driver.save_screenshot(fn1)
|
||||
@@ -1,5 +1,8 @@
|
||||
from ykdl.common import url_to_module
|
||||
import random
|
||||
|
||||
import requests
|
||||
|
||||
from . import match1, logger
|
||||
from ..engine.decorators import Plugin
|
||||
from ..engine.download import DownloadBase
|
||||
|
||||
@@ -10,12 +13,43 @@ class Bilibili(DownloadBase):
|
||||
super().__init__(fname, url, suffix)
|
||||
|
||||
def check_stream(self):
|
||||
site, url = url_to_module(self.url)
|
||||
try:
|
||||
info = site.parser(url)
|
||||
except AssertionError:
|
||||
rid = match1(self.url, r'/(\d+)')
|
||||
api1_data = requests.get(f"https://api.live.bilibili.com/room/v1/Room/room_init?id={rid}").json()
|
||||
if api1_data['code'] == 0:
|
||||
vid = api1_data['data']['room_id']
|
||||
else:
|
||||
logger.info('Get room ID from API failed: %s', api1_data['msg'])
|
||||
vid = rid
|
||||
api2_data = requests.get(f"https://api.live.bilibili.com/room/v1/Room/get_info?room_id={vid}").json()
|
||||
if api2_data['code'] != 0:
|
||||
logger.debug(api2_data['msg'])
|
||||
return False
|
||||
stream_id = info.stream_types[0]
|
||||
urls = info.streams[stream_id]['src']
|
||||
self.raw_stream_url = urls[0]
|
||||
api2_data = api2_data['data']
|
||||
if api2_data['live_status'] != 1:
|
||||
logger.debug(api2_data['msg'])
|
||||
return False
|
||||
title = api2_data['title']
|
||||
api3_data = \
|
||||
requests.get(f"https://api.live.bilibili.com/live_user/v1/UserInfo/get_anchor_in_room?roomid={vid}").json()
|
||||
if api3_data['code'] == 0:
|
||||
artist = api3_data['data']['info']['uname']
|
||||
title = '{} - {}'.format(title, artist)
|
||||
logger.debug(title)
|
||||
params = {
|
||||
'https_url_req': 1,
|
||||
'cid': vid,
|
||||
'platform': 'web',
|
||||
'qn': 10000,
|
||||
'ptype': '16'
|
||||
}
|
||||
data = requests.get("https://api.live.bilibili.com/xlive/web-room/v1/playUrl/playUrl", params=params).json()
|
||||
if data['code'] != 0:
|
||||
logger.debug(data['msg'])
|
||||
return False
|
||||
data = data['data']
|
||||
qlt = data['current_qn']
|
||||
aqlts = {x['qn']: x['desc'] for x in data['quality_description']}
|
||||
logger.debug(qlt)
|
||||
logger.debug(aqlts)
|
||||
self.raw_stream_url = random.choice(data['durl'])['url']
|
||||
return True
|
||||
@@ -1,155 +0,0 @@
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
|
||||
from PIL import Image
|
||||
from selenium.webdriver.common.action_chains import ActionChains
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
|
||||
class slider_cracker(object):
|
||||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
self.driver.maximize_window() # 最大化窗口
|
||||
self.driver.set_window_size(1024, 768)
|
||||
self.fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'true_image.png')
|
||||
|
||||
def get_true_image(self, slider_xpath=r'//*[@id="gc-box"]/div/div[3]/div[1]'):
|
||||
# element = WebDriverWait(self.driver, 50).until(EC.element_to_be_clickable((By.XPATH, slider_xpath)))
|
||||
element = WebDriverWait(self.driver, 50).until(
|
||||
EC.element_to_be_clickable((By.CLASS_NAME, "geetest_slider_button")))
|
||||
ActionChains(self.driver).move_to_element(element).perform() # 鼠标移动到滑动框以显示图片
|
||||
js = 'document.querySelector("body > div.geetest_panel.geetest_wind ' \
|
||||
'> div.geetest_panel_box.geetest_no_logo.geetest_panelshowslide ' \
|
||||
'> div.geetest_panel_next > div > div.geetest_wrap > div.geetest_widget ' \
|
||||
'> div > a > div.geetest_canvas_img.geetest_absolute > canvas").' \
|
||||
'style.display = "%s";'
|
||||
self.driver.execute_script(js % "inline")
|
||||
time.sleep(1)
|
||||
true_image = self.get_img(self.fn)
|
||||
self.driver.execute_script(js % "none")
|
||||
return true_image
|
||||
|
||||
def get_img(self, img_name, img_xpath=r'//*[@id="gc-box"]/div/div[1]/div[2]/div[1]/a[2]'): # 260*116
|
||||
fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'slider_screenshot.png')
|
||||
|
||||
screen_shot = self.driver.save_screenshot(fn)
|
||||
# image_element = self.driver.find_element_by_xpath(img_xpath)
|
||||
image_element = self.driver.find_element_by_class_name(r'geetest_window')
|
||||
left = image_element.location['x']
|
||||
top = image_element.location['y'] # selenium截图并获取验证图片location后将其截出保存
|
||||
right = image_element.location['x'] + image_element.size['width']
|
||||
bottom = image_element.location['y'] + image_element.size['height']
|
||||
image = Image.open(fn)
|
||||
image = image.crop((left, top, right, bottom))
|
||||
image.save(img_name)
|
||||
return image
|
||||
|
||||
def analysis(self, true_image, knob_xpath=r'//*[@id="gc-box"]/div/div[3]/div[2]'):
|
||||
fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'img2.png')
|
||||
img1 = Image.open(self.fn)
|
||||
# slider_element = self.driver.find_element_by_xpath(knob_xpath)
|
||||
slider_element = self.driver.find_element_by_class_name("geetest_slider_button")
|
||||
ActionChains(self.driver).click_and_hold(slider_element).perform() # 点击滑块后截取残缺图
|
||||
time.sleep(1)
|
||||
img2 = self.get_img(fn)
|
||||
img1_width, img1_height = img1.size
|
||||
img2_width, img2_height = img2.size
|
||||
left = 0
|
||||
flag = False
|
||||
|
||||
for i in range(69, img1_width): # 遍历x>65的像素点(x<65是拼图块)
|
||||
for j in range(0, img1_height):
|
||||
if not self.is_pixel_equal(img1, img2, i, j):
|
||||
left = i
|
||||
flag = True
|
||||
break
|
||||
if flag:
|
||||
break
|
||||
if left >= 73:
|
||||
left = left - 3 # 误差纠正
|
||||
else:
|
||||
left = left
|
||||
return left
|
||||
|
||||
def is_pixel_equal(self, img1, img2, x, y): # 通过比较俩图片像素点RGB值差值判断是否为缺口
|
||||
pix1 = img1.load()[x, y]
|
||||
pix2 = img2.load()[x, y]
|
||||
if (abs(pix1[0] - pix2[0] < 60) and abs(pix1[1] - pix2[1] < 60) and abs(pix1[2] - pix2[2] < 60)):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_track(self, distance):
|
||||
"""
|
||||
根据偏移量获取移动轨迹
|
||||
:param distance: 偏移量
|
||||
:return: 移动轨迹
|
||||
"""
|
||||
# 移动轨迹
|
||||
track = []
|
||||
# 当前位移
|
||||
current = 0
|
||||
# 减速阈值
|
||||
mid = distance * 4 / 5
|
||||
# 计算间隔
|
||||
t = 0.2
|
||||
# 初速度
|
||||
v = 0
|
||||
|
||||
while current < distance:
|
||||
if current < mid:
|
||||
# 加速度为正2
|
||||
a = 2
|
||||
else:
|
||||
# 加速度为负3
|
||||
a = -3
|
||||
# 初速度v0
|
||||
v0 = v
|
||||
# 当前速度v = v0 + at
|
||||
v = v0 + a * t
|
||||
# 移动距离x = v0t + 1/2 * a * t^2
|
||||
move = v0 * t + 1 / 2 * a * t * t
|
||||
# 当前位移
|
||||
current += move
|
||||
# 加入轨迹
|
||||
track.append(round(move))
|
||||
# print(track)
|
||||
#
|
||||
# print(sum(track))
|
||||
track.append(distance - sum(track))
|
||||
# print(track)
|
||||
# print(sum(track))
|
||||
return track
|
||||
|
||||
def move_to_gap(self, slider, track):
|
||||
"""
|
||||
拖动滑块到缺口处
|
||||
:param slider: 滑块
|
||||
:param track: 轨迹
|
||||
:return:
|
||||
"""
|
||||
ActionChains(self.driver).click_and_hold(slider).perform()
|
||||
for x in track:
|
||||
ActionChains(self.driver).move_by_offset(xoffset=x, yoffset=random.uniform(-5, 2)).perform()
|
||||
time.sleep(0.5)
|
||||
ActionChains(self.driver).release().perform()
|
||||
|
||||
def crack(self):
|
||||
true_image = self.get_true_image()
|
||||
x_offset = self.analysis(true_image)
|
||||
print(x_offset)
|
||||
|
||||
track = self.get_track(x_offset)
|
||||
knob_element = WebDriverWait(self.driver, 50).until(
|
||||
EC.element_to_be_clickable((By.XPATH, r'/html/body/div[2]/div[2]/div[6]/div/div[1]/div[2]/div[2]')))
|
||||
self.move_to_gap(knob_element, track)
|
||||
|
||||
# fn = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'result0.png')
|
||||
# fn1 = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'result1.png')
|
||||
# time.sleep(0.02)
|
||||
# screen_shot = self.driver.save_screenshot(fn)
|
||||
# time.sleep(2)
|
||||
# screen_shot = self.driver.save_screenshot(fn1)
|
||||
+2
-2
@@ -11,10 +11,10 @@ user: # 在填了cookies的情况下优先使用cookies上传,如需使用用
|
||||
lines: AUTO
|
||||
# 单文件并发上传数,未达到带宽上限时增大此值可提高上传速度
|
||||
threads: 3
|
||||
# 录像单文件大小限制,单位Byte,超过此大小分段下载,如需使用时间分段请注释此字段
|
||||
# 录像单文件大小限制,单位Byte,超过此大小分段下载
|
||||
file_size: 2621440000
|
||||
# 录像单文件时间限制,格式'00:00:00'(时分秒),超过此大小分段下载,如需使用大小分段请注释此字段
|
||||
segment_time: '00:50:00'
|
||||
#segment_time: '00:50:00'
|
||||
|
||||
streamers:
|
||||
星际2INnoVation吕布卫星人族天梯第一视角:
|
||||
|
||||
Reference in new issue
Block a user