historyposter/hp/detector.go

187 lines
3.6 KiB
Go
Raw Normal View History

package hp
2020-09-21 21:44:29 +00:00
import (
"context"
"database/sql"
"io/ioutil"
2020-09-21 21:44:29 +00:00
"os"
"path/filepath"
"time"
"git.eeqj.de/sneak/goutil"
2020-09-22 03:30:12 +00:00
// db driver:
_ "github.com/mattn/go-sqlite3"
"github.com/rs/zerolog/log"
2020-09-21 21:44:29 +00:00
)
2020-09-22 03:30:12 +00:00
func (hp *HistoryPoster) postURLs(ctx context.Context, cancel context.CancelFunc) {
log.Info().Msg("finding history files")
files, err := findHistoryFiles()
if err != nil {
hp.shutdown(err.Error(), -1)
}
for _, v := range files {
hl, err := dumpHistoryFromChromeHistoryFile(v)
if err != nil {
log.Error().
Err(err).
Msg("unable to read history from file")
hp.shutdown(err.Error(), -1)
}
for _, hitem := range hl {
2020-09-22 03:30:12 +00:00
hp.processURLFromHistory(hitem)
}
}
}
2020-09-22 03:30:12 +00:00
func (hp *HistoryPoster) processURLFromHistory(hi historyItem) {
log.Debug().
2020-09-22 03:30:12 +00:00
Str("url", hi.URL).
Msg("got url to process")
2020-09-22 03:30:12 +00:00
if hp.store.URLAlreadySeen(hi.URL) {
return
}
log.Debug().
2020-09-22 03:30:12 +00:00
Str("url", hi.URL).
Msg("url is new, must be posted")
2020-09-22 03:30:12 +00:00
err := hp.postURL(hi)
if err != nil {
log.Error().
Err(err).
Msg("url could not be posted :(")
} else {
2020-09-22 03:30:12 +00:00
hp.store.MarkURLSeen(hi.URL)
}
}
2020-09-22 03:30:12 +00:00
func (hp *HistoryPoster) postURL(hi historyItem) error {
// FIXME
2020-09-22 03:30:12 +00:00
// panic("unimplemented")
return nil
}
func findHistoryFiles() ([]string, error) {
2020-09-22 03:30:12 +00:00
// FIXME make this support safari one day
2020-09-21 21:44:29 +00:00
home := os.Getenv("HOME")
chromeDir := home + "/Library/Application Support/Google/Chrome"
defaultProfileDir := chromeDir + "/Default"
output := make([]string, 0)
output = append(output, defaultProfileDir+"/History")
otherProfiles, err := filepath.Glob(chromeDir + "/Profile *")
if err != nil {
return nil, err
2020-09-21 21:44:29 +00:00
}
for _, v := range otherProfiles {
output = append(output, v+"/History")
}
// FIXME check to see if these files actually exist or not
return output, nil
}
type historyItem struct {
2020-09-22 03:30:12 +00:00
lastVisitTime time.Time
URL string
title string
visitCount int
}
func dumpHistoryFromChromeHistoryFile(path string) ([]historyItem, error) {
tempdir, err := ioutil.TempDir(os.Getenv("TMPDIR"), "historyposter")
if err != nil {
return nil, err
}
log.Debug().
Str("tempdir", tempdir).
Msg("created tempdir")
dbfn := tempdir + "/History"
2020-09-22 03:30:12 +00:00
err = goutil.CopyFile(path, dbfn)
if err != nil {
log.Error().
Str("source", path).
Str("target", dbfn).
Err(err).
Msg("unable to copy history file")
return nil, err
}
log.Debug().
Str("dbfn", dbfn).
Msg("copied history file")
defer func() {
os.RemoveAll(tempdir)
log.Debug().
Str("tempdir", tempdir).
Msg("removed tempdir")
}()
db, err := sql.Open("sqlite3", dbfn)
if err != nil {
return nil, err
}
log.Debug().
Str("dbfn", dbfn).
Msg("history file opened")
defer func() {
db.Close()
log.Debug().
Str("filename", dbfn).
Msg("closed history file")
}()
query := `
SELECT
last_visit_time,
url,
title,
visit_count
FROM
urls
ORDER BY
last_visit_time DESC
`
rows, err := db.Query(query)
if err != nil {
return nil, err
}
2020-09-22 03:30:12 +00:00
if rows.Err() != nil {
return nil, rows.Err()
}
defer rows.Close()
output := make([]historyItem, 0)
for rows.Next() {
2020-09-22 03:30:12 +00:00
// log.Debug().Msg("processing row")
var lastVisitTime int64
var url string
var title string
2020-09-22 03:30:12 +00:00
var visitCount int
err := rows.Scan(&lastVisitTime, &url, &title, &visitCount)
if err != nil {
log.Debug().Err(err).Msg("row error")
return nil, err
}
2020-09-22 03:30:12 +00:00
t := goutil.TimeFromWebKit(lastVisitTime).UTC()
hi := historyItem{
2020-09-22 03:30:12 +00:00
lastVisitTime: t,
URL: url,
title: title,
visitCount: visitCount,
}
output = append(output, hi)
}
2020-09-22 03:30:12 +00:00
// pp.Print(output)
return output, nil
2020-09-21 21:44:29 +00:00
}