Add direct upload to YouTube support
This commit is contained in:
@@ -3,6 +3,7 @@ package com.replaymod.extras;
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.extras.playeroverview.PlayerOverview;
|
||||
import com.replaymod.extras.urischeme.UriSchemeExtra;
|
||||
import com.replaymod.extras.youtube.YoutubeUpload;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
|
||||
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
|
||||
@@ -24,6 +25,7 @@ public class ReplayModExtras {
|
||||
private static final List<Class<? extends Extra>> builtin = Arrays.asList(
|
||||
PlayerOverview.class,
|
||||
UriSchemeExtra.class,
|
||||
YoutubeUpload.class,
|
||||
FullBrightness.class,
|
||||
HotkeyButtons.class,
|
||||
LocalizationExtra.class,
|
||||
|
||||
247
src/main/java/com/replaymod/extras/youtube/GuiYoutubeUpload.java
Normal file
247
src/main/java/com/replaymod/extras/youtube/GuiYoutubeUpload.java
Normal file
@@ -0,0 +1,247 @@
|
||||
package com.replaymod.extras.youtube;
|
||||
|
||||
import com.google.api.services.youtube.model.Video;
|
||||
import com.google.api.services.youtube.model.VideoSnippet;
|
||||
import com.google.common.util.concurrent.FutureCallback;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.replaymod.core.utils.Utils;
|
||||
import com.replaymod.render.RenderSettings;
|
||||
import de.johni0702.minecraft.gui.GuiRenderer;
|
||||
import de.johni0702.minecraft.gui.RenderInfo;
|
||||
import de.johni0702.minecraft.gui.container.GuiPanel;
|
||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
||||
import de.johni0702.minecraft.gui.element.*;
|
||||
import de.johni0702.minecraft.gui.element.advanced.GuiDropdownMenu;
|
||||
import de.johni0702.minecraft.gui.element.advanced.GuiProgressBar;
|
||||
import de.johni0702.minecraft.gui.element.advanced.GuiTextArea;
|
||||
import de.johni0702.minecraft.gui.layout.CustomLayout;
|
||||
import de.johni0702.minecraft.gui.layout.VerticalLayout;
|
||||
import de.johni0702.minecraft.gui.popup.GuiFileChooserPopup;
|
||||
import joptsimple.internal.Strings;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import net.minecraft.client.resources.I18n;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.lwjgl.Sys;
|
||||
import org.lwjgl.util.ReadableDimension;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageReader;
|
||||
import javax.imageio.stream.ImageInputStream;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.security.GeneralSecurityException;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class GuiYoutubeUpload extends GuiScreen {
|
||||
private final GuiScreen previousScreen;
|
||||
private final File videoFile;
|
||||
private final int videoFrames;
|
||||
private final RenderSettings settings;
|
||||
private String thumbnailFormat;
|
||||
private byte[] thumbnailImage;
|
||||
|
||||
public final Runnable inputValidation = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String problem = null;
|
||||
|
||||
if (nameField.getText().isEmpty()) problem = "replaymod.gui.titleempty";
|
||||
if (thumbnailImage != null) {
|
||||
if (thumbnailImage.length > 1024 * 1024 * 2) problem = "replaymod.gui.videothumbnailtoolarge";
|
||||
if (!asList("jpeg", "png").contains(thumbnailFormat)) problem = "replaymod.gui.videothumbnailformat";
|
||||
}
|
||||
|
||||
if (upload == null) {
|
||||
if (problem == null) {
|
||||
uploadButton.setEnabled();
|
||||
uploadButton.setTooltip(null);
|
||||
} else {
|
||||
uploadButton.setDisabled();
|
||||
uploadButton.setTooltip(new GuiTooltip().setI18nText(problem));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public final GuiTextField nameField = new GuiTextField().setI18nHint("replaymod.gui.videotitle")
|
||||
.onTextChanged(s -> inputValidation.run());
|
||||
|
||||
public final GuiTextArea descriptionField = new GuiTextArea().setMaxCharCount(Integer.MAX_VALUE)
|
||||
.setMaxTextWidth(Integer.MAX_VALUE).setMaxTextHeight(Integer.MAX_VALUE);
|
||||
{
|
||||
descriptionField.setText(new String[]{I18n.format("replaymod.gui.videodescription")});
|
||||
}
|
||||
|
||||
public final GuiTextField tagsField = new GuiTextField().setI18nHint("replaymod.gui.videotags");
|
||||
|
||||
{
|
||||
nameField.setNext(descriptionField)
|
||||
.getNext().setNext(tagsField)
|
||||
.getNext().setNext(nameField);
|
||||
}
|
||||
|
||||
public final GuiProgressBar progressBar = new GuiProgressBar();
|
||||
|
||||
public final GuiPanel leftPanel = new GuiPanel(this).setLayout(new CustomLayout<GuiPanel>() {
|
||||
@Override
|
||||
protected void layout(GuiPanel container, int width, int height) {
|
||||
size(nameField, width, 20);
|
||||
size(descriptionField, width, height - 90);
|
||||
size(tagsField, width, 20);
|
||||
size(progressBar, width, 20);
|
||||
|
||||
pos(nameField, 0, 0);
|
||||
pos(descriptionField, 0, 30);
|
||||
pos(tagsField, 0, height - 50);
|
||||
pos(progressBar, 0, height - 20);
|
||||
}
|
||||
}).addElements(null, nameField, descriptionField, tagsField, progressBar);
|
||||
|
||||
public final GuiDropdownMenu<VideoVisibility> visibilityDropdown = new GuiDropdownMenu<VideoVisibility>()
|
||||
.setSize(200, 20).setValues(VideoVisibility.values()).setSelected(VideoVisibility.PUBLIC);
|
||||
|
||||
public final GuiButton thumbnailButton = new GuiButton().onClick(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Futures.addCallback(
|
||||
GuiFileChooserPopup.openLoadGui(GuiYoutubeUpload.this, "replaymod.gui.load",
|
||||
ImageIO.getReaderFileSuffixes()).getFuture(),
|
||||
new FutureCallback<File>() {
|
||||
@Override
|
||||
public void onSuccess(@Nullable File result) {
|
||||
if (result != null) {
|
||||
thumbnailButton.setLabel(result.getName());
|
||||
BufferedImage image;
|
||||
try {
|
||||
thumbnailImage = IOUtils.toByteArray(new FileInputStream(result));
|
||||
ImageInputStream in = ImageIO.createImageInputStream(new ByteArrayInputStream(thumbnailImage));
|
||||
ImageReader reader = ImageIO.getImageReaders(in).next();
|
||||
thumbnailFormat = reader.getFormatName().toLowerCase();
|
||||
image = ImageIO.read(new ByteArrayInputStream(thumbnailImage));
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
thumbnailImage = null;
|
||||
image = null;
|
||||
}
|
||||
thumbnail.setTexture(image);
|
||||
inputValidation.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
throw new RuntimeException(t);
|
||||
}
|
||||
});
|
||||
}
|
||||
}).setSize(200, 20).setI18nLabel("replaymod.gui.videothumbnail");
|
||||
|
||||
public final GuiImage thumbnail = new GuiImage().setSize(200, 112).setTexture(Utils.DEFAULT_THUMBNAIL);
|
||||
|
||||
public final GuiButton uploadButton = new GuiButton(this).setSize(98, 20);
|
||||
|
||||
public final GuiButton closeButton = new GuiButton(this).onClick(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
previousScreen.display();
|
||||
}
|
||||
}).setSize(98, 20).setI18nLabel("replaymod.gui.back");
|
||||
|
||||
public final GuiPanel rightPanel = new GuiPanel(this)
|
||||
.addElements(null, visibilityDropdown, thumbnailButton, thumbnail)
|
||||
.setLayout(new VerticalLayout(VerticalLayout.Alignment.TOP).setSpacing(10));
|
||||
|
||||
private YoutubeUploader upload;
|
||||
|
||||
{
|
||||
setLayout(new CustomLayout<GuiScreen>() {
|
||||
@Override
|
||||
protected void layout(GuiScreen container, int width, int height) {
|
||||
pos(leftPanel, 10, 10);
|
||||
size(leftPanel, width - 200 - 30, height - 20);
|
||||
|
||||
pos(rightPanel, width - 210, 10);
|
||||
pos(uploadButton, width - 210, height - 30);
|
||||
pos(closeButton, width - 108, height - 30);
|
||||
}
|
||||
});
|
||||
|
||||
setState(false);
|
||||
inputValidation.run();
|
||||
}
|
||||
|
||||
private void setState(boolean uploading) {
|
||||
forEach(GuiElement.class).setEnabled(!uploading);
|
||||
uploadButton.setEnabled();
|
||||
if (uploading) {
|
||||
uploadButton.onClick(() -> {
|
||||
try {
|
||||
upload.cancel();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).setI18nLabel("replaymod.gui.cancel");
|
||||
} else {
|
||||
uploadButton.onClick(() -> {
|
||||
try {
|
||||
setState(true);
|
||||
|
||||
VideoVisibility visibility = visibilityDropdown.getSelectedValue();
|
||||
VideoSnippet snippet = new VideoSnippet();
|
||||
snippet.setTitle(nameField.getText());
|
||||
snippet.setDescription(Strings.join(descriptionField.getText(), "\n"));
|
||||
snippet.setTags(asList(tagsField.getText().split(",")));
|
||||
upload = new YoutubeUploader(getMinecraft(), videoFile, videoFrames,
|
||||
thumbnailFormat, thumbnailImage, settings, visibility, snippet);
|
||||
ListenableFuture<Video> future = upload.upload();
|
||||
Futures.addCallback(future, new FutureCallback<Video>() {
|
||||
@Override
|
||||
public void onSuccess(Video result) {
|
||||
String url = "https://youtu.be/" + result.getId();
|
||||
try {
|
||||
Desktop.getDesktop().browse(new URL(url).toURI());
|
||||
} catch(Throwable throwable) {
|
||||
Sys.openURL(url);
|
||||
}
|
||||
upload = null;
|
||||
progressBar.setLabel(I18n.format("replaymod.gui.ytuploadprogress.done", url));
|
||||
setState(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Throwable t) {
|
||||
if (t instanceof InterruptedException) {
|
||||
progressBar.setLabel("0%");
|
||||
} else {
|
||||
t.printStackTrace();
|
||||
progressBar.setLabel(t.getLocalizedMessage());
|
||||
}
|
||||
upload = null;
|
||||
setState(false);
|
||||
}
|
||||
});
|
||||
} catch (GeneralSecurityException | IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).setI18nLabel("replaymod.gui.upload");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(GuiRenderer renderer, ReadableDimension size, RenderInfo renderInfo) {
|
||||
if (upload != null && upload.getState() != null) {
|
||||
progressBar.setProgress((float) upload.getProgress());
|
||||
progressBar.setI18nLabel("replaymod.gui.ytuploadprogress." + upload.getState().name().toLowerCase());
|
||||
}
|
||||
super.draw(renderer, size, renderInfo);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.replaymod.extras.youtube;
|
||||
|
||||
import net.minecraft.client.resources.I18n;
|
||||
|
||||
public enum VideoVisibility {
|
||||
PUBLIC, UNLISTED, PRIVATE;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return I18n.format("replaymod.gui.videovisibility." + name().toLowerCase());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.replaymod.extras.youtube;
|
||||
|
||||
import com.replaymod.core.ReplayMod;
|
||||
import com.replaymod.extras.Extra;
|
||||
import com.replaymod.render.gui.GuiRenderingDone;
|
||||
import de.johni0702.minecraft.gui.container.GuiScreen;
|
||||
import de.johni0702.minecraft.gui.element.GuiButton;
|
||||
import net.minecraftforge.client.event.GuiScreenEvent;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
|
||||
|
||||
public class YoutubeUpload implements Extra {
|
||||
@Override
|
||||
public void register(ReplayMod mod) throws Exception {
|
||||
MinecraftForge.EVENT_BUS.register(this);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public void onGuiOpen(GuiScreenEvent.InitGuiEvent.Post event) {
|
||||
if (GuiScreen.from(event.gui) instanceof GuiRenderingDone) {
|
||||
GuiRenderingDone gui = (GuiRenderingDone) GuiScreen.from(event.gui);
|
||||
// Check if there already is a youtube button
|
||||
if (gui.actionsPanel.getChildren().stream().anyMatch(it -> it instanceof YoutubeButton)) {
|
||||
return; // Button already added
|
||||
}
|
||||
// Add the Upload to YouTube button to actions panel
|
||||
gui.actionsPanel.addElements(null,
|
||||
new YoutubeButton().onClick(() ->
|
||||
new GuiYoutubeUpload(gui, gui.videoFile, gui.videoFrames, gui.settings).display()
|
||||
).setSize(200, 20).setI18nLabel("replaymod.gui.youtubeupload"));
|
||||
}
|
||||
}
|
||||
|
||||
private static class YoutubeButton extends GuiButton {}
|
||||
}
|
||||
237
src/main/java/com/replaymod/extras/youtube/YoutubeUploader.java
Normal file
237
src/main/java/com/replaymod/extras/youtube/YoutubeUploader.java
Normal file
@@ -0,0 +1,237 @@
|
||||
package com.replaymod.extras.youtube;
|
||||
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
|
||||
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
||||
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
|
||||
import com.google.api.client.googleapis.json.GoogleJsonError;
|
||||
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
|
||||
import com.google.api.client.googleapis.media.MediaHttpUploader;
|
||||
import com.google.api.client.http.InputStreamContent;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.client.json.gson.GsonFactory;
|
||||
import com.google.api.client.util.store.DataStoreFactory;
|
||||
import com.google.api.client.util.store.FileDataStoreFactory;
|
||||
import com.google.api.services.youtube.YouTube;
|
||||
import com.google.api.services.youtube.YouTubeScopes;
|
||||
import com.google.api.services.youtube.model.Video;
|
||||
import com.google.api.services.youtube.model.VideoSnippet;
|
||||
import com.google.api.services.youtube.model.VideoStatus;
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Suppliers;
|
||||
import com.google.common.util.concurrent.ListenableFuture;
|
||||
import com.google.common.util.concurrent.SettableFuture;
|
||||
import com.replaymod.render.RenderSettings;
|
||||
import com.replaymod.render.metadata.MetadataInjector;
|
||||
import lombok.Getter;
|
||||
import lombok.NonNull;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import org.apache.commons.exec.CommandLine;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
public class YoutubeUploader {
|
||||
private static final String CLIENT_ID = "743126594724-mfe7pj1k7e47uu5pk4503c8st9vj9ibu.apps.googleusercontent.com";
|
||||
private static final String CLIENT_SECRET = "gMwcy3mRYCRamCIjJIYP7rqc";
|
||||
private static final String FFMPEG_ODS =
|
||||
"-i %s -vf scale=iw:iw*9/16,setdar=16:9 -c:v libx264 -preset slow -crf 16 %s";
|
||||
private static final JsonFactory JSON_FACTORY = new GsonFactory();
|
||||
private final NetHttpTransport httpTransport;
|
||||
private final DataStoreFactory dataStoreFactory;
|
||||
private final File videoFile;
|
||||
private final int videoFrames;
|
||||
private final String thumbnailFormat;
|
||||
private final byte[] thumbnailImage;
|
||||
private final RenderSettings settings;
|
||||
|
||||
private final VideoSnippet videoSnippet;
|
||||
private final VideoVisibility videoVisibility;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
@NonNull
|
||||
private Supplier<Double> progress = Suppliers.ofInstance(0d);
|
||||
|
||||
@Getter
|
||||
private State state;
|
||||
|
||||
public YoutubeUploader(Minecraft minecraft, File videoFile, int videoFrames,
|
||||
String thumbnailFormat, byte[] thumbnailImage,
|
||||
RenderSettings settings, VideoVisibility videoVisibility, VideoSnippet videoSnippet)
|
||||
throws GeneralSecurityException, IOException {
|
||||
this.videoFile = videoFile;
|
||||
this.videoFrames = videoFrames;
|
||||
this.thumbnailImage = thumbnailImage;
|
||||
this.thumbnailFormat = thumbnailFormat;
|
||||
this.settings = settings;
|
||||
this.videoVisibility = videoVisibility;
|
||||
this.videoSnippet = videoSnippet;
|
||||
this.httpTransport = GoogleNetHttpTransport.newTrustedTransport();
|
||||
this.dataStoreFactory = new FileDataStoreFactory(minecraft.mcDataDir);
|
||||
|
||||
}
|
||||
|
||||
public ListenableFuture<Video> upload() throws IOException {
|
||||
final SettableFuture<Video> future = SettableFuture.create();
|
||||
thread = new Thread(() -> {
|
||||
try {
|
||||
state = State.AUTH;
|
||||
Credential credential = auth();
|
||||
|
||||
state = State.PREPARE_VIDEO;
|
||||
File processedFile = preUpload();
|
||||
progress = Suppliers.ofInstance(0d);
|
||||
|
||||
YouTube youTube = new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
|
||||
.setApplicationName("ReplayMod").build();
|
||||
|
||||
state = State.UPLOAD;
|
||||
Video video = doUpload(youTube, processedFile);
|
||||
if (thumbnailImage != null) {
|
||||
doThumbUpload(youTube, video);
|
||||
}
|
||||
|
||||
state = State.CLEANUP;
|
||||
postUpload(processedFile);
|
||||
future.set(video);
|
||||
} catch (Throwable t) {
|
||||
future.setException(t);
|
||||
}
|
||||
});
|
||||
thread.start();
|
||||
return future;
|
||||
}
|
||||
|
||||
public void cancel() throws InterruptedException {
|
||||
thread.interrupt();
|
||||
thread.join();
|
||||
}
|
||||
|
||||
private Credential auth() throws IOException {
|
||||
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
|
||||
httpTransport, JSON_FACTORY, CLIENT_ID, CLIENT_SECRET,
|
||||
Collections.singleton(YouTubeScopes.YOUTUBE_UPLOAD)
|
||||
).setDataStoreFactory(dataStoreFactory).build();
|
||||
return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
|
||||
}
|
||||
|
||||
private File preUpload() throws InterruptedException, IOException {
|
||||
if (settings.getRenderMethod() == RenderSettings.RenderMethod.ODS) {
|
||||
File tmpFile = new File(videoFile.getParentFile(), System.currentTimeMillis() + ".mp4");
|
||||
tmpFile.deleteOnExit();
|
||||
|
||||
String args = String.format(FFMPEG_ODS, videoFile.getName(), tmpFile.getName());
|
||||
|
||||
CommandLine commandLine = new CommandLine(settings.getExportCommand());
|
||||
commandLine.addArguments(args);
|
||||
System.out.println("Re-encoding for ODS with " + settings.getExportCommand() + args);
|
||||
Process process = new ProcessBuilder(commandLine.toStrings()).directory(videoFile.getParentFile()).start();
|
||||
|
||||
final AtomicBoolean active = new AtomicBoolean(true);
|
||||
final InputStream in = process.getErrorStream();
|
||||
new Thread(() -> {
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (active.get()) {
|
||||
char c = (char) in.read();
|
||||
if (c == '\r') {
|
||||
String str = sb.toString();
|
||||
System.out.println(str);
|
||||
if (str.startsWith("frame=")) {
|
||||
str = str.substring(6).trim();
|
||||
str = str.substring(0, str.indexOf(' '));
|
||||
double frame = Integer.parseInt(str);
|
||||
progress = Suppliers.ofInstance(frame / videoFrames);
|
||||
}
|
||||
sb = new StringBuilder();
|
||||
} else {
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
|
||||
int result;
|
||||
try {
|
||||
result = process.waitFor();
|
||||
} catch (InterruptedException e) {
|
||||
process.destroy();
|
||||
throw e;
|
||||
} finally {
|
||||
active.set(false);
|
||||
}
|
||||
if (result != 0) {
|
||||
throw new IOException("FFmpeg returned: " + result);
|
||||
}
|
||||
|
||||
MetadataInjector.injectODSMetadata(tmpFile);
|
||||
|
||||
return tmpFile;
|
||||
}
|
||||
return videoFile;
|
||||
}
|
||||
|
||||
private Video doUpload(YouTube youTube, File processedFile) throws IOException {
|
||||
Video video = new Video();
|
||||
VideoStatus videoStatus = new VideoStatus();
|
||||
videoStatus.setPrivacyStatus(videoVisibility.name().toLowerCase());
|
||||
video.setStatus(videoStatus);
|
||||
video.setSnippet(videoSnippet);
|
||||
|
||||
Video result;
|
||||
try (InputStream inputStream = new BufferedInputStream(new FileInputStream(processedFile))) {
|
||||
InputStreamContent content = new InputStreamContent("video/*", inputStream);
|
||||
content.setLength(processedFile.length());
|
||||
YouTube.Videos.Insert videoInsert = youTube.videos().insert("snippet,statistics,status", video, content);
|
||||
final MediaHttpUploader uploader = videoInsert.getMediaHttpUploader();
|
||||
progress = () -> {
|
||||
try {
|
||||
return uploader.getProgress();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
result = videoInsert.execute();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void doThumbUpload(YouTube youTube, Video video) throws IOException {
|
||||
try (ByteArrayInputStream inputStream = new ByteArrayInputStream(thumbnailImage)) {
|
||||
InputStreamContent content = new InputStreamContent("image/" + thumbnailFormat, inputStream);
|
||||
content.setLength(inputStream.available());
|
||||
youTube.thumbnails().set(video.getId(), content).execute();
|
||||
} catch (GoogleJsonResponseException e) {
|
||||
GoogleJsonError.ErrorInfo info = e.getDetails().getErrors().get(0);
|
||||
if ("Authorization".equals(info.getLocation()) && "forbidden".equals(info.getReason())) {
|
||||
e.printStackTrace();
|
||||
// TODO: When rewriting, show popup gui
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void postUpload(File processedFile) {
|
||||
if (processedFile != videoFile) {
|
||||
FileUtils.deleteQuietly(processedFile);
|
||||
}
|
||||
}
|
||||
|
||||
public double getProgress() {
|
||||
return progress.get();
|
||||
}
|
||||
|
||||
public enum State {
|
||||
AUTH, PREPARE_VIDEO, UPLOAD, CLEANUP
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user