diff --git a/modules/SampleData/SampleData.php b/modules/SampleData/SampleData.php
new file mode 100644
index 00000000..f546f2b9
--- /dev/null
+++ b/modules/SampleData/SampleData.php
@@ -0,0 +1,39 @@
+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;
+ }
+}
diff --git a/modules/SampleData/controllers/SampleData.php b/modules/SampleData/controllers/SampleData.php
new file mode 100644
index 00000000..4c72c199
--- /dev/null
+++ b/modules/SampleData/controllers/SampleData.php
@@ -0,0 +1,42 @@
+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']]];
+ }
+}
diff --git a/modules/SampleData/html/sampledata.html b/modules/SampleData/html/sampledata.html
new file mode 100644
index 00000000..93a3a235
--- /dev/null
+++ b/modules/SampleData/html/sampledata.html
@@ -0,0 +1,23 @@
+
+
+
Import Sample Data
+
+Pick a sample data profile and click "Import" to seed your installation. The action is idempotent — items that already exist are skipped, never overwritten.
+
+
+
+ Profile
+
+
+
+
+
+
+ Import Selected Profile
+
+
+
+
diff --git a/modules/SampleData/js/sampledata.js b/modules/SampleData/js/sampledata.js
new file mode 100644
index 00000000..eb227dca
--- /dev/null
+++ b/modules/SampleData/js/sampledata.js
@@ -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('Loading… ');
+ $('#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('No profiles found ');
+ $('#sampledata_module-import').prop('disabled', true);
+ return;
+ }
+
+ $.each(profiles, function (_, profile) {
+ OBModules.SampleData.profiles[profile.directory] = profile;
+ $select.append(
+ $(' ').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);
+ });
+};
diff --git a/modules/SampleData/profiles/en_community_radio/categories.json b/modules/SampleData/profiles/en_community_radio/categories.json
new file mode 100644
index 00000000..f535ebdc
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/categories.json
@@ -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"
+]
diff --git a/modules/SampleData/profiles/en_community_radio/genres.json b/modules/SampleData/profiles/en_community_radio/genres.json
new file mode 100644
index 00000000..d9774f9f
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/genres.json
@@ -0,0 +1,307 @@
+{
+ "Music": [
+ {"name": "Blues", "description": "Blues"},
+ {"name": "Classic Rock", "description": "Classic Rock"},
+ {"name": "Country", "description": "Country"},
+ {"name": "Dance", "description": "Dance"},
+ {"name": "Disco", "description": "Disco"},
+ {"name": "Funk", "description": "Funk"},
+ {"name": "Grunge", "description": "Grunge"},
+ {"name": "Hip Hop", "description": "Hip Hop"},
+ {"name": "Jazz", "description": "Jazz"},
+ {"name": "Metal", "description": "Metal"},
+ {"name": "New Age", "description": "New Age"},
+ {"name": "Oldies", "description": "Oldies"},
+ {"name": "Other", "description": "Other"},
+ {"name": "Pop", "description": "Pop"},
+ {"name": "R&B", "description": "R&B"},
+ {"name": "Rap", "description": "Rap"},
+ {"name": "Reggae", "description": "Reggae"},
+ {"name": "Rock", "description": "Rock"},
+ {"name": "Techno", "description": "Techno"},
+ {"name": "Industrial", "description": "Industrial"},
+ {"name": "Alternative", "description": "Alternative"},
+ {"name": "Ska", "description": "Ska"},
+ {"name": "Death Metal", "description": "Death Metal"},
+ {"name": "Pranks", "description": "Pranks"},
+ {"name": "Soundtrack", "description": "Soundtrack"},
+ {"name": "Euro-Techno", "description": "Euro-Techno"},
+ {"name": "Ambient", "description": "Ambient"},
+ {"name": "Trip Hop", "description": "Trip Hop"},
+ {"name": "Vocal", "description": "Vocal"},
+ {"name": "Jazz+Funk", "description": "Jazz+Funk"},
+ {"name": "Fusion", "description": "Fusion"},
+ {"name": "Trance", "description": "Trance"},
+ {"name": "Classical", "description": "Classical"},
+ {"name": "Instrumental", "description": "Instrumental"},
+ {"name": "Acid", "description": "Acid"},
+ {"name": "House", "description": "House"},
+ {"name": "Game", "description": "Game"},
+ {"name": "Sound Clip", "description": "Sound Clip"},
+ {"name": "Gospel", "description": "Gospel"},
+ {"name": "Noise", "description": "Noise"},
+ {"name": "AlternRock", "description": "Alternative Rock"},
+ {"name": "Bass", "description": "Bass"},
+ {"name": "Soul", "description": "Soul"},
+ {"name": "Punk", "description": "Punk"},
+ {"name": "Space", "description": "Space"},
+ {"name": "Meditative", "description": "Meditative"},
+ {"name": "Instrumental Pop", "description": "Instrumental Pop"},
+ {"name": "Instrumental Rock", "description": "Instrumental Rock"},
+ {"name": "Ethnic", "description": "Ethnic"},
+ {"name": "Gothic", "description": "Gothic"},
+ {"name": "Darkwave", "description": "Darkwave"},
+ {"name": "Techno-Industrial", "description": "Techno-Industrial"},
+ {"name": "Electronic", "description": "Electronic"},
+ {"name": "Pop-Folk", "description": "Pop-Folk"},
+ {"name": "Eurodance", "description": "Eurodance"},
+ {"name": "Dream", "description": "Dream"},
+ {"name": "Southern Rock", "description": "Southern Rock"},
+ {"name": "Comedy", "description": "Comedy"},
+ {"name": "Cult", "description": "Cult"},
+ {"name": "Gangsta", "description": "Gangsta"},
+ {"name": "Top 40", "description": "Top 40"},
+ {"name": "Christian Rap", "description": "Christian Rap"},
+ {"name": "Pop/Funk", "description": "Pop/Funk"},
+ {"name": "Jungle", "description": "Jungle"},
+ {"name": "Native American", "description": "Native American"},
+ {"name": "Cabaret", "description": "Cabaret"},
+ {"name": "New Wave", "description": "New Wave"},
+ {"name": "Psychedelic", "description": "Psychedelic"},
+ {"name": "Rave", "description": "Rave"},
+ {"name": "Showtunes", "description": "Showtunes"},
+ {"name": "Trailer", "description": "Trailer"},
+ {"name": "Lo-Fi", "description": "Lo-Fi"},
+ {"name": "Tribal", "description": "Tribal"},
+ {"name": "Acid Punk", "description": "Acid Punk"},
+ {"name": "Acid Jazz", "description": "Acid Jazz"},
+ {"name": "Polka", "description": "Polka"},
+ {"name": "Retro", "description": "Retro"},
+ {"name": "Musical", "description": "Musical"},
+ {"name": "Rock & Roll", "description": "Rock & Roll"},
+ {"name": "Hard Rock", "description": "Hard Rock"},
+ {"name": "Folk", "description": "Folk"},
+ {"name": "Folk-Rock", "description": "Folk-Rock"},
+ {"name": "National Folk", "description": "National Folk"},
+ {"name": "Swing", "description": "Swing"},
+ {"name": "Fast Fusion", "description": "Fast Fusion"},
+ {"name": "Bebop", "description": "Bebop"},
+ {"name": "Latin", "description": "Latin"},
+ {"name": "Revival", "description": "Revival"},
+ {"name": "Celtic", "description": "Celtic"},
+ {"name": "Bluegrass", "description": "Bluegrass"},
+ {"name": "Avantgarde", "description": "Avantgarde"},
+ {"name": "Gothic Rock", "description": "Gothic Rock"},
+ {"name": "Progressive Rock", "description": "Progressive Rock"},
+ {"name": "Psychedelic Rock", "description": "Psychedelic Rock"},
+ {"name": "Symphonic Rock", "description": "Symphonic Rock"},
+ {"name": "Slow Rock", "description": "Slow Rock"},
+ {"name": "Big Band", "description": "Big Band"},
+ {"name": "Chorus", "description": "Chorus"},
+ {"name": "Easy Listening", "description": "Easy Listening"},
+ {"name": "Acoustic", "description": "Acoustic"},
+ {"name": "Humour", "description": "Humour"},
+ {"name": "Speech", "description": "Speech"},
+ {"name": "Chanson", "description": "Chanson"},
+ {"name": "Opera", "description": "Opera"},
+ {"name": "Chamber Music", "description": "Chamber Music"},
+ {"name": "Sonata", "description": "Sonata"},
+ {"name": "Symphony", "description": "Symphony"},
+ {"name": "Booty Bass", "description": "Booty Bass"},
+ {"name": "Primus", "description": "Primus"},
+ {"name": "Porn Groove", "description": "Porn Groove"},
+ {"name": "Satire", "description": "Satire"},
+ {"name": "Slow Jam", "description": "Slow Jam"},
+ {"name": "Club", "description": "Club"},
+ {"name": "Tango", "description": "Tango"},
+ {"name": "Samba", "description": "Samba"},
+ {"name": "Folklore", "description": "Folklore"},
+ {"name": "Ballad", "description": "Ballad"},
+ {"name": "Power Ballad", "description": "Power Ballad"},
+ {"name": "Rhythmic Soul", "description": "Rhythmic Soul"},
+ {"name": "Freestyle", "description": "Freestyle"},
+ {"name": "Duet", "description": "Duet"},
+ {"name": "Punk Rock", "description": "Punk Rock"},
+ {"name": "Drum Solo", "description": "Drum Solo"},
+ {"name": "A capella", "description": "A capella"},
+ {"name": "Euro-House", "description": "Euro-House"},
+ {"name": "Dance Hall", "description": "Dance Hall"},
+ {"name": "Goa", "description": "Goa"},
+ {"name": "Drum & Bass", "description": "Drum & Bass"},
+ {"name": "Club-House", "description": "Club-House"},
+ {"name": "Hardcore", "description": "Hardcore"},
+ {"name": "Terror", "description": "Terror"},
+ {"name": "Indie", "description": "Indie"},
+ {"name": "BritPop", "description": "BritPop"},
+ {"name": "Negerpunk", "description": "Negerpunk"},
+ {"name": "Polsk Punk", "description": "Polsk Punk"},
+ {"name": "Beat", "description": "Beat"},
+ {"name": "Christian Gangsta", "description": "Christian Gangsta"},
+ {"name": "Heavy Metal", "description": "Heavy Metal"},
+ {"name": "Black Metal", "description": "Black Metal"},
+ {"name": "Crossover", "description": "Crossover"},
+ {"name": "Contemporary Christian", "description": "Contemporary Christian"},
+ {"name": "Christian Rock", "description": "Christian Rock"},
+ {"name": "Merengue", "description": "Merengue"},
+ {"name": "Salsa", "description": "Salsa"},
+ {"name": "Trash Metal", "description": "Trash Metal"},
+ {"name": "Anime", "description": "Anime"},
+ {"name": "JPop", "description": "JPop"},
+ {"name": "Synthpop", "description": "Synthpop"},
+ {"name": "World Music", "description": "World Music"},
+ {"name": "Yukon", "description": "Local Yukon musicians"}
+ ],
+
+ "Images": [
+ {"name": "Abstract", "description": "Abstract"},
+ {"name": "Adults", "description": "Adults"},
+ {"name": "Agriculture", "description": "Agriculture"},
+ {"name": "Animal", "description": "Animal"},
+ {"name": "Architecture", "description": "Architecture"},
+ {"name": "Arctic", "description": "Arctic"},
+ {"name": "Arts", "description": "Arts"},
+ {"name": "Astro Photography", "description": "Astro Photography"},
+ {"name": "Baby", "description": "Baby"},
+ {"name": "Backgrounds", "description": "Backgrounds"},
+ {"name": "Business", "description": "Business"},
+ {"name": "Celebrations", "description": "Celebrations"},
+ {"name": "Children", "description": "Children"},
+ {"name": "City", "description": "City"},
+ {"name": "Comedy Funny", "description": "Comedy Funny"},
+ {"name": "Communications", "description": "Communications"},
+ {"name": "Computers", "description": "Computers"},
+ {"name": "Culture", "description": "Culture"},
+ {"name": "Documentary", "description": "Documentary"},
+ {"name": "Domestic", "description": "Domestic"},
+ {"name": "Earth Photos", "description": "Earth Photos"},
+ {"name": "Education", "description": "Education"},
+ {"name": "Entertainment", "description": "Entertainment"},
+ {"name": "Environmental", "description": "Environmental"},
+ {"name": "Families", "description": "Families"},
+ {"name": "Fantasy", "description": "Fantasy"},
+ {"name": "Fine Art", "description": "Fine Art"},
+ {"name": "Flowers", "description": "Flowers"},
+ {"name": "Food", "description": "Food"},
+ {"name": "General", "description": "General"},
+ {"name": "Glamour", "description": "Glamour"},
+ {"name": "Government", "description": "Government"},
+ {"name": "Health", "description": "Health"},
+ {"name": "Historic", "description": "Historic"},
+ {"name": "Holidays", "description": "Holidays"},
+ {"name": "Homes", "description": "Homes"},
+ {"name": "Industrial", "description": "Industrial"},
+ {"name": "International", "description": "International"},
+ {"name": "Landscape", "description": "Landscape"},
+ {"name": "Landscapes", "description": "Landscapes"},
+ {"name": "Leisure", "description": "Leisure"},
+ {"name": "Lifestyles", "description": "Lifestyles"},
+ {"name": "Logo", "description": "Logo"},
+ {"name": "Love Romance", "description": "Love Romance"},
+ {"name": "Manufacturing", "description": "Manufacturing"},
+ {"name": "Medical", "description": "Medical"},
+ {"name": "Meetings", "description": "Meetings"},
+ {"name": "Men", "description": "Men"},
+ {"name": "Military", "description": "Military"},
+ {"name": "Models", "description": "Models"},
+ {"name": "Money", "description": "Money"},
+ {"name": "Music", "description": "Music"},
+ {"name": "Nature", "description": "Nature"},
+ {"name": "Nautical", "description": "Nautical"},
+ {"name": "Newspaper", "description": "Newspaper"},
+ {"name": "Northern", "description": "Northern"},
+ {"name": "Nostalgia", "description": "Nostalgia"},
+ {"name": "Office", "description": "Office"},
+ {"name": "Other Images", "description": "Other Images"},
+ {"name": "Outdoors", "description": "Outdoors"},
+ {"name": "Patriotic", "description": "Patriotic"},
+ {"name": "Patterns", "description": "Patterns"},
+ {"name": "People", "description": "People"},
+ {"name": "Personality", "description": "Personality"},
+ {"name": "Pets", "description": "Pets"},
+ {"name": "Photo Essay", "description": "Photo Essay"},
+ {"name": "Political", "description": "Political"},
+ {"name": "Portrait", "description": "Portrait"},
+ {"name": "Recreation", "description": "Recreation"},
+ {"name": "Religion", "description": "Religion"},
+ {"name": "Science", "description": "Science"},
+ {"name": "Shopping", "description": "Shopping"},
+ {"name": "Signs", "description": "Signs"},
+ {"name": "Space", "description": "Space"},
+ {"name": "Sports", "description": "Sports"},
+ {"name": "Still Life", "description": "Still Life"},
+ {"name": "Symbols", "description": "Symbols"},
+ {"name": "Teamwork", "description": "Teamwork"},
+ {"name": "Technology", "description": "Technology"},
+ {"name": "Tourism", "description": "Tourism"},
+ {"name": "Traditional", "description": "Traditional"},
+ {"name": "Trains", "description": "Trains"},
+ {"name": "Transportation", "description": "Transportation"},
+ {"name": "Travel", "description": "Travel"},
+ {"name": "Underwater", "description": "Underwater"},
+ {"name": "Vintage", "description": "Vintage"},
+ {"name": "Weather", "description": "Weather"},
+ {"name": "Weird Animals", "description": "Weird Animals"},
+ {"name": "Wildlife", "description": "Wildlife"},
+ {"name": "Women", "description": "Women"},
+ {"name": "Workplace", "description": "Workplace"}
+ ],
+
+ "Video": [
+ {"name": "Action", "description": "Action"},
+ {"name": "Adventure", "description": "Adventure"},
+ {"name": "Amateur", "description": "Amateur"},
+ {"name": "Animation", "description": "Animation"},
+ {"name": "Aviation", "description": "Aviation"},
+ {"name": "Biography", "description": "Biography"},
+ {"name": "Chick Flicks", "description": "Chick Flicks"},
+ {"name": "Christmas Video", "description": "Christmas Video"},
+ {"name": "Classic Hollywood", "description": "Classic Hollywood"},
+ {"name": "Comedy Funny", "description": "Comedy Funny"},
+ {"name": "Crime", "description": "Crime"},
+ {"name": "Cult Movies", "description": "Cult Movies"},
+ {"name": "Detective Mystery", "description": "Detective Mystery"},
+ {"name": "Disaster Films", "description": "Disaster Films"},
+ {"name": "Documentary", "description": "Documentary"},
+ {"name": "Drama", "description": "Drama"},
+ {"name": "Experimental", "description": "Experimental"},
+ {"name": "Family", "description": "Family"},
+ {"name": "Fantasy", "description": "Fantasy"},
+ {"name": "History", "description": "History"},
+ {"name": "Horror", "description": "Horror"},
+ {"name": "Mockumentary", "description": "Mockumentary"},
+ {"name": "Music Concerts", "description": "Music Concerts"},
+ {"name": "Musical", "description": "Musical"},
+ {"name": "News", "description": "News"},
+ {"name": "Northern", "description": "Northern"},
+ {"name": "Organized Crime", "description": "Organized Crime"},
+ {"name": "Other Video", "description": "Other Video"},
+ {"name": "Road Films", "description": "Road Films"},
+ {"name": "Satire", "description": "Satire"},
+ {"name": "SciFi", "description": "SciFi"},
+ {"name": "Short", "description": "Short"},
+ {"name": "Silent Movies", "description": "Silent Movies"},
+ {"name": "Sport", "description": "Sport"},
+ {"name": "Supernatural", "description": "Supernatural"},
+ {"name": "Thrillers Suspense", "description": "Thrillers Suspense"},
+ {"name": "Trailers", "description": "Trailers"},
+ {"name": "War", "description": "War"},
+ {"name": "Western", "description": "Western"}
+ ],
+
+ "SFX": [
+ {"name": "Animal Sounds", "description": "Animal Sounds"},
+ {"name": "Beatle Bits", "description": "Beatle Bits"},
+ {"name": "Christmas", "description": "Christmas"},
+ {"name": "Halloween", "description": "Halloween"},
+ {"name": "Machine Recordings", "description": "Machine Recordings"},
+ {"name": "Movie Bits", "description": "Movie Bits"},
+ {"name": "Star Trek", "description": "Star Trek"},
+ {"name": "TTS", "description": "Text to Speech"}
+ ],
+
+ "PSA Audio": [
+ {"name": "Disabled", "description": "Disabled"},
+ {"name": "Enabled", "description": "Enabled"},
+ {"name": "PSA Audio Regular", "description": "PSA Audio Regular"}
+ ]
+}
diff --git a/modules/SampleData/profiles/en_community_radio/groups.json b/modules/SampleData/profiles/en_community_radio/groups.json
new file mode 100644
index 00000000..8e47f8c9
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/groups.json
@@ -0,0 +1,22 @@
+[
+ {
+ "name": "Basic",
+ "permissions": [
+ "create_own_media",
+ "create_own_playlists"
+ ]
+ },
+ {
+ "name": "Manager",
+ "permissions": [
+ "create_own_media",
+ "approve_own_media",
+ "manage_media",
+ "create_own_playlists",
+ "manage_playlists",
+ "manage_timeslots",
+ "view_player_monitor",
+ "download_media"
+ ]
+ }
+]
diff --git a/modules/SampleData/profiles/en_community_radio/manifest.json b/modules/SampleData/profiles/en_community_radio/manifest.json
new file mode 100644
index 00000000..d0f0e1f0
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/manifest.json
@@ -0,0 +1,8 @@
+{
+ "name": "English Community Radio Station",
+ "description": "Sample data profile for an English-language community radio station. Populates categories, genres, users, permission groups, settings, custom metadata fields, playlists, and a sample schedule.",
+ "version": "1.0.0",
+ "author": "OpenBroadcaster",
+ "locale": "en",
+ "created": "2026-04-01"
+}
diff --git a/modules/SampleData/profiles/en_community_radio/metadata_fields.json b/modules/SampleData/profiles/en_community_radio/metadata_fields.json
new file mode 100644
index 00000000..1111a450
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/metadata_fields.json
@@ -0,0 +1,38 @@
+[
+ {
+ "name": "internal_memo",
+ "description": "Internal Memo (Private)",
+ "type": "textarea",
+ "visibility": "visible",
+ "mode": "optional",
+ "default": "",
+ "id3_key": ""
+ },
+ {
+ "name": "physical_tags",
+ "description": "Physical Tags",
+ "type": "tags",
+ "visibility": "public",
+ "mode": "optional",
+ "default": "",
+ "id3_key": "",
+ "tag_suggestions": [
+ "CD",
+ "Vinyl",
+ "Cassette",
+ "Digital",
+ "Donated",
+ "Library"
+ ]
+ },
+ {
+ "name": "day_parting",
+ "description": "Day Parting Tags",
+ "type": "select",
+ "visibility": "public",
+ "mode": "optional",
+ "default": "Anytime",
+ "id3_key": "",
+ "select_options": "Morning\nMidday\nAfternoon\nEvening\nOvernight\nAnytime"
+ }
+]
diff --git a/modules/SampleData/profiles/en_community_radio/playlists.json b/modules/SampleData/profiles/en_community_radio/playlists.json
new file mode 100644
index 00000000..2d3be17f
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/playlists.json
@@ -0,0 +1,26 @@
+[
+ {
+ "name": "Default Playlist",
+ "description": "Default playlist for the station. Add your most-played content here.",
+ "type": "standard",
+ "status": "public"
+ },
+ {
+ "name": "Sample Music Mix",
+ "description": "A sample music playlist. Replace with your own music selections.",
+ "type": "standard",
+ "status": "public"
+ },
+ {
+ "name": "Station IDs",
+ "description": "Station identification audio clips for broadcast compliance.",
+ "type": "standard",
+ "status": "public"
+ },
+ {
+ "name": "Live Assist Board",
+ "description": "Live assist playlist with quick-access buttons for on-air use.",
+ "type": "live_assist",
+ "status": "public"
+ }
+]
diff --git a/modules/SampleData/profiles/en_community_radio/schedule.json b/modules/SampleData/profiles/en_community_radio/schedule.json
new file mode 100644
index 00000000..8057b15d
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/schedule.json
@@ -0,0 +1,76 @@
+{
+ "player": {
+ "name": "Sample Player",
+ "timezone": "America/Toronto",
+ "support_audio": true,
+ "support_video": true,
+ "support_images": true
+ },
+
+ "shows": [
+ {
+ "title": "Morning Melodies",
+ "description": "Kickstart your day with the best mix of classic and contemporary tunes.",
+ "start_time": "06:00",
+ "duration": 120,
+ "mode": "daily",
+ "recurring_days": 180
+ },
+ {
+ "title": "News Hour",
+ "description": "Stay informed with the latest local, national, and international news stories.",
+ "start_time": "08:00",
+ "duration": 60,
+ "mode": "daily",
+ "recurring_days": 180
+ },
+ {
+ "title": "Community Spotlight",
+ "description": "Highlighting local events, organizations, and people making a difference.",
+ "start_time": "09:00",
+ "duration": 120,
+ "mode": "daily",
+ "recurring_days": 180
+ },
+ {
+ "title": "Lunchtime Jazz",
+ "description": "Enjoy a selection of smooth jazz tracks during your lunch break.",
+ "start_time": "11:00",
+ "duration": 60,
+ "mode": "daily",
+ "recurring_days": 180
+ },
+ {
+ "title": "Indie Hour",
+ "description": "Discover emerging indie artists and bands from around the world.",
+ "start_time": "12:00",
+ "duration": 60,
+ "mode": "daily",
+ "recurring_days": 180
+ },
+ {
+ "title": "Drive Time",
+ "description": "Get the latest traffic updates and upbeat tunes for your drive home.",
+ "start_time": "15:00",
+ "duration": 180,
+ "mode": "daily",
+ "recurring_days": 180
+ },
+ {
+ "title": "Evening Chill",
+ "description": "Wind down with a mix of calming tracks and ambient sounds.",
+ "start_time": "18:00",
+ "duration": 120,
+ "mode": "daily",
+ "recurring_days": 180
+ },
+ {
+ "title": "Late Night Talk",
+ "description": "Join the conversation on various topics with expert guests and callers.",
+ "start_time": "20:00",
+ "duration": 240,
+ "mode": "daily",
+ "recurring_days": 180
+ }
+ ]
+}
diff --git a/modules/SampleData/profiles/en_community_radio/settings.json b/modules/SampleData/profiles/en_community_radio/settings.json
new file mode 100644
index 00000000..1bb2615e
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/settings.json
@@ -0,0 +1,13 @@
+{
+ "settings": {
+ "audio_formats": "flac,mp3,ogg,wav",
+ "video_formats": "avi,mpg,ogg",
+ "image_formats": "jpg,png",
+ "document_formats": "pdf",
+ "core_metadata": "{\"artist\":\"required\",\"album\":\"required\",\"year\":\"required\",\"category_id\":\"required\",\"country_id\":\"enabled\",\"language_id\":\"enabled\",\"comments\":\"enabled\"}"
+ },
+
+ "client_login_message": "Welcome to your Community Radio Station powered by OpenBroadcaster. Please log in to manage your station content, playlists, and schedules.",
+
+ "client_welcome_page": "Welcome to OpenBroadcaster Your community radio station is ready to go! Here are some things you can do:
Upload Media — Add music, audio, images, and video to your libraryCreate Playlists — Organize your media into playlists for broadcastSchedule Shows — Set up your broadcast schedule on the Player ManagerManage Users — Add team members and assign permissionsThis station has been pre-configured with sample categories, genres, and playlists to help you get started. Feel free to modify or remove them as needed.
Need help? Visit openbroadcaster.com for documentation and support.
"
+}
diff --git a/modules/SampleData/profiles/en_community_radio/users.json b/modules/SampleData/profiles/en_community_radio/users.json
new file mode 100644
index 00000000..0df12eb0
--- /dev/null
+++ b/modules/SampleData/profiles/en_community_radio/users.json
@@ -0,0 +1,30 @@
+[
+ {
+ "name": "Admin",
+ "username": "admin",
+ "email": "admin@example.com",
+ "display_name": "Admin",
+ "password": "changeme",
+ "enabled": true,
+ "group": "Administrator",
+ "skip_if_exists": true
+ },
+ {
+ "name": "Basic User",
+ "username": "basic_user",
+ "email": "basic@example.com",
+ "display_name": "Basic User",
+ "password": "changeme",
+ "enabled": true,
+ "group": "Basic"
+ },
+ {
+ "name": "Manager",
+ "username": "manager",
+ "email": "manager@example.com",
+ "display_name": "Manager",
+ "password": "changeme",
+ "enabled": true,
+ "group": "Manager"
+ }
+]