3 Commits

Author SHA1 Message Date
williamp ff02993a0a Merge branch 'master' into code-cleanup
Build only (for PRs) / build-only (pull_request) Successful in 4m52s
2026-03-09 11:05:10 -04:00
williamp 52337254b6 bugfix: handle lack of separate audio/video streams
Build only (for PRs) / build-only (pull_request) Successful in 3m47s
2026-03-09 10:58:56 -04:00
williamp a44bb1bf34 optimize codebase
Build only (for PRs) / build-only (pull_request) Successful in 3m33s
main.go:
- Eliminated ~160 lines of duplicate code: Extracted 3 new helper functions at the bottom of the file:
buildVideoMenuOptions([]VideoOption) — builds the Discord select menu options for video formats
buildAudioMenuOptions([]AudioOption) — same for audio
fetchAndShowFormats(s, i, url) — fetches formats, sorts them, builds menus, stores state, and edits the interaction; previously duplicated identically in both the download and download video command handlers
- Fixed time.Sleep ordering bug: The startAsyncDownload goroutine was launched before InteractionRespond with a 100ms sleep to compensate. Now the download is launched after InteractionRespond returns — no sleep needed. Removed "time" import.
- Used helpers in video_select handler: The two inline menu-building loops in that handler now call buildAudioMenuOptions / buildVideoMenuOptions

misc.go:
- Moved regexp.MustCompile(...) to a package-level var urlPattern — previously it recompiled the regex on every call to extractURLFromString
- Simplified the function body to a single return line
2026-03-09 10:46:10 -04:00
12 changed files with 13 additions and 176 deletions
+3 -3
View File
@@ -14,7 +14,7 @@ jobs:
steps:
# Checkout the repository code
- name: Checkout repository
uses: actions/checkout@v7
uses: actions/checkout@v6
- name: Set outputs
id: vars
@@ -55,7 +55,7 @@ jobs:
if: ${{ success() }}
steps:
- name: Checkout target repository
uses: actions/checkout@v7
uses: actions/checkout@v6
with:
repository: infrastructure/core-apps
token: ${{ secrets.ACTIONS_TOKEN }}
@@ -83,7 +83,7 @@ jobs:
fi
exit 0
- name: Push changes
uses: ad-m/github-push-action@v1.3.0
uses: ad-m/github-push-action@v1.0.0
with:
github_token: ${{ secrets.ACTIONS_TOKEN }}
repository: infrastructure/core-apps
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
steps:
# Checkout the repository code
- name: Checkout repository
uses: actions/checkout@v7
uses: actions/checkout@v6
- name: Set outputs
id: vars
-32
View File
@@ -1,32 +0,0 @@
name: changelog
on:
push:
branches:
- dev
jobs:
changelog:
runs-on: ubuntu-latest
container: docker.io/thegeeklab/git-sv:2.1.3
steps:
- name: install tools
run: |
apk add -q --update --no-cache nodejs curl jq sed
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Generate upcoming changelog
run: |
git sv rn -o changelog.md
export RELEASE_NOTES=$(cat changelog.md)
export ISSUE_NUMBER=$(curl -s "https://git.dubyatp.xyz/api/v1/repos/williamp/yt-dlp-bot/issues?state=open&q=Changelog%20for%20upcoming%20version" | jq '.[].number')
echo $RELEASE_NOTES
JSON_DATA=$(echo "" | jq -Rs --arg title 'Changelog for upcoming version' --arg body "$(cat changelog.md)" '{title: $title, body: $body}')
if [ -z "$ISSUE_NUMBER" ]; then
curl -s -X POST "https://git.dubyatp.xyz/api/v1/repos/williamp/yt-dlp-bot/issues" -H "Authorization: token ${{ secrets.ACTIONS_TOKEN }}" -H "Content-Type: application/json" -d "$JSON_DATA"
else
curl -s -X PATCH "https://git.dubyatp.xyz/api/v1/repos/williamp/yt-dlp-bot/issues/$ISSUE_NUMBER" -H "Authorization: token ${{ secrets.ACTIONS_TOKEN }}" -H "Content-Type: application/json" -d "$JSON_DATA"
fi
-57
View File
@@ -1,57 +0,0 @@
version: '1.1' # Configuration version.
versioning:
update-major: [breaking] # Commit types used to bump major.
update-minor: [feat, perf] # Commit types used to bump minor.
update-patch: [build, ci, chore, fix, perf, refactor, test] # Commit types used to bump patch.
# When type is not present on update rules and is unknown (not mapped on commit message types);
# if ignore-unknown=false bump patch, if ignore-unknown=true do not bump version.
ignore-unknown: false
tag:
pattern: 'v%d.%d.%d' # Pattern used to create git tag.
filter: '' # Enables you to filter for considerable tags using git pattern syntax.
release-notes:
sections: # Array with each section of release note. Check template section for more information.
- name: Breaking Changes
section-type: breaking-changes
- name: Features # Name used on section.
section-type: commits # Type of the section, supported types: commits, breaking-changes.
commit-types: [feat, perf] # Commit types for commit section-type, one commit type cannot be in more than one section.
- name: Bug Fixes
section-type: commits
commit-types: [fix]
- name: Maintenance
section-type: commits
commit-types: [chore, refactor]
- name: Documentation
commit-types: [docs]
section-type: commits
- name: CI
commit-types: [ci]
section-type: commits
branches: # Git branches config.
prefix: ([a-z]+\/)? # Prefix used on branch name, it should be a regex group.
suffix: (-.*)? # Suffix used on branch name, it should be a regex group.
disable-issue: false # Set true if there is no need to recover issue id from branch name.
skip: [] # List of branch names ignored on commit message validation.
skip-detached: false # Set true if a detached branch should be ignored on commit message validation.
commit-message:
# Supported commit types.
types: [build, ci, chore, docs, feat, fix, perf, refactor, revert, style, test]
header-selector: '' # You can put in a regex here to select only a certain part of the commit message. Please define a regex group 'header'.
scope:
# Define supported scopes, if blank, scope will not be validated, if not, only scope listed will be valid.
# Don't forget to add "" on your list if you need to define scopes and keep it optional.
values: []
footer:
issue: # Use "issue: {}" if you wish to disable issue footer.
key: jira # Name used to define an issue on footer metadata.
key-synonyms: [Jira, JIRA] # Supported variations for footer metadata.
use-hash: false # If false, use :<space> separator. If true, use <space># separator.
add-value-prefix: '' # Add a prefix to issue value.
issue:
regex: '[A-Z]+-[0-9]+' # Regex for issue id.
+4 -4
View File
@@ -3,7 +3,7 @@
########################################
# Versions
ARG YT_DLP_VERSION="2026.07.04"
ARG YT_DLP_VERSION="2026.03.03"
################################################################################
# Deno builder stage
@@ -11,7 +11,7 @@ FROM denoland/deno:bin-2.6.6@sha256:9f18d20207f2699595ea26d14e0b7e123cd0cd01100a
################################################################################
# YT-DLP builder stage
FROM alpine:3.24@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b AS yt-dlp-builder
FROM alpine:3.23@sha256:25109184c71bdad752c8312a8623239686a9a2071e8825f20acb8f2198c3f659 AS yt-dlp-builder
ARG YT_DLP_VERSION
ARG TARGETARCH
@@ -38,7 +38,7 @@ RUN case "$TARGETARCH" in \
################################################################################
# FFmpeg builder stage
FROM debian:13-slim@sha256:020c0d20b9880058cbe785a9db107156c3c75c2ac944a6aa7ab59f2add76a7bd AS ffmpeg-builder
FROM debian:13-slim@sha256:1d3c811171a08a5adaa4a163fbafd96b61b87aa871bbc7aa15431ac275d3d430 AS ffmpeg-builder
RUN apt-get update && \
apt-get install -y --no-install-recommends ffmpeg
COPY --from=yt-dlp-builder /rootfs/bin/yt-dlp /yt-dlp
@@ -54,7 +54,7 @@ RUN mkdir -p /rootfs/bin && \
################################################################################
# App builder stage
FROM golang:1.26.5-trixie@sha256:117e07f49461abb984fc8aef661432461ff43d06faa22c3b73af6a49ce325cb9 AS app-builder
FROM golang:1.26.1-trixie@sha256:ab8c4944b04c6f97c2b5bffce471b7f3d55f2228badc55eae6cce87596d5710b AS app-builder
COPY app/ /opt/app
WORKDIR /opt/app
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

+1 -1
View File
@@ -4,7 +4,7 @@ go 1.25.2
require (
github.com/bwmarrin/discordgo v0.29.0
github.com/lrstanley/go-ytdlp v1.3.5
github.com/lrstanley/go-ytdlp v1.3.3
)
require (
-4
View File
@@ -16,10 +16,6 @@ github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0U
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/lrstanley/go-ytdlp v1.3.3 h1:Y9kJcdTwskPWDiwONMIl501Dhi+OrTF7HHY6J6+Lbco=
github.com/lrstanley/go-ytdlp v1.3.3/go.mod h1:VgjnTrvkTf+23JuySjyPq1iQ8ijSovBtTPpXH5XrLtI=
github.com/lrstanley/go-ytdlp v1.3.4 h1:x3ppgdeN3FbguT5ifc6ISrgjYN10+dVUAbprA7/dYrk=
github.com/lrstanley/go-ytdlp v1.3.4/go.mod h1:VgjnTrvkTf+23JuySjyPq1iQ8ijSovBtTPpXH5XrLtI=
github.com/lrstanley/go-ytdlp v1.3.5 h1:eT+29mK3Lp+XPMQOH25+jVerrrjifYW1o3IkTYJ9SMs=
github.com/lrstanley/go-ytdlp v1.3.5/go.mod h1:VgjnTrvkTf+23JuySjyPq1iQ8ijSovBtTPpXH5XrLtI=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+1 -28
View File
@@ -6,7 +6,6 @@ import (
"os"
"os/signal"
"sort"
"strings"
"syscall"
"github.com/bwmarrin/discordgo"
@@ -366,28 +365,12 @@ func main() {
h(s, i)
}
case discordgo.InteractionMessageComponent:
customID := i.MessageComponentData().CustomID
if h, ok := componentHandlers[customID]; ok {
if h, ok := componentHandlers[i.MessageComponentData().CustomID]; ok {
h(s, i)
} else if strings.HasPrefix(customID, "retry:") {
url := strings.TrimPrefix(customID, "retry:")
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseUpdateMessage,
Data: &discordgo.InteractionResponseData{
Content: fmt.Sprintf("%s Fetching available formats...", loading_emoji),
Components: []discordgo.MessageComponent{},
Flags: discordgo.MessageFlagsEphemeral,
},
})
go fetchAndShowFormats(s, i, url)
}
}
})
log.Println("Initialize loading emoji")
initLoadingEmoji(s)
log.Println("Adding commands")
registeredCommands := make([]*discordgo.ApplicationCommand, len(commands))
for i, v := range commands {
@@ -457,16 +440,6 @@ func fetchAndShowFormats(s *discordgo.Session, i *discordgo.InteractionCreate, u
if err != nil {
_, err = s.InteractionResponseEdit(i.Interaction, &discordgo.WebhookEdit{
Content: ptr("❌ Error fetching formats: " + err.Error()),
Components: &[]discordgo.MessageComponent{
&discordgo.ActionsRow{
Components: []discordgo.MessageComponent{
discordgo.Button{
Label: "Retry",
CustomID: fmt.Sprintf("retry:%s", url),
},
},
},
},
})
if err != nil {
log.Printf("Error updating interaction: %v", err)
+2 -36
View File
@@ -2,45 +2,11 @@ package main
import (
"fmt"
"log"
"os"
"regexp"
_ "embed"
"encoding/base64"
"github.com/bwmarrin/discordgo"
)
var loading_emoji string
//go:embed assets/loading.webp
var rawLoadingEmoji []byte
var loadingEmojiBase64 = func() string {
s := "data:image/webp;base64," + base64.StdEncoding.EncodeToString(rawLoadingEmoji)
rawLoadingEmoji = nil
return s
}()
func initLoadingEmoji(s *discordgo.Session) {
emojis, err := s.ApplicationEmojis(s.State.User.ID)
if err != nil {
log.Panic("Cannot get emojis")
}
for _, e := range emojis {
if e.Name == "loading" {
loading_emoji = fmt.Sprintf("<a:%s:%s>", e.Name, e.ID)
return
}
}
e, err := s.ApplicationEmojiCreate(s.State.User.ID, &discordgo.EmojiParams{
Name: "loading",
Image: loadingEmojiBase64,
})
if err != nil {
log.Panicf("Cannot create loading emoji: %s", err)
}
loading_emoji = fmt.Sprintf("<a:%s:%s>", e.Name, e.ID)
}
var loading_emoji = os.Getenv("LOADING_EMOJI")
var urlPattern = regexp.MustCompile(`https?://\S+`)
+1 -3
View File
@@ -19,9 +19,7 @@ func GetFormats(url string) (*FormatOptions, error) {
SkipDownload().
DumpJSON()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
defer cancel()
result, err := dl.Run(ctx, url)
result, err := dl.Run(context.TODO(), url)
if err != nil {
return nil, err
}
-7
View File
@@ -14,12 +14,5 @@
"depNameTemplate": "yt-dlp/yt-dlp",
"versioningTemplate": "regex:^(?<major>\\d{4})\\.(?<minor>\\d{2})\\.(?<patch>\\d{2})$"
}
],
"packageRules": [
{
"description": "Automerge digest-level image updates",
"matchUpdateTypes": ["digest"],
"automerge": true
}
]
}