Last active
August 29, 2015 14:15
-
-
Save AKB428/4a9fdd1e52bcce6da3e7 to your computer and use it in GitHub Desktop.
Twitterの新機能である動画投稿のツイートからの動画URLをJSONから抽出し、動画をじゃぶじゃぶダウンロードする ref: http://qiita.com/AKB428/items/f61f2e87e652eb1690d9
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Twitter twitter = new TwitterFactory(cb.build()).getInstance(); | |
twitter.setOAuthConsumer(twitterModel.getConsumerKey(), twitterModel.getConsumerSecret()); | |
twitter.setOAuthAccessToken(new AccessToken(twitterModel.getAccessToken(), twitterModel.getAccessToken_secret())); | |
List<Status> statuses = twitter.getUserTimeline(args[0]); | |
System.out.println("Showing home timeline."); | |
for (Status status : statuses) { | |
System.out.println(status.getUser().getName() + ":" + status.getText()); | |
String rawJSON = DataObjectFactory.getRawJSON(status); | |
System.out.println(rawJSON); | |
// Twitter4Jを使用し画像URL(1枚のみ)を取得 | |
MediaEntity[] arrMedia = status.getMediaEntities(); | |
for (MediaEntity media : arrMedia) { | |
System.out.println("MediaEntity= " + media.getMediaURL()); | |
} | |
// Twitter4Jを使用し画像URL(複数)を取得 | |
MediaEntity[] arrMediaExt = status.getExtendedMediaEntities(); | |
for (MediaEntity media : arrMediaExt) { | |
System.out.println("ExtendedMediaEntities= " + media.getMediaURL()); | |
} | |
URLEntity[] entity = status.getURLEntities(); | |
for (URLEntity urlEntity : entity) { | |
System.out.println("URLEntity= " + urlEntity.getExpandedURL()); | |
} | |
// VideoInfoクラスを使用し動画URLを取得 | |
List<VideoInfo> videoInfoList = VideoInfo.fromRawJson(rawJSON); | |
if (videoInfoList != null) { | |
for (VideoInfo videoInfo : videoInfoList) { | |
videoInfo.printFormatVideoInfo(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
video_info | |
|-- duration_millis : 11965 | |
|-- aspect_ratio : [1, 1] | |
|-- variants : [ | |
{ | |
|-- bitrate : 832000 | |
|-- content_type : video/webm | |
|-- url : https://video.twimg.com/ext_tw_video/561814337585569793/pu/vid/480x480/QKhWzHdEK0QDPtg8.webm | |
} | |
{ | |
|-- bitrate : 1280000 | |
|-- content_type : video/mp4 | |
|-- url : https://video.twimg.com/ext_tw_video/561814337585569793/pu/vid/720x720/IdBKWbELa8D8cqLD.mp4 | |
} | |
{ | |
|-- bitrate : 320000 | |
|-- content_type : video/mp4 | |
|-- url : https://video.twimg.com/ext_tw_video/561814337585569793/pu/vid/240x240/7EK_gSEEPFBATzXI.mp4 | |
} | |
{ | |
|-- bitrate : 832000 | |
|-- content_type : video/mp4 | |
|-- url : https://video.twimg.com/ext_tw_video/561814337585569793/pu/vid/480x480/QKhWzHdEK0QDPtg8.mp4 | |
} | |
{ | |
|-- bitrate : null | |
|-- content_type : application/x-mpegURL | |
|-- url : https://video.twimg.com/ext_tw_video/561814337585569793/pu/pl/6G6kgS5lRXAOiCcg.m3u8 | |
} | |
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package akb428.tkws; | |
import java.io.IOException; | |
import java.util.List; | |
import org.codehaus.jackson.JsonProcessingException; | |
import akb428.twitter.model.VideoInfo; | |
//arg[0] = ツイッターの生JSON | |
public class TwitterVideoInfoParserSample { | |
public static void main(String[] args) throws JsonProcessingException, IOException { | |
String rawJsonString = args[0]; | |
List<VideoInfo> videoInfoList = VideoInfo.fromRawJson(rawJsonString); | |
for (VideoInfo videoInfo : videoInfoList) { | |
videoInfo.printFormatVideoInfo(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package akb428.twitter.model.videoinfo; | |
public class Variant { | |
private Long bitrate = null; | |
private String contentType = null; | |
private String url = null; | |
//TODO publicなgetter setter メソッドは記載省略 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"contributors": null, | |
"text": "ツイッター動画投稿テスト http://t.co/y9hjEfABw1", | |
"geo": null, | |
"retweeted": false, | |
"in_reply_to_screen_name": null, | |
"possibly_sensitive": false, | |
"truncated": false, | |
"lang": "ja", | |
"entities": { | |
"symbols": [], | |
"urls": [], | |
"hashtags": [], | |
"media": [ | |
{ | |
"sizes": { | |
"thumb": { | |
"w": 150, | |
"resize": "crop", | |
"h": 150 | |
}, | |
"small": { | |
"w": 340, | |
"resize": "fit", | |
"h": 340 | |
}, | |
"large": { | |
"w": 720, | |
"resize": "fit", | |
"h": 720 | |
}, | |
"medium": { | |
"w": 600, | |
"resize": "fit", | |
"h": 600 | |
} | |
}, | |
"id": 561814337585569800, | |
"media_url_https": "https://pbs.twimg.com/ext_tw_video_thumb/561814337585569793/pu/img/ZyW1taT-3_AkDB-4.jpg", | |
"media_url": "http://pbs.twimg.com/ext_tw_video_thumb/561814337585569793/pu/img/ZyW1taT-3_AkDB-4.jpg", | |
"expanded_url": "http://twitter.com/n428dev/status/561814427150741505/video/1", | |
"indices": [ | |
13, | |
35 | |
], | |
"id_str": "561814337585569793", | |
"type": "photo", | |
"display_url": "pic.twitter.com/y9hjEfABw1", | |
"url": "http://t.co/y9hjEfABw1" | |
} | |
], | |
"user_mentions": [] | |
}, | |
"in_reply_to_status_id_str": null, | |
"id": 561814427150741500, | |
"extended_entities": { | |
"media": [ | |
{ | |
"sizes": { | |
"thumb": { | |
"w": 150, | |
"resize": "crop", | |
"h": 150 | |
}, | |
"small": { | |
"w": 340, | |
"resize": "fit", | |
"h": 340 | |
}, | |
"large": { | |
"w": 720, | |
"resize": "fit", | |
"h": 720 | |
}, | |
"medium": { | |
"w": 600, | |
"resize": "fit", | |
"h": 600 | |
} | |
}, | |
"id": 561814337585569800, | |
"media_url_https": "https://pbs.twimg.com/ext_tw_video_thumb/561814337585569793/pu/img/ZyW1taT-3_AkDB-4.jpg", | |
"video_info": { | |
"duration_millis": 11965, | |
"variants": [ | |
{ | |
"bitrate": 832000, | |
"content_type": "video/webm", | |
"url": "https://video.twimg.com/ext_tw_video/561814337585569793/pu/vid/480x480/QKhWzHdEK0QDPtg8.webm" | |
}, | |
{ | |
"bitrate": 1280000, | |
"content_type": "video/mp4", | |
"url": "https://video.twimg.com/ext_tw_video/561814337585569793/pu/vid/720x720/IdBKWbELa8D8cqLD.mp4" | |
}, | |
{ | |
"bitrate": 320000, | |
"content_type": "video/mp4", | |
"url": "https://video.twimg.com/ext_tw_video/561814337585569793/pu/vid/240x240/7EK_gSEEPFBATzXI.mp4" | |
}, | |
{ | |
"bitrate": 832000, | |
"content_type": "video/mp4", | |
"url": "https://video.twimg.com/ext_tw_video/561814337585569793/pu/vid/480x480/QKhWzHdEK0QDPtg8.mp4" | |
}, | |
{ | |
"content_type": "application/x-mpegURL", | |
"url": "https://video.twimg.com/ext_tw_video/561814337585569793/pu/pl/6G6kgS5lRXAOiCcg.m3u8" | |
} | |
], | |
"aspect_ratio": [ | |
1, | |
1 | |
] | |
}, | |
"media_url": "http://pbs.twimg.com/ext_tw_video_thumb/561814337585569793/pu/img/ZyW1taT-3_AkDB-4.jpg", | |
"expanded_url": "http://twitter.com/n428dev/status/561814427150741505/video/1", | |
"indices": [ | |
13, | |
35 | |
], | |
"id_str": "561814337585569793", | |
"type": "video", | |
"display_url": "pic.twitter.com/y9hjEfABw1", | |
"url": "http://t.co/y9hjEfABw1" | |
} | |
] | |
}, | |
"source": "<a href=\"http://twitter.com/download/iphone\" rel=\"nofollow\">Twitter for iPhone</a>", | |
"in_reply_to_user_id_str": null, | |
"favorited": false, | |
"in_reply_to_status_id": null, | |
"retweet_count": 0, | |
"created_at": "Sun Feb 01 09:12:52 +0000 2015", | |
"in_reply_to_user_id": null, | |
"favorite_count": 0, | |
"id_str": "561814427150741505", | |
"place": null, | |
"user": { | |
"location": "", | |
"default_profile": true, | |
"profile_background_tile": false, | |
"statuses_count": 66, | |
"lang": "ja", | |
"profile_link_color": "0084B4", | |
"id": 826661216, | |
"following": false, | |
"protected": false, | |
"profile_location": null, | |
"favourites_count": 5, | |
"profile_text_color": "333333", | |
"description": "428で働くプログラマー", | |
"verified": false, | |
"contributors_enabled": false, | |
"profile_sidebar_border_color": "C0DEED", | |
"name": "AKB428", | |
"profile_background_color": "C0DEED", | |
"created_at": "Sun Sep 16 07:06:52 +0000 2012", | |
"is_translation_enabled": false, | |
"default_profile_image": false, | |
"followers_count": 9, | |
"profile_image_url_https": "https://pbs.twimg.com/profile_images/507934202185011200/HcQGt2_r_normal.jpeg", | |
"geo_enabled": false, | |
"profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", | |
"profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", | |
"follow_request_sent": false, | |
"entities": { | |
"description": { | |
"urls": [] | |
} | |
}, | |
"url": null, | |
"utc_offset": 32400, | |
"time_zone": "Irkutsk", | |
"notifications": false, | |
"profile_use_background_image": true, | |
"friends_count": 40, | |
"profile_sidebar_fill_color": "DDEEF6", | |
"screen_name": "n428dev", | |
"id_str": "826661216", | |
"profile_image_url": "http://pbs.twimg.com/profile_images/507934202185011200/HcQGt2_r_normal.jpeg", | |
"listed_count": 0, | |
"is_translator": false | |
}, | |
"coordinates": null | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package akb428.twitter.model; | |
import java.io.IOException; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.List; | |
import org.codehaus.jackson.JsonNode; | |
import org.codehaus.jackson.JsonProcessingException; | |
import org.codehaus.jackson.map.ObjectMapper; | |
import akb428.twitter.model.videoinfo.Variant; | |
public class VideoInfo { | |
private Long durationMillis = 0L; | |
private List<Variant> variants = null; | |
private List<Long> aspectRatio = null; | |
/** | |
* ツイートの生JSON文字列からVideoInfo情報をListにして返却します VideoInfoが見つからない場合はnullを返却します | |
* ツイートの生JSONはTwitter4Jであれば | |
* | |
* ---------------------------------------------------------------- | |
* ConfigurationBuilder cb = new ConfigurationBuilder(); | |
* cb.setJSONStoreEnabled(true); String rawJsonString = | |
* DataObjectFactory.getRawJSON(Status status); | |
* ---------------------------------------------------------------- | |
* | |
* で取得できます。 | |
* | |
* @param rawJsonString | |
* JSON文字列 | |
* @return VideoInfoのリスト。ビデオ情報がない場合はnull | |
* @throws JsonProcessingException | |
* @throws IOException | |
*/ | |
public static List<VideoInfo> fromRawJson(String rawJsonString) throws JsonProcessingException, IOException { | |
List<VideoInfo> videoInfoList = new ArrayList<>(); | |
ObjectMapper mapper = new ObjectMapper(); | |
JsonNode rootNode = mapper.readTree(rawJsonString); | |
JsonNode extentdedEntitiesNode = rootNode.get("extended_entities"); | |
if (extentdedEntitiesNode == null) { | |
return null; | |
} | |
JsonNode mediaNodo = extentdedEntitiesNode.get("media"); | |
if (mediaNodo == null) { | |
return null; | |
} | |
Iterator<JsonNode> mediaNodeList = mediaNodo.getElements(); | |
// mediaノードにはビデオ以外もあるので、動画情報のみ取得するようにする | |
// video_infoがあるかどうか | |
// media.type="video" かどうか | |
// のいずれかで判定する | |
// media: [ {type: video, video_info:{}}, {type: video, video_info:{}}, | |
// {}, ] | |
while (mediaNodeList.hasNext()) { | |
JsonNode videoNode = mediaNodeList.next().get("video_info"); | |
if (videoNode != null) { | |
VideoInfo videoInfo = fromVideoJsonNode(videoNode); | |
videoInfoList.add(videoInfo); | |
} | |
} | |
return videoInfoList; | |
} | |
/** | |
* videoInfo(JsonNodeクラス)をVideoInfoクラスに変換します | |
* VideoInfoクラスの各フィールドに対応するJSONプロパティが存在しないときはフィールドには何も設定しません。(nullのまま) | |
* | |
* @param videoNode | |
* @return | |
*/ | |
public static VideoInfo fromVideoJsonNode(JsonNode videoNode) { | |
VideoInfo videoInfo = new VideoInfo(); | |
JsonNode durationMillisNode = videoNode.get("duration_millis"); | |
if (durationMillisNode != null) { | |
videoInfo.setDurationMillis(durationMillisNode.getLongValue()); | |
} | |
JsonNode aspectRatioNode = videoNode.get("aspect_ratio"); | |
if (aspectRatioNode != null) { | |
List<Long> aspectRatioList = new ArrayList<>(); | |
Iterator<JsonNode> aspectRatioChildNodes = aspectRatioNode.getElements(); | |
while (aspectRatioChildNodes.hasNext()) { | |
aspectRatioList.add(aspectRatioChildNodes.next().getLongValue()); | |
} | |
videoInfo.setAspectRatio(aspectRatioList); | |
} | |
JsonNode variantsNode = videoNode.get("variants"); | |
if (variantsNode != null) { | |
List<Variant> variantList = new ArrayList<>(); | |
Iterator<JsonNode> variantChildNodes = variantsNode.getElements(); | |
while (variantChildNodes.hasNext()) { | |
Variant variant = new Variant(); | |
JsonNode child = variantChildNodes.next(); | |
if (child.get("bitrate") != null) { | |
variant.setBitrate(child.get("bitrate").getLongValue()); | |
} | |
variant.setContentType(child.get("content_type").getTextValue()); | |
variant.setUrl(child.get("url").getTextValue()); | |
variantList.add(variant); | |
} | |
videoInfo.setVariants(variantList); | |
} | |
return videoInfo; | |
} | |
/** | |
* VideoInfoリストを整形してprintします | |
*/ | |
public void printFormatVideoInfo() { | |
System.out.println("video_info"); | |
System.out.println("|-- duration_millis : " + this.getDurationMillis()); | |
System.out.println("|-- aspect_ratio : " + this.getAspectRatio()); | |
System.out.println("|-- variants : [ "); | |
for (Variant variant : this.getVariants()) { | |
System.out.println(" {"); | |
System.out.println(" |-- bitrate : " + variant.getBitrate()); | |
System.out.println(" |-- content_type : " + variant.getContentType()); | |
System.out.println(" |-- url : " + variant.getUrl()); | |
System.out.println(" }"); | |
} | |
System.out.println(" ]"); | |
} | |
//TODO publicなgetter setter メソッドは記載省略 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment