Objective

In this article I will go through the steps of pulling the latest news from a news API, compose a video summary of these news using a vertical video template that can be used for Instagram or Tiktok.

This demo will use the video editing API to generate the video summary as an example of how it can be useful for media publishers for automating the publication of their latest news in social media.

This is an example of the resulting video:

You can download the final JSON that generates the video above.

The source of news

For this demo I will use NewsAPI.org as my source of news. NewsAPI.org is an amazing service that indexes thousands of articles every day from tens of countries and in different languages, allowing you to query this database by keywords, countries, topics, etc.

As an example, you can get the latest news about Tesla, or what has been published about a particular keyword in the last 4 years in the main media outlets. For this demo, I will pull the latest science news in the United States.

If you are a media publisher you can pull your own news feed from your database or use your own MRSS feed.

Setup the project

This demonstration will be built with some plain PHP. This will be a really short demonstration, but it would be easy to translate the code to other languages like Node JS or Python. The idea is to show how easy it is to get started with programmatic video creation.

If you are interested in going deeper on creating video editing scripts with PHP you can check my other articles on PHP.

The only thing I need is to install the JSON2Video PHP SDK:

composer require json2video/json2video-php-sdk

This will create the vendor directory and the composer.json and composer.lock files in the current directory.

The PHP script starts loading the SDK and defining the API Keys:

<?php

    require "vendor/autoload.php";

    use JSON2Video\Scene;
    use JSON2Video\Movie;

    $json2video_apikey = "---- YOUR JSON2VIDEO API KEY HERE ----";
    $newsapi_apikey = "---- YOUR NEWSAPI API KEY HERE ----";

Curate the input for the video

Getting the news feed from NewsAPI.org

The service has a free tier of 100 calls per day that is good enough for the purpose of this demo. You can get an API Key from its website.

To get the latest science news in the United States, I used the following API request:

https://newsapi.org/v2/top-headlines?category=science&country=us&apiKey=[[YOUR_API_KEY]]

And this is the response I got:

{
    "status": "ok",
    "totalResults": 19,
    "articles": [
        {
            "source": {
                "id": null,
                "name": "Space.com"
            },
            "author": "Mike Wall",
            "title": "SpaceX Dragon cargo ship docks at space station to deliver solar arrays, seeds and more - Space.com",
            "description": "The robotic Dragon supply ship linked up with he ISS around 7:30 a.m. EST on Sunday (Nov. 27).",
            "url": "https://www.space.com/spacex-dragon-crs-26-arrive-space-station",
            "urlToImage": "https://cdn.mos.cms.futurecdn.net/nHUkuD2Zwmrzn67TK6UgHk-1200-80.jpg",
            "publishedAt": "2022-11-27T14:02:11Z",
            "content": "SpaceX's latest Dragon cargo ship arrived at the International Space Station (ISS) early Sunday (Nov. 27) to deliver tons of fresh supplies, new solar wings nd even some ice cream for the orbiting la\u2026 [+2973 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "SciTechDaily"
            },
            "author": null,
            "title": "NASA Artemis I \u2013 Orion Spacecraft Surpasses Apollo 13 Record Distance From Earth - SciTechDaily",
            "description": "On day 11 of the Artemis I mission, Orion continues its journey beyond the Moon after entering a distant retrograde orbit on Friday, November 25, at 3:52 p.m. CST. Orion will remain in this orbit for six days before exiting lunar orbit to put the spacecraft o\u2026",
            "url": "https://scitechdaily.com/nasa-artemis-i-orion-spacecraft-surpasses-apollo-13-record-distance-from-earth/",
            "urlToImage": "https://scitechdaily.com/images/Orion-Looks-Back-at-Earth-scaled.jpg",
            "publishedAt": "2022-11-27T11:04:24Z",
            "content": "On flight day 11, NASAS Orion spacecraft captured imagery looking back at the Earth from a camera mounted on one of its solar arrays. The spacecraft is currently in a distant retrograde orbit around \u2026 [+2415 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "NDTV News"
            },
            "author": null,
            "title": "NASA Shares Stunning Image Of Pluto That Shows Its ''True Colours'' - NDTV",
            "description": "Pluto was once considered the ninth planet in the solar system, however, it was demoted in 2006 and reclassified as a dwarf planet.",
            "url": "https://www.ndtv.com/world-news/nasa-shares-stunning-image-of-pluto-that-shows-its-true-colours-3556835",
            "urlToImage": "https://c.ndtvimg.com/2022-11/jkvf5s08_nasa-explained-plutos-surface-as-cracked-and-cratered-coloured-white-tan-and-brownishred_625x300_27_November_22.jpg",
            "publishedAt": "2022-11-27T03:28:07Z",
            "content": "NASA explained Pluto's surface as cracked and cratered, coloured white, tan, and brownish-red\r\nNASA on Saturday shared a stunning image on Instagram taken by its New Horizons spacecraft, showing Plut\u2026 [+2473 chars]"
        },
        {
            "source": {
                "id": "google-news",
                "name": "Google News"
            },
            "author": null,
            "title": "Mars Perseverance rover finds organic molecules that could indicate life - The Jerusalem Post",
            "description": null,
            "url": "https://news.google.com/__i/rss/rd/articles/CBMiLGh0dHBzOi8vd3d3Lmpwb3N0LmNvbS9zY2llbmNlL2FydGljbGUtNzIzNDQy0gEA?oc=5",
            "urlToImage": null,
            "publishedAt": "2022-11-27T02:57:00Z",
            "content": null
        },
        {
            "source": {
                "id": null,
                "name": "Neurosciencenews.com"
            },
            "author": "Neuroscience News",
            "title": "What Octopus and Human Brains Have in Common - Neuroscience News",
            "description": "Octopuses have a massively expanded repertoire of miRNA in their neural tissue, reflecting a similar development to that which occurred in vertebrates. Findings suggest miRNA plays a significant role in the development of complex brains.",
            "url": "https://neurosciencenews.com/octopus-mirna-complex-brain-21945/",
            "urlToImage": "https://neurosciencenews.com/files/2022/11/octopus-brain-neurosicences-.png",
            "publishedAt": "2022-11-27T00:27:24Z",
            "content": "Summary: Octopuses have a massively expanded repertoire of miRNA in their neural tissue, reflecting a similar development to that which occurred in vertebrates. Findings suggest miRNA plays a signifi\u2026 [+7484 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "ScienceAlert"
            },
            "author": "Michelle Starr",
            "title": "We Just Got The Most Detailed View of an Exoplanet Atmosphere Yet - And It's Active - ScienceAlert",
            "description": "WASP-39b, a gas giant about 700 light-years away, is turning out to be quite the exoplanetary treasure.",
            "url": "https://www.sciencealert.com/we-just-got-the-most-detailed-view-of-an-exoplanet-atmosphere-yet-and-its-active",
            "urlToImage": "https://www.sciencealert.com/images/2022/11/wasp-38b-illustration.jpg",
            "publishedAt": "2022-11-26T23:00:40Z",
            "content": "WASP-39b, a gas giant about 700 light-years away, is turning out to be quite the exoplanetary treasure.\r\nEarlier this year, WASP-39b was the subject of the first-ever detection of carbon dioxide in t\u2026 [+4869 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "Ancient Origins"
            },
            "author": "Nathan Falde",
            "title": "What Could Go Wrong?! 48500-Year-Old Siberian Virus is Revived - Ancient Origins",
            "description": "The world\u2019s oldest known frozen and dormant virus has been revived in a French laboratory leading many to express concerns about the dangers of bringing to life ancient microbes.",
            "url": "https://www.ancient-origins.net/news-science-space/siberian-virus-0017581",
            "urlToImage": "https://www.ancient-origins.net/sites/default/files/field/image/Siberian-virus.jpg",
            "publishedAt": "2022-11-26T22:02:00Z",
            "content": "The worlds oldest known frozen and dormant virus has been revived in a French laboratory leading many to express concerns about the dangers of bringing to life ancient microbes. The virus was removed\u2026 [+7839 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "SciTechDaily"
            },
            "author": null,
            "title": "MIT Finds Indoor Humidity \u201cSweet Spot\u201d To Reduce Spread of COVID-19 - SciTechDaily",
            "description": "New research links very dry and very humid indoor environments with worse COVID-19 outcomes. We know proper indoor ventilation is key to reducing the spread of COVID-19. Now, a study by MIT researchers finds that indoor relative humidity may also influence th\u2026",
            "url": "https://scitechdaily.com/mit-finds-indoor-humidity-sweet-spot-to-reduce-spread-of-covid-19/",
            "urlToImage": "https://scitechdaily.com/images/Humidifier.jpg",
            "publishedAt": "2022-11-26T21:06:25Z",
            "content": "ByJennifer Chu, Massachusetts Institute of TechnologyNovember 26, 2022\r\nAn MIT study shows that keeping indoor humidity at a sweet spot may reduce the spread of COVID-19.\r\nNew research links very dry\u2026 [+9051 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "New York Post"
            },
            "author": "Fox News",
            "title": "Hubble Space Telescope image shows galaxies merge 671M light-years away - New York Post ",
            "description": "Scientists at NASA and the European Space Agency (ESA) released an image on Friday showcasing a pair of merging galaxies.",
            "url": "https://nypost.com/2022/11/26/hubble-space-telescope-image-shows-galaxies-merge-671m-light-years-away/",
            "urlToImage": "https://nypost.com/wp-content/uploads/sites/2/2022/11/hubble-space-telescope-homepage.jpg?quality=75&strip=all&w=1024",
            "publishedAt": "2022-11-26T20:28:00Z",
            "content": "Scientists at NASA and the European Space Agency (ESA) released an image on Friday showcasing a pair of merging galaxies.\u00a0\r\nThe galaxy merger,\u00a0known as Arp-Madore 417-391, is located 671 million ligh\u2026 [+817 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "Phys.Org"
            },
            "author": "Nicholas R. Longrich",
            "title": "What if the dinosaurs hadn't gone extinct? Why our world might look very different - Phys.org",
            "description": "Sixty-six million years ago, an asteroid hit the Earth with the force of 10 billion atomic bombs and changed the course of evolution. The skies darkened and plants stopped photosynthesising. The plants died, then the animals that fed on them. The food chain c\u2026",
            "url": "https://phys.org/news/2022-11-dinosaurs-hadnt-extinct-world.html",
            "urlToImage": "https://scx2.b-cdn.net/gfx/news/2022/what-if-the-dinosaurs.jpg",
            "publishedAt": "2022-11-26T17:10:01Z",
            "content": "Sixty-six million years ago, an asteroid hit the Earth with the force of 10 billion atomic bombs and changed the course of evolution. The skies darkened and plants stopped photosynthesising. The plan\u2026 [+6683 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "ScienceAlert"
            },
            "author": "Tessa Koumoundouros",
            "title": "There's a Weird Link Between Teeth And The Evolution of Pregnancy - ScienceAlert",
            "description": "Human babies pack a lot of growth into those nine months between conception and birth to give them and their meaty, complex brains a chance at survival.",
            "url": "https://www.sciencealert.com/theres-a-weird-link-between-teeth-and-the-evolution-of-pregnancy",
            "urlToImage": "https://www.sciencealert.com/images/2022/11/ThreeDifferentSpeciesOfPrimateScullsInARow.jpg",
            "publishedAt": "2022-11-26T17:00:21Z",
            "content": "Human babies pack a lot of growth into those nine months between conception and birth to give them and their meaty, complex brains a chance at survival.\r\nJust how evolution came to grant humans such \u2026 [+3497 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "NDTV News"
            },
            "author": null,
            "title": "Watch: NASA Turns \"Light Echoes\" From A Black Hole Into Sound - NDTV",
            "description": "According to NASA, the black hole in the video is about 7,800 light years away from Earth and has a mass between five and ten times that of the Sun.",
            "url": "https://www.ndtv.com/world-news/watch-nasa-turns-light-echoes-from-a-black-hole-into-sound-3556273",
            "urlToImage": "https://c.ndtvimg.com/2022-11/436avhag_the-light-echoes-from-the-black-hole-were-converted-into-sound-by-the-us-space-agency_625x300_26_November_22.jpg",
            "publishedAt": "2022-11-26T15:55:03Z",
            "content": "The \"light echoes\" from the black hole were converted into sound by the US Space agency.\r\nThe mysteries of the black hole continue to baffle us despite extensive space exploration. In a new video, NA\u2026 [+2265 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "indy100"
            },
            "author": "Sinead Butler",
            "title": "Scientists created a mini black hole and it started radiating - indy100",
            "description": "Scientists have managed to simulate their very own black hole in their lab and witnessed how it began to glow.The black hole event horizon was created by a team of physicists from the University of Amsterdam, who used a chain of atoms in a single file to gain\u2026",
            "url": "https://www.indy100.com/science-tech/scientists-created-mini-black-hole-2658785515",
            "urlToImage": "https://www.indy100.com/media-library/astronomers-detect-mysterious-star-that-defies-black-hole-theory.jpg?id=32126757&width=1200&height=600&coordinates=0%2C95%2C0%2C259",
            "publishedAt": "2022-11-26T14:11:41Z",
            "content": "Scientists have managed to simulate their very own black hole in their lab and witnessed how it began to glow.\r\nThe black hole event horizon was created by a team of physicists from the University of\u2026 [+2240 chars]"
        },
        {
            "source": {
                "id": "wired",
                "name": "Wired"
            },
            "author": "Rhett Allain",
            "title": "The Physics of Scuba Diving - WIRED",
            "description": "A deep dive into the science of staying alive underwater.",
            "url": "https://www.wired.com/story/the-physics-of-scuba-diving/",
            "urlToImage": "https://media.wired.com/photos/63780322a18206af1dfb46a2/191:100/w_1280,c_limit/Scuba-Diving-Physics-TOP-Science-147398339.jpg",
            "publishedAt": "2022-11-26T12:00:00Z",
            "content": "Another unit is the bar, where 1 bar is equal to 14.5 psi. The value of 1 bar is very close to the pressure of air on Earth. The atmospheric pressure of the air that surrounds you right now is probab\u2026 [+3735 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "Hindustan Times"
            },
            "author": "HT Tech",
            "title": "BEWARE! 65-foot asteroid set to get dangerously close to Earth today, warns NASA - HT Tech",
            "description": "NASA warns that a 65-foot wide asteroid will be coming dangerously close to the Earth today, November 26. Know the consequences that a gigantic asteroid has.",
            "url": "https://tech.hindustantimes.com/tech/news/beware-65-foot-asteroid-set-to-get-dangerously-close-to-earth-today-warns-nasa-71669446742062.html",
            "urlToImage": "https://images.hindustantimes.com/tech/img/2022/11/26/1600x900/asteroid-4145080_1920_1646293428986_1668502642196_1669446771045_1669446771045.jpg",
            "publishedAt": "2022-11-26T07:16:00Z",
            "content": "When it comes to space, both exploration and protection is equally important for scientists and space agencies. That is why before the Artemis-1 mission, which is aiming to send crewed spacecraft bac\u2026 [+1869 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "Washington Examiner"
            },
            "author": "Jack Birle, Washington Examiner",
            "title": "'World's oldest meal' discovered in ancient fossil - Out There Colorado",
            "description": "Scientists have discovered the last meal for ancient animal inhabitants of Earth, from more than 550 million years ago, in a fossil.",
            "url": "https://www.washingtonexaminer.com/news/worlds-oldest-meal-discovered-ancient-fossil?utm_source=gazette.com&utm_medium=referral&utm_campaign=csg_news_feed",
            "urlToImage": "https://bloximages.newyork1.vip.townnews.com/outtherecolorado.com/content/tncms/assets/v3/editorial/b/3a/b3adb2c9-8e53-581c-984a-96d0503136ca/6382412900929.image.jpg?crop=352%2C185%2C98%2C0&resize=352%2C185&order=crop%2Cresize",
            "publishedAt": "2022-11-26T05:00:00Z",
            "content": "Scientists have discovered the last meal for ancient animal inhabitants of Earth, from more than 550 million years ago, in a fossil.\r\nThe researchers found phytosterol molecules, a type of fat found \u2026 [+1202 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "Salon"
            },
            "author": "Sean Liddick, Artemis Spyrou",
            "title": "A particle accelerator that just turned on could reveal rare forms of matter - Salon",
            "description": "A physics experiment in Michigan could provide new insights into the fundamental nature of the universe",
            "url": "https://www.salon.com/2022/11/25/a-particle-accelerator-that-just-turned-on-could-reveal-rare-forms-of-matter_partner/",
            "urlToImage": "https://mediaproxy.salon.com/width/1200/https://media.salon.com/2022/11/atom_illustration_713786859.jpg",
            "publishedAt": "2022-11-26T00:30:00Z",
            "content": null
        },
        {
            "source": {
                "id": null,
                "name": "SciTechDaily"
            },
            "author": null,
            "title": "Earth Might Be Experiencing 7th Mass Extinction, Not 6th \u2013 \u201cA True Decrease in the Abundance of Organisms\u201d - SciTechDaily",
            "description": "550-million-year-old creatures\u2019 message to the present. Earth is currently in the midst of a mass extinction, losing thousands of species each year. New research suggests environmental changes caused the first such event in history, which occurred millions of\u2026",
            "url": "https://scitechdaily.com/earth-might-be-experiencing-7th-mass-extinction-not-6th-a-true-decrease-in-the-abundance-of-organisms/",
            "urlToImage": "https://scitechdaily.com/images/Ediacaran-Sea-Floor.jpg",
            "publishedAt": "2022-11-25T22:22:47Z",
            "content": "ByUniversity of California - RiversideNovember 25, 2022\r\nNew research indicates that a mass extinction occurred 550 million years ago, during the Ediacaran period.\r\n550-million-year-old creatures mes\u2026 [+5405 chars]"
        },
        {
            "source": {
                "id": null,
                "name": "Space.com"
            },
            "author": "Tereza Pultarova",
            "title": "Mars helicopter Ingenuity aces 1st flight after major software update - Space.com",
            "description": "The update will make Ingenuity more capable in hilly terrain.",
            "url": "https://www.space.com/ingenuity-mars-helicopter-flight-34-new-software",
            "urlToImage": "https://cdn.mos.cms.futurecdn.net/gtPwS57tf6Q79aV4g7WKih-1200-80.jpg",
            "publishedAt": "2022-11-25T18:28:47Z",
            "content": "NASA's Mars helicopter Ingenuity has performed its shortest-ever flight, the first after a major software update that will allow the little chopper to land more safely and navigate over rugged terrai\u2026 [+2936 chars]"
        }
    ]
}

This response includes 19 articles from different media publishers published in the last few hours, including the article headline, the source name, the publication date and a URL to the article's main image.

This is just what I need to create my news video summary! ✌️

This is the PHP code to query the API:

// Get the news from the API
$api_url = "https://newsapi.org/v2/top-headlines?category=science&country=us&apiKey=" . $newsapi_apikey;
$api_response = file_get_contents($api_url);
$api_json = json_decode($api_response, true);
if (!$api_json) die("Error reading NewsAPI");

Fixing minor issues

Reviewing the NewsAPI output, I notice that I need to transform a few things:

Therefore, I will create a new array just with the info I need:

// Parse the response and create the news source
$articles = [];
$num_articles = 0;

foreach ($api_json["articles"] as $article) {

    // Bypass any URL that includes ".gif"
    if (empty($article["urlToImage"])) continue;
    if (strpos($article["urlToImage"], ".gif")!==false) continue;

    // Remove anything from " - " and after
    $source_position = strpos($article["title"], " - ");
    if ($source_position!==false) $headline = substr($article["title"], 0, $source_position);
    else $headline = $article["title"];

    // Convert to human readible date
    $human_date = date("M jS", strtotime($article["publishedAt"]));

    // Add a new article to the list
    $articles[] = [
        "headline" => $headline,
        "date" => $human_date,
        "image" => $article["urlToImage"],
        "source" => $article["source"]["name"]
    ];

    // Limit the number of articles in the list
    $num_articles++;
    if ($num_articles>=6) break;
}

Create the video

Now that I have all the content I need, we can create the video movie.

Movie object setup

First, create a Movie object and setup it up:

// Create a new movie
$movie = new Movie;

// Set your API key
// Get your free API key at https://json2video.com
$movie->setAPIKey($json2video_apikey);

// Set movie quality: low, medium, high
$movie->quality = "high";

// Create video as a final video (without watermark)
$movie->draft = false;

// Set movie dimensions for an Instagram story
$movie_width = 607;
$movie_height = 1080;
$margin = "4vw";

$movie->width = $movie_width;
$movie->height = $movie_height;

I define three variables ($movie_width, $movie_height and $margin) that will be used later on in the code. $movie_width and $movie_height are the video dimensions. $margin is the margin used to position the elements in the scene.

Instragram story videos must have 9:16 ratio with a maximum of 1920 pixels in height. However, I will use a smaller size (still 9:16) of 607 x 1080.

Add an intro bumper

The video will start with a bumper showing my acme brand: "SCIENCE TODAY":

// Intro bumper 
$intro = new Scene;

$intro->addElement([
    "type" => "component",
    "component" => "basic/052",
    "settings" => [
        "card" => [
            "vertical-align" => "center",
            "horizontal-align" => "center"
        ],
        "section" => [
            "text" => "SCIENCE",
            "font-family" => "Inter",
            "font-weight" => "700"
        ],
        "headline" => [
            "text" => "TODAY",
            "font-family" => "Inter",
            "font-weight" => "700"
        ]
    ]
]);
$intro->duration = 6;

$movie->addScene($intro);

Add the articles

Now, I can create an scene for each article, adding the article's image as a background (with pan left or right effect), the headline at the bottom, the publisher and date at the top-left and a voice-over reading the headline:

// Create an scene for each article

foreach ($articles as $key => $article) {
    
    $scene =  new Scene;

    $scene->addElement([
        "type" => "component",
        "component" => "advanced/100",
        "settings" => [
            "image" => [
                "src" => $article["image"],
                "final_left" => "0%",
                "final_width" => "100%",
                "duration" => 0.5
            ]
        ]
    ]);

    // Add the headline at the bottom using the 011 style
    $scene->addElement([
        "type" => "text",
        "style" => "011",
        "text" => $article["headline"],
        "settings" => [
            "vertical-position" => "bottom",
            "horizontal-position" => "left",
            "text-align" => "left",
            "margin" => $margin,
            "font-size" => "8vw",
            "font-family" => "Inter",
            "font-weight" => "700",
            "background-color" => "black"
        ],
        "cache" => false
    ]);

    // Add the publisher name and date at the top-left
    // keeping a margin
    $scene->addElement([
        "type" => "component",
        "component" => "basic/052",
        "settings" => [
            "card" => [
                "vertical-align" => "top",
                "horizontal-align" => "right",
                "padding" => $margin
            ],
            "section" => [
                "text" => $article["source"],
                "font-size" => "5vw"
            ],
            "headline" => [
                "text" => $article["date"],
                "font-size" => "5vw"
            ]
        ]
    ]);

    // Generate the voice over from the headline
    // using the male voice en-US-GuyNeural
    $scene->addElement([
        "type" => "voice",
        "voice" => "en-US-GuyNeural",
        "text" => $article["headline"],
        "start" => 0.5,
        "extra-time" => 0.5
    ]);

    // Add the scene into the movie
    $movie->addScene($scene);
}

Add a closing scene

I will close my video with a black scene showing "Powered by JSON2Video.com".

// Add a closing scene
$closing = new Scene;
$closing->addElement([
    "type" => "text",
    "style" => "005",
    "text" => "Powered by JSON2Video.com",
    "settings" => [
        "font-size" => "4vw"
    ]
]);
$closing->duration = 5;

$movie->addScene($closing);

Add a background music

Finally, I will add a background music across the movie:

// Add a background music to the movie
$movie->addElement([
    "type" => "audio",
    "src" => "https://assets.json2video.com/assets/audios/news-opening-01.mp3",
    "volume" => 0.2,
    "duration" => -2,
    "fade-out" => 2
]);

Render the movie

The last step is to send the movie to be rendered by JSON2Video and wait until the movie is ready:

// Call JSON2Video API and start rendering the movie
$render = $movie->render();

// Wait for the render to finish
$movie->waitToFinish();

The final result

The final PHP script code is:

<?php

require "vendor/autoload.php";

use JSON2Video\Scene;
use JSON2Video\Movie;

$json2video_apikey = "---- YOUR JSON2VIDEO API KEY HERE ----";
$newsapi_apikey = "---- YOUR NEWSAPI API KEY HERE ----";

// Get the news from the API
$news_api_url = "https://newsapi.org/v2/top-headlines?category=science&country=us&apiKey=" . $newsapi_apikey;

$api_response = @file_get_contents($news_api_url);

$api_json = json_decode($api_response, true);
if (!$api_json) {
    echo $api_response, PHP_EOL;
    die("Error reading NewsAPI: " . $news_api_url);
}

// Parse the response and create the news source
$articles = [];
$num_articles = 0;

foreach ($api_json["articles"] as $article) {

    // Bypass any URL that includes ".gif"
    if (empty($article["urlToImage"])) continue;
    if (strpos($article["urlToImage"], ".gif")!==false) continue;

    // Remove anything from " - " and after
    $source_position = strpos($article["title"], " - ");
    if ($source_position!==false) $headline = substr($article["title"], 0, $source_position);
    else $headline = $article["title"];

    // Convert to human readible date
    $human_date = date("M jS", strtotime($article["publishedAt"]));

    // Add a new article to the list
    $articles[] = [
        "headline" => $headline,
        "date" => $human_date,
        "image" => $article["urlToImage"],
        "source" => $article["source"]["name"]
    ];

    // Limit the number of articles in the list
    $num_articles++;
    if ($num_articles>=6) break;
}


// Create a new movie
$movie = new Movie;

// Set your API key
// Get your free API key at https://json2video.com
$movie->setAPIKey($json2video_apikey);

// Set movie quality: low, medium, high
$movie->quality = "high";

// Create video as a final video (without watermark)
$movie->draft = false;

// Set movie dimensions for an Instagram story
$movie_width = 607;
$movie_height = 1080;
$margin = "4vw";

$movie->width = $movie_width;
$movie->height = $movie_height;


// Intro bumper 
$intro = new Scene;

$intro->addElement([
    "type" => "component",
    "component" => "basic/052",
    "settings" => [
        "card" => [
            "vertical-align" => "center",
            "horizontal-align" => "center"
        ],
        "section" => [
            "text" => "SCIENCE",
            "font-family" => "Inter",
            "font-weight" => "700"
        ],
        "headline" => [
            "text" => "TODAY",
            "font-family" => "Inter",
            "font-weight" => "700"
        ]
    ]
]);
$intro->duration = 6;

$movie->addScene($intro);


// Create an scene for each article

foreach ($articles as $key => $article) {
    
    $scene =  new Scene;

    $scene->addElement([
        "type" => "component",
        "component" => "advanced/100",
        "settings" => [
            "image" => [
                "src" => $article["image"],
                "final_left" => "0%",
                "final_width" => "100%",
                "duration" => 0.5
            ]
        ]
    ]);

    // Add the headline at the bottom using the 011 style
    $scene->addElement([
        "type" => "text",
        "style" => "011",
        "text" => $article["headline"],
        "settings" => [
            "vertical-position" => "bottom",
            "horizontal-position" => "left",
            "text-align" => "left",
            "margin" => $margin,
            "font-size" => "8vw",
            "font-family" => "Inter",
            "font-weight" => "700",
            "background-color" => "black"
        ],
        "cache" => false
    ]);

    // Add the publisher name and date at the top-left
    // keeping a margin
    $scene->addElement([
        "type" => "component",
        "component" => "basic/052",
        "settings" => [
            "card" => [
                "vertical-align" => "top",
                "horizontal-align" => "right",
                "padding" => $margin
            ],
            "section" => [
                "text" => $article["source"],
                "font-size" => "5vw"
            ],
            "headline" => [
                "text" => $article["date"],
                "font-size" => "5vw"
            ]
        ]
    ]);

    // Generate the voice over from the headline
    // using the male voice en-US-GuyNeural
    $scene->addElement([
        "type" => "voice",
        "voice" => "en-US-GuyNeural",
        "text" => $article["headline"],
        "start" => 0.5,
        "extra-time" => 0.5
    ]);

    // Add the scene into the movie
    $movie->addScene($scene);
}

// Add a closing scene
$closing = new Scene;
$closing->addElement([
    "type" => "text",
    "style" => "005",
    "text" => "Powered by JSON2Video.com",
    "settings" => [
        "font-size" => "4vw"
    ]
]);
$closing->duration = 5;

$movie->addScene($closing);


// Add a background music to the movie
$movie->addElement([
    "type" => "audio",
    "src" => "https://assets.json2video.com/assets/audios/news-opening-01.mp3",
    "volume" => 0.2,
    "duration" => -2,
    "fade-out" => 2
]);

// Call JSON2Video API and start rendering the movie
$render = $movie->render();

// Wait for the render to finish
$movie->waitToFinish();

And the resulting video is:

Credits

Published on November 28th, 2022

Author
David Bosch
David Bosch David is an experienced engineer, now collaborating with JSON2Video.