[{"data":1,"prerenderedAt":1411},["ShallowReactive",2],{"/docs/scripts/sky-dj/setup/installation":3,"/docs/scripts/sky-dj/setup/installation-surround":1403,"/docs/scripts/sky-dj/setup/installation-implemented-suggestions":1410},{"id":4,"title":5,"body":6,"description":1394,"extension":1395,"head":1396,"implementedSuggestions":1396,"meta":1397,"navigation":202,"path":1398,"schemaOrg":1396,"seo":1399,"sitemap":1400,"stem":1401,"__hash__":1402},"docs/1.docs/scripts/7.sky-dj/2.setup/1.installation.md","Installation",{"type":7,"value":8,"toc":1382},"minimark",[9,14,87,103,106,110,341,345,348,383,394,452,478,491,495,506,509,520,540,544,558,672,698,717,721,724,732,739,784,798,805,854,857,874,895,932,941,945,961,974,977,993,1018,1021,1082,1106,1110,1120,1182,1199,1208,1263,1266,1273,1335,1344,1347,1351,1354,1364,1378],[10,11,13],"h2",{"id":12},"requirements","Requirements",[15,16,17,30],"table",{},[18,19,20],"thead",{},[21,22,23,27],"tr",{},[24,25,26],"th",{},"Requirement",[24,28,29],{},"Purpose",[31,32,33,42,55,65,76],"tbody",{},[21,34,35,39],{},[36,37,38],"td",{},"FiveM server with OneSync enabled",[36,40,41],{},"Shared club state, routing buckets and server-side position checks",[21,43,44,52],{},[36,45,46,47,51],{},"ESX with ",[48,49,50],"code",{},"RunStaticPlayerMethod"," support",[36,53,54],{},"Player access and framework integration",[21,56,57,62],{},[36,58,59],{},[48,60,61],{},"ox_lib",[36,63,64],{},"Callbacks and shared utilities",[21,66,67,73],{},[36,68,69,72],{},[48,70,71],{},"sky_base"," with a working database connection",[36,74,75],{},"Framework bridge, interactions and automatic SQL persistence",[21,77,78,84],{},[36,79,80,81],{},"Optional ",[48,82,83],{},"ox_target",[36,85,86],{},"Target interaction when selected in Sky Base",[88,89,90,91,94,95,98,99,102],"p",{},"Use the database provider already configured for Sky Base, such as ",[48,92,93],{},"oxmysql"," or ",[48,96,97],{},"mysql-async",". Sky DJ includes its audio engine; a separate sound resource and ",[48,100,101],{},"sky_jobs_base"," are not required.",[88,104,105],{},"The standard resource installation does not require external Node.js, Python or FFmpeg. The published package already contains the frontend. Separate Windows and Linux instructions below apply only to preparing and serving the optional FFmpeg/Opus music export.",[10,107,109],{"id":108},"install-the-resource","Install the resource",[111,112,114,119,145,152,169,173,179,234,249,256,260,278,295,315,319,329,338],"steps",{"level":113},"3",[115,116,118],"h3",{"id":117},"copy-the-complete-resource","Copy the complete resource",[88,120,121,122,125,126,132,133,136,137,140,141,144],{},"Extract the release package and copy its ",[48,123,124],{},"resources/[sky]/sky_dj"," folder into your server's resources directory. Keep the resource name ",[127,128,129],"strong",{},[48,130,131],{},"sky_dj"," and retain its complete ",[48,134,135],{},"config",", ",[48,138,139],{},"source/html"," and ",[48,142,143],{},"stream"," folders.",[88,146,147,148,151],{},"The resulting resource path is ",[48,149,150],{},"resources/[sky]/sky_dj/fxmanifest.lua",".",[88,153,154,155,158,159,161,162,164,165,168],{},"Your installation must contain ",[48,156,157],{},"fxmanifest.lua"," directly inside ",[48,160,131],{},", without an extra nested ",[48,163,131],{}," directory. Keep the package-root documentation and ",[48,166,167],{},"prepare-music-stream.cjs"," separately; they are not resources to start.",[115,170,172],{"id":171},"configure-the-database-and-start-order","Configure the database and start order",[88,174,175,176,178],{},"Start your database provider and ESX before the Sky resources. The following example uses an existing ",[48,177,93],{}," installation; retain your own database connection settings and provider.",[180,181,187],"pre",{"className":182,"code":183,"filename":184,"language":185,"meta":186,"style":186},"language-cfg shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","set onesync on\n\nensure oxmysql\nensure es_extended\nensure ox_lib\nensure sky_base\nensure sky_dj\n","server.cfg","cfg","",[48,188,189,197,204,210,216,222,228],{"__ignoreMap":186},[190,191,194],"span",{"class":192,"line":193},"line",1,[190,195,196],{},"set onesync on\n",[190,198,200],{"class":192,"line":199},2,[190,201,203],{"emptyLinePlaceholder":202},true,"\n",[190,205,207],{"class":192,"line":206},3,[190,208,209],{},"ensure oxmysql\n",[190,211,213],{"class":192,"line":212},4,[190,214,215],{},"ensure es_extended\n",[190,217,219],{"class":192,"line":218},5,[190,220,221],{},"ensure ox_lib\n",[190,223,225],{"class":192,"line":224},6,[190,226,227],{},"ensure sky_base\n",[190,229,231],{"class":192,"line":230},7,[190,232,233],{},"ensure sky_dj\n",[88,235,236,237,140,244,151],{},"OneSync must be enabled before resource startup. See the official ",[238,239,243],"a",{"href":240,"rel":241},"https://docs.fivem.net/docs/server-manual/server-commands/#resource-commands",[242],"nofollow","FiveM resource commands",[238,245,248],{"href":246,"rel":247},"https://docs.fivem.net/docs/server-manual/server-commands/#onesync-onofflegacy",[242],"OneSync setting",[88,250,251,252,255],{},"Sky Base creates the ",[48,253,254],{},"sky_dj_state"," table and missing initial records automatically. The database account must be able to create or alter the resource's tables and read and write their data. No manual SQL import is required.",[115,257,259],{"id":258},"choose-who-owns-the-settings","Choose who owns the settings",[88,261,262,263,266,267,273,274,277],{},"The default ",[48,264,265],{},"Config.IngameSettings = true"," uses saved SQL settings. Open ",[127,268,269,272],{},[48,270,271],{},"/djadmin"," → Settings"," as an authorized administrator and save changes there. Other global values in ",[48,275,276],{},"config/config.lua"," do not override these settings, including on first startup.",[88,279,280,281,284,285,288,289,291,292,294],{},"To configure global settings through files, change the existing ",[48,282,283],{},"IngameSettings"," entry to ",[48,286,287],{},"false",", edit ",[48,290,276],{},", and restart ",[48,293,131],{},". This disables global settings writes in-game while retaining the saved SQL settings. Club layouts, placed devices and playlists remain in SQL in either mode.",[88,296,297,298,301,302,305,306,309,310,314],{},"Administrator access defaults to ESX ",[48,299,300],{},"admin"," / ",[48,303,304],{},"superadmin"," or ACE ",[48,307,308],{},"sky.dj.admin",". See ",[238,311,313],{"href":312},"/docs/scripts/sky-dj/setup/configuration","Configuration"," for permissions, language and the configuration ownership rules.",[115,316,318],{"id":317},"add-music-and-verify-startup","Add music and verify startup",[88,320,321,322,325,326,328],{},"Add your own MP3 files to ",[48,323,324],{},"sky_dj/config/music/",", then restart ",[48,327,131],{},". The customer package does not include a music library.",[88,330,331,332,337],{},"Open ",[127,333,334,336],{},[48,335,271],{}," → Settings → Music & Playlists",", create a playlist and add tracks. Assign that playlist to a club and save the club. At its DJ booth, load an assigned track into deck A or B and test playback.",[88,339,340],{},"The fixed festival is configured separately from your own clubs. For a new custom club, place its DJ booth and at least one speaker before saving. Music synchronization is optional and starts disabled; ordinary playback does not require it.",[10,342,344],{"id":343},"standard-mp3-delivery","Standard MP3 delivery",[88,346,347],{},"In the default mode, FiveM downloads the MP3s published in the owning resource's manifest when players connect. No external webserver is required.",[349,350,351,359,374,377,380],"ul",{},[352,353,354,355,358],"li",{},"Use at most ",[127,356,357],{},"500 MP3 files"," in the selected directory. Subfolders are not scanned.",[352,360,361,362,365,366,369,370,373],{},"Keep each file below ",[127,363,364],{},"50 MiB",". Names may contain ASCII letters, numbers, spaces, underscores, hyphens and periods, must start with a letter, number, underscore or hyphen, and must end in lowercase ",[48,367,368],{},".mp3",". Maximum length is 160 characters; ",[48,371,372],{},".."," is rejected.",[352,375,376],{},"Keep paths and filename capitalization consistent, especially on Linux. Folder paths use forward slashes.",[352,378,379],{},"Upload files through your server's file manager or SFTP. The in-game library does not upload audio files.",[352,381,382],{},"Restart the resource owning the music after adding or replacing files.",[88,384,385,386,389,390,393],{},"To keep music in a separate resource, create ",[48,387,388],{},"resources/[music]/sky_dj_music/music/"," and put this manifest beside its ",[48,391,392],{},"music"," folder:",[180,395,400],{"className":396,"code":397,"filename":398,"language":399,"meta":186,"style":186},"language-lua shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","fx_version 'cerulean'\ngame 'gta5'\nfiles { 'music/*.mp3' }\n","sky_dj_music/fxmanifest.lua — standard MP3 mode","lua",[48,401,402,419,431],{"__ignoreMap":186},[190,403,404,408,412,416],{"class":192,"line":193},[190,405,407],{"class":406},"s2Zo4","fx_version",[190,409,411],{"class":410},"sMK4o"," '",[190,413,415],{"class":414},"sfazB","cerulean",[190,417,418],{"class":410},"'\n",[190,420,421,424,426,429],{"class":192,"line":199},[190,422,423],{"class":406},"game",[190,425,411],{"class":410},[190,427,428],{"class":414},"gta5",[190,430,418],{"class":410},[190,432,433,436,440,443,446,449],{"class":192,"line":206},[190,434,435],{"class":406},"files",[190,437,439],{"class":438},"sTEyZ"," { ",[190,441,442],{"class":410},"'",[190,444,445],{"class":414},"music/*.mp3",[190,447,448],{"class":410},"' ",[190,450,451],{"class":438},"}\n",[88,453,454,455,458,459,461,462,465,466,469,470,473,474,477],{},"Start ",[48,456,457],{},"sky_dj_music"," before ",[48,460,131],{},", then set ",[127,463,464],{},"Music folder"," to ",[48,467,468],{},"@sky_dj_music/music"," under ",[127,471,472],{},"Settings → Music & Playlists → Library & Queues",". In file mode, use ",[48,475,476],{},"Config.MusicDirectory = '@sky_dj_music/music'"," instead.",[88,479,480,481,484,485,487,488,490],{},"This MP3 resource must not be ",[48,482,483],{},"server_only",". A custom folder inside ",[48,486,131],{}," also needs a matching manifest ",[48,489,435],{}," entry. Absolute Windows/Linux paths and symlinked folders are not supported as runtime music sources.",[10,492,494],{"id":493},"optional-https-opus-delivery","Optional HTTPS Opus delivery",[496,497,500],"callout",{"color":498,"icon":499},"warning","i-lucide-triangle-alert",[88,501,502,505],{},[127,503,504],{},"Advanced setup: only continue if you know what you are doing."," You must understand HTTPS certificates, webserver file access, CORS and client-download exclusions. Incorrect configuration can stop music playback or expose files you did not intend to publish. If you are unsure, keep standard MP3 delivery until someone experienced can configure and verify the streaming host.",[88,507,508],{},"This mode keeps the files on your server but delivers audio through a separate HTTPS webserver. Players request a track when it is loaded or buffered, rather than downloading the selected library through the FiveM connection packfile. Normal browser buffering and caching still apply.",[88,510,511,512,519],{},"The flow is ",[127,513,514,515,518],{},"original MP3 → offline FFmpeg export → private server catalogue + HTTPS ",[48,516,517],{},".opus"," files",". FXServer does not launch FFmpeg or the external Node.js executable for playback. You can prepare the export on another computer and copy the complete result to the server.",[496,521,522],{"color":498,"icon":499},[88,523,524,525,136,527,136,530,94,533,535,536,539],{},"Converting the files or switching on HTTPS does not remove existing client downloads. Back up your original MP3s, then remove or move their client-published copies. Do not include the export in any client ",[48,526,435],{},[48,528,529],{},"client_script",[48,531,532],{},"shared_script",[48,534,143],{}," entries. MP3s left in ",[48,537,538],{},"config/music/*.mp3",", or published by another resource, still download on connection.",[115,541,543],{"id":542},"_1-install-the-preparation-tools","1. Install the preparation tools",[88,545,546,547,140,552,557],{},"Use a supported ",[238,548,551],{"href":549,"rel":550},"https://nodejs.org/en/download",[242],"Node.js LTS release",[238,553,556],{"href":554,"rel":555},"https://ffmpeg.org/ffmpeg-codecs.html#libopus",[242],"FFmpeg with its libopus encoder",". No npm packages are needed.",[559,560,561,598],"code-group",{},[180,562,567],{"className":563,"code":564,"filename":565,"language":566,"meta":186,"style":186},"language-powershell shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","winget install --id OpenJS.NodeJS.LTS --exact --source winget\nwinget install --id Gyan.FFmpeg --exact --source winget\n\n# Open a new PowerShell window after installation.\nnode --version\nffmpeg -hide_banner -encoders | Select-String 'libopus'\n","Windows — PowerShell","powershell",[48,568,569,574,579,583,588,593],{"__ignoreMap":186},[190,570,571],{"class":192,"line":193},[190,572,573],{},"winget install --id OpenJS.NodeJS.LTS --exact --source winget\n",[190,575,576],{"class":192,"line":199},[190,577,578],{},"winget install --id Gyan.FFmpeg --exact --source winget\n",[190,580,581],{"class":192,"line":206},[190,582,203],{"emptyLinePlaceholder":202},[190,584,585],{"class":192,"line":212},[190,586,587],{},"# Open a new PowerShell window after installation.\n",[190,589,590],{"class":192,"line":218},[190,591,592],{},"node --version\n",[190,594,595],{"class":192,"line":224},[190,596,597],{},"ffmpeg -hide_banner -encoders | Select-String 'libopus'\n",[180,599,604],{"className":600,"code":601,"filename":602,"language":603,"meta":186,"style":186},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# Install a supported Node.js LTS release using the Node.js download instructions.\nsudo apt update\nsudo apt install ffmpeg\n\nnode --version\nffmpeg -hide_banner -encoders | grep 'libopus'\n","Ubuntu / Debian","bash",[48,605,606,612,624,636,640,648],{"__ignoreMap":186},[190,607,608],{"class":192,"line":193},[190,609,611],{"class":610},"sHwdD","# Install a supported Node.js LTS release using the Node.js download instructions.\n",[190,613,614,618,621],{"class":192,"line":199},[190,615,617],{"class":616},"sBMFI","sudo",[190,619,620],{"class":414}," apt",[190,622,623],{"class":414}," update\n",[190,625,626,628,630,633],{"class":192,"line":206},[190,627,617],{"class":616},[190,629,620],{"class":414},[190,631,632],{"class":414}," install",[190,634,635],{"class":414}," ffmpeg\n",[190,637,638],{"class":192,"line":212},[190,639,203],{"emptyLinePlaceholder":202},[190,641,642,645],{"class":192,"line":218},[190,643,644],{"class":616},"node",[190,646,647],{"class":414}," --version\n",[190,649,650,653,656,659,662,665,667,670],{"class":192,"line":224},[190,651,652],{"class":616},"ffmpeg",[190,654,655],{"class":414}," -hide_banner",[190,657,658],{"class":414}," -encoders",[190,660,661],{"class":410}," |",[190,663,664],{"class":616}," grep",[190,666,411],{"class":410},[190,668,669],{"class":414},"libopus",[190,671,418],{"class":410},[88,673,674,675,680,681,685,686,691,692,694,695,151],{},"The Windows commands use ",[238,676,679],{"href":677,"rel":678},"https://learn.microsoft.com/en-us/windows/package-manager/winget/install",[242],"WinGet's exact package selection",". If WinGet is unavailable on your Windows installation, use the ",[238,682,684],{"href":549,"rel":683},[242],"Node.js installer"," and a Windows build linked from the ",[238,687,690],{"href":688,"rel":689},"https://ffmpeg.org/download.html",[242],"FFmpeg download page",", then make ",[48,693,652],{}," available on ",[48,696,697],{},"PATH",[88,699,700,701,704,705,707,708,710,711,713,714,151],{},"On Windows, the preparation tool also detects an ordinary ",[48,702,703],{},"ffmpeg.exe"," beside ",[48,706,167],{},". On Linux, install ",[48,709,652],{}," on ",[48,712,697],{}," or pass its executable with ",[48,715,716],{},"--ffmpeg",[115,718,720],{"id":719},"_2-prepare-the-export","2. Prepare the export",[88,722,723],{},"For automatic paths, retain the extracted package layout:",[180,725,730],{"className":726,"code":728,"language":729,"meta":186},[727],"language-text","Sky-DJ-package/\n├── prepare-music-stream.cjs\n└── resources/\n    └── [sky]/\n        └── sky_dj/\n            ├── fxmanifest.lua\n            └── config/\n                └── music/\n","text",[48,731,728],{"__ignoreMap":186},[88,733,734,735,738],{},"Place the original MP3s in that ",[48,736,737],{},"config/music/"," directory and run the helper from the package root:",[559,740,741,756],{},[180,742,744],{"className":563,"code":743,"filename":565,"language":566,"meta":186,"style":186},"Set-Location -LiteralPath 'D:\\Sky-DJ-package'\nnode '.\\prepare-music-stream.cjs'\n",[48,745,746,751],{"__ignoreMap":186},[190,747,748],{"class":192,"line":193},[190,749,750],{},"Set-Location -LiteralPath 'D:\\Sky-DJ-package'\n",[190,752,753],{"class":192,"line":199},[190,754,755],{},"node '.\\prepare-music-stream.cjs'\n",[180,757,759],{"className":600,"code":758,"filename":602,"language":603,"meta":186,"style":186},"cd '/opt/sky-dj-package'\nnode './prepare-music-stream.cjs'\n",[48,760,761,773],{"__ignoreMap":186},[190,762,763,766,768,771],{"class":192,"line":193},[190,764,765],{"class":406},"cd",[190,767,411],{"class":410},[190,769,770],{"class":414},"/opt/sky-dj-package",[190,772,418],{"class":410},[190,774,775,777,779,782],{"class":192,"line":199},[190,776,644],{"class":616},[190,778,411],{"class":410},[190,780,781],{"class":414},"./prepare-music-stream.cjs",[190,783,418],{"class":410},[88,785,786,787,789,790,793,794,797],{},"The helper reads ",[48,788,737],{}," and creates ",[48,791,792],{},"config/music-stream/"," beside it. It writes 48 kHz stereo Ogg Opus at 128 kbit/s VBR, with SHA-256 filenames and a ",[48,795,796],{},"music-stream.json"," catalogue. The original MP3 filenames remain the playlist IDs. Original audio is not modified or deleted. The helper runs outside the resource and does not need to modify or decrypt its Lua core.",[88,799,800,801,804],{},"Automatic discovery supports this package layout and the development checkout's ",[48,802,803],{},"tools/"," location. It does not search arbitrary server directories. If you moved only the runtime resource, keep the original package for preparation or provide both paths explicitly:",[559,806,807,817],{},[180,808,811],{"className":563,"code":809,"filename":810,"language":566,"meta":186,"style":186},"node 'D:\\Sky-DJ-package\\prepare-music-stream.cjs' --input 'D:\\Music\\Originals' --output 'D:\\FXServer\\server-data\\resources\\[sky]\\sky_dj\\config\\music-stream'\n","Windows — custom paths",[48,812,813],{"__ignoreMap":186},[190,814,815],{"class":192,"line":193},[190,816,809],{},[180,818,821],{"className":600,"code":819,"filename":820,"language":603,"meta":186,"style":186},"node '/opt/sky-dj-package/prepare-music-stream.cjs' --input '/srv/music-originals' --output '/opt/fivem/server-data/resources/[sky]/sky_dj/config/music-stream'\n","Ubuntu / Debian — custom paths",[48,822,823],{"__ignoreMap":186},[190,824,825,827,829,832,834,837,839,842,844,847,849,852],{"class":192,"line":193},[190,826,644],{"class":616},[190,828,411],{"class":410},[190,830,831],{"class":414},"/opt/sky-dj-package/prepare-music-stream.cjs",[190,833,442],{"class":410},[190,835,836],{"class":414}," --input",[190,838,411],{"class":410},[190,840,841],{"class":414},"/srv/music-originals",[190,843,442],{"class":410},[190,845,846],{"class":414}," --output",[190,848,411],{"class":410},[190,850,851],{"class":414},"/opt/fivem/server-data/resources/[sky]/sky_dj/config/music-stream",[190,853,418],{"class":410},[88,855,856],{},"Input and output must be separate, non-nested directories without symlinks. A failed conversion leaves the previous catalogue active; unchanged sources reuse verified exports.",[88,858,859,860,863,864,866,867,869,870,873],{},"Copy ",[127,861,862],{},"the complete generated folder",", including ",[48,865,796],{}," and every referenced ",[48,868,517],{}," file, to the matching ",[48,871,872],{},"sky_dj/config/music-stream/"," on FXServer. If you prepared music in the live resource, move its original MP3 copies out of client-published locations after backing them up.",[88,875,876,877,879,880,883,884,887,888,891,892,894],{},"With ",[127,878,464],{}," left at ",[48,881,882],{},"config/music",", enabling HTTPS automatically selects ",[48,885,886],{},"config/music-stream",". A custom music-folder value remains an explicit override. For a separate streaming resource, place the complete export in ",[48,889,890],{},"sky_dj_music/music/",", use ",[48,893,468],{},", and replace the earlier MP3 manifest with:",[180,896,899],{"className":396,"code":897,"filename":898,"language":399,"meta":186,"style":186},"fx_version 'cerulean'\ngame 'gta5'\nserver_only 'yes'\n","sky_dj_music/fxmanifest.lua — HTTPS mode only",[48,900,901,911,921],{"__ignoreMap":186},[190,902,903,905,907,909],{"class":192,"line":193},[190,904,407],{"class":406},[190,906,411],{"class":410},[190,908,415],{"class":414},[190,910,418],{"class":410},[190,912,913,915,917,919],{"class":192,"line":199},[190,914,423],{"class":406},[190,916,411],{"class":410},[190,918,428],{"class":414},[190,920,418],{"class":410},[190,922,923,925,927,930],{"class":192,"line":206},[190,924,483],{"class":406},[190,926,411],{"class":410},[190,928,929],{"class":414},"yes",[190,931,418],{"class":410},[88,933,934,935,937,938,940],{},"Start this resource before ",[48,936,131],{},". Keep the complete catalogue on FXServer even when another machine hosts the public audio. Do not add client ",[48,939,435],{}," entries to this streaming-only resource.",[115,942,944],{"id":943},"_3-serve-the-files-with-caddy","3. Serve the files with Caddy",[88,946,947,948,951,952,955,956,151],{},"The following manual examples use a dedicated ",[48,949,950],{},"audio.example.com"," hostname on the same machine as FXServer. Point its public DNS records at that machine, make TCP ports ",[127,953,954],{},"80 and 443"," reachable, and use your real hostname. Caddy manages certificates for an eligible public hostname; see its ",[238,957,960],{"href":958,"rel":959},"https://caddyserver.com/docs/quick-starts/https",[242],"HTTPS prerequisites",[88,962,963,964,969,970,973],{},"Install Caddy using its ",[238,965,968],{"href":966,"rel":967},"https://caddyserver.com/docs/install",[242],"official Windows binary or Debian/Ubuntu package instructions",". For Debian/Ubuntu, follow the signed repository setup on that page; the official package installs the ",[48,971,972],{},"caddy"," systemd service. These examples do not install or configure Caddy automatically.",[88,975,976],{},"Use one of these hostname blocks in your Caddyfile. Replace the domain and export path. If you already host other sites, retain their existing configuration.",[559,978,979,986],{},[180,980,984],{"className":981,"code":982,"filename":983,"language":729,"meta":186},[727],"audio.example.com {\n    header {\n        Access-Control-Allow-Origin \"*\"\n        Access-Control-Allow-Methods \"GET, HEAD, OPTIONS\"\n        Access-Control-Allow-Headers \"Range\"\n        Access-Control-Expose-Headers \"Accept-Ranges, Content-Length, Content-Range\"\n    }\n    @preflight method OPTIONS\n    handle @preflight {\n        respond \"\" 204\n    }\n    @audio path /music/*.opus\n    handle @audio {\n        uri strip_prefix /music\n        root * \"D:/FXServer/server-data/resources/[sky]/sky_dj/config/music-stream\"\n        header Content-Type \"audio/ogg; codecs=opus\"\n        file_server\n    }\n    handle {\n        respond \"Not found\" 404\n    }\n    handle_errors {\n        header Access-Control-Allow-Origin \"*\"\n        respond \"{err.status_code}\" {err.status_code}\n    }\n}\n","Windows — C:/Caddy/Caddyfile",[48,985,982],{"__ignoreMap":186},[180,987,991],{"className":988,"code":989,"filename":990,"language":729,"meta":186},[727],"audio.example.com {\n    header {\n        Access-Control-Allow-Origin \"*\"\n        Access-Control-Allow-Methods \"GET, HEAD, OPTIONS\"\n        Access-Control-Allow-Headers \"Range\"\n        Access-Control-Expose-Headers \"Accept-Ranges, Content-Length, Content-Range\"\n    }\n    @preflight method OPTIONS\n    handle @preflight {\n        respond \"\" 204\n    }\n    @audio path /music/*.opus\n    handle @audio {\n        uri strip_prefix /music\n        root * \"/opt/fivem/server-data/resources/[sky]/sky_dj/config/music-stream\"\n        header Content-Type \"audio/ogg; codecs=opus\"\n        file_server\n    }\n    handle {\n        respond \"Not found\" 404\n    }\n    handle_errors {\n        header Access-Control-Allow-Origin \"*\"\n        respond \"{err.status_code}\" {err.status_code}\n    }\n}\n","Ubuntu / Debian — /etc/caddy/Caddyfile",[48,992,989],{"__ignoreMap":186},[88,994,995,996,998,999,1001,1002,136,1007,140,1012,1017],{},"The webserver account must be able to read the exported files and traverse their parent directories. The examples expose only matching ",[48,997,517],{}," URLs; ",[48,1000,796],{},", configuration files and directory browsing remain unavailable. See Caddy's ",[238,1003,1006],{"href":1004,"rel":1005},"https://caddyserver.com/docs/caddyfile/directives/file_server",[242],"file server",[238,1008,1011],{"href":1009,"rel":1010},"https://caddyserver.com/docs/caddyfile/directives/header",[242],"response headers",[238,1013,1016],{"href":1014,"rel":1015},"https://caddyserver.com/docs/caddyfile/directives/handle_errors",[242],"error handling"," references.",[88,1019,1020],{},"Validate the configuration, then run or reload Caddy:",[559,1022,1023,1038],{},[180,1024,1026],{"className":563,"code":1025,"filename":565,"language":566,"meta":186,"style":186},"& 'C:\\Caddy\\caddy.exe' validate --config 'C:\\Caddy\\Caddyfile' --adapter caddyfile\n& 'C:\\Caddy\\caddy.exe' run --config 'C:\\Caddy\\Caddyfile' --adapter caddyfile\n",[48,1027,1028,1033],{"__ignoreMap":186},[190,1029,1030],{"class":192,"line":193},[190,1031,1032],{},"& 'C:\\Caddy\\caddy.exe' validate --config 'C:\\Caddy\\Caddyfile' --adapter caddyfile\n",[190,1034,1035],{"class":192,"line":199},[190,1036,1037],{},"& 'C:\\Caddy\\caddy.exe' run --config 'C:\\Caddy\\Caddyfile' --adapter caddyfile\n",[180,1039,1041],{"className":600,"code":1040,"filename":602,"language":603,"meta":186,"style":186},"sudo caddy validate --config '/etc/caddy/Caddyfile' --adapter caddyfile\nsudo systemctl reload caddy\n",[48,1042,1043,1069],{"__ignoreMap":186},[190,1044,1045,1047,1050,1053,1056,1058,1061,1063,1066],{"class":192,"line":193},[190,1046,617],{"class":616},[190,1048,1049],{"class":414}," caddy",[190,1051,1052],{"class":414}," validate",[190,1054,1055],{"class":414}," --config",[190,1057,411],{"class":410},[190,1059,1060],{"class":414},"/etc/caddy/Caddyfile",[190,1062,442],{"class":410},[190,1064,1065],{"class":414}," --adapter",[190,1067,1068],{"class":414}," caddyfile\n",[190,1070,1071,1073,1076,1079],{"class":192,"line":199},[190,1072,617],{"class":616},[190,1074,1075],{"class":414}," systemctl",[190,1077,1078],{"class":414}," reload",[190,1080,1081],{"class":414}," caddy\n",[88,1083,1084,1085,1088,1089,1094,1095,1100,1101,151],{},"The Windows ",[48,1086,1087],{},"run"," command stays in the foreground for initial verification. For permanent hosting, install a ",[238,1090,1093],{"href":1091,"rel":1092},"https://caddyserver.com/docs/running#windows-service",[242],"Windows service using Caddy's service instructions","; a foreground terminal is not a service. On Linux, use the official package's ",[238,1096,1099],{"href":1097,"rel":1098},"https://caddyserver.com/docs/running#using-the-service",[242],"systemd service",". Command behavior is documented in the ",[238,1102,1105],{"href":1103,"rel":1104},"https://caddyserver.com/docs/command-line",[242],"Caddy CLI reference",[115,1107,1109],{"id":1108},"_4-verify-https-and-enable-streaming","4. Verify HTTPS and enable streaming",[88,1111,1112,1113,1115,1116,1119],{},"Choose an actual 64-character ",[48,1114,517],{}," filename from the export and replace ",[48,1117,1118],{},"YOUR_HASH"," below. Test from outside the server's local network:",[559,1121,1122,1131],{},[180,1123,1125],{"className":563,"code":1124,"filename":565,"language":566,"meta":186,"style":186},"curl.exe -sS -D - -o NUL -H 'Origin: https://cfx-nui-sky_dj' -H 'Range: bytes=0-1023' 'https://audio.example.com/music/YOUR_HASH.opus'\n",[48,1126,1127],{"__ignoreMap":186},[190,1128,1129],{"class":192,"line":193},[190,1130,1124],{},[180,1132,1134],{"className":600,"code":1133,"filename":602,"language":603,"meta":186,"style":186},"curl -sS -D - -o /dev/null -H 'Origin: https://cfx-nui-sky_dj' -H 'Range: bytes=0-1023' 'https://audio.example.com/music/YOUR_HASH.opus'\n",[48,1135,1136],{"__ignoreMap":186},[190,1137,1138,1141,1144,1147,1150,1153,1156,1159,1161,1164,1166,1168,1170,1173,1175,1177,1180],{"class":192,"line":193},[190,1139,1140],{"class":616},"curl",[190,1142,1143],{"class":414}," -sS",[190,1145,1146],{"class":414}," -D",[190,1148,1149],{"class":414}," -",[190,1151,1152],{"class":414}," -o",[190,1154,1155],{"class":414}," /dev/null",[190,1157,1158],{"class":414}," -H",[190,1160,411],{"class":410},[190,1162,1163],{"class":414},"Origin: https://cfx-nui-sky_dj",[190,1165,442],{"class":410},[190,1167,1158],{"class":414},[190,1169,411],{"class":410},[190,1171,1172],{"class":414},"Range: bytes=0-1023",[190,1174,442],{"class":410},[190,1176,411],{"class":410},[190,1178,1179],{"class":414},"https://audio.example.com/music/YOUR_HASH.opus",[190,1181,418],{"class":410},[88,1183,1184,1185,136,1188,136,1191,1194,1195,1198],{},"Expect a valid public TLS certificate, ",[48,1186,1187],{},"206 Partial Content",[48,1189,1190],{},"Content-Range",[48,1192,1193],{},"Accept-Ranges: bytes",", the Opus-compatible content type and ",[48,1196,1197],{},"Access-Control-Allow-Origin: *",". Keep CORS headers on partial and error responses. The endpoint must work without login, cookies or authentication. A track playing in an ordinary browser tab alone does not prove that cross-origin WebAudio and music analysis will work.",[88,1200,1201,1202,1207],{},"With the default SQL configuration, open ",[127,1203,1204,1206],{},[48,1205,271],{}," → Settings → Music & Playlists → Library & Queues",":",[15,1209,1210,1220],{},[18,1211,1212],{},[21,1213,1214,1217],{},[24,1215,1216],{},"Setting",[24,1218,1219],{},"Default-path setup",[31,1221,1222,1237,1249],{},[21,1223,1224,1228],{},[36,1225,1226],{},[127,1227,464],{},[36,1229,1230,1231,1233,1234,1236],{},"Leave ",[48,1232,882],{},"; HTTPS selects ",[48,1235,886],{}," automatically",[21,1238,1239,1244],{},[36,1240,1241],{},[127,1242,1243],{},"HTTPS music folder URL",[36,1245,1246],{},[48,1247,1248],{},"https://audio.example.com/music/",[21,1250,1251,1256],{},[36,1252,1253],{},[127,1254,1255],{},"HTTPS music streaming",[36,1257,1258,1259,1262],{},"Enable, confirm ",[127,1260,1261],{},"Are you sure?",", then save",[88,1264,1265],{},"Cancel or Escape leaves the switch disabled. A new enable also requires the acknowledgement on the server; an already saved enabled setup does not ask again on restart.",[88,1267,1268,1269,325,1271,1207],{},"For file-owned configuration, edit these existing entries in ",[48,1270,276],{},[48,1272,131],{},[180,1274,1277],{"className":396,"code":1275,"filename":1276,"language":399,"meta":186,"style":186},"IngameSettings = false,\nMusicDirectory = 'config/music',\nMusicStreamingEnabled = true,\nMusicStreamingBaseUrl = 'https://audio.example.com/music/',\n","config/config.lua — existing Config entries",[48,1278,1279,1293,1308,1320],{"__ignoreMap":186},[190,1280,1281,1284,1287,1290],{"class":192,"line":193},[190,1282,1283],{"class":438},"IngameSettings ",[190,1285,1286],{"class":410},"=",[190,1288,1289],{"class":410}," false",[190,1291,1292],{"class":438},",\n",[190,1294,1295,1298,1300,1302,1304,1306],{"class":192,"line":199},[190,1296,1297],{"class":438},"MusicDirectory ",[190,1299,1286],{"class":410},[190,1301,411],{"class":410},[190,1303,882],{"class":414},[190,1305,442],{"class":410},[190,1307,1292],{"class":438},[190,1309,1310,1313,1315,1318],{"class":192,"line":206},[190,1311,1312],{"class":438},"MusicStreamingEnabled ",[190,1314,1286],{"class":410},[190,1316,1317],{"class":410}," true",[190,1319,1292],{"class":438},[190,1321,1322,1325,1327,1329,1331,1333],{"class":192,"line":212},[190,1323,1324],{"class":438},"MusicStreamingBaseUrl ",[190,1326,1286],{"class":410},[190,1328,411],{"class":410},[190,1330,1248],{"class":414},[190,1332,442],{"class":410},[190,1334,1292],{"class":438},[88,1336,1337,1338,1340,1341,477],{},"The URL must be an HTTPS folder address without credentials, query parameters, fragments or traversal. The system appends the generated ",[48,1339,517],{}," filename. For a custom streaming resource, use ",[48,1342,1343],{},"MusicDirectory = '@sky_dj_music/music'",[88,1345,1346],{},"Restart the resource owning the export after publishing changes. Reload tracks already on the decks so they use the new delivery URL. Missing or invalid exports make the catalogue unavailable; the system does not silently fall back to a downloaded MP3 library. Keeping the original MP3 filename IDs preserves playlist entries and club assignments when switching delivery.",[10,1348,1350],{"id":1349},"final-check-and-updates","Final check and updates",[88,1352,1353],{},"Test playback, seeking, A/B transitions and music synchronization from two FiveM clients. In private HTTPS mode, verify that neither the exported audio nor published copies of the original MP3s remain in FiveM's connection download. Confirm saved settings and club assignments after restarting.",[88,1355,1356,1357,1360,1361,1363],{},"Before updating, back up ",[48,1358,1359],{},"config/",", your music/export folders and the ",[48,1362,254],{}," database table. Replace the complete published runtime together so Lua, NUI and streamed assets match. Keep a custom music resource separate from the runtime replacement. After a map update, fully exit and relaunch FiveM before checking streaming and collision.",[88,1365,1366,1367,140,1371,1373,1374,151],{},"Continue with ",[238,1368,1370],{"href":1369},"/docs/scripts/sky-dj/overview","Overview",[238,1372,313],{"href":312},". For missing tracks, connection downloads, playback or access errors, use ",[238,1375,1377],{"href":1376},"/docs/scripts/sky-dj/reference/troubleshooting","Troubleshooting",[1379,1380,1381],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":186,"searchDepth":193,"depth":199,"links":1383},[1384,1385,1386,1387,1393],{"id":12,"depth":199,"text":13},{"id":108,"depth":199,"text":109},{"id":343,"depth":199,"text":344},{"id":493,"depth":199,"text":494,"children":1388},[1389,1390,1391,1392],{"id":542,"depth":206,"text":543},{"id":719,"depth":206,"text":720},{"id":943,"depth":206,"text":944},{"id":1108,"depth":206,"text":1109},{"id":1349,"depth":199,"text":1350},"Install the resource, add your music library, and optionally prepare FFmpeg/Opus streaming with Windows or Linux instructions.","md",null,{},"/docs/scripts/sky-dj/setup/installation",{"title":5,"description":1394},{"loc":1398},"1.docs/scripts/7.sky-dj/2.setup/1.installation","HPBDbtNtdvoksVYBUajgKDiUzNac9KsYOnfVU9yW1xw",[1404,1407],{"title":1370,"path":1369,"stem":1405,"description":1406,"children":-1},"1.docs/scripts/7.sky-dj/1.overview","Set up Sky DJ-System with two-deck mixing, custom clubs, spatial speakers, synchronized lighting and portable boomboxes.",{"title":313,"path":312,"stem":1408,"description":1409,"children":-1},"1.docs/scripts/7.sky-dj/2.setup/2.configuration","Complete reference for global settings, Music Sync, boombox limits, permissions, music delivery and advanced audio files.",[],1792547848293]