Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions modules/SampleData/SampleData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

// Copyright 2012-2026 OpenBroadcaster, Inc.
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OpenBroadcaster\Modules\SampleData;

use OpenBroadcaster\Base\Module;

class SampleData extends Module
{
public $name = 'SampleData v1.0';
public $description = 'Seed sample data profiles into a fresh Observer instance.';

public function callbacks()
{
}

public function install()
{
$this->permission_enable('administration', 'import_sample_data', 'import sample data profiles into Observer');

return true;
}

public function uninstall()
{
$this->permission_disable('import_sample_data');

return true;
}

public function purge()
{
$this->permission_delete('import_sample_data');

return true;
}
}
42 changes: 42 additions & 0 deletions modules/SampleData/controllers/SampleData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

// Copyright 2012-2026 OpenBroadcaster, Inc.
// SPDX-License-Identifier: AGPL-3.0-or-later

namespace OpenBroadcaster\Modules\SampleData\Controllers;

use OpenBroadcaster\Base\Controller;

class SampleData extends Controller
{
public function __construct()
{
parent::__construct();

$this->user->require_permission('import_sample_data');
$this->SampleDataModel = $this->load->model('SampleData', 'SampleData');
}

public function listProfiles()
{
$profiles = $this->SampleDataModel('listProfiles');
return [true, 'Sample data profiles.', $profiles];
}

public function runProfile()
{
$profile = trim((string) $this->data('profile'));

if ($profile === '' || !preg_match('/^[a-z0-9_]+$/', $profile)) {
return [false, 'Invalid profile name.'];
}

$result = $this->SampleDataModel('runProfile', $profile);

if (!$result['success']) {
return [false, $result['error'], ['log' => $result['log']]];
}

return [true, 'Sample data imported.', ['log' => $result['log']]];
}
}
23 changes: 23 additions & 0 deletions modules/SampleData/html/sampledata.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<!--/*
Copyright 2012-2026 OpenBroadcaster, Inc.
SPDX-License-Identifier: AGPL-3.0-or-later
*/-->

<h1>Import Sample Data</h1>

<p id="sampledata_module-info">Pick a sample data profile and click "Import" to seed your installation. The action is idempotent — items that already exist are skipped, never overwritten.</p>

<table class="table">
<tr>
<td><label for="sampledata_module-profile">Profile</label></td>
<td><select id="sampledata_module-profile"></select></td>
</tr>
<tr>
<td colspan="2"><p id="sampledata_module-description"></p></td>
</tr>
<tr>
<td colspan="2"><button id="sampledata_module-import" class="button">Import Selected Profile</button></td>
</tr>
</table>

<pre id="sampledata_module-log" style="display: none; white-space: pre-wrap; background: #111; color: #eee; padding: 1em; border-radius: 4px; margin-top: 1em;"></pre>
101 changes: 101 additions & 0 deletions modules/SampleData/js/sampledata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// Copyright 2012-2026 OpenBroadcaster, Inc.
// SPDX-License-Identifier: AGPL-3.0-or-later

OBModules.SampleData = new Object();

OBModules.SampleData.init = function () {
OB.Callbacks.add('ready', 0, OBModules.SampleData.initMenu);
};

OBModules.SampleData.initMenu = function () {
OB.UI.addSubMenuItem(
'admin',
'Import Sample Data',
'import_sample_data',
OBModules.SampleData.importPage,
110,
'import_sample_data'
);
};

OBModules.SampleData.importPage = function () {
OB.UI.replaceMain('modules/sampledata/sampledata.html');

OBModules.SampleData.profiles = {};
$('#sampledata_module-profile').html('<option value="">Loading…</option>');
$('#sampledata_module-import').prop('disabled', true);
$('#sampledata_module-log').hide().text('');

OB.API.post('sampledata', 'listProfiles', {}, function (response) {
if (!response.status) {
$('#sampledata_module-info').text('Error loading sample data profiles.');
return;
}

var profiles = response.data || [];
var $select = $('#sampledata_module-profile');
$select.empty();

if (profiles.length === 0) {
$select.append('<option value="">No profiles found</option>');
$('#sampledata_module-import').prop('disabled', true);
return;
}

$.each(profiles, function (_, profile) {
OBModules.SampleData.profiles[profile.directory] = profile;
$select.append(
$('<option></option>').val(profile.directory).text(profile.name)
);
});

OBModules.SampleData.updateDescription();
$('#sampledata_module-import').prop('disabled', false);
});

$('#sampledata_module-profile').off('change').on('change', OBModules.SampleData.updateDescription);
$('#sampledata_module-import').off('click').on('click', function () {
OBModules.SampleData.runImport(false);
});
};

OBModules.SampleData.updateDescription = function () {
var dir = $('#sampledata_module-profile').val();
var profile = OBModules.SampleData.profiles[dir];
$('#sampledata_module-description').text(profile ? (profile.description || '') : '');
};

OBModules.SampleData.runImport = function (confirmed) {
var dir = $('#sampledata_module-profile').val();
if (!dir) {
return;
}

if (!confirmed) {
OB.UI.confirm(
'Import sample data profile "' + dir + '"?\n\nThis will create permission groups, users, playlists, a sample player and schedule, and apply settings. The action is idempotent — existing items are skipped — but it cannot be undone.',
function () { OBModules.SampleData.runImport(true); },
'Yes, Import',
'No, Cancel',
'delete'
);
return;
}

$('#sampledata_module-info').text('Importing…');
$('#sampledata_module-import').prop('disabled', true);
$('#sampledata_module-log').show().text('');

OB.API.post('sampledata', 'runProfile', { profile: dir }, function (response) {
var log = (response.data && response.data.log) ? response.data.log.join('\n') : '';
$('#sampledata_module-log').text(log);

if (response.status) {
$('#sampledata_module-info').text('Sample data imported.');
} else {
$('#sampledata_module-info').text('Import failed: ' + (response.msg || 'unknown error'));
}

$('#sampledata_module-import').prop('disabled', false);
});
};
22 changes: 22 additions & 0 deletions modules/SampleData/profiles/en_community_radio/categories.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[
"Commercial Ad",
"Community Events",
"Documents",
"Images",
"Interviews",
"Lecture Talk or Discussion",
"Music",
"News",
"Pop Vox",
"Priority Broadcast",
"PSA Audio",
"PSA Image",
"PSA Video",
"SFX",
"Show Promotion",
"Show Sponsor",
"Shows Complete",
"Station ID",
"Video",
"VoiceTrack"
]
Loading
Loading