diff --git a/Core.lua b/Core.lua index 35909d6..883b30f 100644 --- a/Core.lua +++ b/Core.lua @@ -627,6 +627,81 @@ local function SetStatus(msg, r, g, b) end end +----------------------------------------------------------------------- +-- NOW-PLAYING ANNOUNCE +----------------------------------------------------------------------- +-- Broadcasts the currently playing track to a chat channel. Off by +-- default; configured via the Options panel on the main GUI, or the +-- "/rj np [channel]" slash command for a one-off manual announce. +-- +-- RelationshipsJukeboxDB.announce = { +-- enabled = false, -- auto-announce on track change +-- channel = "AUTO", -- AUTO | PARTY | RAID | GUILD | SAY | YELL +-- format = "\226\153\170 Now Playing: %s", +-- } +local VALID_ANNOUNCE_CHANNELS = { + AUTO = true, PARTY = true, RAID = true, GUILD = true, SAY = true, YELL = true, +} + +local function EnsureAnnounceSettings() + if type(RelationshipsJukeboxDB) ~= "table" then return end + if type(RelationshipsJukeboxDB.announce) ~= "table" then + RelationshipsJukeboxDB.announce = {} + end + local a = RelationshipsJukeboxDB.announce + if type(a.enabled) ~= "boolean" then a.enabled = false end + if type(a.channel) ~= "string" or not VALID_ANNOUNCE_CHANNELS[a.channel] then + a.channel = "AUTO" + end + if type(a.format) ~= "string" or a.format == "" then + a.format = "\226\153\170 Now Playing: %s" + end +end + +-- Resolve AUTO -> best available channel for the current group state. +-- Returns nil when AUTO is selected and the player is solo (so auto- +-- announce stays quiet instead of spamming /say). +local function ResolveAnnounceChannel(chan) + chan = chan or "AUTO" + if chan ~= "AUTO" then return chan end + local raid = (GetNumRaidMembers and GetNumRaidMembers()) or 0 + if raid > 0 then return "RAID" end + local party = (GetNumPartyMembers and GetNumPartyMembers()) or 0 + if party > 0 then return "PARTY" end + return nil +end + +-- force=true -> manual announce (slash command); falls back to SAY +-- when AUTO resolves to solo, and ignores the enabled flag. +-- force=false -> automatic announce on track change; requires enabled=true +-- and stays silent when solo under AUTO. +function AnnounceNowPlaying(force, channelOverride) + EnsureAnnounceSettings() + local a = RelationshipsJukeboxDB.announce + if not force and not a.enabled then return end + local name = RJ.currentName + if not name or name == "" then + if force then SetStatus("No track is playing.", 1, 0.4, 0.4) end + return + end + local chan = channelOverride or a.channel or "AUTO" + if not VALID_ANNOUNCE_CHANNELS[chan] then + if force then SetStatus("Unknown channel: " .. chan, 1, 0.4, 0.4) end + return + end + local resolved = ResolveAnnounceChannel(chan) + if not resolved then + if force then + resolved = "SAY" + else + return + end + end + if not SendChatMessage then return end + local msg = string.format(a.format or "Now Playing: %s", name) + SendChatMessage(msg, resolved) +end + local function ShuffleQueue(queue) local i if not queue then return end @@ -1223,6 +1298,7 @@ PlayTrack = function(indexOrEntry, fromQueue) end RefreshPlaybackButtons() RefreshMiniPlayer() + AnnounceNowPlaying(false) else SetStatus("Playback error for: " .. (name or "?"), 1, 0.2, 0.2) end @@ -1324,6 +1400,7 @@ PlayTrack = function(indexOrEntry, fromQueue) end RefreshPlaybackButtons() + if ok then AnnounceNowPlaying(false) end return ok end @@ -2139,6 +2216,137 @@ local function CreateRow(parent, i) end +-- Options subpanel that lives inside the main jukebox frame. Exposes +-- controls for the Now-Playing announce feature: an on/off checkbox and +-- a channel dropdown (Auto / Party / Raid / Guild / Say / Yell). +local ANNOUNCE_CHANNEL_ORDER = { "AUTO", "PARTY", "RAID", "GUILD", "SAY", "YELL" } +local ANNOUNCE_CHANNEL_LABEL = { + AUTO = "Auto (Raid > Party)", + PARTY = "Party", + RAID = "Raid", + GUILD = "Guild", + SAY = "Say", + YELL = "Yell", +} + +function CreateAnnounceOptionsPanel(parent) + if RJ.optionsFrame then return RJ.optionsFrame end + EnsureAnnounceSettings() + + local p = CreateFrame("Frame", "RJOptionsFrame", parent) + RJ.optionsFrame = p + p:SetWidth(360) + p:SetHeight(210) + p:SetPoint("TOPRIGHT", parent, "TOPRIGHT", -16, -46) + p:SetFrameStrata("DIALOG") + p:EnableMouse(true) + p:Hide() + + if p.SetBackdrop then + p:SetBackdrop({ + bgFile = "Interface\\DialogFrame\\UI-DialogBox-Background", + edgeFile = "Interface\\DialogFrame\\UI-DialogBox-Border", + tile = true, tileSize = 32, edgeSize = 24, + insets = { left = 8, right = 8, top = 8, bottom = 8 } + }) + p:SetBackdropColor(0, 0, 0, 0.95) + end + + local title = p:CreateFontString(nil, "OVERLAY", "GameFontHighlight") + title:SetPoint("TOP", p, "TOP", 0, -14) + title:SetText("Announce Now Playing") + + local closeBtn = MakeButton(nil, p, 22, 20, "X") + closeBtn:SetPoint("TOPRIGHT", p, "TOPRIGHT", -8, -10) + closeBtn:SetScript("OnClick", function() p:Hide() end) + + -- Enable checkbox + local cb = CreateFrame("CheckButton", "RJAnnounceEnable", p, "UICheckButtonTemplate") + cb:SetPoint("TOPLEFT", p, "TOPLEFT", 18, -44) + cb:SetWidth(24); cb:SetHeight(24) + local cbLabel = getglobal and getglobal(cb:GetName() .. "Text") or nil + if cbLabel then cbLabel:SetText("Auto-announce when a new track starts") end + cb:SetScript("OnClick", function() + EnsureAnnounceSettings() + local checked = cb:GetChecked() and true or false + RelationshipsJukeboxDB.announce.enabled = checked + if checked then + SetStatus("Auto-announce ON", 0.2, 1, 0.2) + else + SetStatus("Auto-announce OFF", 0.7, 0.7, 0.7) + end + end) + RJ.announceCheckbox = cb + + -- Channel dropdown + local chanLabel = p:CreateFontString(nil, "OVERLAY", "GameFontNormal") + chanLabel:SetPoint("TOPLEFT", cb, "BOTTOMLEFT", 4, -14) + chanLabel:SetText("Send to:") + + local dd = CreateFrame("Frame", "RJAnnounceChannelDD", p, "UIDropDownMenuTemplate") + dd:SetPoint("LEFT", chanLabel, "RIGHT", -6, -2) + RJ.announceChannelDD = dd + + local function ChooseChannel(value) + EnsureAnnounceSettings() + RelationshipsJukeboxDB.announce.channel = value + if UIDropDownMenu_SetSelectedValue then + UIDropDownMenu_SetSelectedValue(dd, value) + end + if UIDropDownMenu_SetText then + UIDropDownMenu_SetText(ANNOUNCE_CHANNEL_LABEL[value] or value, dd) + end + SetStatus("Announce channel: " .. (ANNOUNCE_CHANNEL_LABEL[value] or value), 0.2, 1, 0.2) + end + + local function InitChannelDD() + local info + for i = 1, Count(ANNOUNCE_CHANNEL_ORDER) do + local v = ANNOUNCE_CHANNEL_ORDER[i] + info = {} + info.text = ANNOUNCE_CHANNEL_LABEL[v] or v + info.value = v + info.checked = (RelationshipsJukeboxDB.announce.channel == v) + info.func = function() ChooseChannel(this and this.value or v) end + UIDropDownMenu_AddButton(info) + end + end + UIDropDownMenu_Initialize(dd, InitChannelDD) + UIDropDownMenu_SetWidth(160, dd) + + -- Test / manual announce button + local testBtn = MakeButton(nil, p, 130, 22, "Announce Now") + testBtn:SetPoint("TOPLEFT", chanLabel, "BOTTOMLEFT", -4, -14) + testBtn:SetScript("OnClick", function() + AnnounceNowPlaying(true) + end) + AttachTooltip(testBtn, "Announce Now", + "Send the currently playing track to the selected channel right now. Works even when auto-announce is off.") + + local help = p:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall") + help:SetPoint("BOTTOMLEFT", p, "BOTTOMLEFT", 16, 14) + help:SetPoint("BOTTOMRIGHT", p, "BOTTOMRIGHT", -16, 14) + help:SetJustifyH("LEFT") + help:SetText("Slash: /rj np [party|raid|guild|say|yell|auto]\nAuto mode picks Raid if in a raid, else Party.") + if help.SetTextColor then help:SetTextColor(0.8, 0.8, 0.8) end + + -- Sync visible controls with saved settings whenever the panel opens. + RJ.RefreshOptionsPanel = function() + EnsureAnnounceSettings() + local a = RelationshipsJukeboxDB.announce + if cb.SetChecked then cb:SetChecked(a.enabled) end + if UIDropDownMenu_SetSelectedValue then + UIDropDownMenu_SetSelectedValue(dd, a.channel) + end + if UIDropDownMenu_SetText then + UIDropDownMenu_SetText(ANNOUNCE_CHANNEL_LABEL[a.channel] or a.channel, dd) + end + end + RJ.RefreshOptionsPanel() + + return p +end + local function CreateUI() if RJ.frame then return end @@ -2178,6 +2386,25 @@ local function CreateUI() close:SetPoint("TOPRIGHT", f, "TOPRIGHT", -14, -14) close:SetScript("OnClick", function() f:Hide() end) + -- Options button (opens the Announce settings panel). + local optionsBtn = MakeButton(nil, f, 70, 22, "Options") + optionsBtn:SetPoint("RIGHT", close, "LEFT", -6, 0) + optionsBtn:SetScript("OnClick", function() + if RJ.optionsFrame then + if RJ.optionsFrame:IsShown() then + RJ.optionsFrame:Hide() + else + if RJ.RefreshOptionsPanel then RJ.RefreshOptionsPanel() end + RJ.optionsFrame:Show() + end + end + end) + AttachTooltip(optionsBtn, "Options", "Configure the Now Playing announce channel and toggle auto-announce on or off.") + RJ.optionsButton = optionsBtn + + -- ----- Options panel (Announce settings) -------------------------- + CreateAnnounceOptionsPanel(f) + -- Search input row local searchLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal") searchLabel:SetPoint("TOPLEFT", f, "TOPLEFT", 24, -76) @@ -3247,6 +3474,7 @@ loader:SetScript("OnEvent", function() EnsureDB() EnsurePlaylists() + EnsureAnnounceSettings() @@ -3368,6 +3596,39 @@ SlashCmdList["RELJUKEBOX"] = function(msg) SetStatus("No track is playing.", 1, 0.4, 0.4) end return + elseif command == "np" or string.sub(command, 1, 3) == "np " then + -- /rj np [party|raid|guild|say|yell|auto] -- announce now-playing track + local arg = Trim(string.sub(command, 3)) + local chan = nil + if arg ~= "" then + chan = string.upper(arg) + if chan == "P" then chan = "PARTY" + elseif chan == "R" then chan = "RAID" + elseif chan == "G" then chan = "GUILD" + elseif chan == "S" then chan = "SAY" + elseif chan == "Y" then chan = "YELL" + end + if not VALID_ANNOUNCE_CHANNELS[chan] then + SetStatus("Unknown channel: " .. arg .. " (party/raid/guild/say/yell/auto)", 1, 0.4, 0.4) + return + end + end + AnnounceNowPlaying(true, chan) + return + elseif command == "announce" then + -- Toggle auto-announce on/off. + EnsureAnnounceSettings() + local a = RelationshipsJukeboxDB.announce + a.enabled = not a.enabled + if a.enabled then + SetStatus("Auto-announce ON (channel: " .. a.channel .. ")", 0.2, 1, 0.2) + else + SetStatus("Auto-announce OFF", 0.7, 0.7, 0.7) + end + if RJ.announceCheckbox and RJ.announceCheckbox.SetChecked then + RJ.announceCheckbox:SetChecked(a.enabled) + end + return elseif string.sub(command, 1, 9) == "playlist " then -- /rj playlist -- switch view. Special values: all, favorites, -- folder:, user:. Plain names are treated as user playlists.