package handler import ( "context" "fmt" "strconv" "strings" "github.com/go-telegram/bot/models" "uptodownBot/internal/domain" ) func (h *Handler) handleSearchCommand(ctx context.Context, msg *models.Message, userID int64) { h.promptForInput(ctx, msg.Chat.ID, 0, userID, PendingSearch, "Enter a YouTube search query:", map[string]string{"source": "youtube"}) } func (h *Handler) handleMusicSearchCommand(ctx context.Context, msg *models.Message, userID int64) { h.promptForInput(ctx, msg.Chat.ID, 0, userID, PendingSearch, "Enter a YouTube Music search query:", map[string]string{"source": "ytmusic"}) } func (h *Handler) handleSearchQuery(ctx context.Context, chatID int64, text string, userID int64, source string) { results, err := h.YtDlp.Search(text, source, 10) if err != nil { h.sendText(ctx, chatID, fmt.Sprintf("Search failed: %s", err.Error())) return } if len(results) == 0 { h.sendText(ctx, chatID, "No results found.") return } state := &domain.SearchState{ Query: text, Entries: results, Page: 0, PerPage: 5, Source: source, } ss := &stepState{SearchState: state} h.setUserStepState(chatID, ss) kb := searchResultsKeyboard(state) h.sendWithKB(ctx, chatID, fmt.Sprintf("Search results for '%s':", text), kb) } func (h *Handler) handleSearchCallback(ctx context.Context, chatID int64, msgID int, userID int64, data string) { switch { case data == "refresh": ss := h.getUserStepState(chatID) if ss == nil || ss.SearchState == nil { return } h.handleSearchQuery(ctx, chatID, ss.SearchState.Query, userID, ss.SearchState.Source) case strings.HasPrefix(data, "page_"): h.handleSearchPage(ctx, chatID, msgID, userID, data[5:]) case strings.HasPrefix(data, "select_"): h.handleSearchSelect(ctx, chatID, msgID, userID, data[7:]) } } func (h *Handler) handleSearchPage(ctx context.Context, chatID int64, msgID int, userID int64, pageStr string) { ss := h.getUserStepState(chatID) if ss == nil || ss.SearchState == nil { return } page, err := strconv.Atoi(pageStr) if err != nil { return } totalPages := (len(ss.SearchState.Entries) + ss.SearchState.PerPage - 1) / ss.SearchState.PerPage if page < 0 || page >= totalPages { return } ss.SearchState.Page = page h.setUserStepState(chatID, ss) kb := searchResultsKeyboard(ss.SearchState) h.editText(ctx, chatID, msgID, fmt.Sprintf("Search results for '%s':", ss.SearchState.Query), &kb) } func (h *Handler) handleSearchSelect(ctx context.Context, chatID int64, msgID int, userID int64, entryURL string) { h.clearStepState(chatID) h.editText(ctx, chatID, msgID, "Fetching media info...", nil) h.handleURLInput(ctx, chatID, entryURL, userID) } func searchResultsKeyboard(state *domain.SearchState) models.InlineKeyboardMarkup { totalPages := (len(state.Entries) + state.PerPage - 1) / state.PerPage if totalPages < 1 { totalPages = 1 } rows := [][]models.InlineKeyboardButton{} start := state.Page * state.PerPage end := start + state.PerPage if end > len(state.Entries) { end = len(state.Entries) } for i := start; i < end; i++ { e := state.Entries[i] title := e.Title if len(title) > 40 { title = title[:37] + "..." } label := title if e.Duration > 0 { label += fmt.Sprintf(" (%s)", formatDuration(e.Duration)) } rows = append(rows, []models.InlineKeyboardButton{ {Text: label, CallbackData: "search_select_" + e.URL}, }) } navRow := []models.InlineKeyboardButton{} navRow = append(navRow, models.InlineKeyboardButton{ Text: "<", CallbackData: fmt.Sprintf("search_page_%d", state.Page-1), }) navRow = append(navRow, models.InlineKeyboardButton{ Text: fmt.Sprintf("Page %d/%d", state.Page+1, totalPages), CallbackData: "noop", }) navRow = append(navRow, models.InlineKeyboardButton{ Text: ">", CallbackData: fmt.Sprintf("search_page_%d", state.Page+1), }) rows = append(rows, navRow) rows = append(rows, []models.InlineKeyboardButton{ {Text: "New Search", CallbackData: "search_refresh"}, {Text: "Cancel", CallbackData: "cancel_dl"}, }) return models.InlineKeyboardMarkup{InlineKeyboard: rows} }