mirror of
https://github.com/Geniusay/ChopperBot.git
synced 2026-06-08 02:17:32 +08:00
账号模块完成视频账号通道,视频发布模块重构视频发布架构,完成b站和抖音的视频发布
This commit is contained in:
4
.idea/compiler.xml
generated
4
.idea/compiler.xml
generated
@@ -38,7 +38,7 @@
|
||||
</component>
|
||||
<component name="JavacSettings">
|
||||
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
|
||||
<module name="ChopperBot" options="" />
|
||||
<module name="ChopperBot" options="-parameters" />
|
||||
<module name="chopperbot-account" options="-parameters" />
|
||||
<module name="chopperbot-barrage" options="-parameters" />
|
||||
<module name="chopperbot-common" options="-parameters" />
|
||||
@@ -53,4 +53,4 @@
|
||||
<module name="chopperbot-test" options="-parameters" />
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
||||
</project>
|
||||
|
||||
@@ -114,5 +114,9 @@
|
||||
<artifactId>okio</artifactId>
|
||||
<version>3.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.example.core.init;
|
||||
|
||||
import org.example.constpool.ModuleName;
|
||||
import org.example.constpool.PluginName;
|
||||
import org.example.core.guard.VideoPushGuard;
|
||||
import org.example.init.CommonInitMachine;
|
||||
import org.example.plugin.CommonPlugin;
|
||||
import org.example.plugin.annotation.Plugin;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author welsir
|
||||
* @Date 2023/10/13 19:09
|
||||
*/
|
||||
@Plugin(moduleName = ModuleName.ACCOUNT,
|
||||
pluginName = PluginName.VIDEO_PUSH_PLUGIN,
|
||||
pluginName_CN = "视频推送插件",
|
||||
pluginDescription = "用于将切片好的视频自动推送至对应类型账号",
|
||||
needPlugin = {},
|
||||
pluginClass= VideoPushGuard.class )
|
||||
public class VideoPushGuardInitMachine extends CommonInitMachine {
|
||||
public VideoPushGuardInitMachine(List<String> needPlugins, boolean isAutoStart, String moduleName, String name, Class<? extends CommonPlugin> clazz) {
|
||||
super(needPlugins, isAutoStart, moduleName, name, clazz);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import org.example.core.factory.PlatformOperation;
|
||||
import org.example.mapper.AccountMapper;
|
||||
|
||||
import org.example.core.pojo.Account;
|
||||
import org.junit.Test;
|
||||
import org.openqa.selenium.By;
|
||||
import org.openqa.selenium.Cookie;
|
||||
import org.openqa.selenium.WebElement;
|
||||
@@ -50,15 +51,17 @@ public class Bilibili implements PlatformOperation {
|
||||
Thread.sleep(3000L);
|
||||
WebElement avator = confirmLogin.findElement(By.xpath("/html/body/div[2]/div[2]/div[1]/div[1]/ul[2]/li[1]"));
|
||||
if(avator!=null){
|
||||
Account user = new Account();
|
||||
user.setCookies(cookies.toString());
|
||||
user.setPlatformId(1);
|
||||
user.setUsername(username);
|
||||
user.setPassword(password);
|
||||
accountMapper.insert(user);
|
||||
// Account user = new Account();
|
||||
// user.setCookies(cookies.toString());
|
||||
// user.setPlatformId(1);
|
||||
// user.setUsername(username);
|
||||
// user.setPassword(password);
|
||||
// accountMapper.insert(user);
|
||||
System.out.println("登陆成功!");
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.JSONReader;
|
||||
import org.example.core.factory.PlatformOperation;
|
||||
import org.example.mapper.AccountMapper;
|
||||
import org.example.core.pojo.Account;
|
||||
import org.example.mapper.AccountMapper;
|
||||
import org.openqa.selenium.Cookie;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -15,6 +15,8 @@ import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static org.example.util.GetScriptPath.getScriptPath;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author welsir
|
||||
@@ -23,7 +25,9 @@ import java.util.List;
|
||||
public class Douyin implements PlatformOperation {
|
||||
|
||||
final String FILE_PATH = "D:\\Douyincookies.txt";
|
||||
final String LOGIN_SCRIPT_PATH = "org/example/core/script/douyin/Login.py";
|
||||
|
||||
final String CONFIRM_LOGIN_SCRIPT_PATH = "org/example/core/script/douyin/ConfirmLogin.py";
|
||||
@Resource
|
||||
AccountMapper accountMapper;
|
||||
@Override
|
||||
@@ -31,41 +35,49 @@ public class Douyin implements PlatformOperation {
|
||||
try {
|
||||
List<String> command = new ArrayList<>();
|
||||
command.add("python"); // Python 解释器
|
||||
command.add("D:\\code\\gitHubProject\\Text_select_captcha\\DouyinLogin.py"); // 要运行的 Python 脚本文件名
|
||||
command.add(getScriptPath(LOGIN_SCRIPT_PATH).toString()); // 要运行的 Python 脚本文件名
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||
Process process = processBuilder.start();
|
||||
List<String> command1 = new ArrayList<>();
|
||||
command1.add("python"); // Python 解释器
|
||||
command1.add("D:\\code\\gitHubProject\\Text_select_captcha\\Douyin.py");
|
||||
ProcessBuilder processBuilder1 = new ProcessBuilder(command1);
|
||||
Process process1 = processBuilder1.start();
|
||||
// 获取Python脚本的标准输出流
|
||||
InputStream inputStream1 = process1.getInputStream();
|
||||
BufferedReader reader1 = new BufferedReader(new InputStreamReader(inputStream1));
|
||||
int backCode = process.waitFor();
|
||||
System.out.println(backCode);
|
||||
if(backCode==0){
|
||||
List<String> command1 = new ArrayList<>();
|
||||
command1.add("python"); // Python 解释器
|
||||
command1.add(getScriptPath(CONFIRM_LOGIN_SCRIPT_PATH).toString());
|
||||
ProcessBuilder processBuilder1 = new ProcessBuilder(command1);
|
||||
Process process1 = processBuilder1.start();
|
||||
// 获取Python脚本的标准输出流
|
||||
InputStream inputStream1 = process1.getInputStream();
|
||||
BufferedReader reader1 = new BufferedReader(new InputStreamReader(inputStream1));
|
||||
|
||||
String line1;
|
||||
StringBuilder callBack = new StringBuilder();
|
||||
String line1;
|
||||
StringBuilder callBack = new StringBuilder();
|
||||
|
||||
// 读取Python脚本的输出
|
||||
while ((line1 = reader1.readLine()) != null) {
|
||||
callBack.append(line1).append("\n");
|
||||
}
|
||||
System.out.println("验证flag:" + callBack);
|
||||
// 等待Python脚本执行完成
|
||||
int exitCode = process1.waitFor();
|
||||
if (exitCode == 0) {
|
||||
System.out.println("抖音登录成功!");
|
||||
Account account = new Account();
|
||||
account.setUsername(username);
|
||||
account.setCookies(loadCookiesFromFile(FILE_PATH).toString());
|
||||
account.setPlatformId(2);
|
||||
accountMapper.insert(account);
|
||||
// 读取Python脚本的输出
|
||||
while ((line1 = reader1.readLine()) != null) {
|
||||
callBack.append(line1).append("\n");
|
||||
}
|
||||
System.out.println("验证flag:" + callBack);
|
||||
// 等待Python脚本执行完成
|
||||
int exitCode = process1.waitFor();
|
||||
if (exitCode == 0) {
|
||||
System.out.println("抖音登录成功!");
|
||||
Account account = new Account();
|
||||
account.setUsername(username);
|
||||
account.setCookies(loadCookiesFromFile(FILE_PATH).toString());
|
||||
account.setPlatformId(2);
|
||||
accountMapper.insert(account);
|
||||
}
|
||||
}else{
|
||||
throw new RuntimeException("登陆失败!");
|
||||
}
|
||||
} catch (IOException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
public HashSet<Cookie> loadCookiesFromFile (String filePath) throws IOException {
|
||||
|
||||
//从本地文件获取cookie
|
||||
private HashSet<Cookie> loadCookiesFromFile (String filePath) throws IOException {
|
||||
HashSet<Cookie> cookies = new HashSet<>();
|
||||
try (FileReader fileReader = new FileReader(filePath)) {
|
||||
JSONReader reader = new JSONReader(fileReader);
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
package org.example.core.pojo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author welsir
|
||||
* @Date 2023/10/13 19:02
|
||||
*/
|
||||
|
||||
@Data
|
||||
public class VideoToPublish {
|
||||
|
||||
private String videoPath;
|
||||
private String cookies;
|
||||
private PlatformType platform;
|
||||
private String coverPath;
|
||||
private String devicePath;
|
||||
private String tag;
|
||||
private String title;
|
||||
private String type;
|
||||
|
||||
private VideoToPublish(Buider buider){
|
||||
this.videoPath = buider.videoPath;
|
||||
this.cookies = buider.cookies;
|
||||
this.coverPath = buider.coverPath;
|
||||
this.devicePath = buider.devicePath;
|
||||
this.tag = buider.tag;
|
||||
this.title = buider.title;
|
||||
this.type = buider.type;
|
||||
}
|
||||
|
||||
public static class Buider{
|
||||
private String videoPath;
|
||||
private String cookies;
|
||||
private PlatformType platform;
|
||||
private String coverPath;
|
||||
private String devicePath;
|
||||
private String tag;
|
||||
private String title;
|
||||
private String type;
|
||||
|
||||
public Buider(String videoPath,String cookies,int platform){
|
||||
this.videoPath = videoPath;
|
||||
this.cookies = cookies;
|
||||
this.platform = PlatformType.getPlatform(platform);
|
||||
}
|
||||
|
||||
public Buider setCoverPath(String coverPath) {
|
||||
this.coverPath = coverPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Buider setDevicePath(String devicePath) {
|
||||
this.devicePath = devicePath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Buider setTag(String tag) {
|
||||
this.tag = tag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Buider setTitle(String title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Buider setType(String type) {
|
||||
this.type = type;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getVideoPath() {
|
||||
return videoPath;
|
||||
}
|
||||
|
||||
public String getCookies() {
|
||||
return cookies;
|
||||
}
|
||||
|
||||
public String getCoverPath() {
|
||||
return coverPath;
|
||||
}
|
||||
|
||||
public String getDevicePath() {
|
||||
return devicePath;
|
||||
}
|
||||
|
||||
public String getTag() {
|
||||
return tag;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public VideoToPublish build(){
|
||||
return new VideoToPublish(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.wait import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
|
||||
class douyin(object):
|
||||
|
||||
def __init__(self):
|
||||
chrome_options = self.options()
|
||||
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
|
||||
# 解决报错,设置无界面运行
|
||||
chrome_options.add_argument('--no-sandbox')
|
||||
chrome_options.add_argument('--disable-dev-shm-usage')
|
||||
chrome_options.add_argument('window-size=1920x1280') # 指定浏览器分辨率
|
||||
chrome_options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug
|
||||
chrome_options.add_argument('--hide-scrollbars') # 隐藏滚动条, 应对一些特殊页面
|
||||
self.browser = webdriver.Chrome(chrome_options)
|
||||
self.wait = WebDriverWait(self.browser, 30)
|
||||
self.url = "https://www.douyin.com/"
|
||||
|
||||
def options(self):
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
return chrome_options
|
||||
|
||||
def click(self, xpath):
|
||||
self.wait.until(EC.presence_of_element_located(
|
||||
(By.XPATH, xpath))).click()
|
||||
|
||||
def loadCookie(self):
|
||||
f = open('D:\\Douyincookies.txt')
|
||||
cookies = json.loads(f.read())
|
||||
self.browser.get(self.url)
|
||||
self.browser.delete_all_cookies()
|
||||
for cookie in cookies:
|
||||
self.browser.add_cookie(cookie)
|
||||
|
||||
self.browser.implicitly_wait(10)
|
||||
time.sleep(2)
|
||||
self.browser.refresh()
|
||||
self.browser.get(self.url)
|
||||
userMsg = '/html/body/div[2]/div[1]/div[4]/div[2]/div[1]/header/div/div/div[2]/div/div/div[6]/div/a'
|
||||
loginFlag = self.browser.find_element(By.XPATH, userMsg)
|
||||
if not loginFlag is None:
|
||||
print("success")
|
||||
else:
|
||||
print("error")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
jd = douyin()
|
||||
jd.loadCookie()
|
||||
@@ -0,0 +1,47 @@
|
||||
import json
|
||||
import time
|
||||
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.wait import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
class dy(object):
|
||||
|
||||
def __init__(self):
|
||||
chrome_options = self.options()
|
||||
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
|
||||
# 解决报错,设置无界面运行
|
||||
chrome_options.add_argument('--no-sandbox')
|
||||
chrome_options.add_argument('--disable-dev-shm-usage')
|
||||
chrome_options.add_argument('window-size=1920x1280') # 指定浏览器分辨率
|
||||
chrome_options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug
|
||||
chrome_options.add_argument('--hide-scrollbars') # 隐藏滚动条, 应对一些特殊页面
|
||||
self.browser = webdriver.Chrome(chrome_options)
|
||||
self.wait = WebDriverWait(self.browser, 30)
|
||||
self.url = "https://www.douyin.com/"
|
||||
|
||||
def options(self):
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
return chrome_options
|
||||
|
||||
def click(self, xpath):
|
||||
self.wait.until(EC.presence_of_element_located(
|
||||
(By.XPATH, xpath))).click()
|
||||
|
||||
def saveCookie(self):
|
||||
# 打开浏览器
|
||||
self.browser.get(self.url)
|
||||
time.sleep(35)
|
||||
# 读取cook
|
||||
cook = self.browser.get_cookies()
|
||||
# 保存cook
|
||||
f = open('D:\\Douyincookies.txt', 'w')
|
||||
f.write(json.dumps(cook, ensure_ascii=True)) # 格式转化,这不管你是学的那种语言都必须要知道的
|
||||
f.close()
|
||||
print("success")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
jd = dy()
|
||||
jd.saveCookie()
|
||||
@@ -0,0 +1,19 @@
|
||||
package org.example.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author welsir
|
||||
* @Date 2023/10/15 20:43
|
||||
*/
|
||||
public class GetScriptPath {
|
||||
|
||||
public static Path getScriptPath(String path){
|
||||
// 构建绝对路径
|
||||
File scriptFile = new File(path);
|
||||
return Path.of(scriptFile.getAbsolutePath());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -39,31 +39,6 @@ public class BarrageEvent {
|
||||
private List<Barrage> barrages;
|
||||
private boolean isSort = false;
|
||||
|
||||
public BarrageEvent(String platform, String action, String liver, String date) {
|
||||
this.action = action;
|
||||
this.platform = platform;
|
||||
this.liver = liver;
|
||||
this.date = date;
|
||||
this.fileName = Paths.get(FileNameBuilder.buildBarrageFileName(liver,date)).toString();
|
||||
}
|
||||
|
||||
public BarrageEvent(String platform, String action, String liver, String date, List<Barrage> barrages) {
|
||||
this.action = action;
|
||||
this.platform = platform;
|
||||
this.liver = liver;
|
||||
this.date = date;
|
||||
this.barrages = barrages;
|
||||
this.fileName = Paths.get(FileNameBuilder.buildBarrageFileName(liver,date)).toString();
|
||||
}
|
||||
|
||||
public BarrageEvent(String platform, String action, String liver, String date, String fileName) {
|
||||
this.platform = platform;
|
||||
this.action = action;
|
||||
this.liver = liver;
|
||||
this.date = date;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
public String getBarrageFilePath(){
|
||||
if(platform==null||action==null){
|
||||
return fileName;
|
||||
@@ -71,6 +46,14 @@ public class BarrageEvent {
|
||||
return Paths.get(BarrageSaveFile.fileRoot(action,platform), fileName).toString();
|
||||
}
|
||||
|
||||
private BarrageEvent(Builder builder){
|
||||
this.action = builder.action;
|
||||
this.date = builder.date;
|
||||
this.fileName = builder.fileName;
|
||||
this.liver = builder.liver;
|
||||
this.platform = builder.platform;
|
||||
}
|
||||
|
||||
public List<Barrage> getBarrages() {
|
||||
if(barrages==null){
|
||||
try {
|
||||
@@ -87,4 +70,63 @@ public class BarrageEvent {
|
||||
}
|
||||
return barrages;
|
||||
}
|
||||
public static class Builder{
|
||||
private String platform;
|
||||
|
||||
private String action;
|
||||
private String liver;
|
||||
private String date;
|
||||
|
||||
private String fileName;
|
||||
|
||||
|
||||
public BarrageEvent build(){
|
||||
return new BarrageEvent(this);
|
||||
}
|
||||
|
||||
public Builder setPlatform(String platform){
|
||||
this.platform = platform;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setAction(String action){
|
||||
this.action = action;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setLiver(String liver){
|
||||
this.liver = liver;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setDate(String date){
|
||||
this.date = date;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setFilename(String fileName){
|
||||
this.fileName = fileName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getPlatform() {
|
||||
return platform;
|
||||
}
|
||||
|
||||
public String getAction() {
|
||||
return action;
|
||||
}
|
||||
|
||||
public String getLiver() {
|
||||
return liver;
|
||||
}
|
||||
|
||||
public String getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,5 +43,10 @@
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>chopperbot-account</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.example.api;
|
||||
|
||||
import org.example.core.factory.platformSelectionFactory;
|
||||
import org.example.core.pojo.VideoToPublish;
|
||||
import org.example.core.publisher.PlatformVideoPublisher;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author welsir
|
||||
* @Date 2023/10/13 17:14
|
||||
*/
|
||||
public class VedioPublishApi {
|
||||
|
||||
public static void publishVideo(VideoToPublish videoEntity){
|
||||
PlatformVideoPublisher publisher = platformSelectionFactory.creatPlatformPublisher(videoEntity.getPlatform().getId());
|
||||
publisher.publishVideo(videoEntity);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
package org.example.core.apiUrl;
|
||||
package org.example.core.constpool;
|
||||
|
||||
/**
|
||||
* @author dhx
|
||||
* @date 2023/9/25 21:01
|
||||
* @Description
|
||||
* @Author welsir
|
||||
* @Date 2023/10/13 20:07
|
||||
*/
|
||||
public class BilibiliApiUrl {
|
||||
public class BilibiliURL {
|
||||
|
||||
public final static String VIDEO_PREUPLOAD_URL = "https://member.bilibili.com/preupload?probe_version=20221109&upcdn=bda2&zone=cs&name=test.mp4&r=upos&profile=ugcfx%%2Fbup&ssl=0&version=2.14.0.0&build=2140000&size=%s&webVersion=2.14.0";
|
||||
|
||||
public final static String TXT_PREUPLOAD_URL= "https://member.bilibili.com/preupload?name=file_meta.txt&size=2000&r=upos&profile=fxmeta%2Fbup&ssl=0&version=2.14.0.0&build=2140000&webVersion=2.14.0";
|
||||
@@ -18,4 +20,5 @@ public class BilibiliApiUrl {
|
||||
public final static String COVER_UPLOAD_URL = "https://member.bilibili.com/x/vu/web/cover/up?t=";
|
||||
|
||||
public final static String SEND_MANUSCRIPT_URL = "https://member.bilibili.com/x/vu/web/add/v3?t=%s&csrf=%s";
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.example.core.factory;
|
||||
|
||||
import org.example.core.publisher.PlatformVideoPublisher;
|
||||
import org.example.core.publisher.impl.BilibiliVideoPublisher;
|
||||
import org.example.core.publisher.impl.DouyinVideoPublisher;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author welsir
|
||||
* @Date 2023/10/13 21:09
|
||||
*/
|
||||
public class platformSelectionFactory {
|
||||
public static PlatformVideoPublisher creatPlatformPublisher(int platformId) {
|
||||
switch (platformId){
|
||||
case 2:
|
||||
return new BilibiliVideoPublisher();
|
||||
case 3:
|
||||
return new DouyinVideoPublisher();
|
||||
default:
|
||||
throw new IllegalArgumentException("平台参数不正确!");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
package org.example.core.publisher;
|
||||
|
||||
import org.example.pojo.Uploader;
|
||||
import org.example.core.pojo.VideoToPublish;
|
||||
|
||||
/**
|
||||
* @author dhx
|
||||
* @date 2023/9/18 20:49
|
||||
*/
|
||||
public interface PlatformVideoPublisher<T extends Uploader> {
|
||||
void publishVideo(T uploader);
|
||||
public interface PlatformVideoPublisher {
|
||||
void publishVideo(VideoToPublish video);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ import org.apache.http.entity.ByteArrayEntity;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClients;
|
||||
import org.apache.http.message.BasicNameValuePair;
|
||||
import org.example.core.apiUrl.BilibiliApiUrl;
|
||||
import org.example.core.constpool.BilibiliURL;
|
||||
import org.example.core.pojo.VideoToPublish;
|
||||
import org.example.core.publisher.PlatformVideoPublisher;
|
||||
import org.example.exception.ChopperBotException;
|
||||
import org.example.pojo.BilibiliUploader;
|
||||
@@ -32,14 +33,15 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
* @author dhx
|
||||
* @date 2023/9/18 20:49
|
||||
*/
|
||||
public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUploader> {
|
||||
public class BilibiliVideoPublisher implements PlatformVideoPublisher {
|
||||
|
||||
@Override
|
||||
public void publishVideo(BilibiliUploader bilibiliUploader) {
|
||||
Map<String, String> header = bilibiliUploader.getHeader();
|
||||
String videoPath = bilibiliUploader.getVideoPath();
|
||||
String devicePath = bilibiliUploader.getDeviceVideoPath();
|
||||
String cookie = bilibiliUploader.getCookie();
|
||||
String coverPath = bilibiliUploader.getCoverPath();
|
||||
public void publishVideo(VideoToPublish video) {
|
||||
Map<String, String> header = new HashMap<>();
|
||||
String videoPath = video.getVideoPath();
|
||||
String devicePath = video.getDevicePath();
|
||||
String cookie = video.getCookies();
|
||||
String coverPath = video.getCoverPath();
|
||||
String csrf = CookieUtil.getParam(cookie,"bili_jct");
|
||||
if(csrf == null){
|
||||
throw new ChopperBotException("Cookie错误");
|
||||
@@ -48,9 +50,8 @@ public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUp
|
||||
if (filesize == -1) {
|
||||
throw new ChopperBotException("获取文件大小失败");
|
||||
}
|
||||
|
||||
//申请上传
|
||||
String res = HttpClientUtil.get(String.format(BilibiliApiUrl.VIDEO_PREUPLOAD_URL,filesize)
|
||||
String res = HttpClientUtil.get(String.format(BilibiliURL.VIDEO_PREUPLOAD_URL,filesize)
|
||||
, header);
|
||||
JSONObject mp4Obj = JSONObject.parseObject(res);
|
||||
String mp4_upos_uri = mp4Obj.getString("upos_uri");
|
||||
@@ -61,10 +62,10 @@ public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUp
|
||||
String auth = mp4Obj.getString("auth");
|
||||
|
||||
|
||||
String res2 = HttpClientUtil.get(BilibiliApiUrl.TXT_PREUPLOAD_URL, header);
|
||||
String res2 = HttpClientUtil.get(BilibiliURL.TXT_PREUPLOAD_URL, header);
|
||||
JSONObject txtObj = JSONObject.parseObject(res2);
|
||||
String meta_upos_uri = txtObj.getString("upos_uri");
|
||||
String preUploadUrl = String.format(BilibiliApiUrl.PREUPLOAD_URL, endpoint, mp4_upos_uri.substring(mp4_upos_uri.indexOf('/') + 1), put_query.substring(put_query.indexOf('&')), String.valueOf(filesize), chunk_size, meta_upos_uri, biz_id);
|
||||
String preUploadUrl = String.format(BilibiliURL.PREUPLOAD_URL, endpoint, mp4_upos_uri.substring(mp4_upos_uri.indexOf('/') + 1), put_query.substring(put_query.indexOf('&')), String.valueOf(filesize), chunk_size, meta_upos_uri, biz_id);
|
||||
Map<String, String> header2 = new HashMap<>();
|
||||
header2.put("X-Upos-Auth", auth);
|
||||
String res3 = HttpClientUtil.post(preUploadUrl, "{}", header2);
|
||||
@@ -78,7 +79,6 @@ public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUp
|
||||
} else {
|
||||
throw new ChopperBotException("分割视频失败");
|
||||
}
|
||||
|
||||
//上传视频
|
||||
for (int i = 1; i <= chunkNumber; i++) {
|
||||
long end = i == chunkNumber ? filesize : i * chunk_size;
|
||||
@@ -88,7 +88,7 @@ public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUp
|
||||
throw new ChopperBotException(String.format("未找到视频片段%s", i));
|
||||
}
|
||||
try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
HttpPut httpPut = new HttpPut(String.format(BilibiliApiUrl.VIDEO_UPLOAD_URL,
|
||||
HttpPut httpPut = new HttpPut(String.format(BilibiliURL.VIDEO_UPLOAD_URL,
|
||||
endpoint, mp4_upos_uri.substring(mp4_upos_uri.indexOf('/') + 1), i, upload_id, i - 1, chunkNumber, end - start, start, end, filesize)); // 替换为实际的目标URL
|
||||
|
||||
byte[] binaryData = new byte[(int) file.length()];
|
||||
@@ -125,7 +125,7 @@ public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUp
|
||||
body.put("parts", parts);
|
||||
String res4 = HttpClientUtil.post(
|
||||
String.format(
|
||||
BilibiliApiUrl.UPLOAD_FINISHI_URL,
|
||||
BilibiliURL.UPLOAD_FINISHI_URL,
|
||||
endpoint, mp4_upos_uri.substring(mp4_upos_uri.indexOf('/') + 1), put_query.substring(put_query.indexOf('&')), upload_id, biz_id
|
||||
), body.toString(), header2
|
||||
);
|
||||
@@ -147,7 +147,7 @@ public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUp
|
||||
list.add(new BasicNameValuePair("cover", base64Image));
|
||||
list.add(new BasicNameValuePair("csrf", csrf));
|
||||
UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list, UTF_8);
|
||||
String res5 = HttpClientUtil.post(BilibiliApiUrl.COVER_UPLOAD_URL + LocalTime.now(), urlEncodedFormEntity, header);
|
||||
String res5 = HttpClientUtil.post(BilibiliURL.COVER_UPLOAD_URL + LocalTime.now(), urlEncodedFormEntity, header);
|
||||
JSONObject cover = JSONObject.parseObject(res5);
|
||||
JSONObject coverData = cover.getJSONObject("data");
|
||||
if (coverData == null) return;
|
||||
@@ -187,7 +187,7 @@ public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUp
|
||||
body1.put("web_os", 1);
|
||||
body1.put("subtitle", subtitle);
|
||||
body1.put("videos", videos);
|
||||
String res6 = HttpClientUtil.post(String.format(BilibiliApiUrl.SEND_MANUSCRIPT_URL, LocalTime.now(), csrf), body1.toString(), header);
|
||||
String res6 = HttpClientUtil.post(String.format(BilibiliURL.SEND_MANUSCRIPT_URL, LocalTime.now(), csrf), body1.toString(), header);
|
||||
JSONObject res6Obj = JSONObject.parseObject(res6);
|
||||
int code = res6Obj.getInteger("code");
|
||||
if (code == 0) {
|
||||
@@ -197,4 +197,170 @@ public class BilibiliVideoPublisher implements PlatformVideoPublisher<BilibiliUp
|
||||
throw new ChopperBotException("发布失败,请手动发布");
|
||||
}
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public void publishVideo(BilibiliUploader bilibiliUploader) {
|
||||
// Map<String, String> header = bilibiliUploader.getHeader();
|
||||
// String videoPath = bilibiliUploader.getVideoPath();
|
||||
// String devicePath = bilibiliUploader.getDeviceVideoPath();
|
||||
// String cookie = bilibiliUploader.getCookie();
|
||||
// String coverPath = bilibiliUploader.getCoverPath();
|
||||
// String csrf = CookieUtil.getParam(cookie,"bili_jct");
|
||||
// if(csrf == null){
|
||||
// throw new ChopperBotException("Cookie错误");
|
||||
// }
|
||||
// int filesize = FileUtil.getFilesize(videoPath);
|
||||
// if (filesize == -1) {
|
||||
// throw new ChopperBotException("获取文件大小失败");
|
||||
// }
|
||||
//
|
||||
// //申请上传
|
||||
// String res = HttpClientUtil.get(String.format(BilibiliURL.VIDEO_PREUPLOAD_URL,filesize)
|
||||
// , header);
|
||||
// JSONObject mp4Obj = JSONObject.parseObject(res);
|
||||
// String mp4_upos_uri = mp4Obj.getString("upos_uri");
|
||||
// String put_query = mp4Obj.getString("put_query");
|
||||
// String endpoint = mp4Obj.getString("endpoint");
|
||||
// Long chunk_size = mp4Obj.getLong("chunk_size");
|
||||
// Long biz_id = mp4Obj.getLong("biz_id");
|
||||
// String auth = mp4Obj.getString("auth");
|
||||
//
|
||||
//
|
||||
// String res2 = HttpClientUtil.get(BilibiliURL.TXT_PREUPLOAD_URL, header);
|
||||
// JSONObject txtObj = JSONObject.parseObject(res2);
|
||||
// String meta_upos_uri = txtObj.getString("upos_uri");
|
||||
// String preUploadUrl = String.format(BilibiliURL.PREUPLOAD_URL, endpoint, mp4_upos_uri.substring(mp4_upos_uri.indexOf('/') + 1), put_query.substring(put_query.indexOf('&')), String.valueOf(filesize), chunk_size, meta_upos_uri, biz_id);
|
||||
// Map<String, String> header2 = new HashMap<>();
|
||||
// header2.put("X-Upos-Auth", auth);
|
||||
// String res3 = HttpClientUtil.post(preUploadUrl, "{}", header2);
|
||||
// JSONObject uploadObj = JSONObject.parseObject(res3);
|
||||
// String upload_id = uploadObj.getString("upload_id");
|
||||
//
|
||||
// //视频分片
|
||||
// int chunkNumber = VideoDeviceUtil.device(videoPath, devicePath, chunk_size);
|
||||
// if (chunkNumber != -1) {
|
||||
// chunkNumber--;
|
||||
// } else {
|
||||
// throw new ChopperBotException("分割视频失败");
|
||||
// }
|
||||
//
|
||||
// //上传视频
|
||||
// for (int i = 1; i <= chunkNumber; i++) {
|
||||
// long end = i == chunkNumber ? filesize : i * chunk_size;
|
||||
// long start = (i - 1) * chunk_size;
|
||||
// File file = new File(devicePath + "chunk_" + i + ".bin");
|
||||
// if (!file.exists()) {
|
||||
// throw new ChopperBotException(String.format("未找到视频片段%s", i));
|
||||
// }
|
||||
// try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
|
||||
// HttpPut httpPut = new HttpPut(String.format(BilibiliURL.VIDEO_UPLOAD_URL,
|
||||
// endpoint, mp4_upos_uri.substring(mp4_upos_uri.indexOf('/') + 1), i, upload_id, i - 1, chunkNumber, end - start, start, end, filesize)); // 替换为实际的目标URL
|
||||
//
|
||||
// byte[] binaryData = new byte[(int) file.length()];
|
||||
// FileInputStream fileInputStream = new FileInputStream(file);
|
||||
// fileInputStream.read(binaryData);
|
||||
// fileInputStream.close();
|
||||
//
|
||||
// ByteArrayEntity entity = new ByteArrayEntity(binaryData);
|
||||
// httpPut.setEntity(entity);
|
||||
// httpPut.setHeader("Content-Type", "application/octet-stream");
|
||||
// httpPut.setHeader("X-Upos-Auth", auth);
|
||||
//
|
||||
// CloseableHttpResponse response = httpClient.execute(httpPut);
|
||||
// int statusCode = response.getStatusLine().getStatusCode();
|
||||
// if (statusCode == 200) {
|
||||
// System.out.println("上传中:" + i * 100 / chunkNumber + "%");
|
||||
// }
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// VideoDeviceUtil.deleteChunks(devicePath);
|
||||
//
|
||||
// //通知上传完成
|
||||
// JSONObject body = new JSONObject();
|
||||
// JSONArray parts = new JSONArray();
|
||||
// for (int i = 1; i <= chunkNumber; i++) {
|
||||
// JSONObject item = new JSONObject();
|
||||
// item.put("partNumber", i);
|
||||
// item.put("eTag", "etag");
|
||||
// parts.add(item);
|
||||
// }
|
||||
// body.put("parts", parts);
|
||||
// String res4 = HttpClientUtil.post(
|
||||
// String.format(
|
||||
// BilibiliURL.UPLOAD_FINISHI_URL,
|
||||
// endpoint, mp4_upos_uri.substring(mp4_upos_uri.indexOf('/') + 1), put_query.substring(put_query.indexOf('&')), upload_id, biz_id
|
||||
// ), body.toString(), header2
|
||||
// );
|
||||
//
|
||||
// //上传封面
|
||||
// String base64Image = "";
|
||||
// try {
|
||||
// File imageFile = new File(coverPath);
|
||||
// FileInputStream fileInputStream = new FileInputStream(imageFile);
|
||||
// byte[] imageData = new byte[(int) imageFile.length()];
|
||||
// fileInputStream.read(imageData);
|
||||
// fileInputStream.close();
|
||||
// base64Image = Base64.getEncoder().encodeToString(imageData);
|
||||
// base64Image = "data:image/jpeg;base64," + base64Image;
|
||||
// } catch (IOException e) {
|
||||
// e.printStackTrace();
|
||||
// }
|
||||
// List<NameValuePair> list = new ArrayList<>();
|
||||
// list.add(new BasicNameValuePair("cover", base64Image));
|
||||
// list.add(new BasicNameValuePair("csrf", csrf));
|
||||
// UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list, UTF_8);
|
||||
// String res5 = HttpClientUtil.post(BilibiliURL.COVER_UPLOAD_URL + LocalTime.now(), urlEncodedFormEntity, header);
|
||||
// JSONObject cover = JSONObject.parseObject(res5);
|
||||
// JSONObject coverData = cover.getJSONObject("data");
|
||||
// if (coverData == null) return;
|
||||
// String coverUrl = coverData.getString("url");
|
||||
//
|
||||
// //发布视频
|
||||
// JSONObject body1 = new JSONObject();
|
||||
// JSONObject subtitle = new JSONObject();
|
||||
// JSONArray videos = new JSONArray();
|
||||
// subtitle.put("open", 0);
|
||||
// subtitle.put("lan", " ");
|
||||
// JSONObject param_video = new JSONObject();
|
||||
// param_video.put("filename", mp4_upos_uri.substring(mp4_upos_uri.lastIndexOf('/') + 1, mp4_upos_uri.indexOf('.')));
|
||||
// param_video.put("title", "test");
|
||||
// param_video.put("desc", "");
|
||||
// param_video.put("cid", biz_id);
|
||||
// videos.add(param_video);
|
||||
// body1.put("act_reserve_create", 0);
|
||||
// body1.put("copyright", 1);
|
||||
// body1.put("cover", coverUrl); //封面
|
||||
// body1.put("csrf", csrf);
|
||||
// body1.put("desc", "");
|
||||
// body1.put("desc_format_id", 0);
|
||||
// body1.put("dolby", 0);
|
||||
// body1.put("dynamic", "");
|
||||
// body1.put("interactive", 0);
|
||||
// body1.put("lossless_music", 0);
|
||||
// body1.put("no_disturbance", 0);
|
||||
// body1.put("no_reprint", 1);
|
||||
// body1.put("recreate", -1);
|
||||
// body1.put("tag", "助眠,音乐"); //视频标签
|
||||
// body1.put("tid", 130); //视频分区 130:音乐综合
|
||||
// body1.put("title", "test");
|
||||
// body1.put("up_close_danmu", false);
|
||||
// body1.put("up_close_reply", false);
|
||||
// body1.put("up_selection_reply", false);
|
||||
// body1.put("web_os", 1);
|
||||
// body1.put("subtitle", subtitle);
|
||||
// body1.put("videos", videos);
|
||||
// String res6 = HttpClientUtil.post(String.format(BilibiliURL.SEND_MANUSCRIPT_URL, LocalTime.now(), csrf), body1.toString(), header);
|
||||
// JSONObject res6Obj = JSONObject.parseObject(res6);
|
||||
// int code = res6Obj.getInteger("code");
|
||||
// if (code == 0) {
|
||||
// System.out.println("发布成功");
|
||||
// } else {
|
||||
// System.out.println(res6);
|
||||
// throw new ChopperBotException("发布失败,请手动发布");
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.example.core.publisher.impl;
|
||||
|
||||
import org.example.core.pojo.VideoToPublish;
|
||||
import org.example.core.publisher.PlatformVideoPublisher;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.example.util.GetScriptPath.getScriptPath;
|
||||
|
||||
/**
|
||||
* @Description
|
||||
* @Author welsir
|
||||
* @Date 2023/10/13 20:11
|
||||
*/
|
||||
public class DouyinVideoPublisher implements PlatformVideoPublisher {
|
||||
|
||||
final String DOUYIN_PUBLISH_VIDEO = "org/example/core/script/douyin/DouyinVideoPublish.py";
|
||||
|
||||
@Override
|
||||
public void publishVideo(VideoToPublish video) {
|
||||
try {
|
||||
List<String> command = new ArrayList<>();
|
||||
command.add("python"); // Python 解释器
|
||||
command.add(getScriptPath(DOUYIN_PUBLISH_VIDEO).toString()); // 要运行的 Python 脚本文件名
|
||||
//目前默认只有三个参数
|
||||
command.add(video.getCookies());
|
||||
command.add(video.getVideoPath());
|
||||
command.add(video.getTitle());
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(command);
|
||||
Process process;
|
||||
process = processBuilder.start();
|
||||
int backCode = process.waitFor();
|
||||
if(backCode==0){
|
||||
System.out.println("视频发布成功!");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
import sys
|
||||
|
||||
import time
|
||||
|
||||
from selenium.webdriver.chrome import webdriver
|
||||
from selenium import webdriver
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.wait import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
class douyin(object):
|
||||
|
||||
def __init__(self):
|
||||
chrome_options = self.options()
|
||||
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
|
||||
# 解决报错,设置无界面运行
|
||||
chrome_options.add_argument('--no-sandbox')
|
||||
chrome_options.add_argument('--disable-dev-shm-usage')
|
||||
chrome_options.add_argument('window-size=1920x1280') # 指定浏览器分辨率
|
||||
chrome_options.add_argument('--disable-gpu') # 谷歌文档提到需要加上这个属性来规避bug
|
||||
chrome_options.add_argument('--hide-scrollbars') # 隐藏滚动条, 应对一些特殊页面
|
||||
self.browser = webdriver.Chrome(chrome_options)
|
||||
self.wait = WebDriverWait(self.browser, 30)
|
||||
self.url = "https://www.douyin.com/"
|
||||
|
||||
def options(self):
|
||||
chrome_options = webdriver.ChromeOptions()
|
||||
return chrome_options
|
||||
|
||||
def click(self, xpath):
|
||||
self.wait.until(EC.presence_of_element_located(
|
||||
(By.XPATH, xpath))).click()
|
||||
|
||||
def puiblish(self):
|
||||
cookies = sys.argv[0]
|
||||
self.browser.get(self.url)
|
||||
self.browser.delete_all_cookies()
|
||||
for cookie in cookies:
|
||||
self.browser.add_cookie(cookie)
|
||||
self.browser.implicitly_wait(10)
|
||||
time.sleep(2)
|
||||
self.browser.refresh()
|
||||
self.browser.get(self.url)
|
||||
userMsg = '/html/body/div[2]/div[1]/div[4]/div[2]/div[1]/header/div/div/div[2]/div/div/div[6]/div/a'
|
||||
loginFlag = self.wait.until(EC.presence_of_element_located(
|
||||
(By.XPATH, userMsg)))
|
||||
if not loginFlag is None:
|
||||
self.click(userMsg)
|
||||
time.sleep(2)
|
||||
videoPage = '/html/body/div[2]/div[1]/div[3]/div[3]/div/div/div[3]/div[2]/div[2]/div[1]/div[2]/div/div[1]/a'
|
||||
self.click(videoPage)
|
||||
all_h = self.browser.window_handles
|
||||
self.browser.switch_to.window(all_h[1])
|
||||
h2 = self.browser.current_window_handle
|
||||
send_video = "/html/body/div[1]/div/div[2]/div[2]/div/div/div/div[1]/button"
|
||||
self.click(send_video)
|
||||
time.sleep(2)
|
||||
video_path = '/html/body/div[1]/div/div[2]/div[3]/div/div/div/div[2]/div/div/div/div[3]/div/div[1]/div/div[1]/div/label/input'
|
||||
filePath = sys.argv[1]
|
||||
self.wait.until(EC.presence_of_element_located((By.XPATH, video_path))).send_keys(filePath)
|
||||
time.sleep(2)
|
||||
video_title = '/html/body/div[1]/div/div[2]/div[3]/div/div/div/div[2]/div/div/div/div[2]/div[1]/div[2]/div/div/div/div[1]/div'
|
||||
self.wait.until(EC.presence_of_element_located((By.XPATH, video_title))).send_keys(
|
||||
sys.argv[2])
|
||||
push_video = '/html/body/div[1]/div/div[2]/div[3]/div/div/div/div[2]/div/div/div/div[2]/div[1]/div[18]/button[1]'
|
||||
time.sleep(2)
|
||||
self.click(push_video)
|
||||
time.sleep(2)
|
||||
else:
|
||||
print("error")
|
||||
|
||||
if __name__ == '__main__':
|
||||
jd = douyin()
|
||||
jd.puiblish()
|
||||
Reference in New Issue
Block a user