mastodon media upload seems working

fixed npe
This commit is contained in:
Mariotaku Lee 2017-04-20 03:31:07 +08:00
parent 4e9a167a73
commit f224c0f0be
No known key found for this signature in database
GPG Key ID: 15C10F89D7C33535
11 changed files with 92 additions and 32 deletions

View File

@ -36,7 +36,7 @@ subprojects {
Kotlin : '1.1.1',
SupportLib : '25.3.1',
MariotakuCommons : '0.9.13',
RestFu : '0.9.50',
RestFu : '0.9.51',
ObjectCursor : '0.9.16',
PlayServices : '10.2.1',
MapsUtils : '0.4.4',

View File

@ -21,9 +21,21 @@
package org.mariotaku.microblog.library.mastodon.api;
import org.mariotaku.microblog.library.MicroBlogException;
import org.mariotaku.microblog.library.mastodon.model.Attachment;
import org.mariotaku.restfu.annotation.method.POST;
import org.mariotaku.restfu.annotation.param.Param;
import org.mariotaku.restfu.http.BodyType;
import org.mariotaku.restfu.http.mime.Body;
/**
* Created by mariotaku on 2017/4/17.
*/
public interface MediaResources {
@POST("/v1/media")
@BodyType(BodyType.MULTIPART)
Attachment uploadMediaAttachment(@Param("file") Body body) throws MicroBlogException;
}

View File

@ -44,9 +44,9 @@ public class StatusUpdate extends SimpleValueMap {
public StatusUpdate mediaIds(String[] ids) {
if (ids != null) {
put("in_reply_to_id[]", ids);
put("media_ids[]", ids);
} else {
remove("in_rpely_to_id[]");
remove("media_ids[]");
}
return this;
}

View File

@ -26,6 +26,10 @@ inline fun <T, reified R> Array<T>.mapToArray(transform: (T) -> R): Array<R> {
return Array(size) { transform(this[it]) }
}
inline fun <T, reified R> Array<T>.mapIndexedToArray(transform: (Int, T) -> R): Array<R> {
return Array(size) { transform(it, this[it]) }
}
inline fun <reified R> LongArray.mapToArray(transform: (Long) -> R): Array<R> {
return Array(size) { transform(this[it]) }
}

View File

@ -1415,7 +1415,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
val (replyStartIndex, replyText, _, excludedMentions, replyToOriginalUser) =
replyTextAndMentions
if (replyText.isEmpty() && media.isEmpty()) throw NoContentException()
if (!statusShortenerUsed && validator.getTweetLength(replyText) > maxLength) {
if (!statusShortenerUsed && maxLength > 0 && validator.getTweetLength(replyText) > maxLength) {
throw StatusTooLongException(replyStartIndex + replyText.offsetByCodePoints(0, maxLength))
}
update.text = replyText
@ -1428,7 +1428,7 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener
}
} else {
if (text.isEmpty() && media.isEmpty()) throw NoContentException()
if (!statusShortenerUsed && validator.getTweetLength(text) > maxLength) {
if (!statusShortenerUsed && maxLength > 0 && validator.getTweetLength(text) > maxLength) {
throw StatusTooLongException(text.offsetByCodePoints(0, maxLength))
}
update.text = text

View File

@ -113,7 +113,7 @@ fun ParcelableMessageConversation.getSummaryText(context: Context, manager: User
fun ParcelableMessageConversation.addParticipants(users: Collection<ParcelableUser>) {
val participants = this.participants
val participants: Array<ParcelableUser?>? = this.participants
if (participants == null) {
if (user != null) {
this.participants = arrayOf(user)
@ -123,7 +123,7 @@ fun ParcelableMessageConversation.addParticipants(users: Collection<ParcelableUs
} else {
val addingUsers = ArrayList<ParcelableUser>()
users.forEach { user ->
val index = participants.indexOfFirst { it.key == user.key }
val index = participants.indexOfFirst { it?.key == user.key }
if (index >= 0) {
participants[index] = user
} else {

View File

@ -404,7 +404,7 @@ class MessageConversationInfoFragment : BaseFragment(), IToolBarSupportFragment,
this.uri = uri.toString()
this.delete_always = true
})
val uploadResult = UpdateStatusTask.uploadAllMediaShared(context,
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
upload, account, media, null, true, null)
deleteAlways = uploadResult.deleteAlways
val avatarId = uploadResult.ids.first()

View File

@ -23,12 +23,12 @@ import org.mariotaku.microblog.library.MicroBlog
import org.mariotaku.microblog.library.MicroBlogException
import org.mariotaku.microblog.library.fanfou.model.PhotoStatusUpdate
import org.mariotaku.microblog.library.mastodon.Mastodon
import org.mariotaku.microblog.library.mastodon.model.Attachment
import org.mariotaku.microblog.library.twitter.TwitterUpload
import org.mariotaku.microblog.library.twitter.model.ErrorInfo
import org.mariotaku.microblog.library.twitter.model.MediaUploadResponse
import org.mariotaku.microblog.library.twitter.model.NewMediaMetadata
import org.mariotaku.microblog.library.twitter.model.StatusUpdate
import org.mariotaku.microblog.library.mastodon.model.StatusUpdate as MastodonStatusUpdate
import org.mariotaku.restfu.http.ContentType
import org.mariotaku.restfu.http.mime.Body
import org.mariotaku.restfu.http.mime.FileBody
@ -62,6 +62,7 @@ import java.io.FileNotFoundException
import java.io.IOException
import java.util.*
import java.util.concurrent.TimeUnit
import org.mariotaku.microblog.library.mastodon.model.StatusUpdate as MastodonStatusUpdate
/**
* Update status
@ -368,7 +369,7 @@ class UpdateStatusTask(
if (pendingUpdate.sharedMediaIds != null) {
mediaIds = pendingUpdate.sharedMediaIds
} else {
val (ids, deleteOnSuccess, deleteAlways) = uploadAllMediaShared(context,
val (ids, deleteOnSuccess, deleteAlways) = uploadMicroBlogMediaShared(context,
upload, account, update.media, ownerIds, true, stateCallback)
mediaIds = ids
deleteOnSuccess.addAllTo(pendingUpdate.deleteOnSuccess)
@ -383,12 +384,20 @@ class UpdateStatusTask(
AccountType.STATUSNET -> {
// TODO use their native API
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
val (ids, deleteOnSuccess, deleteAlways) = uploadAllMediaShared(context,
val (ids, deleteOnSuccess, deleteAlways) = uploadMicroBlogMediaShared(context,
upload, account, update.media, ownerIds, false, stateCallback)
mediaIds = ids
deleteOnSuccess.addAllTo(pendingUpdate.deleteOnSuccess)
deleteAlways.addAllTo(pendingUpdate.deleteAlways)
}
AccountType.MASTODON -> {
val mastodon = account.newMicroBlogInstance(context, cls = Mastodon::class.java)
val (ids, deleteOnSuccess, deleteAlways) = uploadMastodonMedia(context,
mastodon, account, update.media, false, stateCallback)
mediaIds = ids
deleteOnSuccess.addAllTo(pendingUpdate.deleteOnSuccess)
deleteAlways.addAllTo(pendingUpdate.deleteAlways)
}
else -> {
mediaIds = null
}
@ -686,18 +695,13 @@ class UpdateStatusTask(
private val BULK_SIZE = 256 * 1024// 128 Kib
@Throws(UploadException::class)
fun uploadAllMediaShared(
context: Context,
upload: TwitterUpload,
account: AccountDetails,
media: Array<ParcelableMediaUpdate>,
ownerIds: Array<String>?,
chucked: Boolean,
callback: UploadCallback?
): SharedMediaUploadResult {
fun uploadMicroBlogMediaShared(context: Context, upload: TwitterUpload,
account: AccountDetails, media: Array<ParcelableMediaUpdate>,
ownerIds: Array<String>?, chucked: Boolean, callback: UploadCallback?):
SharedMediaUploadResult {
val deleteOnSuccess = ArrayList<MediaDeletionItem>()
val deleteAlways = ArrayList<MediaDeletionItem>()
val mediaIds = media.mapIndexed { index, media ->
val mediaIds = media.mapIndexedToArray { index, media ->
val resp: MediaUploadResponse
//noinspection TryWithIdenticalCatches
var body: MediaStreamBody? = null
@ -732,9 +736,44 @@ class UpdateStatusTask(
// Ignore
}
}
return@mapIndexed resp.id
return@mapIndexedToArray resp.id
}
return SharedMediaUploadResult(mediaIds.toTypedArray(), deleteOnSuccess, deleteAlways)
return SharedMediaUploadResult(mediaIds, deleteOnSuccess, deleteAlways)
}
@Throws(UploadException::class)
fun uploadMastodonMedia(context: Context, mastodon: Mastodon,
account: AccountDetails, media: Array<ParcelableMediaUpdate>,
chucked: Boolean, callback: UploadCallback?): SharedMediaUploadResult {
val deleteOnSuccess = ArrayList<MediaDeletionItem>()
val deleteAlways = ArrayList<MediaDeletionItem>()
val mediaIds = media.mapIndexedToArray { index, media ->
val resp: Attachment
//noinspection TryWithIdenticalCatches
var body: MediaStreamBody? = null
try {
val sizeLimit = account.mediaSizeLimit
body = getBodyFromMedia(context, media, sizeLimit, chucked,
ContentLengthInputStream.ReadListener { length, position ->
callback?.onUploadingProgressChanged(index, position, length)
})
resp = mastodon.uploadMediaAttachment(body.body)
} catch (e: IOException) {
throw UploadException(e).apply {
this.deleteAlways = deleteAlways
}
} catch (e: MicroBlogException) {
throw UploadException(e).apply {
this.deleteAlways = deleteAlways
}
} finally {
body?.close()
}
body?.deleteOnSuccess?.addAllTo(deleteOnSuccess)
body?.deleteAlways?.addAllTo(deleteAlways)
return@mapIndexedToArray resp.id
}
return SharedMediaUploadResult(mediaIds, deleteOnSuccess, deleteAlways)
}
@Throws(IOException::class)
@ -772,7 +811,9 @@ class UpdateStatusTask(
}
cis.setReadListener(readListener)
val mimeType = data?.type ?: mediaType ?: "application/octet-stream"
val body = FileBody(cis, "attachment", cis.length(), ContentType.parse(mimeType))
val extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType) ?: ".bin"
val fileName = mediaUri.lastPathSegment?.substringBeforeLast(".") ?: "attachment"
val body = FileBody(cis, "$fileName.$extension", cis.length(), ContentType.parse(mimeType))
val deleteOnSuccess: MutableList<MediaDeletionItem> = mutableListOf()
val deleteAlways: MutableList<MediaDeletionItem> = mutableListOf()
if (media.delete_always) {
@ -854,11 +895,9 @@ class UpdateStatusTask(
return null
}
if (imageLimit != null) {
if (imageLimit.checkGeomentry(o.outWidth, o.outHeight)) return null
if (imageLimit == null || imageLimit.checkGeomentry(o.outWidth, o.outHeight)) return null
o.inSampleSize = BitmapUtils.calculateInSampleSize(o.outWidth, o.outHeight,
imageLimit.maxWidth, imageLimit.maxHeight)
}
o.inJustDecodeBounds = false
// Do actual image decoding
val bitmap = context.contentResolver.openInputStream(mediaUri).use {

View File

@ -113,7 +113,7 @@ class SendMessageTask(
if (message.media.isNotNullOrEmpty()) {
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
val uploadResult = UpdateStatusTask.uploadAllMediaShared(context,
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
upload, account, message.media, null, true, null)
newDm.setMediaId(uploadResult.ids[0])
deleteAlways = uploadResult.deleteAlways
@ -150,7 +150,7 @@ class SendMessageTask(
var mediaId: String? = null
if (message.media.isNotNullOrEmpty()) {
val upload = account.newMicroBlogInstance(context, cls = TwitterUpload::class.java)
val uploadResult = UpdateStatusTask.uploadAllMediaShared(context,
val uploadResult = UpdateStatusTask.uploadMicroBlogMediaShared(context,
upload, account, message.media, null, true, null)
mediaId = uploadResult.ids[0]
deleteAlways = uploadResult.deleteAlways

View File

@ -174,9 +174,13 @@ class StatusViewHolder(private val adapter: IStatusesAdapter<*>, itemView: View)
statusContentUpperSpace.visibility = View.GONE
} else if (status.in_reply_to_status_id != null && status.in_reply_to_user_key != null && displayInReplyTo) {
val inReplyTo = colorNameManager.getDisplayName(status.in_reply_to_user_key!!,
status.in_reply_to_name, status.in_reply_to_screen_name, nameFirst)
statusInfoLabel.text = context.getString(R.string.in_reply_to_name, formatter.unicodeWrap(inReplyTo))
if (status.in_reply_to_name != null && status.in_reply_to_screen_name != null) {
val inReplyTo = colorNameManager.getDisplayName(status.in_reply_to_user_key!!,
status.in_reply_to_name, status.in_reply_to_screen_name, nameFirst)
statusInfoLabel.text = context.getString(R.string.in_reply_to_name, formatter.unicodeWrap(inReplyTo))
} else {
statusInfoLabel.text = context.getString(R.string.label_status_type_reply)
}
statusInfoIcon.setImageResource(R.drawable.ic_activity_action_reply)
statusInfoLabel.visibility = View.VISIBLE
statusInfoIcon.visibility = View.VISIBLE

View File

@ -567,6 +567,7 @@
<string name="label_sensitive_content">Sensitive content</string>
<string name="label_status_hint">What\'s happening?</string>
<string name="label_status_not_available">Tweet not available</string>
<string name="label_status_type_reply">Reply</string>
<string name="label_statuses">Tweets</string>
<string name="label_statuses_replies">Tweets and replies</string>
<string name="label_statuses_retweets">Tweets and retweets</string>