package io.scal.secureshareui.controller; import timber.log.Timber; import io.scal.secureshareui.login.YoutubeLoginActivity; import io.scal.secureshareui.model.Account; import io.scal.secureshareuilibrary.R; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import android.app.Activity; import android.app.IntentService; import android.content.Context; import android.content.Intent; import android.os.AsyncTask; import android.os.Handler; import android.util.Log; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential; import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAuthIOException; import com.google.api.client.googleapis.extensions.android.gms.auth.GooglePlayServicesAvailabilityIOException; import com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuthIOException; import com.google.api.client.googleapis.media.MediaHttpUploader; import com.google.api.client.googleapis.media.MediaHttpUploaderProgressListener; import com.google.api.client.http.HttpTransport; 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.services.youtube.YouTube; import com.google.api.services.youtube.YouTubeRequestInitializer; 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; public class YoutubeSiteController extends SiteController { private static final String TAG = "YouTubeSiteController"; public static final String SITE_NAME = "YouTube"; public static final String SITE_KEY = "youtube"; private static final String CLIENT_ID = "279338940292-7pqin08vmde3nhheekijn6cfetknotbs.apps.googleusercontent.com"; HttpTransport transport = new NetHttpTransport(); final JsonFactory jsonFactory = new GsonFactory(); private YouTube mYoutube; private static String VIDEO_FILE_FORMAT = "video/*"; public YoutubeSiteController(Context context, Handler handler, String jobId) { super(context, handler, jobId); } @Override public void startAuthentication(Account account) { Intent intent = new Intent(mContext, YoutubeLoginActivity.class); intent.putExtra(SiteController.EXTRAS_KEY_CREDENTIALS, account.getCredentials()); ((Activity) mContext).startActivityForResult(intent, SiteController.CONTROLLER_REQUEST_CODE); // FIXME not a safe cast, context might be a service } @Override public void upload(Account account, HashMap<String, String> valueMap) { Timber.d("Upload file: Entering upload"); String title = valueMap.get(VALUE_KEY_TITLE); String body = valueMap.get(VALUE_KEY_BODY); String mediaPath = valueMap.get(VALUE_KEY_MEDIA_PATH); boolean useTor = (valueMap.get(VALUE_KEY_USE_TOR).equals("true")) ? true : false; List<String> scopes = new ArrayList<String>(); scopes.add(YouTubeScopes.YOUTUBE_UPLOAD); //set username GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(super.mContext, scopes); credential.setSelectedAccountName(account.getCredentials()); //set proxy useTor=false; //FIXME Hardcoded until we find a Tor workaround if(super.torCheck(useTor, super.mContext)) { Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(ORBOT_HOST, ORBOT_HTTP_PORT)); transport = new NetHttpTransport.Builder().setProxy(proxy).build(); } mYoutube = new com.google.api.services.youtube.YouTube.Builder(transport, jsonFactory, credential) .setApplicationName(mContext.getString(R.string.google_app_name)) .setGoogleClientRequestInitializer(new YouTubeRequestInitializer(CLIENT_ID)) .build(); File mediaFile = new File(mediaPath); YouTube.Videos.Insert requestInsert = prepareUpload(title, body, mediaFile); new VideoUploadAsyncTask().execute(requestInsert); } public YouTube.Videos.Insert prepareUpload(String title, String body, File mediaFile) { try { if(!super.isVideoFile(mediaFile)){ jobFailed(null, 1231291, mContext.getString(R.string.invalid_file_format)); return null; } Video videoObjectDefiningMetadata = new Video(); //set the video to private by default VideoStatus status = new VideoStatus(); status.setPrivacyStatus("unlisted"); videoObjectDefiningMetadata.setStatus(status); //we set a majority of the metadata with the VideoSnippet object VideoSnippet snippet = new VideoSnippet(); //video file name. snippet.setTitle(title); snippet.setDescription(body); //set keywords. List<String> tags = new ArrayList<String>(); tags.add("storymaker"); snippet.setTags(tags); //set completed snippet to the video object videoObjectDefiningMetadata.setSnippet(snippet); InputStreamContent mediaContent = new InputStreamContent(VIDEO_FILE_FORMAT, new BufferedInputStream(new FileInputStream(mediaFile))); mediaContent.setLength(mediaFile.length()); YouTube.Videos.Insert requestInsert = mYoutube.videos().insert("snippet,statistics,status", videoObjectDefiningMetadata, mediaContent); //set the upload type and add event listener. MediaHttpUploader uploader = requestInsert.getMediaHttpUploader(); uploader.setDirectUploadEnabled(false); uploader.setChunkSize(MediaHttpUploader.MINIMUM_CHUNK_SIZE); MediaHttpUploaderProgressListener progressListener = new MediaHttpUploaderProgressListener() { public void progressChanged(MediaHttpUploader uploader) throws IOException { switch (uploader.getUploadState()) { case INITIATION_STARTED: Timber.d("Upload file: Initiation Started"); break; case INITIATION_COMPLETE: Timber.d("Upload file: Initiation Completed"); break; case MEDIA_IN_PROGRESS: Timber.d("YouTube Upload: Upload in progress"); float uploadPercent = (float) (uploader.getProgress()); jobProgress(uploadPercent, mContext.getString(R.string.youtube_uploading)); break; case MEDIA_COMPLETE: Timber.d("Upload file: Upload Completed!"); break; case NOT_STARTED: Timber.d("Upload file: Upload Not Started!"); break; } } }; uploader.setProgressListener(progressListener); return requestInsert; } catch (FileNotFoundException e) { String msg = e.getMessage() != null ? e.getMessage() + ", " : ""; String errorMessage = e.getCause() + msg; Timber.e("File not found: " + errorMessage); return null; } catch (IOException e) { String msg = e.getMessage() != null ? e.getMessage() + ", " : ""; String errorMessage = e.getCause() + msg; Timber.e("Progress IOException: " + errorMessage); return null; } } public class VideoUploadAsyncTask extends AsyncTask<YouTube.Videos.Insert, Void, Void> { @Override protected Void doInBackground(YouTube.Videos.Insert... requestInserts) { int errorId = -1; String errorMessage = null; String uploadedVideoId = null; YouTube.Videos.Insert requestInsert = requestInserts[0]; Exception exception = null; if (null == requestInsert) { errorId = 1231231; errorMessage = "Video is Null"; } else { try { Video uploadedVideo = requestInsert.execute(); uploadedVideoId = uploadedVideo.getId(); } catch (final GooglePlayServicesAvailabilityIOException e) { exception = e; errorId = 1231232; String msg = e.getMessage() != null ? e.getMessage() + ", " : ""; errorMessage = mContext.getString(R.string.google_play_services_not_avail) + ": " + e.getCause() + msg; } catch (UserRecoverableAuthIOException e) { exception = e; Intent intent = e.getIntent(); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); ((IntentService)mContext).startActivity(intent); errorId = 1231233; String msg = e.getMessage() != null ? e.getMessage() + ", " : ""; errorMessage = mContext.getString(R.string.insufficient_permissions) + ": " + e.getCause() + msg; } catch (GoogleAuthIOException e) { exception = e; errorId = 1231234; String msg = e.getMessage() != null ? e.getMessage() + ", " : ""; String cause = "" + e.getCause(); //if bad username error, explain to user how to fix if(cause.contains("BadUsername")) { errorMessage = mContext.getString(R.string.connect_your_google_account_to_device); } else { errorMessage = "GoogleAuth IOException: " + e.getCause() + msg; // FIXME move to strings } }catch (IOException e) { exception = e; errorId = 1231235; String msg = e.getMessage() != null ? e.getMessage() + ", " : ""; errorMessage = "AsyncTask IOException: " + e.getCause() + msg; // FIXME move to strings } } //success if (errorId == -1) { jobSucceeded(uploadedVideoId); } else { Timber.e(errorId + "_" + errorMessage); // jobFailed(exception, errorId, errorMessage); jobFailed(null, errorId, errorMessage); // because UserRecoverableAuthException's are not parcelable and cause a crash here } return null; } } @Override public void startMetadataActivity(Intent intent) { return; // nop } }