NR_DJ
A feature-rich DJ booth script that integrates with xSound to play YouTube music at configurable locations with job/gang restrictions, volume control, and playback history.
Features
- Multiple booth locations - Configure unlimited DJ booth locations across the map
- Job & gang restrictions - Limit booth access to specific jobs, gangs, or make them public
- YouTube integration - Play any YouTube video's audio via xSound
- Volume control - Adjustable volume with slider interface (1-100%)
- Playback controls - Play, pause, resume, and stop functionality
- Song history - Access previously played songs for quick replay
- 3D positional audio - Sound originates from booth location with configurable radius
- Real-time progress - Shows current timestamp and total duration
- Live stream support - Detects and displays live streams appropriately
- Optional props - Spawn visual DJ equipment props at booth locations
- ox_target integration - Clean third-eye interaction system
- Network synced - All players hear the same music simultaneously
- Debug mode - Visual markers and console logging for development
Dependencies
| Resource | Description | Required |
|---|---|---|
| qbx_core or qb-core | Core framework | Yes |
| ox_lib | UI library (context menus, input dialogs, notifications) | Yes |
| ox_target | Interaction system | Yes |
| xsound | 3D sound system for YouTube audio | Yes |
Installation
Step 1: Download
Download NR_DJ from your Tebex purchase and extract it to your resources folder:
server/
└── resources/
└── [nightrider]/
└── NR_DJ/
Step 2: server.cfg
Add the resource to your server configuration. xsound must start before NR_DJ:
ensure xsound
ensure ox_lib
ensure ox_target
ensure qbx_core
ensure NR_DJ
Step 3: Configuration
Edit config.lua to add your DJ booth locations. Configure job/gang restrictions, audio ranges, and default volumes as needed.
Step 4: Restart
Restart your server to load the resource.
xsound must be started before NR_DJ in your server.cfg. Without xsound, no audio will play.
How It Works
1. Approaching a Booth
Player walks up to a configured DJ booth location. ox_target shows a "DJ Booth" interaction option. The option only appears if the player has the required job/gang (if configured).
2. Opening the Menu
Player uses third eye (ox_target) to interact. A context menu opens showing current song status with the song title, timestamp, and playback status.
3. Playing a Song
Select "Play Song" from the menu. An input dialog prompts for a YouTube URL — full URL, short URL, or just the video ID. The song starts playing for all players in range.
4. Song History
"History" option shows previously played songs. Click any song to replay it instantly. History persists for the resource session.
5. Playback Controls
- Pause/Resume - Toggle playback
- Volume - Adjust from 1-100% using slider
- Stop - Completely stop and clear current song
6. Audio Experience
Music plays in 3D space from the booth's soundLoc position. Volume fades based on distance, and players beyond the configured radius cannot hear the music.
Configuration
General Settings
Config.Debug = false -- Enable debug mode (visual markers, console logs)
Config.Language = 'en' -- Locale language
DJ Booth Location Structure
{
name = "Booth Name", -- Descriptive name
enableBooth = true, -- Enable/disable this location
-- Access Control
job = "public", -- "public", specific job, or table of jobs
gang = nil, -- nil, specific gang, or table of gangs
-- Location Settings
coords = vec3(x, y, z), -- Interaction point (ox_target zone)
soundLoc = vec3(x, y, z), -- Where sound originates from
-- Audio Settings
DefaultVolume = 0.15, -- Starting volume (0.0 - 1.0)
radius = 60, -- Hearing distance in GTA units
-- Optional Prop
prop = {
model = "prop_dj_deck_01",
coords = vec4(x, y, z, heading)
},
}
Example: Public Booth
{
name = "Nightclub",
enableBooth = true,
job = "public",
gang = nil,
coords = vec3(119.52, -1299.95, 29.22),
soundLoc = vec3(119.52, -1299.95, 29.22),
DefaultVolume = 0.15,
radius = 60,
prop = {
model = "prop_dj_deck_01",
coords = vec4(119.52, -1299.95, 29.22, 180.0)
},
}
Example: Job-Locked Booth
{
name = "Police Station",
enableBooth = true,
job = "police",
gang = nil,
coords = vec3(441.0, -982.0, 30.68),
soundLoc = vec3(441.0, -982.0, 30.68),
DefaultVolume = 0.10,
radius = 40,
prop = nil,
}
Example: Gang-Locked Booth
{
name = "Gang Hideout",
enableBooth = true,
job = nil,
gang = "ballas",
coords = vec3(100.0, -1900.0, 21.0),
soundLoc = vec3(100.0, -1900.0, 21.0),
DefaultVolume = 0.20,
radius = 50,
prop = nil,
}
Example: Multiple Jobs Allowed
{
name = "Staff Room",
enableBooth = true,
job = {"police", "ambulance", "mechanic"},
gang = nil,
coords = vec3(300.0, -580.0, 43.26),
soundLoc = vec3(300.0, -580.0, 43.26),
DefaultVolume = 0.12,
radius = 35,
prop = nil,
}
Booth Identification System
Each booth is identified by: (job or gang) + zoneNum
| Example | Identifier |
|---|---|
| Public booth #1 | public1 |
| Police booth #3 | police3 |
| Ballas booth #2 | ballas2 |
This allows multiple booths with different access levels. Song history is stored per booth identifier and persists until resource restart.
Audio Settings
Volume System
| Config Value | Menu Display | xSound Value |
|---|---|---|
DefaultVolume = 0.15 |
15% | 0.15 |
DefaultVolume = 0.50 |
50% | 0.50 |
Recommended Volume Levels
| Venue Type | Volume Range |
|---|---|
| Nightclubs | 0.15 - 0.25 |
| Bars | 0.10 - 0.15 |
| Outdoor events | 0.20 - 0.30 |
| Background music | 0.05 - 0.10 |
Radius & Distance
| Venue Size | Radius |
|---|---|
| Small room | 25 |
| Medium venue | 50 |
| Large outdoor area | 100 |
| Entire block | 150 |
Sound Location vs Interaction Point
coords = vec3(x, y, z) -- Where player clicks (ox_target zone)
soundLoc = vec3(x, y, z) -- Where audio emanates from
Usually these are the same, but you can offset soundLoc for better audio positioning (e.g., center of dance floor vs booth location).
YouTube URL Formats
The following formats are supported:
-- Full URL
https://www.youtube.com/watch?v=dQw4w9WgXcQ
-- Short URL
https://youtu.be/dQw4w9WgXcQ
-- Video ID only
dQw4w9WgXcQ
The script auto-corrects partial URLs by prepending https://www.youtube.com/watch?v=. Live streams are automatically detected — they show "LIVE" instead of a timestamp.
Props & Visual Elements
DJ Equipment Props
| Prop | Description |
|---|---|
prop_dj_deck_01 |
Standard DJ deck |
prop_speaker_01 |
Large speaker |
prop_speaker_02 |
Small speaker |
prop_speaker_03 |
Floor speaker |
prop_studio_light_01 |
Stage light |
Set prop = nil to disable props for a booth. Props are purely cosmetic.
Localization
The script supports full localization. Edit Config.Locale in config.lua:
Config.Locale = {
['en'] = {
target = {
dj_booth = "DJ Booth",
},
menu = {
play = "Play Song",
youtube_url = "Enter YouTube URL",
history = "Song History",
no_song = "No Song Playing",
cur_playing = "Currently Playing",
cur_paused = "Currently Paused",
},
notify = {
load_link = "Loading song: ",
new_volume = "Volume set to: ",
},
}
}
Add new languages by copying the ['en'] block and translating strings.
Advanced Features
Dynamic Booth Creation
Add booths at runtime using the export:
exports['NR_DJ']:AddLocation({
name = "New Venue",
enableBooth = true,
job = "public",
gang = nil,
coords = vec3(100.0, 200.0, 30.0),
soundLoc = vec3(100.0, 200.0, 30.0),
DefaultVolume = 0.15,
radius = 50,
prop = nil,
})
This broadcasts to all clients and creates the booth immediately.
Song Timestamp Display
🔊 (02:45/04:30) -- Playing
🔇 (02:45/04:30) -- Paused
LIVE -- Live stream
YouTube Thumbnails
The menu automatically shows video thumbnails extracted from the YouTube URL.
Performance
| Metric | Value |
|---|---|
| Resmon impact | ~0.00ms (idle), ~0.01ms (menu open) |
| Network traffic | Minimal (event-based synchronization) |
| Memory usage | ~1.2 MB |
| xSound load | Depends on active songs (handled by xSound) |
| Threads | 1 (debug markers if enabled) |
Troubleshooting
No sound playing
- Verify xsound is started before NR_DJ
- Check YouTube URL is valid
- Ensure player is within booth radius
- Check if video is region-locked or age-restricted
ox_target not showing
- Verify player has required job/gang
- Check if
enableBooth = true - Confirm coords are correct
- Ensure ox_target is running
Menu not opening
- Check ox_lib is loaded
- Verify
QBX.PlayerDataexists - Check client console for errors
Volume not working
- Ensure xsound is functioning
- Try stopping and restarting the song
- Check if value is between 0.01-1.0
Props not spawning
- Verify prop model name is correct
- Check if coords include heading (vec4)
- Use
/coordsto verify prop placement
History not saving
- History clears on resource restart
- Each booth has separate history
- Only stores songs played during session
Multiple booths interfering
- Each booth has a unique identifier
- Ensure job or gang differs between nearby booths
- Check booth numbers are sequential
Best Practices
- Place
soundLocat the center of the desired audio coverage - Use larger radius for outdoor areas, smaller for indoor venues
- Use
"public"for general entertainment venues - Job-lock for faction-specific locations, gang-lock for territory RP
- Test audio range with
Config.Debug = true - Props are purely cosmetic — consider performance with many props
Support
For paid script support, open a ticket in our Discord server for priority assistance.