List of commits:
Subject Hash Author Date (UTC)
Fix CLI for channel dumps e2ea0a179ea584fa994a05dc913298c904060412 terorie 2018-07-29 22:10:50
Move work command fec4a5e0677f2f72a87db79fd673aab17c776241 terorie 2018-07-29 21:56:21
Set API by CLI a9589194e7b5cbd33d5cf0fc96d71334d094520a terorie 2018-07-29 21:53:47
include GPLv3 e9b14041d4ecc991f1c40ecff4e13b737b1ccc15 terorie 2018-07-29 21:34:50
Refactor API selection c3b6047f98184e618ceb88965583e2aabe71fb7d terorie 2018-07-29 21:34:19
Channel url dump CLI 0429c2f1ceef84d2e7505591a0fee9babce7eb52 terorie 2018-07-29 02:09:59
Cobra & channel video dumper b6a0e418403b24df1162b749878d24a9918f9b8c terorie 2018-07-28 23:49:38
Rename project to yt-mango 0f19dcfd3f54c3902a0aa97b8c0f4aa932538d73 terorie 2018-07-28 15:10:49
Remove debug output 9f5b9dd87324b30044723539875ee8a419b7eee0 terorie 2018-07-28 14:45:13
Decode video formats bafc6c4ad3587e2de7a88cf532ad1df5ee5a7964 terorie 2018-07-28 14:34:57
Add formats from youtube-dl e612768d79ed1743b415073d9dba713e785e2ea6 terorie 2018-07-28 13:33:48
Initial README 0e9d46ecadcc5b019b9fae4e356bc3360f521b5e terorie 2018-07-28 03:56:26
Initial commit 3b5744c589494163e05a9d54fba10c71e5965d6a terorie 2018-07-28 03:55:53
Commit e2ea0a179ea584fa994a05dc913298c904060412 - Fix CLI for channel dumps
Author: terorie
Author date (UTC): 2018-07-29 22:10
Committer name: terorie
Committer date (UTC): 2018-07-29 22:10
Parent(s): fec4a5e0677f2f72a87db79fd673aab17c776241
Signing key:
Tree: 38e0a55f10ca8dc3b6fcc4ef78335861056ceb4c
File Lines added Lines deleted
api/api.go 8 0
cmd/channeldump.go 36 18
main.go 3 1
File api/api.go changed (mode: 100644) (index 06ccb2b..32f2f90)
... ... type API struct {
16 16 // TODO Fallback option // TODO Fallback option
17 17 var DefaultAPI *API = nil var DefaultAPI *API = nil
18 18
19 // TODO: Remove when everything is implemented
20 var TempAPI = API{
21 GetVideo: apiclassic.GetVideo,
22 GetVideoSubtitleList: apiclassic.GetVideoSubtitleList,
23 GetChannel: apiclassic.GetChannel,
24 GetChannelVideoURLs: apijson.GetChannelVideoURLs,
25 }
26
19 27 var ClassicAPI = API{ var ClassicAPI = API{
20 28 GetVideo: apiclassic.GetVideo, GetVideo: apiclassic.GetVideo,
21 29 GetVideoSubtitleList: apiclassic.GetVideoSubtitleList, GetVideoSubtitleList: apiclassic.GetVideoSubtitleList,
File cmd/channeldump.go changed (mode: 100644) (index b1b843c..4a1ebf0)
... ... package cmd
3 3 import ( import (
4 4 "github.com/spf13/cobra" "github.com/spf13/cobra"
5 5 "net/url" "net/url"
6 "fmt"
7 6 "os" "os"
8 7 "strings" "strings"
9 8 "time" "time"
10 9 "bufio" "bufio"
11 10 "log" "log"
12 11 "github.com/terorie/yt-mango/api" "github.com/terorie/yt-mango/api"
12 "fmt"
13 13 ) )
14 14
15 15 var channelDumpCmd = cobra.Command{ var channelDumpCmd = cobra.Command{
16 Use: "dumpurls <channel ID> <file>",
16 Use: "dumpurls <channel ID> [file]",
17 17 Short: "Get all public video URLs from channel", Short: "Get all public video URLs from channel",
18 18 Long: "Write all videos URLs of a channel to a file", Long: "Write all videos URLs of a channel to a file",
19 Args: cobra.ExactArgs(2),
19 Args: cobra.RangeArgs(1, 2),
20 20 Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
21 printResults := false
22 fileName := ""
21 23 channelID := args[0] channelID := args[0]
22 fileName := args[1]
24 if len(args) != 2 {
25 printResults = true
26 } else {
27 fileName = args[1]
28 }
23 29
24 30 if !matchChannelID.MatchString(channelID) { if !matchChannelID.MatchString(channelID) {
25 31 // Check if youtube.com domain // Check if youtube.com domain
26 32 _url, err := url.Parse(channelID) _url, err := url.Parse(channelID)
27 33 if err != nil || (_url.Host != "www.youtube.com" && _url.Host != "youtube.com") { if err != nil || (_url.Host != "www.youtube.com" && _url.Host != "youtube.com") {
28 fmt.Fprintln(os.Stderr, "Not a channel ID:", channelID)
34 log.Fatal("Not a channel ID:", channelID)
29 35 os.Exit(1) os.Exit(1)
30 36 } }
31 37
32 38 // Check if old /user/ URL // Check if old /user/ URL
33 39 if strings.HasPrefix(_url.Path, "/user/") { if strings.HasPrefix(_url.Path, "/user/") {
34 40 // TODO Implement extraction of channel ID // TODO Implement extraction of channel ID
35 fmt.Fprintln(os.Stderr, "New /channel/ link is required!\n" +
41 log.Fatal("New /channel/ link is required!\n" +
36 42 "The old /user/ links do not work.") "The old /user/ links do not work.")
37 43 os.Exit(1) os.Exit(1)
38 44 } }
 
... ... var channelDumpCmd = cobra.Command{
41 47 channelID = strings.TrimPrefix(_url.Path, "/channel/") channelID = strings.TrimPrefix(_url.Path, "/channel/")
42 48 if len(channelID) == len(_url.Path) { if len(channelID) == len(_url.Path) {
43 49 // No such prefix to be removed // No such prefix to be removed
44 fmt.Fprintln(os.Stderr, "Not a channel ID:", channelID)
50 log.Fatal("Not a channel ID:", channelID)
45 51 os.Exit(1) os.Exit(1)
46 52 } }
47 53
 
... ... var channelDumpCmd = cobra.Command{
62 68 flags = os.O_WRONLY | os.O_CREATE | os.O_EXCL flags = os.O_WRONLY | os.O_CREATE | os.O_EXCL
63 69 } }
64 70
65 file, err := os.OpenFile(fileName, flags, 0640)
66 defer file.Close()
67 writer := bufio.NewWriter(file)
68 defer writer.Flush()
71 var file *os.File
72 var writer *bufio.Writer
73
74 if !printResults {
75 var err error
76 file, err = os.OpenFile(fileName, flags, 0640)
77 if err != nil {
78 log.Fatal(err)
79 os.Exit(1)
80 }
81 defer file.Close()
69 82
70 if err != nil {
71 fmt.Fprintln(os.Stderr, err)
72 os.Exit(1)
83 writer = bufio.NewWriter(file)
84 defer writer.Flush()
73 85 } }
74 86
75 87 totalURLs := 0 totalURLs := 0
76 88 for i := offset; true; i++ { for i := offset; true; i++ {
77 89 channelURLs, err := api.DefaultAPI.GetChannelVideoURLs(channelID, uint(i)) channelURLs, err := api.DefaultAPI.GetChannelVideoURLs(channelID, uint(i))
78 90 if err != nil { if err != nil {
79 log.Printf("Aborting on error %v.", err)
91 log.Printf("Aborting on error: %v.", err)
80 92 break break
81 93 } }
82 94 if len(channelURLs) == 0 { if len(channelURLs) == 0 {
 
... ... var channelDumpCmd = cobra.Command{
86 98 totalURLs += len(channelURLs) totalURLs += len(channelURLs)
87 99 log.Printf("Received page %d: %d videos.", i, len(channelURLs)) log.Printf("Received page %d: %d videos.", i, len(channelURLs))
88 100
89 for _, _url:= range channelURLs {
90 _, err := writer.WriteString(_url + "\n")
91 if err != nil { panic(err) }
101 if printResults {
102 for _, _url := range channelURLs {
103 fmt.Println(_url)
104 }
105 } else {
106 for _, _url := range channelURLs {
107 _, err := writer.WriteString(_url + "\n")
108 if err != nil { panic(err) }
109 }
92 110 } }
93 111 } }
94 112
File main.go changed (mode: 100644) (index 18b1170..0b08cf1)
... ... func main() {
35 35 fmt.Println(Version) fmt.Println(Version)
36 36 os.Exit(0) os.Exit(0)
37 37 } }
38 },
39 PersistentPreRun: func(cmd *cobra.Command, args []string) {
38 40 switch forceAPI { switch forceAPI {
39 case "": break
41 case "": api.DefaultAPI = &api.TempAPI
40 42 case "classic": api.DefaultAPI = &api.ClassicAPI case "classic": api.DefaultAPI = &api.ClassicAPI
41 43 case "json": api.DefaultAPI = &api.JsonAPI case "json": api.DefaultAPI = &api.JsonAPI
42 44 default: default:
Hints:
Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://rocketgit.com/user/anomie/yt-user

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@ssh.rocketgit.com/user/anomie/yt-user

Clone this repository using git:
git clone git://git.rocketgit.com/user/anomie/yt-user

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a merge request:
... clone the repository ...
... make some changes and some commits ...
git push origin main