javascripttwittertumblr

how do i use the tumblr tweets.js file to embed my tweets with the attached images?


I'm not good at all with javascript, but I'm coding a tumblr blog and using their integrated javascript to display my last tweets: a script is automatically generated by tumblr for my twitter acc, and is currently available at https://d-agonet.tumblr.com/tweets.js. I put it in my footer and added a second script that fetches and displays the data: (an example was given by tumblr and i modified it a bit so i could hide the RTs and replies, and add a class on tweets that have images attached to them) :

<ul id="tweetcontainer"></ul>
            
<script type="text/javascript">
    function recent_tweets(data) {
        document.getElementById("twitterwrapper").style.display = "block";
        
        for(i = 0; i < data.length; i++) {
            if(data[i].text.startsWith("@") == false){
                if(data[i].text.startsWith("RT @") == false){
                    if(data[i].text.includes("https://t.co/") == false){
                        document.getElementById("tweetcontainer").innerHTML = document.getElementById("tweetcontainer").innerHTML + '<li><a target="_blank" href="http://twitter.com/{TwitterUsername}/status/' + (data[i].id_str ? data[i].id_str : data[i].id) + '"><div class="content">' + data[i].text + '</div></a></li>';
                    }
                    else{
                        document.getElementById("tweetcontainer").innerHTML = document.getElementById("tweetcontainer").innerHTML + '<li class="yaimg"><a target="_blank" href="http://twitter.com/{TwitterUsername}/status/' + (data[i].id_str ? data[i].id_str : data[i].id) + '"><div class="content">' + data[i].text + '</div></a></li>';
                    }
                }
            }
        }
    }
</script>

Despite how ugly the code probably looks, it currently works as intended, but I've noticed that the .js file generated by tumblr also stores the urls for the images attached to tweets, so I wanted to fetch this data and display it on the relevant tweets.

As you can see, the data for a tweet is basically structured this way:

{
    "created_at": "DATE",
    "id": SOME ID NUMBER,
    "id_str": "SOME ID NUMBER",
    "text": "TEXT FROM TWEET",
    "truncated": false,
    "entities": {
        "hashtags": [],
        "symbols": [],
        "urls": [],
        "media": [{
            "id": SOME OTHER ID NUMBER,
            "id_str": "SOME OTHER ID NUMBER",
            "indices": [XX, XX],
            "media_url": "THE IMAGE URL",
            "media_url_https": "THE IMAGE URL WITH HTTPS",
            "type": "photo",
            etc
        }]
      },
    etc
}

So, I understand that what I'd like to get is what I called "THE IMAGE URL WITH HTTPS" above, and for that I need to add something to the end of my script, something like this:

else{
    document.getElementById("tweetcontainer").innerHTML = document.getElementById("tweetcontainer").innerHTML + '<li class="yaimg"><a target="_blank" href="http://twitter.com/{TwitterUsername}/status/' + (data[i].id_str ? data[i].id_str : data[i].id) + '">' + data[i].entities.media.media_url_https + '<div class="content">' + data[i].text + '</div></a></li>';
}

Unfortunately, it doesn't work and now the tweets with images attached just don't display at all. (whereas through trial and error with "data[i].media_url_https" I got "undefined" before the tweet's text, and "data[i].entities" gave me "[object Object]" before the text.)

I came upon this previous answer which led me to my current try with "data[i].entities.media.media_url_https" and seems to explain how to go about it, but I'm really struggling to understand it and I have no idea how to apply it to my situation :/ I'm guessing my problem comes from the fact that "media" is an array, so it should be something resembling "data[i].entities.media[????].media_url_https" but i have no idea which number to put in the ????, I tried 0 and 1 to no effect :/


Solution

  • I have a solution which may work (it depends on the tumblr implementation, it might not work on older browsers).

    Try this:

    function recent_tweets(data) {
        document.getElementById("twitterwrapper").style.display = "block";
    
        for(i = 0; i < data.length; i++) {
          if(!data[i].text.startsWith("@") || !data[i].text.startsWith("RT @") || !data[i].text.includes("https://t.co/")){
            const media = data[i].entities?.media;
            if (media?.length) {
              const image = media[0].media_url_https;
              document.getElementById("tweetcontainer").innerHTML = document.getElementById("tweetcontainer").innerHTML + '<li><a target="_blank" href="http://twitter.com/{TwitterUsername}/status/' + (data[i].id_str ? data[i].id_str : data[i].id) + '"><div class="content">' + data[i].text + '<img src=' + image + ' /></div></a></li>';
            } else {
              document.getElementById("tweetcontainer").innerHTML = document.getElementById("tweetcontainer").innerHTML + '<li class="yaimg"><a target="_blank" href="http://twitter.com/{TwitterUsername}/status/' + (data[i].id_str ? data[i].id_str : data[i].id) + '"><div class="content">' + data[i].text + '</div></a></li>';
            }
          }
        }
      }
    

    There are a few things to note here.

    Firstly in your loop you are testing for a boolean condition and then nesting another boolean test inside of it:

    if(data[i].text.startsWith("@") == false){
        if(data[i].text.startsWith("RT @") == false){
    

    Instead you can add the test into one line and check if they are false like this:

    if(!data[i].text.startsWith("@") || !data[i].text.startsWith("RT @") || !data[i].text.includes("https://t.co/")){
    

    II is the OR operator. And instead of writing if (someVar === false) we can use the logical NOT operator !. So if (!someVar)

    If the image does exist it is always in the first indexed array so we can access it like this: media[0].media_url_https;.

    The other thing to note is that not every object in your data contains a media or image property, in that case we need to test if it exists and then spit out the image, and if not continue and append the html without an image.

    That uses optional chaining. So media?.some_property checks if the media object exists first and then if it has the prop we are looking for. This is the bit that is quite new in JS, so you may run into issues. But I believe this will do what you need.

    See here for more information: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

    EDIT Something else to note, it's not super critical, but it makes for better separation of layout and logic, currently your markup has a div which is later manipulated by javascript, but the javascript function is nested inside the div like this:

    <div id="twitterwrapper" style="display: block;">
      <h2 class="heading" id="twitter">
        Tweets
      </h2>
    
      <ul id="tweetcontainer"></ul>
    
        <script type="text/javascript">
          function recent_tweets(data) {
              ...
          }
        </script>
    </div>
    

    Generally people tend to add of their js scripts at the bottom of the file just before the closing <body> tag. Not always, but it is a good idea with tumblr templates IMO.