Javascript 显示来自 twitter api 的动画 gif
Posted
技术标签:
【中文标题】Javascript 显示来自 twitter api 的动画 gif【英文标题】:Javascript displaying animated gifs from twitter api 【发布时间】:2019-08-03 00:26:44 【问题描述】:有谁知道让 Jason Mayes Twitter Post Fetcher 包含动画 gif 的方法?我设法提取了 gif,但它们显示为 jpg 而不是 gif/video 格式...
这里还有一个codepen链接:https://codepen.io/anon/pen/bZomxM
这里是 Post Fetcher 的 javascript、CSS 和 html:
/*********************************************************************
* #### Twitter Post Fetcher v18.0.3 ####
* Coded by Jason Mayes 2015. A present to all the developers out there.
* www.jasonmayes.com
* Please keep this disclaimer with my code if you use it. Thanks. :-)
* Got feedback or questions, ask here:
* http://www.jasonmayes.com/projects/twitterApi/
* Github: https://github.com/jasonmayes/Twitter-Post-Fetcher
* Updates will be posted to this site.
*********************************************************************/
(function(root, factory)
if (typeof define === 'function' && define.amd)
// AMD. Register as an anonymous module.
define([], factory);
else if (typeof exports === 'object')
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory();
else
// Browser globals.
factory();
(this, function()
var domNode = '';
var maxTweets = 20;
var parseLinks = true;
var queue = [];
var inProgress = false;
var printTime = true;
var printUser = true;
var formatterFunction = null;
var supportsClassName = true;
var showRts = true;
var customCallbackFunction = null;
var showInteractionLinks = true;
var showImages = true;
var useEmoji = true;
var targetBlank = true;
var lang = 'en';
var permalinks = true;
var dataOnly = false;
var script = null;
var scriptAdded = false;
function handleTweets(tweets)
if (customCallbackFunction === null)
var x = tweets.length;
var n = 0;
var element = document.getElementById(domNode);
var html = '<ul>';
while(n < x)
html += '<li>' + tweets[n] + '</li>';
n++;
html += '</ul>';
element.innerHTML = html;
else
customCallbackFunction(tweets);
function strip(data)
return data.replace(/<b[^>]*>(.*?)<\/b>/gi, function(a,s)return s;)
.replace(/class="(?!(tco-hidden|tco-display|tco-ellipsis))+.*?"|data-query-source=".*?"|dir=".*?"|rel=".*?"/gi,
'');
function targetLinksToNewWindow(el)
var links = el.getElementsByTagName('a');
for (var i = links.length - 1; i >= 0; i--)
links[i].setAttribute('target', '_blank');
links[i].setAttribute('rel', 'noopener');
function getElementsByClassName (node, classname)
var a = [];
var regex = new RegExp('(^| )' + classname + '( |$)');
var elems = node.getElementsByTagName('*');
for (var i = 0, j = elems.length; i < j; i++)
if(regex.test(elems[i].className))
a.push(elems[i]);
return a;
function extractImagesUrl(image_data)
if (image_data !== undefined && image_data.innerHTML.indexOf('data-image') >= 0)
var data_src = image_data.innerHTML.match(/data-image=\"([^"]+)\"/ig);
for (var i = 0; i < data_src.length; i++)
data_src[i] = data_src[i].match(/data-image=\"([^"]+)\"/i)[1];
data_src[i] = decodeURIComponent(data_src[i]) + '.jpg';
return data_src;
var twitterFetcher =
fetch: function(config)
if (config.maxTweets === undefined)
config.maxTweets = 20;
if (config.enableLinks === undefined)
config.enableLinks = true;
if (config.showUser === undefined)
config.showUser = true;
if (config.showTime === undefined)
config.showTime = true;
if (config.dateFunction === undefined)
config.dateFunction = 'default';
if (config.showRetweet === undefined)
config.showRetweet = true;
if (config.customCallback === undefined)
config.customCallback = null;
if (config.showInteraction === undefined)
config.showInteraction = true;
if (config.showImages === undefined)
config.showImages = false;
if (config.useEmoji === undefined)
config.useEmoji = false;
if (config.linksInNewWindow === undefined)
config.linksInNewWindow = true;
if (config.showPermalinks === undefined)
config.showPermalinks = true;
if (config.dataOnly === undefined)
config.dataOnly = false;
if (inProgress)
queue.push(config);
else
inProgress = true;
domNode = config.domId;
maxTweets = config.maxTweets;
parseLinks = config.enableLinks;
printUser = config.showUser;
printTime = config.showTime;
showRts = config.showRetweet;
formatterFunction = config.dateFunction;
customCallbackFunction = config.customCallback;
showInteractionLinks = config.showInteraction;
showImages = config.showImages;
useEmoji = config.useEmoji;
targetBlank = config.linksInNewWindow;
permalinks = config.showPermalinks;
dataOnly = config.dataOnly;
var head = document.getElementsByTagName('head')[0];
if (script !== null)
head.removeChild(script);
script = document.createElement('script');
script.type = 'text/javascript';
if (config.list !== undefined)
script.src = 'https://syndication.twitter.com/timeline/list?' +
'callback=__twttrf.callback&dnt=false&list_slug=' +
config.list.listSlug + '&screen_name=' + config.list.screenName +
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
'&rnd=' + Math.random();
else if (config.profile !== undefined)
script.src = 'https://syndication.twitter.com/timeline/profile?' +
'callback=__twttrf.callback&dnt=false' +
'&screen_name=' + config.profile.screenName +
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
'&rnd=' + Math.random();
else if (config.likes !== undefined)
script.src = 'https://syndication.twitter.com/timeline/likes?' +
'callback=__twttrf.callback&dnt=false' +
'&screen_name=' + config.likes.screenName +
'&suppress_response_codes=true&lang=' + (config.lang || lang) +
'&rnd=' + Math.random();
else
script.src = 'https://cdn.syndication.twimg.com/widgets/timelines/' +
config.id + '?&lang=' + (config.lang || lang) +
'&callback=__twttrf.callback&' +
'suppress_response_codes=true&rnd=' + Math.random();
head.appendChild(script);
,
callback: function(data)
if (data === undefined || data.body === undefined)
inProgress = false;
if (queue.length > 0)
twitterFetcher.fetch(queue[0]);
queue.splice(0,1);
return;
// Remove emoji and summary card images.
if(!useEmoji)
data.body = data.body.replace(/(<img[^c]*class="Emoji[^>]*>)|(<img[^c]*class="u-block[^>]*>)/g, '');
// Remove display images.
if (!showImages)
data.body = data.body.replace(/(<img[^c]*class="NaturalImage-image[^>]*>|(<img[^c]*class="CroppedImage-image[^>]*>))/g, '');
// Remove avatar images.
if (!printUser)
data.body = data.body.replace(/(<img[^c]*class="Avatar"[^>]*>)/g, '');
var div = document.createElement('div');
div.innerHTML = data.body;
if (typeof(div.getElementsByClassName) === 'undefined')
supportsClassName = false;
function swapDataSrc(element)
var avatarImg = element.getElementsByTagName('img')[0];
if (avatarImg)
avatarImg.src = avatarImg.getAttribute('data-src-2x');
else
var screenName = element.getElementsByTagName('a')[0]
.getAttribute('href').split('twitter.com/')[1];
var img = document.createElement('img');
img.setAttribute('src', 'https://twitter.com/' + screenName +
'/profile_image?size=bigger');
element.prepend(img);
return element;
var tweets = [];
var authors = [];
var times = [];
var images = [];
var rts = [];
var tids = [];
var permalinksURL = [];
var x = 0;
if (supportsClassName)
var tmp = div.getElementsByClassName('timeline-Tweet');
while (x < tmp.length)
if (tmp[x].getElementsByClassName('timeline-Tweet-retweetCredit').length > 0)
rts.push(true);
else
rts.push(false);
if (!rts[x] || rts[x] && showRts)
tweets.push(tmp[x].getElementsByClassName('timeline-Tweet-text')[0]);
tids.push(tmp[x].getAttribute('data-tweet-id'));
if (printUser)
authors.push(swapDataSrc(tmp[x].getElementsByClassName('timeline-Tweet-author')[0]));
times.push(tmp[x].getElementsByClassName('dt-updated')[0]);
permalinksURL.push(tmp[x].getElementsByClassName('timeline-Tweet-timestamp')[0]);
if (tmp[x].getElementsByClassName('timeline-Tweet-media')[0] !==
undefined)
images.push(tmp[x].getElementsByClassName('timeline-Tweet-media')[0]);
else
images.push(undefined);
x++;
else
var tmp = getElementsByClassName(div, 'timeline-Tweet');
while (x < tmp.length)
if (getElementsByClassName(tmp[x], 'timeline-Tweet-retweetCredit').length > 0)
rts.push(true);
else
rts.push(false);
if (!rts[x] || rts[x] && showRts)
tweets.push(getElementsByClassName(tmp[x], 'timeline-Tweet-text')[0]);
tids.push(tmp[x].getAttribute('data-tweet-id'));
if (printUser)
authors.push(swapDataSrc(getElementsByClassName(tmp[x],'timeline-Tweet-author')[0]));
times.push(getElementsByClassName(tmp[x], 'dt-updated')[0]);
permalinksURL.push(getElementsByClassName(tmp[x], 'timeline-Tweet-timestamp')[0]);
if (getElementsByClassName(tmp[x], 'timeline-Tweet-media')[0] !== undefined)
images.push(getElementsByClassName(tmp[x], 'timeline-Tweet-media')[0]);
else
images.push(undefined);
x++;
if (tweets.length > maxTweets)
tweets.splice(maxTweets, (tweets.length - maxTweets));
authors.splice(maxTweets, (authors.length - maxTweets));
times.splice(maxTweets, (times.length - maxTweets));
rts.splice(maxTweets, (rts.length - maxTweets));
images.splice(maxTweets, (images.length - maxTweets));
permalinksURL.splice(maxTweets, (permalinksURL.length - maxTweets));
var arrayTweets = [];
var x = tweets.length;
var n = 0;
if (dataOnly)
while (n < x)
arrayTweets.push(
tweet: tweets[n].innerHTML,
author: authors[n] ? authors[n].innerHTML : 'Unknown Author',
author_data:
profile_url: authors[n] ? authors[n].querySelector('[data-scribe="element:user_link"]').href : null,
profile_image: authors[n] ?
'https://twitter.com/' + authors[n].querySelector('[data-scribe="element:screen_name"]').title.split('@')[1] + '/profile_image?size=bigger' : null,
profile_image_2x: authors[n] ? 'https://twitter.com/' + authors[n].querySelector('[data-scribe="element:screen_name"]').title.split('@')[1] + '/profile_image?size=original' : null,
screen_name: authors[n] ? authors[n].querySelector('[data-scribe="element:screen_name"]').title : null,
name: authors[n] ? authors[n].querySelector('[data-scribe="element:name"]').title : null
,
time: times[n].textContent,
timestamp: times[n].getAttribute('datetime').replace('+0000', 'Z').replace(/([\+\-])(\d\d)(\d\d)/, '$1$2:$3'),
image: (extractImagesUrl(images[n]) ? extractImagesUrl(images[n])[0] : undefined),
images: extractImagesUrl(images[n]),
rt: rts[n],
tid: tids[n],
permalinkURL: (permalinksURL[n] === undefined) ?
'' : permalinksURL[n].href
);
n++;
else
while (n < x)
if (typeof(formatterFunction) !== 'string')
var datetimeText = times[n].getAttribute('datetime');
var newDate = new Date(times[n].getAttribute('datetime')
.replace(/-/g,'/').replace('T', ' ').split('+')[0]);
var dateString = formatterFunction(newDate, datetimeText);
times[n].setAttribute('aria-label', dateString);
if (tweets[n].textContent)
// IE hack.
if (supportsClassName)
times[n].textContent = dateString;
else
var h = document.createElement('p');
var t = document.createTextNode(dateString);
h.appendChild(t);
h.setAttribute('aria-label', dateString);
times[n] = h;
else
times[n].textContent = dateString;
var op = '';
if (parseLinks)
if (targetBlank)
targetLinksToNewWindow(tweets[n]);
if (printUser)
targetLinksToNewWindow(authors[n]);
if (printUser)
op += '<div class="user">' + strip(authors[n].innerHTML) +
'</div>';
op += '<p class="tweet">' + strip(tweets[n].innerHTML) + '</p>';
if (printTime)
if (permalinks)
op += '<p class="timePosted"><a href="' + permalinksURL[n] +
'">' + times[n].getAttribute('aria-label') + '</a></p>';
else
op += '<p class="timePosted">' +
times[n].getAttribute('aria-label') + '</p>';
else
if (tweets[n].textContent)
if (printUser)
op += '<p class="user">' + authors[n].textContent + '</p>';
op += '<p class="tweet">' + tweets[n].textContent + '</p>';
if (printTime)
op += '<p class="timePosted">' + times[n].textContent + '</p>';
else
if (printUser)
op += '<p class="user">' + authors[n].textContent + '</p>';
op += '<p class="tweet">' + tweets[n].textContent + '</p>';
if (printTime)
op += '<p class="timePosted">' + times[n].textContent + '</p>';
if (showInteractionLinks)
op += '<p class="interact"><a href="https://twitter.com/intent/' +
'tweet?in_reply_to=' + tids[n] +
'" class="twitter_reply_icon"' +
(targetBlank ? ' target="_blank" rel="noopener">' : '>') +
'</a><a href="https://twitter.com/intent/retweet?' +
'tweet_id=' + tids[n] + '" class="twitter_retweet_icon"' +
(targetBlank ? ' target="_blank" rel="noopener">' : '>') + '</a>' +
'<a href="https://twitter.com/intent/favorite?tweet_id=' +
tids[n] + '" class="twitter_fav_icon"' +
(targetBlank ? ' target="_blank" rel="noopener">' : '>') + '</a></p>';
if (showImages && images[n] !== undefined && extractImagesUrl(images[n]) !== undefined)
var extractedImages = extractImagesUrl(images[n]);
for (var i = 0; i < extractedImages.length; i++)
op += '<div class="media">' +
'<img src="' + extractedImages[i] +
'" />' + '</div>';
if (showImages)
arrayTweets.push(op);
else if (!showImages && tweets[n].textContent.length)
arrayTweets.push(op);
n++;
handleTweets(arrayTweets);
inProgress = false;
if (queue.length > 0)
twitterFetcher.fetch(queue[0]);
queue.splice(0,1);
;
// It must be a global variable because it will be called by JSONP.
window.__twttrf = twitterFetcher;
window.twitterFetcher = twitterFetcher;
return twitterFetcher;
));
// Prepend polyfill for IE/Edge.
(function (arr)
arr.forEach(function (item)
if (item.hasOwnProperty('prepend'))
return;
Object.defineProperty(item, 'prepend',
configurable: true,
enumerable: true,
writable: true,
value: function prepend()
var argArr = Array.prototype.slice.call(arguments),
docFrag = document.createDocumentFragment();
argArr.forEach(function (argItem)
var isNode = argItem instanceof Node;
docFrag.appendChild(isNode ? argItem : document.createTextNode(String(argItem)));
);
this.insertBefore(docFrag, this.firstChild);
);
);
)([Element.prototype, Document.prototype, DocumentFragment.prototype]);
/**
* ### HOW TO CREATE A VALID ID TO USE: ###
* Go to www.twitter.com and sign in as normal, go to your settings page.
* Go to "Widgets" on the left hand side.
* Create a new widget for what you need eg "user time line" or "search" etc.
* Feel free to check "exclude replies" if you don't want replies in results.
* Now go back to settings page, and then go back to widgets page and
* you should see the widget you just created. Click edit.
* Look at the URL in your web browser, you will see a long number like this:
* 345735908357048478
* Use this as your ID below instead!
*/
/**
* How to use TwitterFetcher's fetch function:
*
* @function fetch(object) Fetches the Twitter content according to
* the parameters specified in object.
*
* @param object Object An object containing case sensitive key-value pairs
* of properties below.
*
* You may specify at minimum the following two required properties:
*
* @param object.id string The ID of the Twitter widget you wish
* to grab data from (see above for how to generate this number).
* @param object.domId string The ID of the DOM element you want
* to write results to.
*
* You may also specify one or more of the following optional properties
* if you desire:
*
* @param object.maxTweets [int] The maximum number of tweets you want
* to return. Must be a number between 1 and 20. Default value is 20.
* @param object.enableLinks [boolean] Set false if you don't want
* urls and hashtags to be hyperlinked.
* @param object.showUser [boolean] Set false if you don't want user
* photo / name for tweet to show.
* @param object.showTime [boolean] Set false if you don't want time of tweet
* to show.
* @param object.dateFunction [function] A function you can specify
* to format date/time of tweet however you like. This function takes
* a JavaScript date as a parameter and returns a String representation
* of that date.
* @param object.showRetweet [boolean] Set false if you don't want retweets
* to show.
* @param object.customCallback [function] A function you can specify
* to call when data are ready. It also passes data to this function
* to manipulate them yourself before outputting. If you specify
* this parameter you must output data yourself!
* @param object.showInteraction [boolean] Set false if you don't want links
* for reply, retweet and favourite to show.
* @param object.showImages [boolean] Set true if you want images from tweet
* to show.
* @param object.lang [string] The abbreviation of the language you want to use
* for Twitter phrases like "posted on" or "time ago". Default value
* is "en" (English).
*/
var configProfile =
profile: screenName: "toongif" ,
domId: "example1",
maxTweets: 5,
enableLinks: true,
showUser: true,
showTime: true,
showImages: true,
lang: "en",
showInteraction: true
;
twitterFetcher.fetch(configProfile);
/*
* Example style!
* You can do whatever the hell you want on your site :-)
*/
h2
clear:both;
p, a
margin:10px 0 0 0;
color: #FFF;
text-decoration:none;
font-family: 'Roboto', sans-serif;
a, a:visited
color: #63b7e5;
text-decoration:none;
a:hover
color:#82afff;
ul
position: relative;
display: inline-flex;
ul li
list-style:none;
overflow:hidden;
margin:0px 20px;
max-width:300px;
width: 300px;
display:inline-block;
text-align: left;
vertical-align:top;
background-color: #417abd;
display: flex;
flex-direction: column;
ul li:hover
/*background-color:#f0f3fb;*/
.user, .tweet, .timePosted
float:left;
.user
width:100%;
color: #FFF;
padding:10px;
background-color:#396aa5;
.user a
color:#FFF;
.tweet
padding:20px;
line-height: 1.65em;
font-size:1em;
flex: 1;
.timePosted
padding: 0px 20px;
font-size: 1em;
text-transform: uppercase;
text-decoration: none;
/* flex: 41;*/
margin: 0 auto;
.user a
width: 100px;
.user span span
display:block;
float: left;
width: 180px
.user img, .user a > span
float:left;
.user div
/*clear: left; */
margin: 5px 10px 0px 10px;
float: left;
font-size: 1em;
width:180px
.interact
float:left;
width:100%;
margin: 20px 0px;
text-align:center;
.interact a
margin: 0px 30px;
display: inline-block;
.user a > span
margin-left:10px;
.media img
width:100%;
max-width:100%;
vertical-align: bottom;
max-height:200px;
#linkage
position:fixed;
top:0px;
right:0px;
background-color:#3d3d3d;
color:#ffffff;
text-decoration:none;
padding:5px;
width:10%;
font-family:arial;
.twitter_reply_icon:before
content:"\f075";
display:block;
font-family: FontAwesome;
.twitter_retweet_icon:before
content:"\f079";
display:block;
font-family: FontAwesome;
.twitter_fav_icon:before
content:"\f004";
display:block;
font-family: FontAwesome;
<head><link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"></head>
<body>
<div style="height:600px; color:#fff; padding:50px;">
<div id="example1"></div>
</div>
</body>
【问题讨论】:
【参考方案1】:问题是 Twitter 将 .gif
文件转换为 .mp4
视频格式,因此脚本应该搜索它们。我对脚本进行了一些小修改以查找这些视频。
我改变的部分:
function extractImagesUrl(image_data)
if (image_data !== undefined && image_data.innerHTML.indexOf('data-image') >= 0)
var data_src = image_data.innerHTML.match(/data-image=\"([^"]+)\"/ig);
var type = '';
for (var i = 0; i < data_src.length; i++)
data_src[i] = data_src[i].match(/data-image=\"([^"]+)\"/i)[1];
/* Check if source has tweet_video_thumb in data-image attribute */
if (data_src[i].includes('tweet_video_thumb'))
type = 'video';
data_src[i] = decodeURIComponent(data_src[i]).slice(-15) + '.mp4';
else
type = 'image';
data_src[i] = decodeURIComponent(data_src[i]).slice(-15) + '.jpg';
/* return media object with type (either video or image) and id */
var obj =
mediaType: type,
id: data_src[0]
return obj
与:
if (showImages && images[n] !== undefined && extractImagesUrl(images[n]) !== undefined)
var extractedImages = extractImagesUrl(images[n]);
/* if mediaType === 'video' return video container else return image container */
if (extractedImages.mediaType === 'video')
op += '<video autoplay loop class="media">' +
'<source type="video/mp4" src="https://video.twimg.com/tweet_video/' + extractedImages.id + '"/>' + '</video>';
else
op += '<img class="media" src="https://pbs.twimg.com/media/' + extractedImages.id + '"/>'
在css中:
/*.media img */
.media video
width:100%;
max-width:100%;
vertical-align: bottom;
max-height:200px;
这是一个有效的fiddle
【讨论】:
非常感谢!快速提问 - 这也适用于视频吗?你也知道是什么使视频上方和下方的填充而不是与底部对齐吗? 好的,我设法删除了多余的填充,所以不用担心。不幸的是,您修改的代码也不适用于视频和图像,这部分是我的错,因为我之前没有指定。您能否指出如何为 jpeg、图像和视频启用它的方向?认为我需要某种 if 语句?再次感谢 @CodePine 抱歉,我有点忙,很高兴您的样式可以正常工作:) 我更新了部分代码,以便您可以同时提取图像和视频。也更新了小提琴。本来可以做得更干净一些,但至少现在可以了:) 啊!谢谢你向我展示了如何使用 else 语句。我认为视频现在正在拉动缩略图是对的吗?有什么方法可以让它在悬停时自动播放/播放还是不支持?还注意到它不会为某些视频拉大拇指 - 你知道为什么吗?你也可以向我解释一下“.slice(-15)”是做什么的吗?感谢您的出色帮助,并对我的所有问题感到抱歉! :) 没问题 :) 让它在悬停时自动播放/播放需要一些额外的修改,但绝对可行。使用.slice()
,我们从初始字符串中提取视频/图像ID,在本例中为最后15 个字符。你可以阅读更多关于它here以上是关于Javascript 显示来自 twitter api 的动画 gif的主要内容,如果未能解决你的问题,请参考以下文章
使用 Twitter 流 API,是不是可以只显示来自特定用户的推文?