Source

ukiyo / ukiyo.go

package main

import (
	"fmt"
	"github.com/jmoiron/go-pkg-optarg"
	"strconv"
	"strings"
)

const VERSION = "0.1b"

type Options struct {
	Help            bool
	Version         bool
	Verbose         bool
	Update          bool
	SetDownloadPath string
	Download        bool
	ListSites       bool
	AddSite         string
	RemoveSite      string
	SetSitePriority string
	List            bool
	Add             bool
	Remove          bool
	Sync            bool
	Search          bool
	Show            bool
	Filter          *Filter
}

var opts Options

// print only if verbose is on
func vPrintf(s string, x ...interface{}) {
	if opts.Verbose {
		fmt.Printf(s, x...)
	}
}

func main() {
	defer config.db.Close()

	if opts.Help {
		optarg.Usage()
		return
	}
	if opts.Version {
		fmt.Printf("%s\n", VERSION)
		return
	}
	if opts.Verbose {
		vPrintf("Verbosity on.\n")
	}

	if len(opts.SetDownloadPath) > 0 {
		config.SetVal("DownloadPath", opts.SetDownloadPath)
		return
	}

	if len(opts.SetSitePriority) > 0 {
		if len(optarg.Remainder) != 1 {
			fmt.Printf("Error: --set-site-priority requires a name and a priority.\n")
			return
		}
		priority, err := strconv.ParseInt(optarg.Remainder[0], 10, 32)
		if err != nil {
			fmt.Printf("Error: priority must be a valid integer.\n")
			return
		}
		SetSitePriority(opts.SetSitePriority, int(priority))
	}

	if opts.ListSites {
		ListSites()
		return
	}

	if len(opts.AddSite) > 0 {
		var priority int
		var err error
		name := opts.AddSite
		if len(optarg.Remainder) == 0 {
			fmt.Printf("Error: --add-site requires at least a name and a url for argument.")
			return
		}
		url := optarg.Remainder[0]

		// set the optional priority, or use the max
		if len(optarg.Remainder) > 1 {
			priority, err = strconv.Atoi(optarg.Remainder[1])
			if err != nil {
				fmt.Printf("Error with priority argument: %s\n", err)
			}
		} else {
			row := config.db.QueryRow("select max(priority) from sites")
			err = row.Scan(&priority)
			if err != nil {
				priority = 1
			} else {
				priority += 1
			}
		}

		AddSite(name, url, priority)
		return
	}

	if len(opts.RemoveSite) > 0 {
		RemoveSite(opts.RemoveSite)
		return
	}

	if opts.Update {
		Update()
		return
	}

	if opts.Search {
		Search(optarg.Remainder...)
		return
	}

	if opts.Show {
		Show(optarg.Remainder...)
		return
	}

	DownloadChapters(optarg.Remainder...)
}

func Update() {
	UpdateSites(false)
}

func SetSitePriority(name string, priority int) {
	config.SetSitePriority(name, priority)
}

func ListSites() {
	var err error
	rows := Query(config.db, "SELECT name, url, priority FROM sites ORDER BY priority")

	for rows.Next() {
		site := new(Site)
		err = rows.Scan(&site.Name, &site.Url, &site.Priority)
		if err == nil {
			fmt.Printf(" %d. %s [%s]\n", site.Priority, site.Name, site.Url)
		} else {
			fmt.Printf("Error: %s\n", err)
		}
	}
}

func Search(terms ...string) {
	UpdateSites(false)
	series, err := FindSeries(true, terms...)
	if err != nil {
		fmt.Printf("Error searching for terms: %s\n", err)
	}

	for _, s := range series {
		fmt.Printf(" * %s (%s)\n", s.Name, s.Site)
	}
}

func Show(terms ...string) {
	UpdateSites()
	series, err := FindOneSeries(true, terms...)
	if err != nil {
		fmt.Printf("Error searching for terms: %s\n", err)
	}

	if len(series) == 0 {
		fmt.Printf("No series found matching term %s\n", strings.Join(terms, " "))
		return
	}
	if len(series) > 1 {
		fmt.Printf("Found %d series matching term \"%s\":\n", len(series), strings.Join(terms, " "))
		for _, s := range series {
			fmt.Printf(" * %s (%s)\n", s.Name, s.Site)
		}
		fmt.Printf("Try using the exact name (or key) of a series.\n")
		return
	}

	chapters := UpdateChapters(series[0].Name)
	for _, c := range chapters {
		if opts.Filter.Match(c.Number) {
			fmt.Printf(" * %s %s (%s)\n", c.Series, c.Number, c.Site)
		}
	}
}

func DownloadChapters(terms ...string) {
	UpdateSites()
	series, err := FindOneSeries(true, terms...)
	if err != nil {
		fmt.Printf("Error searching for terms: %s\n", err)
	}

	if len(series) == 0 {
		fmt.Printf("No series found matching term %s\n", strings.Join(terms, " "))
		return
	}
	if len(series) > 1 {
		fmt.Printf("Found %d series matching term \"%s\":\n", len(series), strings.Join(terms, " "))
		for _, s := range series {
			fmt.Printf(" * %s (%s)\n", s.Name, s.Site)
		}
		fmt.Printf("Try using the exact name (or key) of a series.\n")
		return
	}

	chapters := UpdateChapters(series[0].Name)
	for _, c := range chapters {
		if opts.Filter.Match(c.Number) {
			DownloadChapter(c)
		}
	}

}

func AddSite(name, url string, priority int) {
	err := config.AddSite(name, url, priority)
	if err != nil {
		fmt.Printf("Error adding site: %s\n", err)
	}
}

func RemoveSite(name string) {
	err := config.RemoveSite(name)
	if err != nil {
		fmt.Printf("Error removing site: %s\n", err)
	}
}

func init() {
	optarg.HeaderFmt = "\n  %s options"

	optarg.Add("h", "help", "Show help.", false)
	optarg.Add("", "version", "Show version and exit.", false)
	optarg.Add("v", "verbose", "Show more output.", false)

	optarg.Header("Downloading")
	optarg.Add("u", "update", "Update all site & series info.", false)
	optarg.Add("", "sync", "Sync series info with what is on disk.", false)
	optarg.Add("d", "download", "Download new chapters from series.", false)
	optarg.Add("", "set-download-path",
		fmt.Sprintf("Change destination for sync and downloads. (Current: %s)", config.DownloadPath), "")

	optarg.Header("Sites")
	optarg.Add("", "sites", "List sites.", false)
	optarg.Add("", "add-site", "<name> <url> [priority], Add a site.", "")
	optarg.Add("", "rm-site", "<name>, Remove a site.", "")
	optarg.Add("", "set-site-priority", "<name> <priority>, Set download priority.", "")

	optarg.Header("Series")
	optarg.Add("l", "list", "List series being followed.", false)
	optarg.Add("a", "add", "Add a series to the follow list.", false)
	optarg.Add("r", "remove", "Remove a series from the follow list.", false)
	optarg.Add("", "del", "Alias for --remove", false)
	optarg.Add("", "set", "Set a chapter for a series.", false)
	optarg.Add("", "find", "Find a series.", false)
	optarg.Add("", "search", "Alias for --find.", false)

	optarg.Header("Chapters")
	optarg.Add("s", "show", "Show chapters from a series.", false)
	optarg.Add("f", "filter", "Filter chapters to show or download.", "")

	opts.Filter = CompileFilter("")

	for opt := range optarg.Parse() {
		switch opt.Name {
		case "help":
			opts.Help = opt.Bool()
		case "version":
			opts.Version = opt.Bool()
		case "verbose":
			opts.Verbose = opt.Bool()
		// downloading
		case "update":
			opts.Update = opt.Bool()
		case "sync":
			opts.Sync = opt.Bool()
		case "download":
			opts.Download = opt.Bool()
		case "set-download-path":
			opts.SetDownloadPath = opt.String()
		// sites
		case "sites":
			opts.ListSites = opt.Bool()
		case "add-site":
			opts.AddSite = opt.String()
		case "rm-site":
			opts.RemoveSite = opt.String()
		case "set-site-priority":
			opts.SetSitePriority = opt.String()
		// series
		case "list":
		case "add":
		case "rm", "del":
		case "set":
		case "find", "search":
			opts.Search = opt.Bool()
		// chapters
		case "show":
			opts.Show = opt.Bool()
		case "filter":
			opts.Filter = CompileFilter(opt.String())
		}
	}

}