feat: support opml from youtube
All checks were successful
build / build (push) Successful in 1m55s

This commit is contained in:
Viktor Varland 2025-04-08 12:32:12 +02:00
parent 4dc4c380c4
commit 3c2ec61635
Signed by: varl
GPG key ID: 7459F0B410115EE8
5 changed files with 60 additions and 20 deletions

View file

@ -12,13 +12,12 @@ out_dir = "./vids" # path to archive vids
[provider.youtube]
cmd = "./yt-dlp" # path to yt-dlp binary
quality = "res:1080" # set the preferred quality
output_path_template = "" # yt-dlp output template
output_path_template = "s%(upload_date>%Y)s/%(channel)s.s%(upload_date>%Y)Se%(upload_date>%m%d)S.%(title)s.%(id)s-1080p.%(ext)s" # yt-dlp output template
url = "https://www.youtube.com" # full yt url
throttle = 1 # throttle yt request
throttle = 5 # throttle yt request, 5s works well
range = "1:5:1" # downloads videos in range 1-5: [START][:STOP][:STEP]
after_date = "20250326" # not in use
cookies = false # control use of cookies file
cookies_file = "./cookies.txt" # pass user cookies to yt
after_date = "20250326" # only download videos after date
cookies_file = "./cookies.txt" # pass user cookies to yt, blank to disable
opml_file = "./opml.xml" # the opml file to use
```
@ -29,14 +28,14 @@ opml_file = "./opml.xml" # the opml file to use
<opml version="1.1">
<body>
<outline ...>
<outline .../>
<outline .../>
<outline .../>
<outline text="" title="" xmlUrl="" .../>
<outline text="" title="" xmlUrl="" .../>
<outline text="" title="" xmlUrl="" .../>
</outline>
<outline ...>
<outline .../>
<outline .../>
<outline .../>
<outline text="" title="" xmlUrl="" .../>
<outline text="" title="" xmlUrl="" .../>
<outline text="" title="" xmlUrl="" .../>
</outline>
</body>
</opml>
@ -59,6 +58,38 @@ E.g. from Chromium:
yt-dlp --cookies-from-browser chromium --cookies cookies.txt
```
## Scheduling
### systemd
`~/.config/systemd/user/subsyt-archival.service`
```
[Unit]
Description=subsyt archival of yt subscribtions
[Service]
Type=oneshot
ExecStart=/home/varl/yt/yt-dlp -U
ExecStart=/home/varl/yt/subsyt
WorkingDirectory=/home/varl/yt
```
`~/.config/systemd/user/subsyt-archival.timer`
```
[Unit]
Description=subsyt archival on boot and daily
[Timer]
OnCalendar=*-*-* 4:00:00
Persistent=true
AccuracySec=1us
RandomizedDelaySec=30
[Install]
WantedBy=timers.target
```
## Container
```
@ -97,3 +128,7 @@ podman run --rm \
│   │   └── Technology_Connextras.s2025e0331.An_unplanned_trip_from_Chicago_to_Milwaukee_in_an_electric_car.3GUQdrpduo0-1080p.webm
│   └── tvshow.nfo
```
## Generate OPML
E.g. https://github.com/jeb5/YouTube-Subscriptions-RSS

View file

@ -13,7 +13,6 @@ type Provider struct {
Range string
After_date string
Cmd string
Cookies bool
Cookies_file string
Opml_file string
Quality string

View file

@ -10,7 +10,6 @@ import (
"os/exec"
"path/filepath"
"strconv"
"strings"
"sync"
"git.meatbag.se/varl/subsyt/internal/config"
@ -27,16 +26,22 @@ func Youtube(d Download, p config.Provider) {
archive := filepath.Join(d.OutDir, "archive.txt")
outdir := d.OutDir
curl := strings.TrimPrefix(d.Url, "/feed/")
furl, err := url.JoinPath(p.Url, curl, "videos")
opmlUrl, err := url.Parse(d.Url)
if err != nil {
panic(err)
}
q := opmlUrl.Query()
cid := q.Get("channel_id")
if cid == "" {
log.Fatal("no channel !")
}
fullUrl, err := url.Parse(furl)
fullUrl, err := url.Parse(p.Url)
if err != nil {
panic(err)
}
channelUrl := fullUrl.JoinPath("channel", cid, "videos")
throttle := strconv.Itoa(p.Throttle)
@ -70,7 +75,7 @@ func Youtube(d Download, p config.Provider) {
args = append(args, "--no-simulate")
}
if p.Cookies == true {
if p.Cookies_file != "" {
args = append(args, "--cookies")
args = append(args, p.Cookies_file)
} else {
@ -82,7 +87,7 @@ func Youtube(d Download, p config.Provider) {
args = append(args, p.After_date)
}
args = append(args, fullUrl.String())
args = append(args, channelUrl.String())
cmd := exec.Command(p.Cmd, args...)
stdout, err := cmd.StdoutPipe()
@ -95,7 +100,7 @@ func Youtube(d Download, p config.Provider) {
log.Fatal(err)
}
log.Printf("[%s] running yt-dlp for: %s\n", d.OutDir, d.Url)
log.Printf("[%s] running yt-dlp with args: %v\n", d.OutDir, args)
var wg sync.WaitGroup
wg.Add(2)

View file

@ -25,7 +25,7 @@ func WriteEpisodeNFO(ep models.Episode, info_path string) {
}
func WriteShowInfo(show models.Show, out_path string) {
log.Printf("writing info from '%s' to '%s'\n", show, out_path)
log.Printf("writing info from '%v' to '%s'\n", show, out_path)
xmlData, err := xml.MarshalIndent(show, "", " ")
if err != nil {

View file

@ -2,6 +2,7 @@ with (import <nixpkgs> {});
mkShell {
buildInputs = [
go_1_24
yt-dlp
];