Skip to content

Instantly share code, notes, and snippets.

@peterhellberg
Created February 5, 2025 11:19
Show Gist options
  • Save peterhellberg/e88b216e045e6e8854d3e4e2821942f0 to your computer and use it in GitHub Desktop.
Save peterhellberg/e88b216e045e6e8854d3e4e2821942f0 to your computer and use it in GitHub Desktop.
Small script that downloads images I publish on Imgur to my own server
package main
import (
"errors"
"flag"
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"time"
)
var (
defaultDir = "/var/www/assets.c7.se/imgur"
defaultURL = "https://assets.c7.se/imgur/"
defaultRaw = false
)
const (
iImgurCom = `https://i.imgur.com/`
firefoxUA = `Mozilla/5.0 (X11; Linux i686; rv:135.0) Gecko/20100101 Firefox/135.0`
)
type config struct {
dir string
url string
src string
img string
raw bool
}
func (cfg config) path() string {
return filepath.Join(cfg.dir, cfg.img)
}
func (cfg config) out() string {
return cfg.url + cfg.img
}
func main() {
if err := run(os.Args, os.Stdout); err != nil {
fmt.Fprintf(os.Stderr, "❌ %s\n", err)
os.Exit(1)
}
}
func run(args []string, w io.Writer) error {
cfg, err := parse(args)
if err != nil {
return err
}
client := &http.Client{
Timeout: time.Minute,
}
if err := download(cfg, client); err != nil {
return err
}
return output(w, cfg)
}
func request(cfg config) (*http.Request, error) {
req, err := http.NewRequest(http.MethodGet, cfg.src, nil)
if err != nil {
return nil, err
}
req.Header.Set("User-Agent", firefoxUA)
return req, nil
}
func download(cfg config, client *http.Client) error {
name := cfg.path()
if _, err := os.Stat(name); !errors.Is(err, os.ErrNotExist) {
return fmt.Errorf("file already exists, served on %s", cfg.out())
}
req, err := request(cfg)
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("bad status: %s", resp.Status)
}
dst, err := os.Create(name)
if err != nil {
return err
}
defer dst.Close()
_, err = io.Copy(dst, resp.Body)
return err
}
func output(w io.Writer, cfg config) error {
if cfg.raw {
return fprintf(w, "%s\n", cfg.out())
}
return fprintf(w, "✅ file downloaded, served on %s\n", cfg.out())
}
func fprintf(w io.Writer, format string, a ...any) error {
_, err := fmt.Fprintf(w, format, a...)
return err
}
func parse(args []string) (config, error) {
var cfg config
flags := flag.NewFlagSet(args[0], flag.ExitOnError)
flags.StringVar(&cfg.dir, "dir", defaultDir, "Local directory to download to")
flags.StringVar(&cfg.url, "url", defaultURL, "URL to construct links from")
flags.BoolVar(&cfg.raw, "raw", defaultRaw, "If to output just the link URL")
if err := flags.Parse(args[1:]); err != nil {
return cfg, err
}
cfg.src = strings.Join(flags.Args(), "")
switch {
case cfg.src == "":
return cfg, fmt.Errorf("no URL provided")
case !strings.HasPrefix(cfg.src, iImgurCom):
return cfg, fmt.Errorf("provided source %q does not have the required prefix %q", cfg.src, iImgurCom)
}
cfg.img = filepath.Base(cfg.src)
return cfg, nil
}
@peterhellberg
Copy link
Author

On my workstation I have a small script that rely on SSHFS to mount my server to a local directory:

#!/bin/bash

umount /var/www/assets.c7.se
sshfs -o allow_other,default_permissions [email protected]:/var/www/assets.c7.se /var/www/assets.c7.se 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment