diff --git a/build.gradle b/build.gradle index 26c48267f..ac7f44ecd 100644 --- a/build.gradle +++ b/build.gradle @@ -17,8 +17,8 @@ allprojects { ext { projectGroupId = 'org.mariotaku.twidere' - projectVersionCode = 505 - projectVersionName = '4.0.6' + projectVersionCode = 506 + projectVersionName = '4.0.7' globalCompileSdkVersion = 29 globalBuildToolsVersion = '29.0.2' diff --git a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/TwitterUpload.java b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/TwitterUpload.java index 50ced2880..7592db5e7 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/TwitterUpload.java +++ b/twidere.component.common/src/main/java/org/mariotaku/microblog/library/twitter/TwitterUpload.java @@ -55,7 +55,7 @@ public interface TwitterUpload { @Params(@KeyValue(key = "command", value = "APPEND")) ResponseCode appendUploadMedia(@Param("media_id") String mediaId, @Param("segment_index") int segmentIndex, - @Param("media") Body media) throws MicroBlogException; + @Param("media_data") String media) throws MicroBlogException; @POST("/media/upload.json") @Params(@KeyValue(key = "command", value = "FINALIZE")) diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt index 1769c2a0c..13ffdeb62 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/service/LengthyOperationsService.kt @@ -26,12 +26,13 @@ import android.content.Context import android.content.Intent import android.os.Handler import android.os.Looper +import android.text.TextUtils +import android.util.Base64 +import android.util.Log +import android.widget.Toast import androidx.annotation.UiThread import androidx.annotation.WorkerThread import androidx.core.app.NotificationCompat -import android.text.TextUtils -import android.util.Log -import android.widget.Toast import nl.komponents.kovenant.task import nl.komponents.kovenant.ui.successUi import org.mariotaku.abstask.library.AbstractTask @@ -43,9 +44,7 @@ import org.mariotaku.microblog.library.MicroBlogException import org.mariotaku.microblog.library.twitter.TwitterUpload import org.mariotaku.microblog.library.twitter.model.MediaUploadResponse import org.mariotaku.microblog.library.twitter.model.MediaUploadResponse.ProcessingInfo -import org.mariotaku.restfu.http.ContentType import org.mariotaku.restfu.http.mime.Body -import org.mariotaku.restfu.http.mime.SimpleBody import org.mariotaku.sqliteqb.library.Expression import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.* @@ -66,7 +65,9 @@ import org.mariotaku.twidere.task.CreateFavoriteTask import org.mariotaku.twidere.task.RetweetStatusTask import org.mariotaku.twidere.task.twitter.UpdateStatusTask import org.mariotaku.twidere.task.twitter.message.SendMessageTask +import org.mariotaku.twidere.util.Utils import org.mariotaku.twidere.util.deleteDrafts +import java.io.ByteArrayOutputStream import java.io.IOException import java.util.concurrent.TimeUnit @@ -323,20 +324,26 @@ class LengthyOperationsService : BaseIntentService("lengthy_operations") { notificationManager.cancel(NOTIFICATION_ID_UPDATE_STATUS) } - @Throws(IOException::class, MicroBlogException::class) private fun uploadMedia(upload: TwitterUpload, body: Body): MediaUploadResponse { val mediaType = body.contentType().contentType val length = body.length() val stream = body.stream() var response = upload.initUploadMedia(mediaType, length, null, null) - val segments = if (length == 0L) 0 else (length / BULK_SIZE + 1).toInt() - for (segmentIndex in 0 until segments) { - val currentBulkSize = Math.min(BULK_SIZE, length - segmentIndex * BULK_SIZE).toInt() - val bulk = SimpleBody(ContentType.OCTET_STREAM, null, currentBulkSize.toLong(), - stream) - upload.appendUploadMedia(response.id, segmentIndex, bulk) - } + run { + var streamReadLength = 0 + var segmentIndex = 0 + while (streamReadLength < length) { + val currentBulkSize = Math.min(BULK_SIZE, length - streamReadLength).toInt() + val output = ByteArrayOutputStream() + Utils.copyStream(stream, output, currentBulkSize) + val data = Base64.encodeToString(output.toByteArray(), Base64.DEFAULT); + upload.appendUploadMedia(response.id, segmentIndex, data) + output.close() + segmentIndex++ + streamReadLength += currentBulkSize + } + } response = upload.finalizeUploadMedia(response.id) run { var info: ProcessingInfo? = response.processingInfo diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/UpdateStatusTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/UpdateStatusTask.kt index d352318ed..911c64f69 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/UpdateStatusTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/twitter/UpdateStatusTask.kt @@ -9,11 +9,12 @@ import android.graphics.Point import android.media.MediaMetadataRetriever import android.net.Uri import android.os.Build +import android.text.TextUtils +import android.util.Base64 +import android.webkit.MimeTypeMap import androidx.annotation.UiThread import androidx.annotation.WorkerThread import androidx.exifinterface.media.ExifInterface -import android.text.TextUtils -import android.webkit.MimeTypeMap import net.ypresto.androidtranscoder.MediaTranscoder import net.ypresto.androidtranscoder.format.MediaFormatStrategyPresets import org.mariotaku.ktextension.* @@ -31,7 +32,6 @@ import org.mariotaku.microblog.library.twitter.model.StatusUpdate import org.mariotaku.restfu.http.ContentType import org.mariotaku.restfu.http.mime.Body import org.mariotaku.restfu.http.mime.FileBody -import org.mariotaku.restfu.http.mime.SimpleBody import org.mariotaku.sqliteqb.library.Expression import org.mariotaku.twidere.R import org.mariotaku.twidere.TwidereConstants.* @@ -54,10 +54,7 @@ import org.mariotaku.twidere.util.* import org.mariotaku.twidere.util.io.ContentLengthInputStream import org.mariotaku.twidere.util.premium.ExtraFeaturesService import org.mariotaku.twidere.util.text.StatusTextValidator -import java.io.Closeable -import java.io.File -import java.io.FileNotFoundException -import java.io.IOException +import java.io.* import java.util.* import java.util.concurrent.TimeUnit @@ -834,7 +831,6 @@ class UpdateStatusTask( } } - @Throws(IOException::class, MicroBlogException::class) private fun uploadMediaChucked(upload: TwitterUpload, body: Body, mediaCategory: String? = null, ownerIds: Array?): MediaUploadResponse { @@ -842,12 +838,19 @@ class UpdateStatusTask( val length = body.length() val stream = body.stream() var response = upload.initUploadMedia(mediaType, length, mediaCategory, ownerIds) - val segments = if (length == 0L) 0 else (length / BULK_SIZE + 1).toInt() - for (segmentIndex in 0 until segments) { - val currentBulkSize = Math.min(BULK_SIZE.toLong(), length - segmentIndex * BULK_SIZE).toInt() - val bulk = SimpleBody(ContentType.OCTET_STREAM, null, currentBulkSize.toLong(), - stream) - upload.appendUploadMedia(response.id, segmentIndex, bulk) + run { + var streamReadLength = 0 + var segmentIndex = 0 + while (streamReadLength < length) { + val currentBulkSize = Math.min(BULK_SIZE.toLong(), length - streamReadLength).toInt() + val output = ByteArrayOutputStream() + Utils.copyStream(stream, output, currentBulkSize) + val data = Base64.encodeToString(output.toByteArray(), Base64.DEFAULT); + upload.appendUploadMedia(response.id, segmentIndex, data) + output.close() + segmentIndex++ + streamReadLength += currentBulkSize + } } response = upload.finalizeUploadMedia(response.id) var info: MediaUploadResponse.ProcessingInfo? = response.processingInfo diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/Utils.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/Utils.kt index 9a092e80e..b6aaccf40 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/Utils.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/Utils.kt @@ -89,6 +89,8 @@ import org.mariotaku.twidere.provider.TwidereDataStore.CachedUsers import org.mariotaku.twidere.util.TwidereLinkify.PATTERN_TWITTER_PROFILE_IMAGES import org.mariotaku.twidere.view.TabPagerIndicator import java.io.File +import java.io.InputStream +import java.io.OutputStream import java.util.* import java.util.regex.Pattern @@ -607,4 +609,16 @@ object Utils { } + fun copyStream(input: InputStream, output: OutputStream, length: Int) { + val buffer = ByteArray(1024) + var bytesRead: Int = 0 + do { + val read = input.read(buffer) + if (read == -1) { + break + } + output.write(buffer, 0, read) + bytesRead += read + } while (bytesRead <= length) + } }