Просмотр исходного кода

feat(rewrite): add support for YouTube Shorts video URL pattern

Frédéric Guillot 10 месяцев назад
Родитель
Сommit
40727704c2

+ 26 - 13
internal/reader/rewrite/rewrite_functions.go

@@ -21,10 +21,11 @@ import (
 )
 )
 
 
 var (
 var (
-	youtubeRegex   = regexp.MustCompile(`youtube\.com/watch\?v=(.*)$`)
-	youtubeIdRegex = regexp.MustCompile(`youtube_id"?\s*[:=]\s*"([a-zA-Z0-9_-]{11})"`)
-	invidioRegex   = regexp.MustCompile(`https?://(.*)/watch\?v=(.*)`)
-	textLinkRegex  = regexp.MustCompile(`(?mi)(\bhttps?:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])`)
+	youtubeVideoRegex = regexp.MustCompile(`youtube\.com/watch\?v=(.*)$`)
+	youtubeShortRegex = regexp.MustCompile(`youtube\.com/shorts/([a-zA-Z0-9_-]{11})$`)
+	youtubeIdRegex    = regexp.MustCompile(`youtube_id"?\s*[:=]\s*"([a-zA-Z0-9_-]{11})"`)
+	invidioRegex      = regexp.MustCompile(`https?://(.*)/watch\?v=(.*)`)
+	textLinkRegex     = regexp.MustCompile(`(?mi)(\bhttps?:\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])`)
 )
 )
 
 
 // titlelize returns a copy of the string s with all Unicode letters that begin words
 // titlelize returns a copy of the string s with all Unicode letters that begin words
@@ -259,22 +260,34 @@ func useNoScriptImages(entryContent string) string {
 	return output
 	return output
 }
 }
 
 
-func addYoutubeVideo(entryURL, entryContent string) string {
-	matches := youtubeRegex.FindStringSubmatch(entryURL)
+func getYoutubVideoIDFromURL(entryURL string) string {
+	matches := youtubeVideoRegex.FindStringSubmatch(entryURL)
+
+	if len(matches) != 2 {
+		matches = youtubeShortRegex.FindStringSubmatch(entryURL)
+	}
 
 
 	if len(matches) == 2 {
 	if len(matches) == 2 {
-		video := `<iframe width="650" height="350" frameborder="0" src="` + config.Opts.YouTubeEmbedUrlOverride() + matches[1] + `" allowfullscreen></iframe>`
-		return video + `<br>` + entryContent
+		return matches[1]
+	}
+	return ""
+}
+
+func addVideoPlayerIframe(absoluteVideoURL, entryContent string) string {
+	video := `<iframe width="650" height="350" frameborder="0" src="` + absoluteVideoURL + `" allowfullscreen></iframe>`
+	return video + `<br>` + entryContent
+}
+
+func addYoutubeVideoRewriteRule(entryURL, entryContent string) string {
+	if videoURL := getYoutubVideoIDFromURL(entryURL); videoURL != "" {
+		return addVideoPlayerIframe(config.Opts.YouTubeEmbedUrlOverride()+videoURL, entryContent)
 	}
 	}
 	return entryContent
 	return entryContent
 }
 }
 
 
 func addYoutubeVideoUsingInvidiousPlayer(entryURL, entryContent string) string {
 func addYoutubeVideoUsingInvidiousPlayer(entryURL, entryContent string) string {
-	matches := youtubeRegex.FindStringSubmatch(entryURL)
-
-	if len(matches) == 2 {
-		video := `<iframe width="650" height="350" frameborder="0" src="https://` + config.Opts.InvidiousInstance() + `/embed/` + matches[1] + `" allowfullscreen></iframe>`
-		return video + `<br>` + entryContent
+	if videoURL := getYoutubVideoIDFromURL(entryURL); videoURL != "" {
+		return addVideoPlayerIframe(`https://`+config.Opts.InvidiousInstance()+`/embed/`+videoURL, entryContent)
 	}
 	}
 	return entryContent
 	return entryContent
 }
 }

+ 1 - 1
internal/reader/rewrite/rewriter.go

@@ -29,7 +29,7 @@ func (rule rule) applyRule(entryURL string, entry *model.Entry) {
 	case "add_dynamic_iframe":
 	case "add_dynamic_iframe":
 		entry.Content = addDynamicIframe(entry.Content)
 		entry.Content = addDynamicIframe(entry.Content)
 	case "add_youtube_video":
 	case "add_youtube_video":
-		entry.Content = addYoutubeVideo(entryURL, entry.Content)
+		entry.Content = addYoutubeVideoRewriteRule(entryURL, entry.Content)
 	case "add_invidious_video":
 	case "add_invidious_video":
 		entry.Content = addInvidiousVideo(entryURL, entry.Content)
 		entry.Content = addInvidiousVideo(entryURL, entry.Content)
 	case "add_youtube_video_using_invidious_player":
 	case "add_youtube_video_using_invidious_player":

+ 82 - 2
internal/reader/rewrite/rewriter_test.go

@@ -66,7 +66,7 @@ func TestRewriteWithNoMatchingRule(t *testing.T) {
 	}
 	}
 }
 }
 
 
-func TestRewriteWithYoutubeLink(t *testing.T) {
+func TestRewriteYoutubeVideoLink(t *testing.T) {
 	config.Opts = config.NewOptions()
 	config.Opts = config.NewOptions()
 
 
 	controlEntry := &model.Entry{
 	controlEntry := &model.Entry{
@@ -86,7 +86,47 @@ func TestRewriteWithYoutubeLink(t *testing.T) {
 	}
 	}
 }
 }
 
 
-func TestRewriteWithYoutubeLinkAndCustomEmbedURL(t *testing.T) {
+func TestRewriteYoutubeShortLink(t *testing.T) {
+	config.Opts = config.NewOptions()
+
+	controlEntry := &model.Entry{
+		URL:     "https://www.youtube.com/shorts/1LUWKWZkPjo",
+		Title:   `A title`,
+		Content: `<iframe width="650" height="350" frameborder="0" src="https://www.youtube-nocookie.com/embed/1LUWKWZkPjo" allowfullscreen></iframe><br>Video Description`,
+	}
+	testEntry := &model.Entry{
+		URL:     "https://www.youtube.com/shorts/1LUWKWZkPjo",
+		Title:   `A title`,
+		Content: `Video Description`,
+	}
+	ApplyContentRewriteRules(testEntry, ``)
+
+	if !reflect.DeepEqual(testEntry, controlEntry) {
+		t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
+	}
+}
+
+func TestRewriteIncorrectYoutubeLink(t *testing.T) {
+	config.Opts = config.NewOptions()
+
+	controlEntry := &model.Entry{
+		URL:     "https://www.youtube.com/some-page",
+		Title:   `A title`,
+		Content: `Video Description`,
+	}
+	testEntry := &model.Entry{
+		URL:     "https://www.youtube.com/some-page",
+		Title:   `A title`,
+		Content: `Video Description`,
+	}
+	ApplyContentRewriteRules(testEntry, ``)
+
+	if !reflect.DeepEqual(testEntry, controlEntry) {
+		t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
+	}
+}
+
+func TestRewriteYoutubeLinkAndCustomEmbedURL(t *testing.T) {
 	os.Clearenv()
 	os.Clearenv()
 	os.Setenv("YOUTUBE_EMBED_URL_OVERRIDE", "https://invidious.custom/embed/")
 	os.Setenv("YOUTUBE_EMBED_URL_OVERRIDE", "https://invidious.custom/embed/")
 
 
@@ -115,6 +155,46 @@ func TestRewriteWithYoutubeLinkAndCustomEmbedURL(t *testing.T) {
 	}
 	}
 }
 }
 
 
+func TestRewriteYoutubeVideoLinkUsingInvidious(t *testing.T) {
+	config.Opts = config.NewOptions()
+	controlEntry := &model.Entry{
+		URL:     "https://www.youtube.com/watch?v=1234",
+		Title:   `A title`,
+		Content: `<iframe width="650" height="350" frameborder="0" src="https://yewtu.be/embed/1234" allowfullscreen></iframe><br>Video Description`,
+	}
+	testEntry := &model.Entry{
+		URL:     "https://www.youtube.com/watch?v=1234",
+		Title:   `A title`,
+		Content: `Video Description`,
+	}
+
+	ApplyContentRewriteRules(testEntry, `add_youtube_video_using_invidious_player`)
+
+	if !reflect.DeepEqual(testEntry, controlEntry) {
+		t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
+	}
+}
+
+func TestRewriteYoutubeShortLinkUsingInvidious(t *testing.T) {
+	config.Opts = config.NewOptions()
+	controlEntry := &model.Entry{
+		URL:     "https://www.youtube.com/shorts/1LUWKWZkPjo",
+		Title:   `A title`,
+		Content: `<iframe width="650" height="350" frameborder="0" src="https://yewtu.be/embed/1LUWKWZkPjo" allowfullscreen></iframe><br>Video Description`,
+	}
+	testEntry := &model.Entry{
+		URL:     "https://www.youtube.com/shorts/1LUWKWZkPjo",
+		Title:   `A title`,
+		Content: `Video Description`,
+	}
+
+	ApplyContentRewriteRules(testEntry, `add_youtube_video_using_invidious_player`)
+
+	if !reflect.DeepEqual(testEntry, controlEntry) {
+		t.Errorf(`Not expected output: got "%+v" instead of "%+v"`, testEntry, controlEntry)
+	}
+}
+
 func TestRewriteWithInexistingCustomRule(t *testing.T) {
 func TestRewriteWithInexistingCustomRule(t *testing.T) {
 	controlEntry := &model.Entry{
 	controlEntry := &model.Entry{
 		URL:     "https://www.youtube.com/watch?v=1234",
 		URL:     "https://www.youtube.com/watch?v=1234",