Forums

The great place to discuss topics with other users

πŸ”₯ Sngine Plugin – Timeline Live (Jitsi Based)

'
Join the Conversation Post Reply
Vince33 Vince33
Moderator
Joined: 2025-05-22 18:50:59
2026-04-30 14:02:15

πŸ“Œ Overview

This is a ready-to-use concept + base implementation for a Sngine plugin that allows users to:

πŸ‘‰ Start a live session directly from the timeline
πŸ‘‰ Create a live post automatically
πŸ‘‰ Join the live from the post
πŸ‘‰ Keep comments/reactions native to Sngine

No Agora / No Twilio → Jitsi based (open-source)


🎯 Features

  • Start live from timeline (publisher)
  • Automatic post creation
  • Unique Jitsi room generation
  • Live embedded inside the post (iframe/API)
  • Join live without leaving timeline
  • Owner can end live
  • Status:
    • LIVE
    • ENDED
  • No replay (privacy friendly)
  • Viewers join muted by default
  • Minimal Jitsi UI

πŸ“ Folder Structure

 
/content/plugins/live_external/
β”‚
β”œβ”€β”€ plugin.php
β”œβ”€β”€ plugin.json
β”‚
β”œβ”€β”€ ajax/
β”‚ β”œβ”€β”€ create_live.php
β”‚ β”œβ”€β”€ end_live.php
β”‚ └── get_live.php
β”‚
β”œβ”€β”€ templates/
β”‚ └── custom_feeds_post_live_external.tpl
β”‚
└── assets/
└── live_external.js
 

🧩 plugin.json

 
{
"name": "Timeline Live Jitsi",
"description": "Live system inside timeline using Jitsi",
"version": "1.0",
"author": "Community",
"enabled": true
}
 

βš™οΈ plugin.php

 
<?php

/**
* Timeline Live Plugin
*/

nuonat_plugin_log('live_external loaded');

add_hook('header', function () {
echo '<script src="/content/plugins/live_external/assets/live_external.js?v=1"></script>';
});
 

πŸ—„οΈ SQL

 
CREATE TABLE posts_live_external (
id INT AUTO_INCREMENT PRIMARY KEY,
post_id INT NOT NULL,
user_id INT NOT NULL,
room VARCHAR(255) NOT NULL,
status ENUM('live','ended') DEFAULT 'live',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
 

⚑ AJAX – create_live.php

 
<?php
require('../../../bootstrap.php');

is_ajax();
user_access(true);

global $db, $user;

$room = "live_" . $user->_data['user_id'] . "_" . time();

/* create post */
$post_id = $user->post("I'm live now");

/* insert live */
$db->query("
INSERT INTO posts_live_external (post_id, user_id, room)
VALUES ({$post_id}, {$user->_data['user_id']}, '{$room}')
");

return_json([
'success' => true,
'post_id' => $post_id
]);
 

⚑ AJAX – end_live.php

 
<?php
require('../../../bootstrap.php');

is_ajax();
user_access(true);

global $db, $user;

$post_id = (int) $_POST['post_id'];

$db->query("
UPDATE posts_live_external
SET status = 'ended'
WHERE post_id = {$post_id}
AND user_id = {$user->_data['user_id']}
");

return_json(['success' => true]);
 

🎨 TEMPLATE

πŸ“ /content/plugins/live_external/templates/custom_feeds_post_live_external.tpl

 
{assign var=live value=$post['live_external']}

<div class="live-post-box">

{if $live.status == "live"}

<div class="live-badge">πŸ”΄ LIVE</div>

<div id="live-container-{$post['post_id']}" class="live-container"></div>

<button class="btn btn-primary js_join_live"
data-room="{$live.room}"
data-id="{$post['post_id']}">
Join Live
</button>

{if $post['author_id'] == $user->_data['user_id']}
<button class="btn btn-danger js_end_live"
data-id="{$post['post_id']}">
End Live
</button>
{/if}

{else}

<div class="live-ended">
Live ended
</div>

{/if}

</div>
 

🧠 JS

πŸ“ /content/plugins/live_external/assets/live_external.js

 
document.addEventListener("click", function(e) {

// JOIN LIVE
if (e.target.classList.contains("js_join_live")) {

let room = e.target.dataset.room;
let post_id = e.target.dataset.id;

let container = document.getElementById("live-container-" + post_id);

if (!container) return;

container.innerHTML = "";

let domain = "meet.jit.si";

new JitsiMeetExternalAPI(domain, {
roomName: room,
parentNode: container,
width: "100%",
height: 400,
configOverwrite: {
startWithAudioMuted: true,
startWithVideoMuted: true
}
});
}

// END LIVE
if (e.target.classList.contains("js_end_live")) {

let post_id = e.target.dataset.id;

fetch("/content/plugins/live_external/ajax/end_live.php", {
method: "POST",
headers: {"Content-Type": "application/x-www-form-urlencoded"},
body: "post_id=" + post_id
})
.then(res => res.json())
.then(() => location.reload());
}

});
 

🧩 TEMPLATE INTEGRATION

In:

 
__feeds_post.tpl
 

Add:

 
{if $post['post_type'] == "live_external"}
{include file='custom_feeds_post_live_external.tpl'}
{/if}
 

βž• Publisher Button

Add in publisher:

 
<button id="startLiveBtn">Start Live</button>
 

JS:

 
document.getElementById("startLiveBtn").addEventListener("click", function() {
fetch("/content/plugins/live_external/ajax/create_live.php")
.then(res => res.json())
.then(data => {
if (data.success) location.reload();
});
});
 

πŸ’‘ Notes

  • Uses Jitsi Meet External API
  • No recording by default
  • Fully compatible with Sngine timeline
  • Does NOT modify core live system
  • Can be extended (notifications, permissions, moderation…)

πŸš€ Goal

Provide a simple, lightweight and open-source live system directly inside Sngine timeline.


πŸ‘€ Looking for

  • Feedback
  • Improvements
  • Security review
  • Performance optimization
  • UI improvements

πŸ‘‰ This can become a real alternative to Agora/Twilio integration inside Sngine.

Vince33 Vince33
Moderator
Joined: 2025-05-22 18:50:59
2026-04-30 14:07:23

Sol30 Tefg
Member
Joined: 2026-05-02 18:13:11
2026-05-03 17:20:27

Thanks for sharing this great things to us, please can you tell me in which folder/file i add publisher button and the last step which is JS file?

 

Vince33 Vince33
Moderator
Joined: 2025-05-22 18:50:59
2026-05-03 17:36:05

βœ… Where to add the "Start Live" button

In Sngine, the publisher is located in:

 
/content/themes/default/templates/_publisher.tpl
 

You need to add the button inside the publisher actions area (where Photo, Feeling, etc. are).

Example:

 
<button type="button" class="btn btn-sm btn-danger ml5" id="startLiveBtn">
πŸ”΄ Live
</button>
 

βœ… Where to add the JavaScript

Do NOT add JS inline in the template.

Use your plugin JS file:

 
/content/plugins/live_external/assets/live_external.js
 

Then add this code inside it:

 
// START LIVE
document.addEventListener("DOMContentLoaded", function() {

let btn = document.getElementById("startLiveBtn");

if (!btn) return;

btn.addEventListener("click", function() {

fetch("/content/plugins/live_external/ajax/create_live.php", {
method: "GET"
})
.then(res => res.json())
.then(data => {
if (data.success) {
window.location.reload();
}
});

});

});
 

βœ… Important: Load Jitsi API

You must load Jitsi External API, otherwise the live will not work.

Update your plugin.php:

 
add_hook('header', function () {
echo '
<script src="https://meet.jit.si/external_api.js"></script>
<script src="/content/plugins/live_external/assets/live_external.js?v=1"></script>
';
});
 

βœ… Template location (important)

Sngine does NOT load templates from plugin folders automatically.

So instead of:

 
/content/plugins/live_external/templates/
 

You must place the file here:

 
/content/themes/default/templates/custom_feeds_post_live_external.tpl
 

βœ… Feed integration

Edit:

 
/content/themes/default/templates/__feeds_post.tpl
 

Add:

 
{if $post['post_type'] == "live_external"}
{include file='custom_feeds_post_live_external.tpl'}
{/if}
 

⚠️ Important fix (post type)

Your current code:

 
$post_id = $user->post("I'm live now");
 

This creates a normal post.

You must force the correct type:

 
$post_id = $user->post("I'm live now");

$db->query("
UPDATE posts
SET post_type = 'live_external'
WHERE post_id = {$post_id}
");
 

⚠️ Important: load live data into post

By default, $post['live_external'] does not exist.

You need to attach it when posts are fetched.

Quick working solution:

Edit:

 
/includes/class-user.php
 

Inside post fetching loop:

 
$get_live = $db->query("
SELECT *
FROM posts_live_external
WHERE post_id = {$post['post_id']}
LIMIT 1
");

if ($get_live->num_rows > 0) {
$post['live_external'] = $get_live->fetch_assoc();
}
 

βœ… Summary

  • Publisher button → _publisher.tpl
  • JS → /content/plugins/live_external/assets/live_external.js
  • Template → /content/themes/default/templates/
  • Feed hook → __feeds_post.tpl
  • Load Jitsi API → plugin.php
  • Force post_type = live_external
  • Attach live data to post

πŸ”’ Small security improvement

Instead of:

 
$room = "live_" . $user->_data['user_id'] . "_" . time();
 

Use:

 
$room = "live_" . $user->_data['user_id'] . "_" . bin2hex(random_bytes(5));
 

If needed, I can help you build a production-ready version with:

  • No core modification
  • Proper hooks
  • Auto-start live (no join button)
  • Viewer counter
  • Permissions (friends/public)
  • Real-time status updates

Just tell me πŸ‘

Ghaith Alrousan
Member
Joined: 2025-05-26 21:19:26
2026-05-17 07:31:40

hi 

can you help me for setup for my domain 

With the added feature of pay-per-view and monthly subscriptions

ScriptsTribe https://scriptstribe.com