Compare commits

...

7 Commits

Author SHA1 Message Date
7337464112 check return of ReadString() 2024-04-26 13:37:38 +02:00
dbb64dcae1 bump version 2024-04-26 12:03:35 +02:00
74db3f534e fix #88: respond accordingly when user double clicks kleingebaeck.exe 2024-04-26 11:36:27 +02:00
8cc5a9e3ed missed commits 2024-02-12 13:36:29 +01:00
d2bcd7b505 fix #80: using os.MkdirAll():
Recursively create ad dir including output dir. The output dir itself
is not being created separately anymore. That way, no directory will
be created if no ads could be downloaded.
2024-02-12 13:32:25 +01:00
c59c2e2931 fix #81: add arm64 build support 2024-02-12 13:32:25 +01:00
2288806105 fix #77: use processed ad dir for duplicate checking, not slug 2024-02-10 15:15:43 +01:00
8 changed files with 53 additions and 26 deletions

View File

@@ -34,7 +34,7 @@ import (
) )
const ( const (
VERSION string = "0.3.4" VERSION string = "0.3.6"
Baseuri string = "https://www.kleinanzeigen.de" Baseuri string = "https://www.kleinanzeigen.de"
Listuri string = "/s-bestandsliste.html" Listuri string = "/s-bestandsliste.html"
Defaultdir string = "." Defaultdir string = "."

1
go.mod
View File

@@ -24,6 +24,7 @@ require (
github.com/corona10/goimagehash v1.1.0 // indirect github.com/corona10/goimagehash v1.1.0 // indirect
github.com/fatih/color v1.16.0 // indirect github.com/fatih/color v1.16.0 // indirect
github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/knadh/koanf/maps v0.1.1 // indirect github.com/knadh/koanf/maps v0.1.1 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect

2
go.sum
View File

@@ -15,6 +15,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww= github.com/jarcoal/httpmock v1.3.1 h1:iUx3whfZWVf3jT01hQTO/Eo5sAYtB2/rqaUuOtpInww=
github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jarcoal/httpmock v1.3.1/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg=
github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs=

27
main.go
View File

@@ -18,13 +18,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
package main package main
import ( import (
"bufio"
"errors" "errors"
"fmt" "fmt"
"io" "io"
"log/slog" "log/slog"
"os" "os"
"runtime"
"runtime/debug" "runtime/debug"
"github.com/inconshreveable/mousetrap"
"github.com/lmittmann/tint" "github.com/lmittmann/tint"
"github.com/tlinden/yadu" "github.com/tlinden/yadu"
) )
@@ -35,6 +38,25 @@ func main() {
os.Exit(Main(os.Stdout)) os.Exit(Main(os.Stdout))
} }
func init() {
// if we're running on Windows AND if the user double clicked the
// exe file from explorer, we tell them and then wait until any
// key has been hit, which will make the cmd window disappear and
// thus give the user time to read it.
if runtime.GOOS == "windows" {
if mousetrap.StartedByExplorer() {
fmt.Println("Do no double click kleingebaeck.exe!")
fmt.Println("Please open a command shell and run it from there.")
fmt.Println()
fmt.Print("Press any key to quit: ")
_, err := bufio.NewReader(os.Stdin).ReadString('\n')
if err != nil {
panic(err)
}
}
}
}
func Main(output io.Writer) int { func Main(output io.Writer) int {
logLevel := &slog.LevelVar{} logLevel := &slog.LevelVar{}
opts := &tint.Options{ opts := &tint.Options{
@@ -116,11 +138,6 @@ func Main(output io.Writer) int {
if err != nil { if err != nil {
return Die(err) return Die(err)
} }
err = Mkdir(outdir)
if err != nil {
return Die(err)
}
conf.Outdir = outdir conf.Outdir = outdir
// used for all HTTP requests // used for all HTTP requests

View File

@@ -22,7 +22,12 @@ freebsd/amd64
linux/amd64 linux/amd64
netbsd/amd64 netbsd/amd64
openbsd/amd64 openbsd/amd64
windows/amd64" windows/amd64
freebsd/arm64
linux/arm64
netbsd/arm64
openbsd/arm64
windows/arm64"
tool="$1" tool="$1"
version="$2" version="$2"

View File

@@ -126,21 +126,32 @@ func ScrapeAd(fetch *Fetcher, uri string) error {
advertisement.CalculateExpire() advertisement.CalculateExpire()
proceed := CheckAdVisited(fetch.Config, advertisement.Slug) // prepare ad dir name
addir, err := AdDirName(fetch.Config, advertisement)
if err != nil {
return err
}
proceed := CheckAdVisited(fetch.Config, addir)
if !proceed { if !proceed {
return nil return nil
} }
// write listing // write listing
addir, err := WriteAd(fetch.Config, advertisement) err = WriteAd(fetch.Config, advertisement, addir)
if err != nil { if err != nil {
return err return err
} }
// tell the user
slog.Debug("extracted ad listing", "ad", advertisement) slog.Debug("extracted ad listing", "ad", advertisement)
// stats
fetch.Config.IncrAds() fetch.Config.IncrAds()
// register for later checks
DirsVisited[addir] = 1
return ScrapeImages(fetch, advertisement, addir) return ScrapeImages(fetch, advertisement, addir)
} }

View File

@@ -72,19 +72,13 @@ func AdDirName(conf *Config, advertisement *Ad) (string, error) {
return buf.String(), nil return buf.String(), nil
} }
func WriteAd(conf *Config, advertisement *Ad) (string, error) { func WriteAd(conf *Config, advertisement *Ad, addir string) error {
// prepare ad dir name
addir, err := AdDirName(conf, advertisement)
if err != nil {
return "", err
}
// prepare output dir // prepare output dir
dir := filepath.Join(conf.Outdir, addir) dir := filepath.Join(conf.Outdir, addir)
err = Mkdir(dir) err := Mkdir(dir)
if err != nil { if err != nil {
return "", err return err
} }
// write ad file // write ad file
@@ -92,7 +86,7 @@ func WriteAd(conf *Config, advertisement *Ad) (string, error) {
listingfd, err := os.Create(listingfile) listingfd, err := os.Create(listingfile)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to create Adlisting.txt: %w", err) return fmt.Errorf("failed to create Adlisting.txt: %w", err)
} }
defer listingfd.Close() defer listingfd.Close()
@@ -104,17 +98,17 @@ func WriteAd(conf *Config, advertisement *Ad) (string, error) {
tmpl, err := tpl.New("adlisting").Parse(conf.Template) tmpl, err := tpl.New("adlisting").Parse(conf.Template)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to parse adlisting template: %w", err) return fmt.Errorf("failed to parse adlisting template: %w", err)
} }
err = tmpl.Execute(listingfd, advertisement) err = tmpl.Execute(listingfd, advertisement)
if err != nil { if err != nil {
return "", fmt.Errorf("failed to execute adlisting template: %w", err) return fmt.Errorf("failed to execute adlisting template: %w", err)
} }
slog.Info("wrote ad listing", "listingfile", listingfile) slog.Info("wrote ad listing", "listingfile", listingfile)
return addir, nil return nil
} }
func WriteImage(filename string, reader *bytes.Reader) error { func WriteImage(filename string, reader *bytes.Reader) error {
@@ -176,9 +170,6 @@ func CheckAdVisited(conf *Config, adname string) bool {
return false return false
} }
// register
DirsVisited[adname] = 1
// overwrite // overwrite
return true return true
} }

View File

@@ -32,7 +32,7 @@ import (
func Mkdir(dir string) error { func Mkdir(dir string) error {
if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) { if _, err := os.Stat(dir); errors.Is(err, os.ErrNotExist) {
err := os.Mkdir(dir, os.ModePerm) err := os.MkdirAll(dir, os.ModePerm)
if err != nil { if err != nil {
return fmt.Errorf("failed to create directory %s: %w", dir, err) return fmt.Errorf("failed to create directory %s: %w", dir, err)
} }