You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
2.4 KiB
98 lines
2.4 KiB
package cmd |
|
|
|
import ( |
|
"github.com/spf13/cobra" |
|
"net/url" |
|
"fmt" |
|
"os" |
|
"strings" |
|
"time" |
|
"bufio" |
|
"log" |
|
"github.com/terorie/yt-mango/apijson" |
|
) |
|
|
|
var channelDumpCmd = cobra.Command{ |
|
Use: "dumpurls <channel ID> <file>", |
|
Short: "Get all public video URLs from channel", |
|
Long: "Write all videos URLs of a channel to a file", |
|
Args: cobra.ExactArgs(2), |
|
Run: func(cmd *cobra.Command, args []string) { |
|
channelID := args[0] |
|
fileName := args[1] |
|
|
|
if !matchChannelID.MatchString(channelID) { |
|
// Check if youtube.com domain |
|
_url, err := url.Parse(channelID) |
|
if err != nil || (_url.Host != "www.youtube.com" && _url.Host != "youtube.com") { |
|
fmt.Fprintln(os.Stderr, "Not a channel ID:", channelID) |
|
os.Exit(1) |
|
} |
|
|
|
// Check if old /user/ URL |
|
if strings.HasPrefix(_url.Path, "/user/") { |
|
// TODO Implement extraction of channel ID |
|
fmt.Fprintln(os.Stderr, "New /channel/ link is required!\n" + |
|
"The old /user/ links do not work.") |
|
os.Exit(1) |
|
} |
|
|
|
// Remove /channel/ path |
|
channelID = strings.TrimPrefix(_url.Path, "/channel/") |
|
if len(channelID) == len(_url.Path) { |
|
// No such prefix to be removed |
|
fmt.Fprintln(os.Stderr, "Not a channel ID:", channelID) |
|
os.Exit(1) |
|
} |
|
|
|
// Remove rest of path from channel ID |
|
slashIndex := strings.IndexRune(channelID, '/') |
|
if slashIndex != -1 { |
|
channelID = channelID[:slashIndex] |
|
} |
|
} |
|
|
|
log.Printf("Starting work on channel ID \"%s\".", channelID) |
|
startTime := time.Now() |
|
|
|
var flags int |
|
if force { |
|
flags = os.O_WRONLY | os.O_CREATE | os.O_TRUNC |
|
} else { |
|
flags = os.O_WRONLY | os.O_CREATE | os.O_EXCL |
|
} |
|
|
|
file, err := os.OpenFile(fileName, flags, 0640) |
|
defer file.Close() |
|
writer := bufio.NewWriter(file) |
|
defer writer.Flush() |
|
|
|
if err != nil { |
|
fmt.Fprintln(os.Stderr, err) |
|
os.Exit(1) |
|
} |
|
|
|
totalURLs := 0 |
|
for i := offset; true; i++ { |
|
channelURLs, err := apijson.GetChannelVideoURLs(channelID, uint(i)) |
|
if err != nil { |
|
log.Printf("Aborting on error %v.", err) |
|
break |
|
} |
|
if len(channelURLs) == 0 { |
|
log.Printf("Page %d returned no videos.", i) |
|
break |
|
} |
|
totalURLs += len(channelURLs) |
|
log.Printf("Received page %d: %d videos.", i, len(channelURLs)) |
|
|
|
for _, _url:= range channelURLs { |
|
_, err := writer.WriteString(_url + "\n") |
|
if err != nil { panic(err) } |
|
} |
|
} |
|
|
|
duration := time.Since(startTime) |
|
log.Printf("Got %d URLs in %s.", totalURLs, duration.String()) |
|
}, |
|
}
|
|
|