Skip to content

Commit

Permalink
Merge #554
Browse files Browse the repository at this point in the history
554: feat: fixed for the issue (#547) r=myConsciousness a=myConsciousness

# 1. Description

<!-- Provide a description of what this PR is doing.
If you're modifying existing behavior, describe the existing behavior, how this PR is changing it,
and what motivated the change. If this is a breaking change, specify explicitly which APIs have been
changed. -->

## 1.1. Checklist

<!-- Before you create this PR confirm that it meets all requirements listed below by checking the
relevant checkboxes (`[x]`). This will ensure a smooth and quick review process. -->

- [x] The title of my PR starts with a [Conventional Commit] prefix (`fix:`, `feat:`, `docs:` etc).
- [x] I have read the [Contributor Guide] and followed the process outlined for submitting PRs.
- [x] I have updated/added tests for ALL new/updated/fixed functionality.
- [x] I have updated/added relevant documentation in `docs` and added dartdoc comments with `///`.
- [x] I have updated/added relevant examples in `examples`.

## 1.2. Breaking Change

<!-- Does your PR require users to manually update their apps to accommodate your change?

If the PR is a breaking change this should be indicated with suffix "!"  (for example, `feat!:`, `fix!:`). See [Conventional Commit] for details.
-->

- [ ] Yes, this is a breaking change.
- [x] No, this is _not_ a breaking change.

## 1.3. Related Issues

<!-- Provide a list of issues related to this PR from the [issue database].
Indicate which of these issues are resolved or fixed by this PR, i.e. Fixes #xxxx* !-->

<!-- Links -->

[issue database]: https://github.com/twitter-dart/twitter-api-v2/issues
[contributor guide]: https://github.com/twitter-dart/twitter-api-v2/blob/main/CONTRIBUTING.md
[style guide]: https://github.com/twitter-dart/twitter-api-v2/blob/main/STYLEGUIDE.md
[conventional commit]: https://conventionalcommits.org


Co-authored-by: myConsciousness <[email protected]>
  • Loading branch information
bors[bot] and myConsciousness authored Nov 10, 2022
2 parents d6a2626 + 2cfebf0 commit 23bd0b1
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 80 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
- Removed deprecated property and constructor.
- Removed `UploadedMediaData.mediaId` and use `UploadedMediaData.id` instead.
- `FilteringRule.sampleOf` and use `FilteringRule.ofSample` instead.
- Supported upload media for direct message. Please specify `MediaCategory.directMessage` to the option in `MediaService.uploadMedia`. ([#547](https://github.com/twitter-dart/twitter-api-v2/issues/547))

## v4.3.5

Expand Down
1 change: 1 addition & 0 deletions lib/src/service/dms/message_attachments_param.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided the conditions.

// Package imports:
import 'package:freezed_annotation/freezed_annotation.dart';

class MessageAttachmentsParam {
Expand Down
1 change: 1 addition & 0 deletions lib/src/service/dms/message_param.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided the conditions.

// Project imports:
import 'message_attachments_param.dart';

class MessageParam {
Expand Down
29 changes: 2 additions & 27 deletions lib/src/service/media/media_category.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,36 +6,11 @@
import 'package:twitter_api_core/twitter_api_core.dart';

enum MediaCategory implements Serializable {
tweetImage('TWEET_IMAGE'),
tweetGif('TWEET_GIF'),
tweetVideo('TWEET_VIDEO'),
videoCaption('SUBTITLES');
tweet('TWEET'),
directMessage('DM');

@override
final String value;

const MediaCategory(this.value);

/// Returns [MediaCategory] based on [mediaMimeType].
static MediaCategory valueOf(final String mediaMimeType) {
if (mediaMimeType.endsWith('x-subrip')) {
return videoCaption;
}

if (mediaMimeType.startsWith('video')) {
return tweetVideo;
}

if (mediaMimeType.startsWith('image')) {
if (mediaMimeType.endsWith('gif')) {
return tweetGif;
}

return tweetImage;
}

throw UnsupportedError(
'Unsupported Mime type [$mediaMimeType].',
);
}
}
41 changes: 41 additions & 0 deletions lib/src/service/media/media_mime_type.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2022 Kato Shinya. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided the conditions.

// Package imports:
import 'package:twitter_api_core/twitter_api_core.dart';

enum MediaMimeType implements Serializable {
image('IMAGE'),
gif('GIF'),
video('VIDEO'),
videoCaption('SUBTITLES');

@override
final String value;

const MediaMimeType(this.value);

/// Returns [MediaMimeType] based on [mediaMimeType].
static MediaMimeType valueOf(final String mediaMimeType) {
if (mediaMimeType.endsWith('x-subrip')) {
return videoCaption;
}

if (mediaMimeType.startsWith('video')) {
return video;
}

if (mediaMimeType.startsWith('image')) {
if (mediaMimeType.endsWith('gif')) {
return gif;
}

return image;
}

throw UnsupportedError(
'Unsupported Mime type [$mediaMimeType].',
);
}
}
41 changes: 38 additions & 3 deletions lib/src/service/media/media_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import '../base_media_service.dart';
import '../common/locale.dart';
import '../response/twitter_response.dart';
import 'media_category.dart';
import 'media_mime_type.dart';
import 'upload_error.dart';
import 'upload_event.dart';
import 'uploaded_media_data.dart';
Expand Down Expand Up @@ -101,6 +102,14 @@ abstract class MediaService {
///
/// - [file]: The raw binary media content (image, gif, video) being uploaded.
///
/// - [category]: Specify whether the media to be uploaded is related to
/// tweets or direct messages. The default value is
/// [MediaCategory.tweet], and this option is not necessary
/// if you are uploading media to be attached to a tweet.
/// However, for media to be attached to a direct message,
/// be sure to specify [MediaCategory.directMessage] for this
/// option.
///
/// - [altText]: Additional descriptive text to be added to images and GIFs.
/// Currently, this option is available only for images and GIFs;
/// if the media file being uploaded is a video, this option
Expand Down Expand Up @@ -136,6 +145,7 @@ abstract class MediaService {
/// - https://developer.twitter.com/en/docs/twitter-api/v1/media/upload-media/api-reference/get-media-upload-status
Future<TwitterResponse<UploadedMediaData, void>> uploadMedia({
required File file,
MediaCategory category = MediaCategory.tweet,
String? altText,
List<String>? additionalOwners,
Function(UploadEvent event)? onProgress,
Expand Down Expand Up @@ -250,6 +260,7 @@ class _MediaService extends BaseMediaService implements MediaService {
@override
Future<TwitterResponse<UploadedMediaData, void>> uploadMedia({
required File file,
MediaCategory category = MediaCategory.tweet,
String? altText,
List<String>? additionalOwners,
Function(UploadEvent event)? onProgress,
Expand All @@ -273,6 +284,7 @@ class _MediaService extends BaseMediaService implements MediaService {
return super.transformUploadedDataResponse(
await _uploadMedia(
file: file,
category: category,
mimeType: mimeType,
altText: altText,
additionalOwners: additionalOwners,
Expand All @@ -290,6 +302,7 @@ class _MediaService extends BaseMediaService implements MediaService {
return super.transformUploadedDataResponse(
await _uploadMedia(
file: file,
category: category,
mimeType: mimeType,
altText: altText,
additionalOwners: additionalOwners,
Expand All @@ -305,14 +318,18 @@ class _MediaService extends BaseMediaService implements MediaService {
required String videoId,
required String captionId,
required core.Language language,
MediaCategory category = MediaCategory.tweet,
}) async =>
super.evaluateResponse(
await super.post(
core.UserContext.oauth1Only,
'/1.1/media/subtitles/create.json',
body: {
'media_id': videoId,
'media_category': MediaCategory.tweetVideo.value,
'media_category': _resolveMediaCategory(
category,
MediaMimeType.video,
),
'subtitle_info': {
'subtitles': [
{
Expand All @@ -331,14 +348,18 @@ class _MediaService extends BaseMediaService implements MediaService {
required String videoId,
required String captionId,
required core.Language language,
MediaCategory mediaCategory = MediaCategory.tweet,
}) async =>
super.evaluateResponse(
await super.post(
core.UserContext.oauth1Only,
'/1.1/media/subtitles/delete.json',
body: {
'media_id': videoId,
'media_category': MediaCategory.tweetVideo.value,
'media_category': _resolveMediaCategory(
mediaCategory,
MediaMimeType.video,
),
'subtitle_info': {
'subtitles': [
{
Expand Down Expand Up @@ -395,6 +416,7 @@ class _MediaService extends BaseMediaService implements MediaService {

Future<core.Response> _uploadMedia({
required File file,
required MediaCategory category,
required String mimeType,
String? altText,
List<String>? additionalOwners,
Expand Down Expand Up @@ -422,6 +444,7 @@ class _MediaService extends BaseMediaService implements MediaService {

final initResponse = await _initUpload(
mediaBytes: mediaBytes,
category: category,
mediaMimeType: mimeType,
additionalOwners: additionalOwners,
);
Expand Down Expand Up @@ -474,6 +497,7 @@ class _MediaService extends BaseMediaService implements MediaService {

Future<core.Response> _initUpload({
required List<int> mediaBytes,
required MediaCategory category,
required String mediaMimeType,
List<String>? additionalOwners,
}) async =>
Expand All @@ -484,7 +508,10 @@ class _MediaService extends BaseMediaService implements MediaService {
'command': 'INIT',
'total_bytes': mediaBytes.length,
'media_type': mediaMimeType,
'media_category': MediaCategory.valueOf(mediaMimeType),
'media_category': _resolveMediaCategory(
category,
MediaMimeType.valueOf(mediaMimeType),
),
'additional_owners': additionalOwners,
},
);
Expand Down Expand Up @@ -689,6 +716,14 @@ class _MediaService extends BaseMediaService implements MediaService {
return mediaMimeType;
}

String _resolveMediaCategory(
final MediaCategory category,
final MediaMimeType mimeType,
) =>
mimeType == MediaMimeType.videoCaption
? mimeType.value
: '${category.value}_${mimeType.value}';

bool _isImage(final String mimeType) => mimeType.startsWith('image');
bool _isVideo(final String mimeType) => mimeType.startsWith('video');
bool _isCaption(final String mimeType) => mimeType.endsWith('x-subrip');
Expand Down
1 change: 1 addition & 0 deletions lib/twitter_api_v2.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export 'package:twitter_api_v2/src/service/lists/list_expansion.dart';
export 'package:twitter_api_v2/src/service/lists/list_field.dart';
export 'package:twitter_api_v2/src/service/lists/list_meta.dart';
export 'package:twitter_api_v2/src/service/lists/lists_service.dart';
export 'package:twitter_api_v2/src/service/media/media_category.dart';
export 'package:twitter_api_v2/src/service/media/media_data.dart';
export 'package:twitter_api_v2/src/service/media/media_field.dart';
export 'package:twitter_api_v2/src/service/media/media_service.dart';
Expand Down
3 changes: 3 additions & 0 deletions test/mocks/mock.mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
// Do not manually edit this file.

// ignore_for_file: no_leading_underscores_for_library_prefixes

// Dart imports:
import 'dart:async' as _i4;

// Package imports:
import 'package:http/http.dart' as _i2;
import 'package:mockito/mockito.dart' as _i1;
import 'package:twitter_api_core/src/client/client_context.dart' as _i3;
Expand Down
54 changes: 4 additions & 50 deletions test/src/service/media/media_category_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,58 +10,12 @@ import 'package:twitter_api_v2/src/service/media/media_category.dart';

void main() {
test('.name', () {
expect(MediaCategory.tweetImage.name, 'tweetImage');
expect(MediaCategory.tweetGif.name, 'tweetGif');
expect(MediaCategory.tweetVideo.name, 'tweetVideo');
expect(MediaCategory.videoCaption.name, 'videoCaption');
expect(MediaCategory.tweet.name, 'tweet');
expect(MediaCategory.directMessage.name, 'directMessage');
});

test('.value', () {
expect(MediaCategory.tweetImage.value, 'TWEET_IMAGE');
expect(MediaCategory.tweetGif.value, 'TWEET_GIF');
expect(MediaCategory.tweetVideo.value, 'TWEET_VIDEO');
expect(MediaCategory.videoCaption.value, 'SUBTITLES');
});

group('.valueOf', () {
test('with png', () {
final mimeType = MediaCategory.valueOf('image/png');

expect(mimeType, MediaCategory.tweetImage);
});

test('with gif', () {
final mimeType = MediaCategory.valueOf('image/gif');

expect(mimeType, MediaCategory.tweetGif);
});

test('with video', () {
final mimeType = MediaCategory.valueOf('video/mp4');

expect(mimeType, MediaCategory.tweetVideo);
});

test('with caption (.srt)', () {
final mimeType = MediaCategory.valueOf('application/x-subrip');

expect(mimeType, MediaCategory.videoCaption);
});

test('with unsupported mime type', () {
expect(
() => MediaCategory.valueOf('application/vnd.ms-excel'),
throwsA(
allOf(
isA<UnsupportedError>(),
predicate(
(dynamic e) =>
e.message ==
'Unsupported Mime type [application/vnd.ms-excel].',
),
),
),
);
});
expect(MediaCategory.tweet.value, 'TWEET');
expect(MediaCategory.directMessage.value, 'DM');
});
}
Loading

0 comments on commit 23bd0b1

Please sign in to comment.