From 66f4ca6f25879144d27ec7740dcb12fc72b9487e Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Fri, 27 Nov 2020 22:36:51 -0800 Subject: [PATCH 01/12] Fixes token login, properly logs out upon exit, supports .mov --- main.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 7ccbabd..b72b7ae 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "os" "os/signal" "path" + "path/filepath" "regexp" "sort" "strconv" @@ -160,7 +161,7 @@ func main() { } if cfg.Section("auth").HasKey("token") { - dg, err = discordgo.New(cfg.Section("auth").Key("token").String()) + dg, err = discordgo.New("Bot " + cfg.Section("auth").Key("token").String()) } else { dg, err = discordgo.New( cfg.Section("auth").Key("email").String(), @@ -227,6 +228,7 @@ func main() { signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-sc myDB.Close() + dg.Close() return } @@ -1040,9 +1042,10 @@ func downloadFromUrl(dUrl string, filename string, path string, channelId string fmt.Printf("[%s] Saving possible duplicate (filenames match): %s to %s\n", time.Now().Format(time.Stamp), tmpPath, completePath) } + extension := filepath.Ext(filename) contentTypeParts := strings.Split(contentType, "/") if t := contentTypeParts[0]; t != "image" && t != "video" && t != "audio" && - !(t == "application" && isAudioFile(filename)) { + !(t == "application" && isAudioFile(filename) && strings.ToLower(extension) != ".mov") { fmt.Println("No image, video, or audio found at", dUrl) return true } From a8c666eb70e9725e46ea5cb16463c10b2afa12b3 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Fri, 27 Nov 2020 22:37:26 -0800 Subject: [PATCH 02/12] version bump --- vars.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vars.go b/vars.go index a5d8f8f..5d300ca 100644 --- a/vars.go +++ b/vars.go @@ -1,7 +1,7 @@ package main const ( - VERSION = "1.37" + VERSION = "1.38" DATABASE_DIR = "database" RELEASE_URL = "https://github.com/Seklfreak/discord-image-downloader-go/releases/latest" RELEASE_API_URL = "https://api.github.com/repos/Seklfreak/discord-image-downloader-go/releases/latest" From a79c790daf4da952ef8e7701f40b858c6d77cd67 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Fri, 27 Nov 2020 22:38:25 -0800 Subject: [PATCH 03/12] typo --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index b72b7ae..e8e43c4 100644 --- a/main.go +++ b/main.go @@ -1045,7 +1045,7 @@ func downloadFromUrl(dUrl string, filename string, path string, channelId string extension := filepath.Ext(filename) contentTypeParts := strings.Split(contentType, "/") if t := contentTypeParts[0]; t != "image" && t != "video" && t != "audio" && - !(t == "application" && isAudioFile(filename) && strings.ToLower(extension) != ".mov") { + !(t == "application" && isAudioFile(filename)) && strings.ToLower(extension) != ".mov" { fmt.Println("No image, video, or audio found at", dUrl) return true } From b4266818a5fb50b3dbbf734a46e5861fd9948887 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Sun, 6 Dec 2020 02:00:19 -0800 Subject: [PATCH 04/12] Removed token prefix --- main.go | 2 +- readme.md | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index e8e43c4..56e3f72 100644 --- a/main.go +++ b/main.go @@ -161,7 +161,7 @@ func main() { } if cfg.Section("auth").HasKey("token") { - dg, err = discordgo.New("Bot " + cfg.Section("auth").Key("token").String()) + dg, err = discordgo.New(cfg.Section("auth").Key("token").String()) } else { dg, err = discordgo.New( cfg.Section("auth").Key("email").String(), diff --git a/readme.md b/readme.md index b3e1cb3..7d256a1 100644 --- a/readme.md +++ b/readme.md @@ -30,6 +30,8 @@ When you run the tool for the first time it creates a `config.ini` file with exa In case you are using two-factor authentication you have to login using your token. Remove the email and password lines under the auth section in the config file and instead put in `token = `. You can acquire your token from the developer tools in your browser (`localStorage.token`) or discord client (Control+Shift+I (Windows) or Command+Option+I, click Application, click Local Storage, click `https://discordapp.com`, and find "token" and paste the value). +If you wish to use a **bot account**, **not a user account**, go to https://discord.com/developers/applications and create an application, then create a bot in the `Bot` tab in application settings. The bot tab will show you your token. You can invite to your server(s) by going to the `OAuth2` tab in application settings, check `bot`, and copy&paste the url into your browser. **In the `config.ini`, add "Bot " before your token. (example: `token = Bot mytokenhere`)** + ## How to download old pictures? By default, the tool only downloads new links posted while the tool is running. You can also set up the tool to download the complete history of a channel. To do this you have to run this tool with a separate discord account. Send your second account a dm on your primary account and get the channel id from the direct message channel. Now add this channel id to the config by adding the following lines: ``` @@ -39,4 +41,4 @@ By default, the tool only downloads new links posted while the tool is running. After this is done restart the tool and send `history` as a DM to your second account. The bot will ask for the channel id of the channel you want to download and start the downloads. You can view all available commands by sending `help`. ### Where do I get the channel id? -Open discord in your browser and go to the channel you want to monitor. In your address bar should be a URL like `https://discordapp.com/channels/1234/5678`. The number after the last slash is the channel id, in this case, `5678`. Or, enable Developer mode and right click the channel you need, and click Copy ID. +Open discord in your browser and go to the channel you want to monitor. In your address bar should be a URL like `https://discordapp.com/channels/1234/5678`. The number after the last slash is the channel id, in this case, `5678`. Or, enable Developer mode and right click the channel you need, and click Copy ID. \ No newline at end of file From ec02ae713db2053710d2876c9a2c9a10262ad8f6 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Tue, 8 Dec 2020 19:45:03 -0800 Subject: [PATCH 05/12] Update readme.md --- main.go | 5 ++++- readme.md | 10 ++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/main.go b/main.go index 56e3f72..78155b6 100644 --- a/main.go +++ b/main.go @@ -1045,7 +1045,10 @@ func downloadFromUrl(dUrl string, filename string, path string, channelId string extension := filepath.Ext(filename) contentTypeParts := strings.Split(contentType, "/") if t := contentTypeParts[0]; t != "image" && t != "video" && t != "audio" && - !(t == "application" && isAudioFile(filename)) && strings.ToLower(extension) != ".mov" { + !(t == "application" && isAudioFile(filename)) && + strings.ToLower(extension) != ".mov" && + strings.ToLower(extension) != ".mp4" && + strings.ToLower(extension) != ".webm" { fmt.Println("No image, video, or audio found at", dUrl) return true } diff --git a/readme.md b/readme.md index 7d256a1..e071bb2 100644 --- a/readme.md +++ b/readme.md @@ -3,9 +3,9 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/Seklfreak/discord-image-downloader-go)](https://goreportcard.com/report/github.com/Seklfreak/discord-image-downloader-go) [![Build Status](https://travis-ci.com/Seklfreak/discord-image-downloader-go.svg?branch=master)](https://travis-ci.com/Seklfreak/discord-image-downloader-go) -[Download the latest release](https://github.com/Seklfreak/discord-image-downloader-go/releases/latest) +[**Download the latest release**](https://github.com/Seklfreak/discord-image-downloader-go/releases/latest) -For an actively maintained fork of this project that implements features such as JSON configuration, see [**get-got/discord-downloader-go**](https://github.com/get-got/discord-downloader-go) +This project is not often maintained, for an actively maintained fork that implements features such as extensive JSON settings with channel-specific configurations, see [**get-got/discord-downloader-go**](https://github.com/get-got/discord-downloader-go) ## Discord SelfBots are forbidden! [Official Statement](https://support.discordapp.com/hc/en-us/articles/115002192352-Automated-user-accounts-self-bots-) @@ -28,9 +28,11 @@ This is a simple tool which downloads pictures (and instagram videos) posted in ## How to use? When you run the tool for the first time it creates a `config.ini` file with example values. Edit these values and run the tool for a second time. It should connect to discords api and wait for new messages. -In case you are using two-factor authentication you have to login using your token. Remove the email and password lines under the auth section in the config file and instead put in `token = `. You can acquire your token from the developer tools in your browser (`localStorage.token`) or discord client (Control+Shift+I (Windows) or Command+Option+I, click Application, click Local Storage, click `https://discordapp.com`, and find "token" and paste the value). +If you are using a normal user account **without two-factor authentication (2FA)**, simply enter your email and password into the corresponding lines in `config.ini`, under the auth section. -If you wish to use a **bot account**, **not a user account**, go to https://discord.com/developers/applications and create an application, then create a bot in the `Bot` tab in application settings. The bot tab will show you your token. You can invite to your server(s) by going to the `OAuth2` tab in application settings, check `bot`, and copy&paste the url into your browser. **In the `config.ini`, add "Bot " before your token. (example: `token = Bot mytokenhere`)** +If you are using **two-factor authentication (2FA) you have to login using your token.** Remove the email and password lines under the auth section in the config file and instead put in `token = `. You can acquire your token from the developer tools in your browser (`localStorage.token`) or discord client (`Ctrl+Shift+I` (Windows) or `Cmd+Option+I`, click Application, click Local Storage, click `https://discordapp.com`, and find "token" and paste the value). + +If you wish to use a **bot account (not a user account)**, go to https://discord.com/developers/applications and create an application, then create a bot in the `Bot` tab in application settings. The bot tab will show you your token. You can invite to your server(s) by going to the `OAuth2` tab in application settings, check `bot`, and copy+paste the url into your browser. **In the `config.ini`, add "Bot " before your token. (example: `token = Bot mytokenhere`)** ## How to download old pictures? By default, the tool only downloads new links posted while the tool is running. You can also set up the tool to download the complete history of a channel. To do this you have to run this tool with a separate discord account. Send your second account a dm on your primary account and get the channel id from the direct message channel. Now add this channel id to the config by adding the following lines: From e27c046def8e6db5cabe39ae263634af524cbf76 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Mon, 14 Dec 2020 14:58:53 -0800 Subject: [PATCH 06/12] Go 1.15, discordgo v0.22.0, xurls v2 fix --- .gitignore | 11 ++++++----- .travis.yml | 2 +- extract.go | 6 +++--- go.mod | 7 +++---- go.sum | 29 ++++++++++------------------- handler.go | 6 +++--- 6 files changed, 26 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 58964a8..fb70a2f 100644 --- a/.gitignore +++ b/.gitignore @@ -29,12 +29,13 @@ _testmain.go config.ini crossbuild.bat -testfolder/* -test/* -database*/ - .idea/ vendor credentials.json -.DS_Store \ No newline at end of file +.DS_Store + +# Exclude subdirectories (things like database, saved images during testing) +/** +# Exclude build command shortcut(s) +*.cmd \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 8a10c54..7556eaa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: go go: - - "1.13" + - "1.15" install: - env GO111MODULE=on go mod download - go get github.com/mitchellh/gox diff --git a/extract.go b/extract.go index 03c11cf..e77a93d 100644 --- a/extract.go +++ b/extract.go @@ -6,7 +6,7 @@ import ( "time" "github.com/bwmarrin/discordgo" - "mvdan.cc/xurls" + "mvdan.cc/xurls/v2" ) func getDownloadLinks(inputURL string, channelID string, interactive bool) (map[string]string, bool) { @@ -216,7 +216,7 @@ func getRawLinksOfMessage(message *discordgo.Message) []*DownloadItem { }) } - foundLinks := xurls.Strict.FindAllString(message.Content, -1) + foundLinks := xurls.Strict().FindAllString(message.Content, -1) for _, foundLink := range foundLinks { links = append(links, &DownloadItem{ Link: foundLink, @@ -231,7 +231,7 @@ func getRawLinksOfMessage(message *discordgo.Message) []*DownloadItem { } if embed.Description != "" { - foundLinks = xurls.Strict.FindAllString(embed.Description, -1) + foundLinks = xurls.Strict().FindAllString(embed.Description, -1) for _, foundLink := range foundLinks { links = append(links, &DownloadItem{ Link: foundLink, diff --git a/go.mod b/go.mod index a9c3d75..eebff47 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Seklfreak/discord-image-downloader-go -go 1.13 +go 1.15 require ( bou.ke/monkey v1.0.1 // indirect @@ -10,16 +10,15 @@ require ( github.com/Jeffail/gabs v1.2.0 github.com/PuerkitoBio/goquery v1.5.0 github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 // indirect - github.com/bwmarrin/discordgo v0.16.1-0.20190826195003-1d90c5da95a4 + github.com/bwmarrin/discordgo v0.22.0 github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect github.com/hashicorp/go-version v1.1.0 - github.com/mvdan/xurls v1.1.0 // indirect github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff // indirect golang.org/x/net v0.0.0-20190322120337-addf6b3196f6 golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914 google.golang.org/api v0.2.0 gopkg.in/ini.v1 v1.42.0 - mvdan.cc/xurls v1.1.0 + mvdan.cc/xurls/v2 v2.2.0 ) diff --git a/go.sum b/go.sum index 24a00b7..8f6ab0f 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,3 @@ -bou.ke/monkey v1.0.1 h1:zEMLInw9xvNakzUUPjfS4Ds6jYPqCFx3m7bRmG5NH2U= bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0 h1:eOI3/cP2VTU6uZLDYAoic+eyzzB9YyGmJ7eIjl8rOPg= @@ -22,10 +21,9 @@ github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9Pq github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 h1:ekDALXAVvY/Ub1UtNta3inKQwZ/jMB/zpOtD8rAYh78= github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330/go.mod h1:nH+k0SvAt3HeiYyOlJpLLv1HG1p7KWP7qU9QPp2/pCo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/bwmarrin/discordgo v0.16.1-0.20190826195003-1d90c5da95a4 h1:8hQXi5T6l9U8ckOd4RSpgJLJOJzruDX7NJRfY82WKQM= -github.com/bwmarrin/discordgo v0.16.1-0.20190826195003-1d90c5da95a4/go.mod h1:O9S4p+ofTFwB02em7jkpkV8M3R0/PUVOwN61zSZ0r4Q= +github.com/bwmarrin/discordgo v0.22.0 h1:uBxY1HmlVCsW1IuaPjpCGT6A2DBwRn0nvOguQIxDdFM= +github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc h1:tP7tkU+vIsEOKiK+l/NSLN4uUtkyuxc6hgYpQeCWAeI= github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc/go.mod h1:ORH5Qp2bskd9NzSfKqAF7tKfONsEkCarTE5ESr/RVBw= @@ -42,10 +40,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= @@ -53,20 +49,18 @@ github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpg github.com/hashicorp/go-version v1.1.0 h1:bPIoEKD27tNdebFGGxxYwcL4nepeY4j1QP23PFRGzg0= github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww= -github.com/mvdan/xurls v1.1.0/go.mod h1:tQlNn3BED8bE/15hnSL2HLkDeLWpNPAwtw7wkEq44oU= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= -github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= @@ -75,13 +69,11 @@ github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1: github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff h1:86HlEv0yBCry9syNuylzqznKXDK11p6D0DT596yNMys= github.com/smartystreets/goconvey v0.0.0-20190306220146-200a235640ff/go.mod h1:KSQcGKpxUMHk3nbYzs/tIBAM2iDooCn0BmttHOJEbLs= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= @@ -113,13 +105,11 @@ golang.org/x/oauth2 v0.0.0-20190319182350-c85d3e98c914/go.mod h1:gOpvHmFTYa4Iltr golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6 h1:bjcUS9ztw9kFmmIxJInhon/0Is3p+EHBKNgquIzo1OI= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a h1:1BGLXjeY4akVXGgbC9HugT3Jv3hCI0z56oJR5vAMgBU= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -132,7 +122,6 @@ google.golang.org/api v0.2.0 h1:B5VXkdjt7K2Gm6fGBC9C9a1OAKJDT95cTqwet+2zib0= google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= @@ -143,6 +132,8 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.42.0 h1:7N3gPTt50s8GuLortA00n8AqRTk75qOP98+mTPpgzRk= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -150,5 +141,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -mvdan.cc/xurls v1.1.0 h1:kj0j2lonKseISJCiq1Tfk+iTv65dDGCl0rTbanXJGGc= -mvdan.cc/xurls v1.1.0/go.mod h1:TNWuhvo+IqbUCmtUIb/3LJSQdrzel8loVpgFm0HikbI= +mvdan.cc/xurls/v2 v2.2.0 h1:NSZPykBXJFCetGZykLAxaL6SIpvbVy/UFEniIfHAa8A= +mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8= diff --git a/handler.go b/handler.go index f0c2ecf..281d9d1 100644 --- a/handler.go +++ b/handler.go @@ -6,7 +6,7 @@ import ( "time" "github.com/bwmarrin/discordgo" - "mvdan.cc/xurls" + "mvdan.cc/xurls/v2" ) // helpHandler displays the help message @@ -212,7 +212,7 @@ func historyHandler(message *discordgo.Message) { startDownload(iAttachment.URL, iAttachment.Filename, folder, msg.ChannelID, msg.Author.ID, fileTime) } } - foundUrls := xurls.Strict.FindAllString(msg.Content, -1) + foundUrls := xurls.Strict().FindAllString(msg.Content, -1) for _, iFoundUrl := range foundUrls { links, _ := getDownloadLinks(iFoundUrl, msg.ChannelID, false) for link, filename := range links { @@ -284,7 +284,7 @@ func defaultHandler(message *discordgo.Message) { interactiveChannelLinkTemp[message.ChannelID] = iAttachment.URL foundLinks = true } - foundUrls := xurls.Strict.FindAllString(message.Content, -1) + foundUrls := xurls.Strict().FindAllString(message.Content, -1) for _, iFoundUrl := range foundUrls { dg.ChannelMessageSend(message.ChannelID, fmt.Sprintf("Where do you want to save <%s>?\nType **.** for default path or **cancel** to cancel the download %s", iFoundUrl, folderName)) interactiveChannelLinkTemp[message.ChannelID] = iFoundUrl From 0ec52e4808fd617cf72f878d3d301a92fcc74ee6 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Mon, 14 Dec 2020 15:06:25 -0800 Subject: [PATCH 07/12] Email/Password Login Fix for dg v0.22.0 --- main.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index 78155b6..cb2e5c6 100644 --- a/main.go +++ b/main.go @@ -168,8 +168,11 @@ func main() { cfg.Section("auth").Key("password").String()) } if err != nil { - fmt.Println("error creating Discord session,", err) - return + // Newer discordgo throws this error for some reason with Email/Password login + if err.Error() != "Unable to fetch discord authentication token. " { + fmt.Println("error creating Discord session,", err) + return + } } dg.AddHandler(messageCreate) From 1b81aaf8e92b0f88ad974cbd3280ab8758951fa2 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Mon, 14 Dec 2020 15:51:41 -0800 Subject: [PATCH 08/12] Status Settings --- common.go | 20 +++++++++++++------- main.go | 20 ++++++++++++++++++-- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/common.go b/common.go index 8885c05..b0f9010 100644 --- a/common.go +++ b/common.go @@ -36,13 +36,19 @@ func deduplicateDownloadItems(DownloadItems []*DownloadItem) []*DownloadItem { } func updateDiscordStatus() { - dg.UpdateStatusComplex(discordgo.UpdateStatusData{ - Game: &discordgo.Game{ - Name: fmt.Sprintf("%d downloaded pictures", countDownloadedImages()), - Type: discordgo.GameTypeWatching, - }, - Status: "online", - }) + if StatusEnabled { + dg.UpdateStatusComplex(discordgo.UpdateStatusData{ + Game: &discordgo.Game{ + Name: fmt.Sprintf("%d %s", countDownloadedImages(), StatusSuffix), + Type: StatusLabel, + }, + Status: StatusType, + }) + } else if StatusType != "online" { + dg.UpdateStatusComplex(discordgo.UpdateStatusData{ + Status: StatusType, + }) + } } func Pagify(text string, delimiter string) []string { diff --git a/main.go b/main.go index cb2e5c6..1ad2811 100644 --- a/main.go +++ b/main.go @@ -48,6 +48,10 @@ var ( twitterClient *anaconda.TwitterApi DownloadTimeout int SendNoticesToInteractiveChannels bool + StatusEnabled bool + StatusType string + StatusLabel discordgo.GameType + StatusSuffix string clientCredentialsJson string DriveService *drive.Service RegexpFilename *regexp.Regexp @@ -66,7 +70,7 @@ type ImgurAlbumObject struct { } func main() { - fmt.Printf("discord-image-downloader-go version %s\n", VERSION) + fmt.Printf("> discord-image-downloader-go v%s -- discordgo v%s\n", VERSION, discordgo.VERSION) if !isLatestRelease() { fmt.Printf("update available on %s !\n", RELEASE_URL) } @@ -99,6 +103,9 @@ func main() { cfg.Section("general").NewKey("max download retries", "5") cfg.Section("general").NewKey("download timeout", "60") cfg.Section("general").NewKey("send notices to interactive channels", "false") + cfg.Section("general").NewKey("set status", "true") + cfg.Section("general").NewKey("status type", "online") + cfg.Section("general").NewKey("status label", fmt.Sprint(discordgo.GameTypeWatching)) cfg.Section("channels").NewKey("channelid1", "C:\\full\\path\\1") cfg.Section("channels").NewKey("channelid2", "C:\\full\\path\\2") cfg.Section("channels").NewKey("channelid3", "C:\\full\\path\\3") @@ -123,6 +130,7 @@ func main() { return } if myDB.Use("Downloads") == nil { + fmt.Println("Creating new database...") if err := myDB.Create("Downloads"); err != nil { fmt.Println("unable to create db", err) return @@ -188,6 +196,11 @@ func main() { DownloadTimeout = cfg.Section("general").Key("download timeout").MustInt(60) SendNoticesToInteractiveChannels = cfg.Section("general").Key("send notices to interactive channels").MustBool(false) + StatusEnabled = cfg.Section("status").Key("status enabled").MustBool(true) + StatusType = cfg.Section("status").Key("status type").MustString("online") + StatusLabel = discordgo.GameType(cfg.Section("status").Key("status label").MustInt(int(discordgo.GameTypeWatching))) + StatusSuffix = cfg.Section("status").Key("status suffix").MustString("downloaded pictures") + // setup google drive client clientCredentialsJson = cfg.Section("google").Key("client credentials json").MustString("") if clientCredentialsJson != "" { @@ -230,8 +243,11 @@ func main() { sc := make(chan os.Signal, 1) signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt) <-sc + fmt.Println("Closing database...") myDB.Close() + fmt.Println("Logging out of Discord...") dg.Close() + fmt.Println("Exiting...") return } @@ -972,7 +988,7 @@ func startDownload(dUrl string, filename string, path string, channelId string, } func downloadFromUrl(dUrl string, filename string, path string, channelId string, userId string, fileTime time.Time) bool { - err := os.MkdirAll(path, 755) + err := os.MkdirAll(path, 0755) if err != nil { fmt.Println("Error while creating folder", path, "-", err) return false From 473aa32d29d3152614621d199e8e6c2009d3b32b Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Mon, 14 Dec 2020 16:09:31 -0800 Subject: [PATCH 09/12] Update readme.md --- readme.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/readme.md b/readme.md index e071bb2..1da1f3b 100644 --- a/readme.md +++ b/readme.md @@ -3,18 +3,18 @@ [![Go Report Card](https://goreportcard.com/badge/github.com/Seklfreak/discord-image-downloader-go)](https://goreportcard.com/report/github.com/Seklfreak/discord-image-downloader-go) [![Build Status](https://travis-ci.com/Seklfreak/discord-image-downloader-go.svg?branch=master)](https://travis-ci.com/Seklfreak/discord-image-downloader-go) -[**Download the latest release**](https://github.com/Seklfreak/discord-image-downloader-go/releases/latest) +[**DOWNLOAD THE LATEST RELEASE BUILD**](https://github.com/Seklfreak/discord-image-downloader-go/releases/latest) -This project is not often maintained, for an actively maintained fork that implements features such as extensive JSON settings with channel-specific configurations, see [**get-got/discord-downloader-go**](https://github.com/get-got/discord-downloader-go) +This project is not often maintained. For an actively maintained fork that implements features such as extensive JSON settings with channel-specific configurations, see [**get-got/discord-downloader-go**](https://github.com/get-got/discord-downloader-go) ## Discord SelfBots are forbidden! [Official Statement](https://support.discordapp.com/hc/en-us/articles/115002192352-Automated-user-accounts-self-bots-) ### You have been warned. -This is a simple tool which downloads pictures (and instagram videos) posted in discord channels of your choice to a local folder. It handles various sources like twitter differently to make sure to download the best quality available. +This is a simple tool which downloads media posted in Discord channels of your choice to a local folder. It handles various sources like Twitter differently to make sure to download the best quality available. ## Websites currently supported -- Discord attachments +- Discord Attachments - Twitter - Tistory - Gfycat @@ -30,11 +30,11 @@ When you run the tool for the first time it creates a `config.ini` file with exa If you are using a normal user account **without two-factor authentication (2FA)**, simply enter your email and password into the corresponding lines in `config.ini`, under the auth section. -If you are using **two-factor authentication (2FA) you have to login using your token.** Remove the email and password lines under the auth section in the config file and instead put in `token = `. You can acquire your token from the developer tools in your browser (`localStorage.token`) or discord client (`Ctrl+Shift+I` (Windows) or `Cmd+Option+I`, click Application, click Local Storage, click `https://discordapp.com`, and find "token" and paste the value). +If you are using **two-factor authentication (2FA) you have to login using your token.** Remove the email and password lines under the auth section in the config file and instead put in `token = `. You can acquire your token from the developer tools in your browser (`localStorage.token`) or discord client (`Ctrl+Shift+I` (Windows) or `Cmd+Option+I` (Mac), click Application, click Local Storage, click `https://discordapp.com`, and find "token" and paste the value). If you wish to use a **bot account (not a user account)**, go to https://discord.com/developers/applications and create an application, then create a bot in the `Bot` tab in application settings. The bot tab will show you your token. You can invite to your server(s) by going to the `OAuth2` tab in application settings, check `bot`, and copy+paste the url into your browser. **In the `config.ini`, add "Bot " before your token. (example: `token = Bot mytokenhere`)** -## How to download old pictures? +## How to download old files? By default, the tool only downloads new links posted while the tool is running. You can also set up the tool to download the complete history of a channel. To do this you have to run this tool with a separate discord account. Send your second account a dm on your primary account and get the channel id from the direct message channel. Now add this channel id to the config by adding the following lines: ``` [interactive channels] @@ -42,5 +42,16 @@ By default, the tool only downloads new links posted while the tool is running. ``` After this is done restart the tool and send `history` as a DM to your second account. The bot will ask for the channel id of the channel you want to download and start the downloads. You can view all available commands by sending `help`. -### Where do I get the channel id? -Open discord in your browser and go to the channel you want to monitor. In your address bar should be a URL like `https://discordapp.com/channels/1234/5678`. The number after the last slash is the channel id, in this case, `5678`. Or, enable Developer mode and right click the channel you need, and click Copy ID. \ No newline at end of file +### Where do I get the Channel ID? +Enable Developer Mode (in Discord Appearance settings) and right click the channel you need, and click Copy ID. + +**OR,** Open discord in your browser and go to the channel you want to monitor. In your address bar should be a URL like `https://discordapp.com/channels/1234/5678`. The number after the last slash is the channel ID, in this case, `5678`. + +### Where do I get the Channel ID for Direct Messages? +1. Inspect Element in the Discord client (`Ctrl+Shift+I` for Windows or `Cmd+Option+I` for Mac) +1. Go to the `Elements` tab on the left. +1. Click this icon ![arrow going into box](https://i.imgur.com/PkDOCyZ.png) (the arrow going into a box) and then click on the avatar for the persons DMs you want to grab the ID for. +1. Somewhere slightly above the HTML it takes you to, there should be a line that looks like this ![](https://i.imgur.com/614rZnX.png) +1. Copy the number after the `/@me/`. That is your Channel ID to use. + +**OR,** Open discord in your browser and go to the channel you want to monitor. In your address bar should be a URL like `https://discordapp.com/channels/@me/5678`. The number after the last slash is the channel ID, in this case, `5678`. \ No newline at end of file From 421769d674cc60ffe7b2f81afd275b6bcfb6d490 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Mon, 14 Dec 2020 16:42:15 -0800 Subject: [PATCH 10/12] Output ignores wsapi warning with user logins --- main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 1ad2811..2adbbaf 100644 --- a/main.go +++ b/main.go @@ -221,12 +221,13 @@ func main() { } } } - + dg.LogLevel = -1 // to ignore dumb wsapi error err = dg.Open() if err != nil { fmt.Println("error opening connection,", err) return } + dg.LogLevel = 0 // reset u, err := dg.User("@me") if err != nil { From 4ac02d2e296a24e24cc614d284adaa1d572f0d41 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Tue, 15 Dec 2020 02:50:26 -0800 Subject: [PATCH 11/12] config fix --- main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 2adbbaf..3e40f4c 100644 --- a/main.go +++ b/main.go @@ -103,9 +103,10 @@ func main() { cfg.Section("general").NewKey("max download retries", "5") cfg.Section("general").NewKey("download timeout", "60") cfg.Section("general").NewKey("send notices to interactive channels", "false") - cfg.Section("general").NewKey("set status", "true") + cfg.Section("general").NewKey("status enabled", "true") cfg.Section("general").NewKey("status type", "online") cfg.Section("general").NewKey("status label", fmt.Sprint(discordgo.GameTypeWatching)) + cfg.Section("general").NewKey("status suffix", "downloaded pictures") cfg.Section("channels").NewKey("channelid1", "C:\\full\\path\\1") cfg.Section("channels").NewKey("channelid2", "C:\\full\\path\\2") cfg.Section("channels").NewKey("channelid3", "C:\\full\\path\\3") From 94c481ce86fa949e5057ed9162c083cb39216f12 Mon Sep 17 00:00:00 2001 From: get-got <43052079+get-got@users.noreply.github.com> Date: Tue, 15 Dec 2020 02:56:07 -0800 Subject: [PATCH 12/12] yet another fix --- main.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index 3e40f4c..c5ea23d 100644 --- a/main.go +++ b/main.go @@ -103,10 +103,10 @@ func main() { cfg.Section("general").NewKey("max download retries", "5") cfg.Section("general").NewKey("download timeout", "60") cfg.Section("general").NewKey("send notices to interactive channels", "false") - cfg.Section("general").NewKey("status enabled", "true") - cfg.Section("general").NewKey("status type", "online") - cfg.Section("general").NewKey("status label", fmt.Sprint(discordgo.GameTypeWatching)) - cfg.Section("general").NewKey("status suffix", "downloaded pictures") + cfg.Section("status").NewKey("status enabled", "true") + cfg.Section("status").NewKey("status type", "online") + cfg.Section("status").NewKey("status label", fmt.Sprint(discordgo.GameTypeWatching)) + cfg.Section("status").NewKey("status suffix", "downloaded pictures") cfg.Section("channels").NewKey("channelid1", "C:\\full\\path\\1") cfg.Section("channels").NewKey("channelid2", "C:\\full\\path\\2") cfg.Section("channels").NewKey("channelid3", "C:\\full\\path\\3")