|
|
|
@@ -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 <name> -- switch view. Special values: all, favorites,
|
|
|
|
|
-- folder:<name>, user:<name>. Plain names are treated as user playlists.
|
|
|
|
|