Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
vittee committed Jun 10, 2024
2 parents 9af94ef + 32358b6 commit 486b901
Show file tree
Hide file tree
Showing 14 changed files with 194 additions and 92 deletions.
58 changes: 36 additions & 22 deletions packages/radio/src/discord/automaton/guild-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -582,34 +582,21 @@ export class GuildState {
return;
}

const embed = new EmbedBuilder();
const dedicatedTracks = await station.findTracksByComment(searchKey, id);

if (info.image) {
embed.setThumbnail(info.image);
}

const tracks = await station.findTracksByComment(searchKey, id);

if (tracks.length < 1) {
const searchResult = await station.search({
q: {
title: info.title,
artist: info.artist
},
limit: 1,
noHistory: true
});

tracks.push(...searchResult);
}

const [track] = sortBy(tracks, t => t.collection.options.auxiliary ? 1 : 0);
const [track] = sortBy(dedicatedTracks, t => t.collection.options.auxiliary ? 1 : 0);

if (track) {
const { id: trackId, extra } = track;

const { title = info.title || 'Unknown', artist = info.artist || 'Unknown' } = extra?.tags ?? {};

const embed = new EmbedBuilder();

if (info.image) {
embed.setThumbnail(info.image);
}

embed
.setTitle('Found a dedicated track for this link')
.addFields(
Expand Down Expand Up @@ -638,6 +625,33 @@ export class GuildState {
}
}

// Search and show the potentials
const searchResult = await station.search({
q: {
title: info.title,
artist: info.artist
},
limit: 1,
noHistory: true
});

if (searchResult.length) {
return {
embeds: [new EmbedBuilder()
.setTitle(`Found ${searchResult.length} potential track(s) for this title`)
],
components: [
new ActionRowBuilder<MessageActionRowComponentBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel('Search')
.setStyle(ButtonStyle.Primary)
.setCustomId(`request:cross_search`)
)
]
}
}

break;
}

Expand Down Expand Up @@ -680,7 +694,7 @@ export class GuildState {
new ButtonBuilder()
.setLabel('Make a request')
.setStyle(ButtonStyle.Primary)
.setCustomId(`request:search:artist$${info.artist}`)
.setCustomId(`request:search:artist$${info.artist}`.slice(0, 100))
)
]
}
Expand Down
4 changes: 2 additions & 2 deletions packages/radio/src/discord/command/commands/collection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, MessageActionRowComponentBuilder, PermissionsBitField, SelectMenuComponentOptionData, StringSelectMenuBuilder } from "discord.js";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, MessageActionRowComponentBuilder, PermissionsBitField, SelectMenuComponentOptionData, StringSelectMenuBuilder } from "discord.js";
import { CommandDescriptor, InteractionHandlerFactory, OptionType, SubCommandLikeOption } from "../type";
import { deny, guildStationGuard, joinStrings, makeAnsiCodeBlock, permissionGuard, warn } from "../utils";
import { chain, startCase } from "lodash";
Expand All @@ -14,7 +14,7 @@ const declaration: SubCommandLikeOption = {

const onGoing = new Set<string>();

const createCommandHandler: InteractionHandlerFactory<CommandInteraction> = (automaton) => async (interaction) => {
const createCommandHandler: InteractionHandlerFactory<ChatInputCommandInteraction> = (automaton) => async (interaction) => {
const isOwnerOverride = automaton.owners.includes(interaction.user.id);

if (!isOwnerOverride) {
Expand Down
4 changes: 2 additions & 2 deletions packages/radio/src/discord/command/commands/latch/remove.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
StringSelectMenuBuilder,
} from "discord.js";

import { guildStationGuard, joinStrings, makeAnsiCodeBlock, makeColoredMessage, permissionGuard, reply } from "../../utils";
import { deferReply, guildStationGuard, joinStrings, makeAnsiCodeBlock, makeColoredMessage, permissionGuard, reply } from "../../utils";
import { onGoing } from "./on-going";
import { getLatchSessionsListing } from "./list";
import { interact } from "../../interactor";
Expand Down Expand Up @@ -37,7 +37,7 @@ export async function remove(options: SubCommandHandlerOptions) {
return;
}

await interaction.deferReply();
await deferReply(interaction);

const selections = sessions.slice(0, 25).map(session => ({
label: `${session.count}/${session.max} from ${session.collection.extra.description} collection`,
Expand Down
4 changes: 2 additions & 2 deletions packages/radio/src/discord/command/commands/latch/set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
StringSelectMenuBuilder,
} from "discord.js";

import { guildStationGuard, joinStrings, makeAnsiCodeBlock, makeColoredMessage, permissionGuard, reply, warn } from "../../utils";
import { deferReply, guildStationGuard, joinStrings, makeAnsiCodeBlock, makeColoredMessage, permissionGuard, reply, warn } from "../../utils";
import { isString, range, startCase } from "lodash";
import { ansi } from "../../../format/ansi";
import { onGoing } from "./on-going";
Expand Down Expand Up @@ -39,7 +39,7 @@ export async function set(options: SubCommandHandlerOptions) {
return;
}

await interaction.deferReply();
await deferReply(interaction);

const selections: Record<string, string | undefined> = {
collection: station.trackPlay?.track?.collection?.id,
Expand Down
4 changes: 2 additions & 2 deletions packages/radio/src/discord/command/commands/lyrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { BoomBoxCoverAnyLyrics, getTrackBanner, MetadataHelper, searchLyrics, St
import { ButtonInteraction, Message, AttachmentBuilder, EmbedBuilder, hyperlink, messageLink, inlineCode } from "discord.js";
import { findLast } from "lodash";
import { CommandDescriptor, InteractionHandlerFactory } from "../type";
import { deny, guildStationGuard, joinStrings, reply, warn } from "../utils";
import { deferReply, deny, guildStationGuard, joinStrings, reply, warn } from "../utils";
import { LyricsSearchResult } from "@seamless-medley/core/src/metadata/lyrics/types";
import { lyricsToText, parseLyrics } from "@seamless-medley/utils";

Expand Down Expand Up @@ -48,7 +48,7 @@ const createButtonHandler: InteractionHandlerFactory<ButtonInteraction> = (autom
const title = trackExtra.tags.title;

if (artist && title) {
await interaction.deferReply();
await deferReply(interaction);

searchResult = await searchLyrics(artist, title).catch(() => undefined);

Expand Down
4 changes: 2 additions & 2 deletions packages/radio/src/discord/command/commands/profile.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, MessageActionRowComponentBuilder, PermissionsBitField, SelectMenuComponentOptionData, StringSelectMenuBuilder } from "discord.js";
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, MessageActionRowComponentBuilder, PermissionsBitField, SelectMenuComponentOptionData, StringSelectMenuBuilder } from "discord.js";
import { CommandDescriptor, InteractionHandlerFactory, OptionType, SubCommandLikeOption } from "../type";
import { guildStationGuard, joinStrings, makeAnsiCodeBlock, permissionGuard, warn } from "../utils";
import { interact } from "../interactor";
Expand All @@ -12,7 +12,7 @@ const declaration: SubCommandLikeOption = {

const onGoing = new Set<string>();

const createCommandHandler: InteractionHandlerFactory<CommandInteraction> = (automaton) => async (interaction) => {
const createCommandHandler: InteractionHandlerFactory<ChatInputCommandInteraction> = (automaton) => async (interaction) => {
const isOwnerOverride = automaton.owners.includes(interaction.user.id);

if (!isOwnerOverride) {
Expand Down
93 changes: 76 additions & 17 deletions packages/radio/src/discord/command/commands/request/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import {
AudienceType,
AudioProperties,
BoomBoxTrack,
BoomBoxTrackExtra,
getTrackBanner,
makeAudience,
MetadataHelper,
Expand All @@ -24,20 +23,22 @@ import {
MessageComponentInteraction,
ButtonInteraction,
userMention,
CommandInteractionOption
RepliableInteraction
} from "discord.js";

import { chain, chunk, clamp, Dictionary, flatten, fromPairs, groupBy, identity, isUndefined, sample, sortBy, truncate, zip } from "lodash";
import { parse as parsePath, extname } from 'node:path';
import { createHash } from 'crypto';
import { toEmoji } from "../../../helpers/emojis";
import { InteractionHandlerFactory } from "../../type";
import { deny, guildStationGuard, joinStrings, makeAnsiCodeBlock, makeColoredMessage, makeRequestPreview, maxSelectMenuOptions, peekRequestsForGuild, reply, ReplyableInteraction } from "../../utils";
import { AutomatonCommandError, InteractionHandlerFactory } from "../../type";
import { declare, deferReply, deny, guildStationGuard, joinStrings, makeAnsiCodeBlock, makeColoredMessage, makeRequestPreview, maxSelectMenuOptions, peekRequestsForGuild, reply } from "../../utils";
import { ansi } from "../../../format/ansi";
import { getVoteMessage } from "../vote";
import { interact } from "../../interactor";
import { groupByAsync } from "@seamless-medley/utils";
import { groupByAsync, waitFor } from "@seamless-medley/utils";
import { MedleyAutomaton } from "../../../automaton";
import { extractSpotifyUrl, fetchSpotifyInfo } from "../../../helpers/spotify";
import { GuildState } from "../../../automaton/guild-state";

type Selection = {
title: string;
Expand Down Expand Up @@ -136,7 +137,7 @@ export const createCommandHandler: InteractionHandlerFactory<ChatInputCommandInt

const noSweep = interaction.options.getBoolean('no-sweep') ?? undefined;

await handleRequestCommand({
return handleRequestCommand({
automaton,
interaction,
artist,
Expand All @@ -148,14 +149,25 @@ export const createCommandHandler: InteractionHandlerFactory<ChatInputCommandInt

export type RequestCommandOptions = {
automaton: MedleyAutomaton;
interaction: ReplyableInteraction;
interaction: RepliableInteraction;
artist?: string;
title?: string;
query?: string;
noSweep?: boolean;
noHistory?: boolean;
}

export const handleRequestCommand = async ({ automaton, interaction, artist, title, query, noSweep }: RequestCommandOptions) => {
export const handleRequestCommand = async (options: RequestCommandOptions) => {
const {
automaton,
interaction,
artist,
title,
query,
noSweep,
noHistory
} = options;

const { guildId, station } = guildStationGuard(automaton, interaction);

if ([artist, title, query].every(isUndefined)) {
Expand All @@ -170,7 +182,7 @@ export const handleRequestCommand = async ({ automaton, interaction, artist, tit
return;
}

await interaction.deferReply();
await deferReply(interaction);

const results = await station.search({
q: {
Expand All @@ -179,7 +191,8 @@ export const handleRequestCommand = async ({ automaton, interaction, artist, tit
query
},
// 10 pages
limit: maxSelectMenuOptions * 10
limit: maxSelectMenuOptions * 10,
noHistory
});

if (results.length < 1) {
Expand All @@ -194,12 +207,15 @@ export const handleRequestCommand = async ({ automaton, interaction, artist, tit
.filter(t => !!t)
.join(' OR ');

reply(interaction, joinStrings([
'Your search:',
...makeAnsiCodeBlock(queryString),
'Did not match any tracks'
]))
return;
return declare(
interaction,
joinStrings([
'Your search:',
...makeAnsiCodeBlock(queryString),
'Did not match any tracks'
]),
{ mention: { type: 'user', subject: interaction.user.id } }
)
}

const groupedSelections = chain(results)
Expand Down Expand Up @@ -255,7 +271,7 @@ export const handleRequestCommand = async ({ automaton, interaction, artist, tit
const originalArtist = sel.track.extra?.tags?.originalArtist;

const description = truncateFirst(
(sel.artist ?? 'Unknown Artist') + originalArtist ? ` (Original by ${originalArtist})` : ''
(sel.artist ?? 'Unknown Artist') + (originalArtist ? ` (Original by ${originalArtist})` : '')
);

return {
Expand Down Expand Up @@ -617,5 +633,48 @@ export const createButtonHandler: InteractionHandlerFactory<ButtonInteraction> =
query: params.query
});
}

case 'cross_search': {
if (!interaction.channel) {
return;
}

const originalMessage = await interaction.message.fetchReference()
.then(ref => ref.fetch())
.catch(() => undefined);

if (!originalMessage) {
return;
}

const [matched] = extractSpotifyUrl(originalMessage.content);
if (!matched?.url || matched?.paths?.[0] !== 'track') {
return
}

const info = await fetchSpotifyInfo(matched.url.href);

if (!info || info.type !== 'track' || !info.artist || !info.title) {
return;
}

return handleRequestCommand({
automaton,
interaction,
artist: info.artist,
title: info.title,
noHistory: true
})
.catch(e => new CrossSearchError(automaton, guildId, e.message));
}
}
}

class CrossSearchError extends AutomatonCommandError {
readonly state?: GuildState;

constructor(automaton: MedleyAutomaton, guildId: string, message: string) {
super(automaton, message);
this.state = automaton.getGuildState(guildId);
}
}
6 changes: 2 additions & 4 deletions packages/radio/src/discord/command/commands/rescan.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CommandInteraction, blockQuote, inlineCode, unorderedList } from "discord.js";
import { CommandDescriptor, InteractionHandlerFactory, OptionType, SubCommandLikeOption } from "../type";
import { deny, guildStationGuard, joinStrings, reply } from "../utils";
import { deferReply, deny, guildStationGuard, joinStrings, reply } from "../utils";
import { LibraryRescanStats, MusicTrackCollection, Station } from "@seamless-medley/core";
import { once } from "lodash";

Expand All @@ -18,9 +18,7 @@ const createCommandHandler: InteractionHandlerFactory<CommandInteraction> = (aut
return;
}

await interaction.deferReply({
ephemeral: true
});
await deferReply(interaction, { ephemeral: true });

const { station } = guildStationGuard(automaton, interaction);

Expand Down
7 changes: 4 additions & 3 deletions packages/radio/src/discord/command/commands/tune.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {
StringSelectMenuBuilder,
StringSelectMenuInteraction,
SelectMenuComponentOptionData,
hyperlink
hyperlink,
RepliableInteraction
} from "discord.js";
import { stubTrue } from "lodash";

Expand Down Expand Up @@ -86,7 +87,7 @@ const handleStationSelection = async (automaton: MedleyAutomaton, interaction: S

const onGoing = new Set<string>();

export async function createStationSelector(automaton: MedleyAutomaton, interaction: CommandInteraction, onDone?: (ok: boolean) => Promise<any>) {
export async function createStationSelector(automaton: MedleyAutomaton, interaction: RepliableInteraction, onDone?: (ok: boolean) => Promise<any>) {
const stations = automaton.stations.all();

if (stations.length <= 0) {
Expand Down Expand Up @@ -149,7 +150,7 @@ export async function createStationSelector(automaton: MedleyAutomaton, interact
});
}

const createCommandHandler: InteractionHandlerFactory<CommandInteraction> = (automaton) => (interaction) => {
const createCommandHandler: InteractionHandlerFactory<RepliableInteraction> = (automaton) => (interaction) => {
const isOwnerOverride = automaton.owners.includes(interaction.user.id);

if (!isOwnerOverride) {
Expand Down
Loading

0 comments on commit 486b901

Please sign in to comment.