sgalinski/sg-youtube

A solution for embedding YouTube videos, playlists, or channels easily into TYPO3 pages.

Installs: 15

Dependents: 0

Suggesters: 0

Security: 0

Type:typo3-cms-extension

8.1.0 2024-12-04 20:02 UTC

README

License: GNU GPL, Version 2

Repository: https://gitlab.sgalinski.de/typo3/sg_youtube

Please report bugs here: https://gitlab.sgalinski.de/typo3/sg_youtube

Installation / Integration

First install the extension and activate it in the Extension Manager.

TypoScript integration

  • Include the TypoScript in Configuration/TypoScript/setup.typoscript and constants.typoscript in your theme.
  • Add your YouTube API key:
plugin.tx_sgyoutube {
	settings {
		# cat=plugin.tx_sgyoutube/file; type=string; label=YouTube API Key
		apiKey = <your-api-key>
	}
}

Registration for more than the free 10.000 quotas per day

It's not 1 quota per 1 API call. Each API has its own costs, which can be seen in the link below.

Currently, at the version 3.2.1 we are using the following APIs:

  • "search/list" for channel videos
  • "playlistItems/list" for videos from a specific playlist
  • "videos/list" for getting the details for each video and the localizations, if needed.

The maximum quota costs would be "102" at the moment for rendering the latest videos from a channel with the video details and translations.

Quota Calculator

YouTube API Services - Audit and Quota Extension Form

Caching behaviour

Because of the quota costs we implemented a caching for the calls for each day. The response from the APIs will be saved and used for 24 hours. Normally the site cache would do it, but it could be, that the cache will be cleared multiple times in a row, or that the plugin is on an uncached page. The TYPO3 registry is used as a cache. The cleanup is handled on the fly.

If the ?disableYoutubeCache=1 parameter is added to the URL, this cache will be ignored as well.

Possible way to solve the quota limit, if it's still reached

You can use a different API key for specific sites. You can implement a TypoScript page uid check and just change the key from the "TypoScript integration" topic.

Making changes in JavaScript/CSS

We are shipping the extension with source files and already minified assets. By default, the minified assets are loaded in the Layout, so that the extension works out of the box just with plug and play. Should you want to change this behavior, you can do the following:

  • Override the layout path in TypoScript local/project_theme/Configuration/TypoScript/Extensions/SgYouTube/Constants.typoscript
plugin.tx_sgyoutube {
	settings {
		apiKey = MY_KEY
	}

	view {
		layoutRootPath = EXT:project_theme/Resources/Private/Layouts/SgYouTube/
	}
}

  • Create a new layout file omitting the assets that you would like to change (for example, loading without CSS)
<div class="tx-sg-youtube">
	<f:asset.script identifier="sgVideoJs" src="EXT:sg_youtube/Resources/Public/JavaScript/Dist/main.bundled.min.js" />
	<f:render section="main"/>
</div>

  • Import the CSS or JavaScript source files in your respective asset pipeline and add them externally.

Compiling CSS/JS assets with SGC

  • Install the sgalinski/sgc-core library via composer
  • Add the sg-youtube extension paths in the .sgc-config.json
  • Remove the loading of the compiled CSS/JS assets from Resources/Private/Templates/Youtube/Index.html
  • Add import the scss and js module file in the corresponding main.scss and main.js
  • Initialize the javascript modules in your main.js: new SgVideoLightbox(); SgVideo.initDefault();
  • If you want to recompile the JS with SGC, you must add excludeFromQa: ['!**/Backend/**/*'] to your .sgc-config.js and also set your main extension in extensions to sg-youtube extensions: ['sg-youtube']

Compiling SASS only without SGC

Example:

npm install -g sass npx sass ./Resources/Public/Sass/Bootstrap5/main.scss ./Resources/Public/StyleSheets/Bootstrap5/main.min.css --style compressed --no-source-map

Using the Bootstrap 5 templates

If you want to use the Bootstrap 5 templates, you have to first install Bootstrap 5 in your theme to use its styles and JavaScript. Afterwards simply set the plugin.tx_project_theme.config.bootstrapVersion TypoScript setup variable to 5.

Using Events to Customize YouTube API Results in TYPO3

This documentation explains how to leverage custom events in your TYPO3 extension to manipulate the results of YouTube API calls. By using these events, you can modify the API parameters, filter results, and further customize the JSON data returned from YouTube.

Available Events

The following events are dispatched in the YouTube video rendering process:

  1. BeforeYoutubeCallEvent
  2. AfterYoutubeCallEvent
  3. AfterFilterVideosEvent
  4. AfterMapCustomThumbnailsEvent

Event Listeners

1. BeforeYoutubeCallEvent

Description: This event is triggered before making the YouTube API call, allowing you to modify the API parameters.

Example Use Case: Change API Key or manipulate other paramters
<?php

namespace Vendor\Extension\EventListener;

use SGalinski\SgYoutube\Event\BeforeVimeoCallEvent;

class BeforeYoutubeCallEventListener
{
    public function __invoke(BeforeVimeoCallEvent $event): void
    {
        // Change the API key
        $event->setApiKey('your-new-api-key');
        // Extend the max results limit by 10 videos
        $event->setMaxResultsWithFilters($event->getMaxResultsWithFilters() + 10);
    }
}

2. AfterYoutubeCallEvent

Description: Add Custom Data to JSON Array

Example Use Case: Change API Key or manipulate other paramters
<?php
namespace SGalinski\SgYoutube\EventListeners;

use SGalinski\SgYoutube\Event\AfterVimeoCallEvent;

class AfterYoutubeCallEventListener
{
	public function __invoke(AfterVimeoCallEvent $event): void
	{
		$jsonArray = $event->getJsonArray();
		// Add custom data
		$jsonArray['customData'] = 'This is some custom data';
		$event->setJsonArray($jsonArray);
	}
}

3. AfterFilterVideosEvent

Description: This event is triggered after the videos have been filtered, allowing you to further manipulate the filtered results.

Example Use Case: Remove the 10 videos that we added initially with the first event
<?php
namespace SGalinski\SgYoutube\EventListeners;

use SGalinski\SgYoutube\Event\AfterFilterVideosEvent;

class AfterFilterVideosEventListener
{
	public function __invoke(AfterFilterVideosEvent $event): void
	{
		// Modify the jsonArray if needed
		$jsonArray = $event->getJsonArray();
		// Add some custom processing here
		// For example let's remove the extra 10 videos that we added in the other event
		if (count($jsonArray['items']) > 10) {
			array_splice($jsonArray['items'], 0, 10);
		}
		$event->setJsonArray($jsonArray);
	}
}

4. AfterMapCustomThumbnailsEvent

Description: This event is triggered after custom thumbnails have been mapped, allowing you to modify the JSON array one last time before rendering.

Example Use Case: Use a custom thumbnail for all videos in the list
<?php
namespace SGalinski\SgYoutube\EventListeners;

use SGalinski\SgYoutube\Event\AfterMapCustomThumbnailsEvent;

class AfterMapCustomThumbnailsEventListener
{
    public function __invoke(AfterMapCustomThumbnailsEvent $event): void
    {
        $jsonArray = $event->getJsonArray();
        // Add a custom thumbnail URL
        foreach ($jsonArray['items'] as &$item) {
            $item['customThumbnail'] = 'https://example.com/custom-thumbnail.jpg';
        }
        $event->setJsonArray($jsonArray);
    }
}

To enable the events just register them in your Services.php as follows (you can use yaml instead if you prefer):

$services->set(BeforeYoutubeCallEventListener::class)
    ->tag('event.listener', ['event' => BeforeYoutubeCallEvent::class]);
$services->set(AfterYoutubeCallEventListener::class)
    ->tag('event.listener', ['event' => AfterYoutubeCallEvent::class]);
$services->set(AfterFilterVideosEventListener::class)
    ->tag('event.listener', ['event' => AfterFilterVideosEvent::class]);
$services->set(AfterMapCustomThumbnailsEventListener::class)
    ->tag('event.listener', ['event' => AfterMapCustomThumbnailsEvent::class]);

Setting Up the Frontend Filers

Step 1: Adding the Plugin to a Page

  1. In the TYPO3 backend, create or edit the page where you want to display YouTube videos.
  2. Add a new content element and select the YouTube plugin from the list.
  3. Provide the necessary YouTube details in the plugin settings (like YouTube API key, video/channel/playlist ID, max results, etc.).

Step 2: Disable caching for the extension and Cache validation for your web page

  1. In the TYPO3 backend, go to Settings -> Extensions and open the sg_youtube settings. Tick the box that says 'uncached' and save.
  2. This way the the extension will not cache the results and the the data will be loaded dynamically based on the filter settings.
  3. Set $GLOBALS['TYPO3_CONF_VARS']['FE']['cacheHash']['enforceValidation'] = false in your TYPO3 configuration, otherwise using the frontend filters may result in a 404 page in some instances.

Step 3: Configuring Filters via FlexForm

  1. In the plugin's FlexForm settings, you will see a section for "Filters."
  2. Depending on your site configuration, filters will be available in a select field. You can select the filters you want to display (like search term, video duration, etc.).
  3. Save your settings and publish the page.

3. Using Filters in the Frontend

Once filters are enabled, they will appear on the frontend in a form, allowing users to interact with the displayed videos dynamically. For example:

  • Search Term: Allows users to input a search term to filter videos based on keywords.
  • Duration Filter: Provides a dropdown to filter videos by length (short, medium, long, etc.).

The filter values are sent to the YouTube API, and the video list updates based on the selected criteria.

4. TypoScript Configuration for Filters

To define custom filters, the plugin uses TypoScript. Below is an example configuration and an explanation of each section:

Example TypoScript Configuration

filters {
	searchTerm {
		label = LLL:EXT:sg_youtube/Resources/Private/Language/locallang.xlf:filter.searchTerm
		partial = Filters/TextField
		filterClass = SGalinski\SgYoutube\Filter\QueryStringFilter
		defaultValues {
#			search = test
		}
		position = top
	}
	duration {
		label = LLL:EXT:sg_youtube/Resources/Private/Language/locallang.xlf:filter.duration
		partial = Filters/Dropdown
		filterClass = SGalinski\SgYoutube\Filter\DurationFilter
		position = top
		options {
			0 {
				label = LLL:EXT:sg_youtube/Resources/Private/Language/locallang.xlf:filter.duration.0
				value = 1
			}
			1 {
				label = LLL:EXT:sg_youtube/Resources/Private/Language/locallang.xlf:filter.duration.1
				value = 2
			}
		}
	}
}

submitButton {
	position = top
	cssClass = btn btn-default
	label = LLL:EXT:sg_youtube/Resources/Private/Language/locallang.xlf:filter.submitButton
}

Explanation of the Configuration

filters

This TypoScript object defines all the available filters for the YouTube plugin. Each filter is a separate sub-object, like searchTerm and duration in the example.

Filter Fields

  1. searchTerm (Text Field)

    • label: The label for the filter form field. This can be translated using the TYPO3 language file (locallang.xlf).
    • partial: Specifies which partial file to use for rendering the filter. In this case, it points to a text field (Filters/TextField).
    • filterClass: This is the PHP class responsible for processing the filter and applying it to the YouTube API request. For the searchTerm, it's a QueryStringFilter.
    • defaultValues: You can specify default values for the filter (commented out in the example).
    • position: Defines where the filter should be displayed on the page. It can be top (above the video list) or bottom (below the video list).
  2. duration (Dropdown)

    • label: The label for the filter form field.
    • partial: Points to a dropdown partial (Filters/Dropdown).
    • filterClass: This is the PHP class responsible for processing the filter. For duration, it's DurationFilter.
    • options: This section defines the options for the dropdown, each with a label (for the user to see) and a value (sent to the API).
    • position: Indicates where the filter should be displayed on the page.

submitButton

  • Defines the configuration for the submit button:
    • position: Determines where the submit button is placed in the form (top in this case). It accepts top, bottom or both
    • cssClass: Adds CSS classes for styling the button.
    • label: Provides the text for the submit button (translatable using locallang.xlf).

5. Adding Custom Filters

You can easily extend the plugin by defining your own filters in TypoScript:

  1. Create a New Filter Add a new filter object under filters in your TypoScript setup. For example, if you want to filter by video quality, your configuration might look like this:

    filters {
        quality {
            label = LLL:EXT:sg_youtube/Resources/Private/Language/locallang.xlf:filter.quality
            partial = Filters/Dropdown
            filterClass = SGalinski\SgYoutube\Filter\QualityFilter
            position = top
            options {
                0 {
                    label = HD
                    value = hd
                }
                1 {
                    label = SD
                    value = sd
                }
            }
        }
    }
    
  2. Implement the Filter Logic You will need to define the corresponding PHP filterClass that handles the logic for applying the filter to the YouTube API request. For example, the QualityFilter class would process the selected video quality and add the appropriate parameters to the API request. It must implement the FilterInterface interface. The modifyRequest method is called before sending the reuqest, while the modifyResponse method is called after receiving the response.

6. Working with Filter Positions

You can choose where filters are displayed (above or below the video list) by setting the position attribute in the TypoScript configuration. This allows you to create a flexible layout for filters:

  • Filters with position = top will be displayed before the video list.
  • Filters with position = bottom will be displayed after the video list.

For example:

filters {
   searchTerm {
       position = top
   }
   duration {
       position = bottom
   }
}

7. Debugging and Error Handling

If something goes wrong (e.g., videos aren't displayed, or the API request fails), here are a few things to check:

  • Make sure the YouTube API key is correctly configured.
  • Check the TypoScript configuration for errors (e.g., missing or incorrect filter definitions).
  • Look for error messages in the TYPO3 backend log for issues related to the plugin.

8. Conclusion

With this flexible filter system, you can easily customize the YouTube video list based on user input. By defining filters in TypoScript and adding them to the plugin's FlexForm, you provide an interactive and tailored experience for your site's visitors.

If you need to add more filters, just extend the TypoScript configuration, create the necessary filter classes, and you're ready to go!