kantv

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 20, 2020 License: GPL-3.0 Imports: 12 Imported by: 1

Documentation

Index

Constants

View Source
const (
	FlagVerbose = "verbose"
	FlagURL     = "url"
	FlagTvid    = "tvid"
	FlagPartid  = "partid"
	FlagOutDir  = "outdir"
)

Constants for flag names. They should all begin with "Flag*".

Variables

View Source
var CmdCountry = &cli.Command{
	Name:  "country",
	Usage: "Get country list.",
	Action: func(c *cli.Context) error {
		var obj, err = api.SendRequest(api.NewGetCountryRequest())
		err = checkError(err, obj)
		if err != nil {
			return err
		}

		f := "%s: %s (%s)\n"
		fmt.Printf(f, "iso_code", "name_cn", "name_en")
		for _, v := range obj["data"].([]interface{}) {
			m := v.(map[string]interface{})
			fmt.Printf(f, m["iso_code"].(string), m["name_cn"].(string), m["name"].(string))
		}
		return nil
	},
}

CmdCountry defines the country-related commands.

View Source
var CmdDownload = &cli.Command{
	Name:    "download",
	Aliases: []string{"d", "dl"},
	Usage: "Download a video with a tvid or specifying an URL, plus other options.\n" +
		"Find more using command: $ kantv d --help",
	Flags: []cli.Flag{
		&cli.StringFlag{
			Name:  FlagURL,
			Usage: "Specify the URL of the video to download.",
		},
		&cli.StringFlag{
			Name:  FlagTvid,
			Usage: "Specify the tvid of the video to download.",
		},
		&cli.StringFlag{
			Name:  FlagPartid,
			Usage: "Specify the partid of the video to download.",
		},
		&cli.StringFlag{
			Name:  FlagOutDir,
			Usage: "Specify the output dir.",
		},
	},
	Action: func(c *cli.Context) error {

		url := c.String(FlagURL)
		tvid := c.String(FlagTvid)
		partid := c.String(FlagPartid)
		outdir := c.String(FlagOutDir)
		if url == "" && tvid == "" {
			return fmt.Errorf("you must specify at least one of tvid or video URL")
		}

		if url != "" && tvid != "" {
			return fmt.Errorf("please do not specify both tvid and video URL")
		}

		if url != "" {
			var err error
			tvid, partid, err = util.ExtractTvidPartidFromURL(url)
			if err != nil {
				return err
			}
			fmt.Printf("Parsed tvid: %s; partid: %s\n", tvid, partid)
		}

		// Tvid is specified
		var obj, err = api.SendRequest(api.NewGetVideoInfoRequest(tvid, partid))
		err = checkError(err, obj)
		if err != nil {
			return err
		}

		data := obj["data"].(map[string]interface{})
		generalInfo := data["info"].(map[string]interface{})
		videoTitle := generalInfo["title"].(string)
		playInfo := data["playinfo"].(map[string]interface{})
		partID := int(playInfo["part"].(float64))
		m3u8URL := playInfo["url"].(string)
		fmt.Printf("Downloading: %s...\n", videoTitle)
		fmt.Printf("Will download from this link: %s\n", m3u8URL)

		baseURL, errBaseURL := util.ExtractM3u8BaseURL(m3u8URL)
		if errBaseURL != nil {
			return errBaseURL
		}

		b, errM3u8 := util.FetchLinkContent(m3u8URL)
		if errM3u8 != nil {
			return errM3u8
		}

		p, listType, errPlaylist := m3u8.DecodeFrom(bytes.NewReader(b), true)
		if errPlaylist != nil {
			return errPlaylist
		}

		if util.VerboseMode {
			switch listType {
			case m3u8.MEDIA:
				mediapl := p.(*m3u8.MediaPlaylist)
				fmt.Printf("MediaPL:\n%+v\n", mediapl)
			case m3u8.MASTER:
				masterpl := p.(*m3u8.MasterPlaylist)
				fmt.Printf("MasterPL:\n%+v\n", masterpl)
			}
		}

		if listType != m3u8.MEDIA {
			return fmt.Errorf("please report this error, the server returns a Master playlist")
		}

		// Download all videos.
		// TODO(#8): Need to refactor this codes. Allow specifying file name.
		var wd string
		if outdir == "" {

			wd, err = os.Getwd()
			if err != nil {
				return err
			}
		} else {
			wd = outdir
			_ = os.MkdirAll(wd, 0744)
		}

		folderName := util.SanitizeFileName(videoTitle)
		_ = os.Mkdir(path.Join(wd, folderName), 0744)
		if util.VerboseMode {
			fmt.Println(path.Join(wd, folderName))
		}

		fmt.Println("Saving all files to folder: " + folderName)
		playlist := p.(*m3u8.MediaPlaylist)
		for i, segment := range playlist.Segments {
			if segment != nil {
				fullURL := baseURL + segment.URI
				if util.VerboseMode {
					fmt.Println("\nDownloading from: " + fullURL)
				}

				startPercentage := float64(i) / float64(len(playlist.Segments)) * 100.0
				finishPercentage := float64(i+1) / float64(len(playlist.Segments)) * 100.0
				fileName := strconv.Itoa(partID) + "-" + util.SanitizeFileName(segment.URI)
				filePath := path.Join(wd, folderName, fileName)
				fileInfo, errStat := os.Stat(filePath)
				fmt.Printf("\r(%.2f%%) Downloading: %s", startPercentage, fileName)
				if errStat != nil && os.IsNotExist(errStat) {

					fmt.Printf("\r(%.2f%%) Downloading: %s", finishPercentage, fileName)
					b, e := util.FetchLinkContentWithRetry(fullURL)
					if e != nil {
						return fmt.Errorf("unable to download %s even after %d times of retry",
							fullURL, util.RetryTimes)
					}
					err := ioutil.WriteFile(filePath, b, 0744)
					if err != nil {
						return err
					}
				} else if errStat != nil {
					return errStat
				} else if fileInfo.IsDir() {
					return fmt.Errorf("file name is taken by a dir: %s", filePath)
				} else {

				}
			} else {

				if util.VerboseMode {
					fmt.Printf("Saw a nil segment at index: %d\n", i)
				}
			}
		}
		fmt.Println()
		return nil
	},
}

CmdDownload defines the downloading-related commands.

Functions

func Cli

func Cli()

Cli is the entry of the command line interface.

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL