This commit is contained in:
Markos Gogoulos
2026-01-28 22:25:33 +02:00
parent bcef59c3a9
commit 40cd7916e7
13 changed files with 1179 additions and 0 deletions

View File

@@ -0,0 +1,54 @@
# Changelog
All notable changes to the MediaCMS LTI Filter plugin will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.0.0] - 2026-01-23
### Added
- Initial release of MediaCMS LTI Filter
- Automatic detection of MediaCMS video URLs in Moodle content
- Transparent LTI 1.3 authentication for embedded videos
- Support for `/view?m=TOKEN` and `/embed?m=TOKEN` URL patterns
- Configurable MediaCMS URL setting
- Configurable LTI tool selection from Moodle's LTI tools
- Configurable iframe dimensions (width/height)
- Auto-submit form mechanism for seamless LTI launch
- Support for Moodle 5.0+
- Privacy provider implementation for GDPR compliance
- Comprehensive documentation (README, INSTALLATION guide)
- Multi-language support framework (English strings included)
### Security
- Only processes content for logged-in users (no guest access)
- Uses Moodle's LTI 1.3 security framework
- Passes user context via secure `login_hint` parameter
- All URLs properly escaped and sanitized
## [Unreleased]
### Planned Features
- Support for additional MediaCMS URL patterns
- Customizable iframe styling options
- Cache optimization for LTI configuration
- Support for playlist URLs
- Admin interface to preview filter behavior
- Bulk URL conversion tool
- Statistics/usage tracking
---
## Version History
- **1.0.0** (2026-01-23) - Initial release
## Upgrade Notes
### Upgrading to 1.0.0
- First release, no upgrade path needed
---
For detailed information about each release, see the Git commit history.

View File

@@ -0,0 +1,223 @@
# Example Output - How the Filter Works
## Input (What users paste)
```
https://deic.mediacms.io/view?m=KmITliaUC
```
## Output (What gets rendered)
### HTML Generated by Filter
```html
<div class="mediacms-lti-embed">
<!-- The iframe where the video will load -->
<iframe
id="mediacms_lti_65b8f9a3e4c21"
width="960"
height="540"
frameborder="0"
allowfullscreen
style="max-width: 100%;">
</iframe>
<!-- Auto-submit form that initiates LTI authentication -->
<form
id="mediacms_lti_65b8f9a3e4c21_form"
action="https://deic.mediacms.io/lti/oidc/login/"
method="POST"
target="mediacms_lti_65b8f9a3e4c21"
style="display: none;">
<!-- LTI Platform Issuer (your Moodle URL) -->
<input type="hidden" name="iss" value="https://your-moodle-site.com" />
<!-- LTI Client ID from tool configuration -->
<input type="hidden" name="client_id" value="ABC123XYZ" />
<!-- Current user's Moodle ID -->
<input type="hidden" name="login_hint" value="42" />
<!-- Where to go after authentication, with video token -->
<input type="hidden" name="target_link_uri" value="https://deic.mediacms.io/lti/launch/?media_friendly_token=KmITliaUC" />
</form>
<!-- JavaScript to auto-submit the form immediately -->
<script>
document.getElementById('mediacms_lti_65b8f9a3e4c21_form').submit();
</script>
</div>
```
## What Happens Step-by-Step
### 1. User Views Page
```
User opens Moodle page containing the MediaCMS URL
Filter detects: https://deic.mediacms.io/view?m=KmITliaUC
Extracts video token: KmITliaUC
```
### 2. HTML Generation
```
Filter generates:
- Iframe with unique ID
- Hidden form with LTI parameters
- JavaScript to auto-submit
```
### 3. LTI Authentication Flow
```
Form submits to MediaCMS OIDC endpoint
MediaCMS receives:
- iss: https://your-moodle-site.com
- client_id: ABC123XYZ
- login_hint: 42 (user's Moodle ID)
- target_link_uri: https://deic.mediacms.io/lti/launch/?media_friendly_token=KmITliaUC
MediaCMS redirects to Moodle's auth endpoint
Moodle validates and creates JWT token
Moodle POSTs JWT back to MediaCMS
MediaCMS validates JWT and creates session
MediaCMS redirects to /lti/embed/KmITliaUC/
MediaCMS checks permissions and redirects to /view?m=KmITliaUC
Video loads in iframe!
```
### 4. User Experience
```
User sees:
1. Page loads
2. Empty iframe appears briefly (< 1 second)
3. Video player loads inside iframe
4. Video starts playing
```
## Real-World Examples
### Example 1: Course Page
**Input:**
```html
<p>Welcome to the course! Watch this introduction:</p>
<p>https://deic.mediacms.io/view?m=KmITliaUC</p>
```
**Output:**
```html
<p>Welcome to the course! Watch this introduction:</p>
<div class="mediacms-lti-embed">
<iframe id="mediacms_lti_..." width="960" height="540" ...></iframe>
<form id="mediacms_lti_..._form" ...>...</form>
<script>...</script>
</div>
```
### Example 2: Multiple Videos
**Input:**
```html
<h2>Week 1 Videos</h2>
<p>Lecture 1: https://deic.mediacms.io/view?m=ABC123</p>
<p>Lecture 2: https://deic.mediacms.io/view?m=XYZ789</p>
```
**Output:**
```html
<h2>Week 1 Videos</h2>
<p>Lecture 1:
<div class="mediacms-lti-embed">
<iframe id="mediacms_lti_abc_..." ...></iframe>
...
</div>
</p>
<p>Lecture 2:
<div class="mediacms-lti-embed">
<iframe id="mediacms_lti_xyz_..." ...></iframe>
...
</div>
</p>
```
Each video gets its own iframe with its own LTI authentication!
### Example 3: Mixed Content
**Input:**
```html
<p>Check out this resource:</p>
<p><a href="https://example.com">Regular link</a></p>
<p>https://deic.mediacms.io/view?m=KmITliaUC</p>
<p>Another link: https://google.com</p>
```
**Output:**
```html
<p>Check out this resource:</p>
<p><a href="https://example.com">Regular link</a></p>
<div class="mediacms-lti-embed">
<iframe id="mediacms_lti_..." ...></iframe>
...
</div>
<p>Another link: https://google.com</p>
```
Only MediaCMS URLs are converted! Other URLs remain unchanged.
## Performance Notes
- **Fast Detection**: Regex-based URL matching is extremely fast
- **No Database Queries**: Configuration is cached
- **Lazy Loading**: Videos only load when iframe initiates LTI flow
- **Minimal Overhead**: Each conversion adds ~500 bytes of HTML
## Security Notes
- **User Context**: Each iframe uses the current user's Moodle ID
- **CSRF Protected**: LTI flow includes state/nonce validation
- **Domain Restricted**: Only configured MediaCMS domain is processed
- **Guest Users**: Filter doesn't run for guest users (returns original text)
## Browser Compatibility
Works in all modern browsers:
- ✅ Chrome/Edge (Chromium)
- ✅ Firefox
- ✅ Safari
- ✅ Mobile browsers (iOS Safari, Chrome Mobile)
## Troubleshooting Examples
### If URL Doesn't Convert
**Check these patterns:**
```
✅ https://deic.mediacms.io/view?m=KmITliaUC
✅ https://deic.mediacms.io/embed?m=KmITliaUC
❌ https://deic.mediacms.io/view/KmITliaUC (no ?m= parameter)
❌ http://other-domain.com/view?m=KmITliaUC (wrong domain)
```
### If Video Doesn't Load
**Check browser console:**
```javascript
// Expected: No errors
// If you see CORS errors: Check MediaCMS iframe settings
// If you see 403 Forbidden: Check LTI configuration
// If you see 404: Check MediaCMS URL in settings
```
---
**This is what makes the transparent LTI authentication possible!**

View File

@@ -0,0 +1,105 @@
# Quick Installation Guide - MediaCMS LTI Filter
## Prerequisites
- Moodle 5.0 or later
- MediaCMS instance with LTI 1.3 support
- LTI External Tool already configured in Moodle for MediaCMS
## Installation Steps
### 1. Install the Plugin
**Option A: Upload via Moodle UI**
```
1. Log in as Moodle admin
2. Site administration → Plugins → Install plugins
3. Upload the filter_mediacmslti.zip file
4. Click "Install plugin from the ZIP file"
5. Complete the installation wizard
```
**Option B: Manual Installation**
```bash
# Copy plugin to Moodle filter directory
cp -r filter_mediacmslti /path/to/moodle/filter/
# Set permissions
chown -R www-data:www-data /path/to/moodle/filter/filter_mediacmslti
# Visit Moodle notifications page to complete installation
```
### 2. Configure the Filter
```
1. Site administration → Plugins → Filters → MediaCMS LTI Filter
2. Set "MediaCMS URL" to your MediaCMS instance (e.g., https://deic.mediacms.io)
3. Select your LTI tool from the "LTI External Tool" dropdown
4. Optionally adjust iframe width/height (defaults: 960x540)
5. Click "Save changes"
```
### 3. Enable the Filter
```
1. Site administration → Plugins → Filters → Manage filters
2. Find "MediaCMS LTI Embed" in the list
3. Change from "Disabled" to "On"
4. Click "Save changes"
```
### 4. Test It!
```
1. Create a Page resource in any course
2. Paste a MediaCMS URL: https://deic.mediacms.io/view?m=KmITliaUC
3. Save the page
4. View the page - video should embed automatically!
```
## Configuration Quick Reference
| Setting | Example Value | Description |
|---------|---------------|-------------|
| MediaCMS URL | `https://deic.mediacms.io` | Your MediaCMS instance (no trailing slash) |
| LTI External Tool | MediaCMS | Select from dropdown |
| Iframe Width | 960 | Width in pixels |
| Iframe Height | 540 | Height in pixels |
## Troubleshooting Quick Fixes
**URLs not converting?**
- Check filter is "On" in Filters → Manage filters
- Verify MediaCMS URL matches the URLs you're pasting
- Ensure user is logged in (not guest)
**Video not loading?**
- Check LTI tool is configured correctly
- Verify client_id and issuer match between Moodle and MediaCMS
- Check browser console for errors
**Need more help?**
See full README.md for detailed troubleshooting and technical documentation.
## What URLs Are Supported?
The filter automatically detects these patterns:
- `https://deic.mediacms.io/view?m=TOKEN`
- `https://deic.mediacms.io/embed?m=TOKEN`
Replace `deic.mediacms.io` with your configured MediaCMS URL.
## Quick Test Checklist
- [ ] Plugin installed successfully
- [ ] Filter settings configured
- [ ] Filter enabled in Manage filters
- [ ] LTI tool configured and working
- [ ] Test URL pasted in Page resource
- [ ] Video embeds and plays correctly
## Support
Full documentation: See README.md
MediaCMS docs: https://docs.mediacms.io

View File

@@ -0,0 +1,22 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
---
Copyright (C) 2026 MediaCMS
For the full text of the GNU GPL v3 license, visit:
https://www.gnu.org/licenses/gpl-3.0.html

View File

@@ -0,0 +1,264 @@
# MediaCMS LTI Filter for Moodle 5
A Moodle filter plugin that automatically converts MediaCMS video URLs into LTI-authenticated embedded video players. Users can simply paste MediaCMS URLs into any Moodle content area (course descriptions, page content, etc.) and the videos will be embedded with transparent LTI authentication.
## Features
- **Automatic URL Detection**: Detects MediaCMS video URLs and converts them to embedded iframes
- **Transparent LTI Authentication**: Automatically initiates LTI 1.3 authentication flow without user interaction
- **Seamless Integration**: Works in any Moodle text area (Pages, Activities, Descriptions, etc.)
- **Configurable**: Admin can set MediaCMS URL, LTI tool, and iframe dimensions
- **Moodle 5 Compatible**: Built specifically for Moodle 5.0+
## How It Works
1. User pastes a MediaCMS URL (e.g., `https://deic.mediacms.io/view?m=KmITliaUC`)
2. Filter detects the URL and extracts the video token
3. Generates an iframe with an auto-submitting form that initiates LTI authentication
4. Form includes:
- Current user's Moodle ID as `login_hint`
- LTI platform issuer (ISS)
- LTI client ID
- Target video via custom parameters
5. Video loads in iframe with proper LTI authentication
## Prerequisites
Before installing this filter, you must have:
1. **MediaCMS with LTI Support**: Your MediaCMS instance must have LTI 1.3 integration enabled
2. **LTI External Tool Configured**: An LTI External Tool must be configured in Moodle that connects to MediaCMS
3. **Moodle 5.0 or later**
## Installation
### Method 1: Via Moodle Plugin Directory (Recommended)
1. Download the plugin ZIP file
2. Log in as Moodle admin
3. Go to **Site administration → Plugins → Install plugins**
4. Upload the ZIP file
5. Click "Install plugin from the ZIP file"
6. Follow the on-screen prompts
### Method 2: Manual Installation
1. Copy the `filter_mediacmslti` directory to your Moodle installation:
```bash
cp -r filter_mediacmslti /path/to/moodle/filter/
```
2. Set proper permissions:
```bash
cd /path/to/moodle
chown -R www-data:www-data filter/filter_mediacmslti
```
3. Log in as Moodle admin and go to **Site administration → Notifications**
4. Moodle will detect the new plugin and prompt you to upgrade
5. Click "Upgrade Moodle database now"
## Configuration
### Step 1: Configure LTI External Tool (if not already done)
1. Go to **Site administration → Plugins → Activity modules → External tool → Manage tools**
2. Click "Configure a tool manually"
3. Enter the following details:
- **Tool name**: MediaCMS
- **Tool URL**: `https://deic.mediacms.io/lti/launch/`
- **LTI version**: LTI 1.3
- **Public key type**: Keyset URL
- **Public keyset**: `https://deic.mediacms.io/lti/jwks/`
- **Initiate login URL**: `https://deic.mediacms.io/lti/oidc/login/`
- **Redirection URI(s)**: `https://deic.mediacms.io/lti/launch/`
4. Enable:
- Deep Linking (Content-Item Message)
- Share launcher's name with tool
- Share launcher's email with tool
5. Click "Save changes"
6. **Note the Tool ID** (you'll need this for the filter configuration)
### Step 2: Configure Filter Settings
1. Go to **Site administration → Plugins → Filters → MediaCMS LTI Filter**
2. Configure the following settings:
- **MediaCMS URL**: Enter your MediaCMS instance URL
- Example: `https://deic.mediacms.io`
- Do NOT include trailing slash
- **LTI External Tool**: Select the MediaCMS tool you configured in Step 1
- Choose from the dropdown of available LTI tools
- **Iframe Width**: Default width in pixels (default: 960)
- **Iframe Height**: Default height in pixels (default: 540)
3. Click "Save changes"
### Step 3: Enable the Filter
1. Go to **Site administration → Plugins → Filters → Manage filters**
2. Find "MediaCMS LTI Embed" in the list
3. Change the setting from "Disabled" to **"On"**
- Alternatively, use "Off, but available" to allow course-level control
4. Adjust the filter order if needed (higher = runs earlier)
5. Click "Save changes"
## Usage
### For Content Creators
Once the filter is enabled, simply paste MediaCMS URLs into any Moodle content area:
#### Example 1: In a Page Resource
1. Create or edit a Page resource
2. In the content editor, paste the MediaCMS URL:
```
https://deic.mediacms.io/view?m=KmITliaUC
```
3. Save the page
4. The URL will automatically be replaced with an embedded video player
#### Example 2: In Course Description
1. Edit course settings
2. In the "Course description" field, paste:
```
Watch this introduction video: https://deic.mediacms.io/view?m=KmITliaUC
```
3. Save
4. The video will be embedded directly in the course summary
#### Example 3: In Activity Description
1. Create any activity (Forum, Assignment, etc.)
2. In the description field, paste MediaCMS URLs
3. Students will see embedded videos when viewing the activity
### Supported URL Formats
The filter recognizes these URL patterns:
- `https://deic.mediacms.io/view?m=TOKEN`
- `https://deic.mediacms.io/embed?m=TOKEN`
- `http://` versions (if your MediaCMS uses HTTP)
### For End Users (Students/Teachers)
No action required! When viewing content with MediaCMS URLs:
1. Page loads normally
2. Video player appears in an iframe
3. LTI authentication happens transparently in the background
4. Video starts playing (if user has permission)
**Note**: Users must be logged into Moodle. Guest users will see the original URL without embedding.
## Troubleshooting
### URLs are not being converted
**Check**:
1. Filter is enabled: **Site admin → Plugins → Filters → Manage filters**
2. MediaCMS URL in settings matches the URLs you're pasting
3. LTI tool is selected in filter settings
4. User is logged in (not guest)
### Video shows "Access Denied" error
**Possible causes**:
1. LTI tool not configured correctly
2. MediaCMS not receiving proper authentication
3. User doesn't have permission to view the video in MediaCMS
**Debug**:
- Check Moodle logs: **Site admin → Reports → Logs**
- Check MediaCMS LTI logs on the MediaCMS admin panel
- Verify LTI tool configuration (client_id, issuer, etc.)
### Iframe shows blank or loading forever
**Check**:
1. MediaCMS URL is accessible from your network
2. Browser console for JavaScript errors
3. LTI tool ID is correct
4. MediaCMS OIDC login endpoint is working: `https://deic.mediacms.io/lti/oidc/login/`
### Multiple iframes from same URL
The filter replaces ALL occurrences of MediaCMS URLs. If you paste the same URL twice, you'll get two embedded players.
**Solution**: Paste the URL only once per page, or use HTML mode to add the URL as plain text (wrap in `<code>` tags).
## Technical Details
### How the Filter Works
1. **Text Processing**: Filter scans all text content using regex patterns
2. **URL Extraction**: Identifies MediaCMS URLs and extracts video tokens
3. **LTI Configuration**: Retrieves LTI settings (issuer, client_id) from configured tool
4. **HTML Generation**: Creates:
- An `<iframe>` element with unique ID
- A hidden `<form>` that posts to MediaCMS OIDC login endpoint
- Form includes: `iss`, `client_id`, `login_hint`, `target_link_uri`
- JavaScript to auto-submit the form on page load
5. **LTI Flow**: Form submission triggers LTI 1.3 authentication:
- OIDC Login → Redirect to Moodle Auth → POST back with JWT → Session created
6. **Video Display**: MediaCMS redirects to video player inside iframe
### Security Considerations
- **Authentication Required**: Filter only works for logged-in users
- **LTI 1.3 Security**: Uses OAuth2/OIDC flow with JWT validation
- **User Context**: Each iframe uses the current user's Moodle ID as `login_hint`
- **No Credentials Stored**: Filter doesn't store user credentials or tokens
- **Content Security**: Iframes are scoped to MediaCMS domain
### Performance
- **Lightweight**: Regex-based URL detection is fast
- **No Database Queries**: Uses cached configuration from Moodle settings
- **Lazy Loading**: Videos load on-demand when iframe initiates LTI flow
## Uninstallation
1. Go to **Site administration → Plugins → Filters → Manage filters**
2. Disable the filter first
3. Go to **Site administration → Plugins → Plugins overview**
4. Find "MediaCMS LTI Filter"
5. Click "Uninstall"
6. Confirm uninstallation
**Note**: Existing MediaCMS URLs will revert to plain text URLs after uninstallation.
## Support
For issues or questions:
- Check MediaCMS documentation: https://docs.mediacms.io
- Report bugs on GitHub: https://github.com/mediacms-io/mediacms
- Moodle plugin directory: (link when published)
## License
This plugin is licensed under the GNU GPL v3 or later.
Copyright (C) 2026 MediaCMS
## Changelog
### Version 1.0.0 (2026-01-23)
- Initial release
- Support for Moodle 5.0+
- Automatic URL detection and embedding
- LTI 1.3 authentication integration
- Configurable iframe dimensions
- Multi-language support (English)
## Credits
Developed by the MediaCMS team.
---
**Enjoy seamless MediaCMS video embedding in Moodle!**

View File

@@ -0,0 +1,39 @@
<?php
// This file is part of Moodle - http://moodle.org/
/**
* LTI Auth Callback for Filter Launches
*
* This handles the OIDC redirect from MediaCMS for filter-initiated launches
*
* @package filter_mediacmslti
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot . '/mod/lti/locallib.php');
// This endpoint receives the response from Moodle's /mod/lti/auth.php
// after it completes the OIDC flow
// Get launch parameters from query string
$state = optional_param('state', '', PARAM_RAW);
$id_token = optional_param('id_token', '', PARAM_RAW);
if (empty($id_token)) {
die('Missing id_token');
}
// Verify and decode the id_token
// Then redirect to the MediaCMS embed
$PAGE->set_context(context_system::instance());
$PAGE->set_pagelayout('embedded');
echo $OUTPUT->header();
echo '<div style="padding: 20px;">';
echo '<p>Processing authentication...</p>';
echo '<p>ID Token received, redirecting to content...</p>';
echo '</div>';
echo $OUTPUT->footer();

View File

@@ -0,0 +1,45 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Privacy provider for MediaCMS LTI Filter.
*
* @package filter_mediacmslti
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace filter_mediacmslti\privacy;
defined('MOODLE_INTERNAL') || die();
/**
* Privacy provider implementation for MediaCMS LTI Filter.
*
* This plugin does not store any personal data.
*/
class provider implements \core_privacy\local\metadata\null_provider {
/**
* Get the language string identifier with the component's language
* file to explain why this plugin stores no data.
*
* @return string
*/
public static function get_reason(): string {
return 'privacy:metadata';
}
}

View File

@@ -0,0 +1,129 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* MediaCMS LTI Filter - Converts MediaCMS URLs to LTI-authenticated iframes.
*
* @package filter_mediacmslti
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace filter_mediacmslti;
defined('MOODLE_INTERNAL') || die();
/**
* Filter class for converting MediaCMS URLs to LTI iframes.
*/
class text_filter extends \core_filters\text_filter {
/**
* Apply the filter to the given text.
*
* @param string $text The text to filter
* @param array $options Filter options
* @return string The filtered text
*/
public function filter($text, array $options = array()) {
global $USER, $CFG, $PAGE;
// Don't process if user is not logged in.
if (!isloggedin() || isguestuser()) {
return $text;
}
// Get plugin configuration.
$mediacmsurl = get_config('filter_mediacmslti', 'mediacmsurl');
$ltitoolid = get_config('filter_mediacmslti', 'ltitoolid');
$iframewidth = get_config('filter_mediacmslti', 'iframewidth') ?: 960;
$iframeheight = get_config('filter_mediacmslti', 'iframeheight') ?: 540;
if (empty($mediacmsurl) || empty($ltitoolid)) {
return $text;
}
// Parse the MediaCMS URL to get the base domain.
$parsedurl = parse_url($mediacmsurl);
if (!isset($parsedurl['host'])) {
return $text;
}
$domain = $parsedurl['host'];
// Escape special regex characters in domain.
$escapeddomain = preg_quote($domain, '/');
// Pattern to match MediaCMS video URLs:
// - https://lti.mediacms.io/view?m=TOKEN
// - https://lti.mediacms.io/embed?m=TOKEN
// - http versions
$pattern = '/https?:\/\/' . $escapeddomain . '\/(view|embed)\?m=([a-zA-Z0-9_-]+)/i';
// Find all matches.
if (!preg_match_all($pattern, $text, $matches, PREG_SET_ORDER)) {
return $text;
}
// Get course context
$context = isset($options['context']) ? $options['context'] : $PAGE->context;
$courseid = 0;
// Try to determine course ID from context
if ($context) {
if ($context->contextlevel == CONTEXT_COURSE) {
$courseid = $context->instanceid;
} else if ($context->contextlevel == CONTEXT_MODULE) {
$cm = get_coursemodule_from_id('', $context->instanceid);
if ($cm) {
$courseid = $cm->course;
}
}
}
// Replace each match with an iframe pointing to launch.php
foreach ($matches as $match) {
$fullurl = $match[0];
$mediatoken = $match[2];
// Build launch URL with parameters (like Kaltura does)
$launchurl = new \moodle_url('/filter/mediacmslti/launch.php', [
'token' => $mediatoken,
'courseid' => $courseid,
'width' => $iframewidth,
'height' => $iframeheight
]);
// Generate iframe (like Kaltura does)
$iframe = \html_writer::tag('iframe', '', array(
'width' => $iframewidth,
'height' => $iframeheight,
'class' => 'mediacms-player-iframe',
'allowfullscreen' => 'true',
'allow' => 'autoplay *; fullscreen *; encrypted-media *; camera *; microphone *; display-capture *;',
'src' => $launchurl->out(false),
'frameborder' => '0'
));
$iframeContainer = \html_writer::tag('div', $iframe, array(
'class' => 'mediacms-player-container'
));
$text = str_replace($fullurl, $iframeContainer, $text);
}
return $text;
}
}

View File

@@ -0,0 +1,55 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Language strings for MediaCMS LTI Filter plugin.
*
* @package filter_mediacmslti
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['pluginname'] = 'MediaCMS LTI Filter';
$string['filtername'] = 'MediaCMS LTI Embed';
// Settings.
$string['mediacmsurl'] = 'MediaCMS URL';
$string['mediacmsurl_desc'] = 'The base URL of your MediaCMS instance (e.g., https://deic.mediacms.io). URLs from this domain will be converted to LTI-authenticated iframes.';
$string['ltitoolid'] = 'LTI External Tool';
$string['ltitoolid_desc'] = 'Select the LTI External Tool that is configured for MediaCMS integration. This tool must be pre-configured with the correct LTI settings.';
$string['noltitoolsfound'] = 'No LTI tools configured';
$string['iframewidth'] = 'Iframe Width';
$string['iframewidth_desc'] = 'Default width for embedded video iframes in pixels (default: 960).';
$string['iframeheight'] = 'Iframe Height';
$string['iframeheight_desc'] = 'Default height for embedded video iframes in pixels (default: 540).';
$string['enablefilterheading'] = 'Enable the Filter';
$string['enablefilterheading_desc'] = 'After configuring the settings above, you must enable this filter:<br><br>
<ol>
<li>Go to <strong>Site administration → Plugins → Filters → Manage filters</strong></li>
<li>Find "MediaCMS LTI Embed" in the list</li>
<li>Change the setting from "Disabled" to "On" or "Off, but available"</li>
<li>Click "Save changes"</li>
</ol>
<br>
Once enabled, any MediaCMS video URL pasted into course descriptions, page content, or other text areas will automatically be converted to an embedded video player with LTI authentication.';
// Privacy.
$string['privacy:metadata'] = 'The MediaCMS LTI Filter plugin does not store any personal data. It processes URLs in content and initiates LTI authentication using the user\'s Moodle ID as the login hint.';

View File

@@ -0,0 +1,96 @@
<?php
// This file is part of Moodle - http://moodle.org/
/**
* LTI Launch for MediaCMS Filter - Uses Moodle's LTI libraries like Kaltura
*
* @package filter_mediacmslti
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
require_once(__DIR__ . '/../../config.php');
require_once($CFG->dirroot . '/mod/lti/lib.php');
require_once($CFG->dirroot . '/mod/lti/locallib.php');
global $SITE;
require_login();
$mediatoken = required_param('token', PARAM_ALPHANUMEXT);
$courseid = optional_param('courseid', 0, PARAM_INT);
$height = optional_param('height', 540, PARAM_INT);
$width = optional_param('width', 960, PARAM_INT);
// Get filter configuration
$mediacmsurl = get_config('filter_mediacmslti', 'mediacmsurl');
$ltitoolid = get_config('filter_mediacmslti', 'ltitoolid');
if (empty($mediacmsurl) || empty($ltitoolid)) {
die('Filter not configured');
}
// Get the LTI tool type
$type = $DB->get_record('lti_types', ['id' => $ltitoolid]);
if (!$type) {
die('LTI tool not found');
}
// Set up context - if courseid is 0, use system context
if (0 != $courseid) {
$context = context_course::instance($courseid);
$course = get_course($courseid);
} else {
$context = context_system::instance();
$course = $SITE;
}
// Set up page
$PAGE->set_url(new moodle_url('/filter/mediacmslti/launch.php', [
'token' => $mediatoken,
'courseid' => $courseid,
'width' => $width,
'height' => $height
]));
$PAGE->set_context($context);
$PAGE->set_pagelayout('embedded');
// Create a dummy LTI instance object (like Kaltura does)
$instance = new stdClass();
$instance->id = 0; // Dummy ID - not a real activity
$instance->course = $course->id;
$instance->typeid = $ltitoolid;
$instance->name = 'MediaCMS video resource';
$instance->instructorchoiceacceptgrades = 0;
$instance->grade = 0;
$instance->instructorchoicesendname = 1;
$instance->instructorchoicesendemailaddr = 1;
$instance->launchcontainer = LTI_LAUNCH_CONTAINER_EMBED_NO_BLOCKS;
// Add custom parameters for media token
$instance->instructorcustomparameters = "media_friendly_token={$mediatoken}";
// Get type config and merge in our custom parameters
$typeconfig = lti_get_type_type_config($ltitoolid);
// Add custom parameters to typeconfig to ensure they're included in the launch
// typeconfig might be an array or object, handle both cases
if (is_array($typeconfig)) {
if (!isset($typeconfig['customparameters'])) {
$typeconfig['customparameters'] = '';
}
$typeconfig['customparameters'] .= "\nmedia_friendly_token={$mediatoken}";
} else {
if (!isset($typeconfig->customparameters)) {
$typeconfig->customparameters = '';
}
$typeconfig->customparameters .= "\nmedia_friendly_token={$mediatoken}";
}
// Use Moodle's LTI launch function to initiate OIDC properly
// This ensures Moodle generates and tracks the state/nonce
$content = lti_initiate_login($course->id, null, $instance, $typeconfig, null, 'MediaCMS video resource');
echo $OUTPUT->header();
echo $content;
echo $OUTPUT->footer();

View File

@@ -0,0 +1,82 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Settings for MediaCMS LTI Filter plugin.
*
* @package filter_mediacmslti
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die;
if ($ADMIN->fulltree) {
// MediaCMS URL setting.
$settings->add(new admin_setting_configtext(
'filter_mediacmslti/mediacmsurl',
get_string('mediacmsurl', 'filter_mediacmslti'),
get_string('mediacmsurl_desc', 'filter_mediacmslti'),
'https://deic.mediacms.io',
PARAM_URL
));
// Get list of LTI tools for dropdown.
$ltioptions = [];
try {
$tools = $DB->get_records('lti_types', null, 'name ASC', 'id, name');
foreach ($tools as $tool) {
$ltioptions[$tool->id] = $tool->name;
}
} catch (Exception $e) {
// Database not ready yet or no tools configured.
$ltioptions[0] = get_string('noltitoolsfound', 'filter_mediacmslti');
}
// LTI Tool ID setting.
$settings->add(new admin_setting_configselect(
'filter_mediacmslti/ltitoolid',
get_string('ltitoolid', 'filter_mediacmslti'),
get_string('ltitoolid_desc', 'filter_mediacmslti'),
0,
$ltioptions
));
// Iframe width setting.
$settings->add(new admin_setting_configtext(
'filter_mediacmslti/iframewidth',
get_string('iframewidth', 'filter_mediacmslti'),
get_string('iframewidth_desc', 'filter_mediacmslti'),
'960',
PARAM_INT
));
// Iframe height setting.
$settings->add(new admin_setting_configtext(
'filter_mediacmslti/iframeheight',
get_string('iframeheight', 'filter_mediacmslti'),
get_string('iframeheight_desc', 'filter_mediacmslti'),
'540',
PARAM_INT
));
// Information about enabling the filter.
$settings->add(new admin_setting_heading(
'filter_mediacmslti/enablefilterheading',
get_string('enablefilterheading', 'filter_mediacmslti'),
get_string('enablefilterheading_desc', 'filter_mediacmslti')
));
}

View File

@@ -0,0 +1,34 @@
<?php
echo "Test 1: PHP works<br>";
echo "Testing path: " . __DIR__ . '<br>';
// Try the path with 4 parent dirs (current version)
if (file_exists(__DIR__ . '/../../../../config.php')) {
echo "Found with ../../../../<br>";
require_once(__DIR__ . '/../../../../config.php');
}
// Try with 2 parent dirs (correct for filter location)
else if (file_exists(__DIR__ . '/../../config.php')) {
echo "Found with ../../<br>";
require_once(__DIR__ . '/../../config.php');
}
else {
die("Cannot find config.php. Tried: <br>" .
__DIR__ . '/../../../../config.php<br>' .
__DIR__ . '/../../config.php');
}
echo "Test 2: Moodle config loaded<br>";
echo "Test 3: Moodle loaded successfully<br>";
echo "wwwroot: " . $CFG->wwwroot . "<br>";
try {
require_login();
echo "Test 4: User logged in: " . $USER->id . "<br>";
} catch (Exception $e) {
die("Login error: " . $e->getMessage());
}
echo "Test 5: All OK!";

View File

@@ -0,0 +1,31 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Version information for MediaCMS LTI Filter plugin.
*
* @package filter_mediacmslti
* @copyright 2026 MediaCMS
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2026012804; // The current plugin version (Date: YYYYMMDDXX).
$plugin->requires = 2024100700; // Requires Moodle 5.0 or later.
$plugin->component = 'filter_mediacmslti'; // Full name of the plugin (used for diagnostics).
$plugin->maturity = MATURITY_STABLE;
$plugin->release = 'v1.1.3';