func loadWatched(manga *Manga) { db, err := ioutil.ReadFile("manga.db") if err != nil { logger.Error(err.Error()) return } err = json.Unmarshal(db, manga) if err != nil { logger.Error(err.Error()) return } }
func parseRSS(rss []byte, source string) (map[string]MangaEntry, error) { src := strings.Split(lib.Sanitise(string(rss[bytes.Index(rss, []byte("<item>")):])), "</item>") src = src[0 : len(src)-1] entries := map[string]MangaEntry{} var title, tmpDate string for _, line := range src { if line == "" { continue } title = line[strings.Index(line, "<title>")+7 : strings.Index(line, "</title>")] title = html.UnescapeString(title) if source == "mangafox" { title = html.UnescapeString(title) // one more time - mangafox double escape sometimes -.- } tmpDate = line[strings.Index(line, "<pubDate>")+9 : strings.Index(line, "</pubDate>")] date, err := time.Parse("Mon, 2 Jan 2006 15:04:05 -0700", tmpDate) if err != nil { logger.Error(err.Error()) return nil, errors.New("parseRSS failed to parse time : " + tmpDate) } entries[strings.ToLower(title)] = MangaEntry{ Title: title, Link: line[strings.Index(line, "<link>")+6 : strings.Index(line, "</link>")], Date: date.Unix(), Desc: line[strings.Index(line, "<description>")+13 : strings.Index(line, "</description>")], } } return entries, nil }
func GetTitle(rawuri string) string { var index int ext := rawuri[strings.LastIndex(rawuri, "//")+2:] if index = strings.LastIndex(ext, "/"); index > 0 { ext = ext[index+1:] if index = strings.Index(ext, "."); index > -1 { ext = ext[index+1:] allow := []string{"htm", "html", "asp", "aspx", "php", "php3", "php5"} if !lib.HasElementString(allow, ext) { logger.Debug(fmt.Sprintf("[web.GetTitle()] Not an OK file extension: %s -> %s", rawuri, ext)) return "" } } } body, err := Get(&rawuri) if err != "" { return "" } r, regErr := regexp.Compile("<title?[^>]+>([^<]+)<\\/title>") if regErr != nil { logger.Error("[web.GetTitle()] Couldn't compile regex title regex") return "" } if title := r.FindString(string(body)); title != "" { rooturl := rawuri[strings.Index(rawuri, "//")+2:] if index = strings.Index(rooturl, "/"); index > -1 { rooturl = rooturl[:index] } return fmt.Sprintf("%s ~ %s", html.UnescapeString(lib.StripHtml(title)), rooturl) } return "" }
func Register(bot *irc.IRC) { defer logger.Info(lib.TimeTrack(lib.TimeNow(), "Loading the Urban Dictionary plugin")) events.CmdListen(&events.CmdListener{ Commands: []string{"urbandictionary", "ud"}, Help: "Looks up Urban Dictionary entries. NSFW", Syntax: bot.Config.Prefix + "ud <term> - Example: " + bot.Config.Prefix + "ud scrobble", Callback: func(input *events.Params) { uri := fmt.Sprintf("http://api.urbandictionary.com/v0/define?term=%s", url.QueryEscape(input.Data)) body, err := web.Get(&uri) if err != "" { bot.Say(input.Context, err) return } ud := &UDResponse{} jserr := json.Unmarshal(body, &ud) if jserr != nil { logger.Error("Couldn't parse UD's JSON: " + jserr.Error()) return } if ud.Result == "no_results" { bot.Say(input.Context, fmt.Sprintf("\"%s\" is not a thing on Urban Dictionary.", input.Data)) return } var resp string = "" var max int = 3 if len(ud.List) < max { max = len(ud.List) } for i := 0; i < max; i++ { resp += fmt.Sprintf("%d) %s, ", i+1, ud.List[i].Definition) } bot.Say(input.Context, ud.List[0].Word+" ~ "+lib.SingleSpace(resp[0:len(resp)-2])) }}) }
func NewStringListDB(filename string) *StringListDB { var err error var index int var data []byte var entries []string nDB := new(StringListDB) nDB.Filename = filename nDB.Entry = map[string]string{} data, err = ioutil.ReadFile("db/" + nDB.Filename) if err != nil { logger.Error(fmt.Sprintf("[storage.NewStringListDB()] Couldn't read db/%s -> %s", nDB.Filename, err.Error())) return nDB } if len(data) > 0 { entries = strings.Split(string(data), "\n") for _, line := range entries { if line == "" { continue } index = strings.Index(line, " ") nDB.Entry[line[:index]] = line[index+1:] } } return nDB }
func getFileContents(filename string) [][]byte { wordList, err := ioutil.ReadFile("data/words/" + filename + ".txt") if err != nil { logger.Error(err.Error()) return nil } return bytes.Split(wordList, []byte("\n")) }
func saveWatched(manga *Manga) { out, err := json.Marshal(*manga) if err != nil { logger.Error(err.Error()) return } ioutil.WriteFile("manga.db", out, 0666) logger.Info("Saved Manga watch list.") }
func EvListenComplex(event *ComplexEventListener) { r, err := regexp.Compile(event.Regex) if err != nil { logger.Error(fmt.Sprintf("EvListenComplex: Couldn't compile %s's Regex: %s", event.Handle, event.Regex)) return } event.r = *r complexListeners[event.Event] = append(complexListeners[event.Event], event) }
func (sdb *StringDB) Save() { var err error var data []byte data, err = json.Marshal(&sdb.Entry) if err != nil { logger.Error(fmt.Sprintf("[StringDB.Save()] Couldn't Marshal %s JSON -> %s", sdb.Filename, err.Error())) return } if len(data) > 0 { err = ioutil.WriteFile("db/"+sdb.Filename, data, 0666) } else { err = ioutil.WriteFile("db/"+sdb.Filename, []byte{}, 0666) } if err != nil { logger.Error(fmt.Sprintf("[StringDB.Save()] Couldn't save db/%s -> %s", sdb.Filename, err.Error())) return } logger.Info(fmt.Sprintf("Saved db/%s ..", sdb.Filename)) }
func NewStringDB(filename string) *StringDB { var err error var data []byte nDB := new(StringDB) nDB.Filename = filename nDB.Entry = map[string]string{} data, err = ioutil.ReadFile("db/" + nDB.Filename) if err != nil { logger.Error(fmt.Sprintf("[storage.NewStringDB()] Couldn't read db/%s -> %s", nDB.Filename, err.Error())) return nDB } if len(data) > 0 { if err = json.Unmarshal(data, &nDB.Entry); err != nil { logger.Error(fmt.Sprintf("[storage.Open()] Couldn't Unmarshal json in db/%s -> %s", nDB.Filename, err.Error())) return nDB } } return nDB }
func (irc *IRC) Connect() bufio.Reader { conn, err := net.Dial("tcp", irc.Config.Server+":"+irc.Config.Port) irc.Conn = conn if err != nil { logger.Error("Connection error") os.Exit(1) } irc.Send(fmt.Sprintf("NICK %s", irc.Config.Nicknames[0])) irc.Send(fmt.Sprintf("USER %s localhost * :%s", irc.Config.Username, irc.Config.Realname)) out := bufio.NewReader(irc.Conn) return *out }
func Register(bot *irc.IRC) { defer logger.Info(lib.TimeTrack(time.Now(), "Loading the YouTube plugin")) events.CmdListen(&events.CmdListener{ Commands: []string{"youtube", "yt"}, Help: "YouTubes stuff.", Syntax: bot.Config.Prefix + "yt <search terms> - Example: " + bot.Config.Prefix + "yt we like big booty bitches", Callback: func(input *events.Params) { ytr := &YouTubeResults{} uri := fmt.Sprintf("http://gdata.youtube.com/feeds/api/videos?q=%s&max-results=1&v=2&alt=json", url.QueryEscape(input.Data)) body, err := web.Get(&uri) if err != "" { logger.Error("YouTube Failed: " + err) bot.Say(input.Context, "Woops.") return } errr := json.Unmarshal(body, &ytr) if errr != nil { logger.Error("Couldn't parse youtube's JSON:" + errr.Error()) bot.Say(input.Context, "Herp. Check logs") return } if len(ytr.Feed.Entry) == 0 { bot.Say(input.Context, fmt.Sprintf("\"%s\" is not a thing on YouTube.", input.Data)) return } yt := &ytr.Feed.Entry[0] duration, errr := time.ParseDuration(yt.Info.Duration["seconds"] + "s") resp := fmt.Sprintf("%s ~ [%s] %s - %s views ~ http://youtu.be/%s ~ %s", *yt.Title["$t"], &duration, yt.Info.Date["$t"][0:10], lib.CommaNum(yt.Stats["viewCount"]), yt.Info.ID["$t"], yt.Info.Description["$t"]) bot.Say(input.Context, resp) resp = "" ytr = nil }}) }
func (irc *IRC) Start() { out := irc.Connect() sem <- 1 for { <-sem line, prefix, err := out.ReadLine() if err != nil { logger.Error("Connection error: " + err.Error()) os.Exit(4) } if prefix == true { sem <- 1 continue } go irc.handleData(line) } }
func (sl *StringListDB) Save() { var err error var entries string if len(sl.Entry) > 0 { for key, entry := range sl.Entry { entries += fmt.Sprintf("%s %s\n", key, entry) } entries = entries[:len(entries)-1] // no trailing \n err = ioutil.WriteFile("db/"+sl.Filename, []byte(entries), 0666) } else { err = ioutil.WriteFile("db/"+sl.Filename, []byte{}, 0666) } if err != nil { logger.Error(fmt.Sprintf("[StringListDB.Save()] Couldn't save to db/%s -> %s", sl.Filename, err.Error())) return } logger.Info(fmt.Sprintf("Saved db/%s ..", sl.Filename)) }
func ReplaceVars(aliasStr string) string { r, err := regexp.Compile("\\$\\{([a-z0-9]+)\\}") if err != nil { logger.Error(fmt.Sprintf("Couldn't compile VarReg regexp: %s", err.Error())) return aliasStr } for i := 0; i < 10; i++ { match := r.FindString(aliasStr) if match != "" { variable := Vars.GetOne(match[2 : len(match)-1]) if variable == match { aliasStr = fmt.Sprintf("%s -> Error: %q variable refers to itself.", aliasStr, variable) return aliasStr } if variable != "" { aliasStr = strings.Replace(aliasStr, match, variable, -1) } } else { return aliasStr } } return aliasStr }
// misc func (irc *IRC) findParams(params *events.Params, line string, args []string) { var command string var index int if strings.Index(args[0], "!") == -1 { // server message? params.Context = args[3] params.Nick = args[0][1:] params.Args = args[1:] params.Data = line return } params.Context = args[2] params.Nick = args[0][1:strings.Index(args[0], "!")] params.Address = args[0][strings.Index(args[0], "!")+1:] switch args[1] { case "NOTICE": fallthrough case "PRIVMSG": if args[2][0:1] != "#" { // queries params.Context = params.Nick } if args[3][1:2] == irc.Config.Prefix && args[3][2:3] != "" { command = args[3][2:] if alias.DB.HasKey(command) { // temporary, need alias/args parser aliasEntry := alias.DB.GetOne(command) index = strings.Index(aliasEntry, " ") params.Command = aliasEntry[:index] if strings.Index(aliasEntry, "${") > -1 { aliasEntry = alias.ReplaceVars(aliasEntry) } if strings.Index(aliasEntry, "{{") > -1 { var aEvent alias.Event aEvent.Populate(params, args[4:len(args)], &aliasEntry) var out bytes.Buffer t, err := template.New(command).Funcs(aEvent.TmplFuncs()).Parse(aliasEntry[index+1:]) if err != nil { params.Data = fmt.Sprintf("Couldn't parse %q template: %s", aliasEntry, err.Error()) logger.Error(params.Data) return } err = t.Execute(&out, aEvent) if err != nil { params.Data = fmt.Sprintf("Couldn't execute %q template: %s", aliasEntry, err.Error()) logger.Error(params.Data) return } params.Data = out.String() params.Args = strings.Fields(params.Data) } else { params.Data = aliasEntry[index+1:] params.Args = strings.Fields(params.Data) } } else { params.Command = command params.Args = args[4:len(args)] params.Data = strings.Join(params.Args, " ") } } else { params.Data = strings.Join(args[3:len(args)], " ")[1:] } case "NICK": params.Newnick = args[2][1:] case "JOIN": if params.Context[0:1] == ":" { params.Context = params.Context[1:] } case "PART": if len(args) > 3 { params.Message = strings.Join(args[3:], " ")[1:] } if params.Context[0:1] == ":" { // Y U NO CONSISTENT params.Context = params.Context[1:] } case "QUIT": params.Message = strings.Join(args[2:], " ")[1:] case "KICK": params.Kicknick = args[3] params.Message = strings.Join(args[4:], " ")[1:] case "MODE": // can't think why this is needed for now, dump its mojo in message params.Message = strings.Join(args[3:], " ") case "TOPIC": params.Message = strings.Join(args[3:], " ")[1:] } if params.Args == nil { params.Args = args } if params.Data == "" { params.Data = line } //fmt.Println(params) }
func catchPanic(listenType string, handle string) { if e := recover(); e != nil { logger.Error(fmt.Sprintf("Caught panic in %s \"%s\": %s", listenType, handle, e)) } }
func checkUpdates(bot *irc.IRC, source string, context string) { var manga Manga var uri, message string var watched map[string]MangaEntry loadWatched(&manga) switch source { case "mangafox": uri = "http://mangafox.me/rss/latest_manga_chapters.xml" watched = manga.MangaFox case "mangastream": uri = "http://mangastream.com/rss" watched = manga.MangaStream } data, err := web.Get(&uri) if err != "" { logger.Error(err) return } var entries map[string]MangaEntry entries, perr := parseRSS(data, source) if perr != nil { logger.Error(perr.Error()) return } keys := getKeys(source) updates := make([]irc.RatedMessage, 0) var method string var newEntry MangaEntry for title, entry := range entries { for _, key := range keys { if strings.Index(title, key) > -1 { if entry.Date > watched[key].Date { // update found switch source { case "mangastream": message = fmt.Sprintf("%s is out! \\o/ ~ %s ~ %q", entry.Title, entry.Link, entry.Desc) newEntry = MangaEntry{ Manga: entry.Title[:len(key)], Title: entry.Title, Date: entry.Date, Desc: entry.Desc, Link: entry.Link, Announce: watched[key].Announce, } case "mangafox": message = fmt.Sprintf("%s is out! \\o/ ~ %s", entry.Title, entry.Link) newEntry = MangaEntry{ Manga: entry.Title[:len(key)], Title: entry.Title, Date: entry.Date, Link: entry.Link, Announce: watched[key].Announce, } } delete(watched, key) watched[key] = newEntry if context != "" && !lib.HasElementString(watched[key].Announce, context) { if context[0:1] == "#" { method = "say" } else { method = "notice" } updates = append(updates, irc.RatedMessage{ Method: method, Target: context, Message: message, }) } for _, target := range watched[key].Announce { if target[0:1] == "#" { method = "say" } else { method = "notice" } updates = append(updates, irc.RatedMessage{ Method: method, Target: target, Message: message, }) } } } } } if len(updates) > 0 { bot.Rated(&updates) saveWatched(&manga) } else if context != "" { bot.Say(context, "Nothing new. :\\") } }