sgg-go

sgg-go is a static gallery generator, a golang implementation of sgg.
git clone http://git.hanabi.in/repos/sgg-go.git
Log | Files | Refs | LICENSE

main.go (10332B)


      1 package main
      2 
      3 import (
      4 	"flag"
      5 	"fmt"
      6 	"io/ioutil"
      7 	"os"
      8 	"path/filepath"
      9 	"regexp"
     10 	"sort"
     11 	"strconv"
     12 	"strings"
     13 	"time"
     14 )
     15 
     16 func main() {
     17 	src, consts, url, videoExt, photoExt, original, useRSS := InitialiseFlags()
     18 	Usage(src, consts)
     19 	DeleteStaticFiles(src, useRSS)
     20 	files := GetFilesList(src, photoExt, videoExt)
     21 	CreateFileByCopying("index.html", consts, "_header.html")
     22 	if useRSS {
     23 		CreateFileByCopying("rss.xml", consts, "_rss-header.xml")
     24 	}
     25 	for _, file := range files {
     26 		title := GetTitle(file)
     27 		if useRSS {
     28 			rssEntry := GetRSSEntry(title, url, file, photoExt, videoExt)
     29 			AppendContentToFile(rssEntry, "rss.xml")
     30 		}
     31 		var listItem string
     32 		if strings.HasSuffix(file, videoExt) {
     33 			listItem = `
     34 				<li id="` + file + `">
     35 					<video class="gallery" controls><source src="` + file + `"></video>
     36 				</li>
     37 			`
     38 		} else if strings.HasSuffix(file, photoExt) {
     39 			highQualityFile := GetHQImg(file, original)
     40 			listItem = `
     41 				<li id="` + file + `">
     42 					<a
     43 						target="_blank"
     44 						rel="noopener noreferrer"
     45 						href="` + highQualityFile + `"
     46 					>
     47 						<img class="gallery" src="` + file + `"/>
     48 					</a>
     49 				</li>
     50 			`
     51 		} else {
     52 			continue // don't write empty listItems to HTML
     53 		}
     54 		AppendContentToFile(listItem, "index.html")
     55 	}
     56 	CompleteFiles(consts, useRSS)
     57 	AddCopyrightToHtml()
     58 	AddDateToRSS(useRSS)
     59 	MoveFile("index.html", src)
     60 	if useRSS {
     61 		MoveFile("rss.xml", src)
     62 	}
     63 	CopyStaticFiles(consts, src)
     64 	os.Exit(0)
     65 }
     66 
     67 func GetHQImg(file string, original string) string {
     68 	extRegex := regexp.MustCompile(`\.[^.]*$`)
     69 	byteFile := []byte(file)
     70 	nothing := []byte("")
     71 	fileWithOutExt := string(extRegex.ReplaceAll(byteFile, nothing))
     72 	hqFile := fileWithOutExt + original
     73 	return hqFile
     74 }
     75 
     76 func InitialiseFlags() (string, string, string, string, string, string, bool) {
     77 	var src string
     78 	var consts string
     79 	var url string
     80 	var videoExt string
     81 	var photoExt string
     82 	var original string
     83 	var useRSS bool
     84 
     85 	flag.StringVar(&src, "s", "src", "Specify the source directory containing images.")
     86 	flag.StringVar(&consts, "c", "consts", "Specify the consts directory containing static files.")
     87 	flag.StringVar(&url, "u", "___http://example.com/___", "Specify the URL of the website.")
     88 	flag.StringVar(&videoExt, "v", "mp4", "Specify which video file extension to use.")
     89 	flag.StringVar(&photoExt, "p", "jpg", "Specify which photo file extension to use.")
     90 	flag.StringVar(&original, "o", ".original.png", "Specify the suffix of the original high quality media.")
     91 	flag.BoolVar(&useRSS, "r", true, "Generate an RSS feed.")
     92 
     93 	flag.Usage = func() {
     94 		fmt.Println("Usage: ``./sgg-go -s src -c consts -u http://example.com -v mp4 -p jpg -o original.png [-r=false]''")
     95 		flag.PrintDefaults()
     96 	}
     97 
     98 	flag.Parse()
     99 	return src, consts, url, videoExt, photoExt, original, useRSS
    100 }
    101 
    102 func CheckDirExists(dir string) {
    103 	_, err := os.Stat(dir)
    104 	if os.IsNotExist(err) {
    105 		fmt.Fprintf(os.Stderr, "%s: No such directory", dir)
    106 		os.Exit(1)
    107 	}
    108 }
    109 
    110 func DeleteStaticFiles(src string, useRSS bool) {
    111 	files := []string{"avtaar.jpg", "index.html", "favicon.png", "style.css"}
    112 	for _, file := range files {
    113 		pathOfFile := filepath.Join(src, file)
    114 		DelFile(pathOfFile)
    115 	}
    116 	if useRSS {
    117 		pathOfFile := filepath.Join(src, "rss.xml")
    118 		DelFile(pathOfFile)
    119 	}
    120 }
    121 
    122 func DelFile(pathOfFile string) {
    123 	_, err := os.Stat(pathOfFile)
    124 	if err == nil {
    125 		os.Remove(pathOfFile)
    126 	}
    127 }
    128 
    129 func GetAllFiles(dir string) []string {
    130 	allFiles := []string{}
    131 	entries, err := ioutil.ReadDir(dir)
    132 	if err != nil {
    133 		fmt.Fprintf(os.Stderr, "%s", err)
    134 		os.Exit(1)
    135 	}
    136 	for _, elem := range entries {
    137 		name := elem.Name()
    138 		isDir := elem.IsDir()
    139 		if isDir == false {
    140 			fullName := filepath.Join(dir, name)
    141 			allFiles = append(allFiles, fullName)
    142 		} else {
    143 			recurredFiles := GetAllFiles(filepath.Join(dir, name))
    144 			for j, _ := range recurredFiles {
    145 				allFiles = append(allFiles, recurredFiles[j])
    146 			}
    147 		}
    148 	}
    149 	return allFiles
    150 }
    151 
    152 func TrimSrc(src string, filenames []string) []string {
    153 	trimedNames := []string{}
    154 	for _, file := range filenames {
    155 		reg := regexp.MustCompile("^" + src)
    156 		replacedName := string(reg.ReplaceAll([]byte(file), []byte("")))
    157 		trimedNames = append(trimedNames, replacedName)
    158 	}
    159 	return trimedNames
    160 }
    161 
    162 func CreateFileByCopying(dstFileName string, srcDir string, srcFileName string) {
    163 	srcFilePath := filepath.Join(srcDir, srcFileName)
    164 	bytesRead := []byte("")
    165 	_, err := os.Stat(srcFilePath)
    166 	if !os.IsNotExist(err) {
    167 		bytesRead, err = ioutil.ReadFile(srcFilePath)
    168 		if err != nil {
    169 			fmt.Fprintf(os.Stderr, "%s", err)
    170 			os.Exit(1)
    171 		}
    172 	}
    173 	err = ioutil.WriteFile(dstFileName, bytesRead, 0644)
    174 	if err != nil {
    175 		fmt.Fprintf(os.Stderr, "%s", err)
    176 		os.Exit(1)
    177 	}
    178 }
    179 
    180 func MoveFile(filename string, dir string) {
    181 	newFilePath := filepath.Join(dir, filename)
    182 	err := os.Rename(filename, newFilePath)
    183 	if err != nil {
    184 		fmt.Fprintf(os.Stderr, "%s", err)
    185 	}
    186 }
    187 
    188 func CopyFile(from string, to string, filename string) {
    189 	srcFilePath := filepath.Join(from, filename)
    190 	dstFilePath := filepath.Join(to, filename)
    191 	_, err := os.Stat(srcFilePath)
    192 	if !os.IsNotExist(err) {
    193 		bytesRead, err := ioutil.ReadFile(srcFilePath)
    194 		if err != nil {
    195 			fmt.Fprintf(os.Stderr, "%s", err)
    196 			os.Exit(1)
    197 		}
    198 		err = ioutil.WriteFile(dstFilePath, bytesRead, 0644)
    199 		if err != nil {
    200 			fmt.Fprintf(os.Stderr, "%s", err)
    201 			os.Exit(1)
    202 		}
    203 	}
    204 }
    205 
    206 func GetTitle(fileName string) string {
    207 	bytedFileName := []byte(fileName)
    208 	empty := []byte("")
    209 	leadingSlashRegex := regexp.MustCompile(`^\/`)
    210 	firstReplace := leadingSlashRegex.ReplaceAll(bytedFileName, empty)
    211 	rmExtRegex := regexp.MustCompile(`\..*$`)
    212 	secondReplace := rmExtRegex.ReplaceAll(firstReplace, empty)
    213 	title := string(secondReplace)
    214 	return title
    215 }
    216 
    217 func ExtractDate(title string) string {
    218 	layoutISO := "2006/01/02"
    219 
    220 	ymd := title[0:10]
    221 
    222 	t, err := time.Parse(layoutISO, ymd)
    223 	if err != nil {
    224 		fmt.Fprintf(os.Stderr, "%s", err)
    225 		os.Exit(1)
    226 	}
    227 	formattedDate := t.Format(time.RFC1123)
    228 	return formattedDate
    229 }
    230 
    231 func GetRSSEntry(title string, url string, file string, photoExt string, videoExt string) string {
    232 	formattedDate := ExtractDate(title)
    233 	imgOrVideo := GetImgOrVideoForRSS(url, file, photoExt, videoExt)
    234 	rssEntry := `
    235     <item>
    236       <title>` + title + `</title>
    237 			<description>
    238         <![CDATA[
    239           <a href="` + url + "/#" + file + `">` + imgOrVideo + `</a>
    240           <br/>
    241           <h2>New media added on ` + formattedDate + `</h2>
    242           <br/>
    243           <small><a href="` + url + `">See more photos.</a></small>
    244           <br/>]]>
    245 			</description>
    246 			<link>` + url + file + `</link>
    247 			<guid>` + url + file + `</guid>
    248 			<pubDate>` + formattedDate + `</pubDate>
    249     </item>
    250 		`
    251 	return rssEntry
    252 }
    253 
    254 func GetImgOrVideoForRSS(url string, file string, photoExt string, videoExt string) string {
    255 	var res string
    256 	if strings.HasSuffix(file, photoExt) {
    257 		res = `<img src="` + url + file + `">`
    258 	} else if strings.HasSuffix(file, videoExt) {
    259 		res = `<video class="gallery" controls><source src="` + url + file + `"></video>`
    260 	}
    261 	return res
    262 }
    263 
    264 func AppendContentToFile(content string, file string) {
    265 	fd, err := os.OpenFile(file, os.O_APPEND|os.O_WRONLY, 0644)
    266 	if err != nil {
    267 		fmt.Fprintf(os.Stderr, "%s", err)
    268 		os.Exit(1)
    269 	}
    270 	if _, err := fd.Write([]byte(content)); err != nil {
    271 		fmt.Fprintf(os.Stderr, "%s", err)
    272 		os.Exit(1)
    273 	}
    274 	defer fd.Close()
    275 }
    276 
    277 func Usage(src string, consts string) {
    278 	CheckDirExists(src)
    279 	CheckDirExists(consts)
    280 }
    281 
    282 func GetFilesList(src string, photoExt string, videoExt string) []string {
    283 	files := GetAllFiles("src")
    284 	trimedFiles := TrimSrc(src, files)
    285 	filteredFiles := []string{}
    286 	for _, file := range trimedFiles {
    287 		if strings.HasSuffix(file, photoExt) || strings.HasSuffix(file, videoExt) {
    288 			filteredFiles = append(filteredFiles, file)
    289 		}
    290 	}
    291 	sort.Strings(filteredFiles)
    292 	filesList := reverse(filteredFiles)
    293 	return filesList
    294 }
    295 
    296 func reverse(arr []string) []string {
    297 	for i, j := 0, len(arr)-1; i < j; i, j = i+1, j-1 {
    298 		arr[i], arr[j] = arr[j], arr[i]
    299 	}
    300 	return arr
    301 }
    302 
    303 func CopyStaticFiles(consts string, src string) {
    304 	CopyFile(consts, src, "avtaar.jpg")
    305 	CopyFile(consts, src, "favicon.png")
    306 	CopyFile(consts, src, "style.css")
    307 }
    308 
    309 func AppendFileToFile(from string, to string) {
    310 	_, err := os.Stat(from)
    311 	if os.IsNotExist(err) {
    312 		fmt.Fprintf(os.Stderr, "%s", err)
    313 		os.Exit(1)
    314 	}
    315 	bytesRead, err := ioutil.ReadFile(from)
    316 	if err != nil {
    317 		fmt.Fprintf(os.Stderr, "%s", err)
    318 		os.Exit(1)
    319 	}
    320 	fd, err := os.OpenFile(to, os.O_APPEND|os.O_WRONLY, 0644)
    321 	if err != nil {
    322 		fmt.Fprintf(os.Stderr, "%s", err)
    323 		os.Exit(1)
    324 	}
    325 	if _, err := fd.Write(bytesRead); err != nil {
    326 		fmt.Fprintf(os.Stderr, "%s", err)
    327 		os.Exit(1)
    328 	}
    329 	defer fd.Close()
    330 }
    331 
    332 func CompleteFiles(consts string, useRSS bool) {
    333 	htmlBottomPath := filepath.Join(consts, "_footer.html")
    334 	AppendFileToFile(htmlBottomPath, "index.html")
    335 	if useRSS {
    336 		rssBottomPath := filepath.Join(consts, "_rss-footer.xml")
    337 		AppendFileToFile(rssBottomPath, "rss.xml")
    338 	}
    339 }
    340 
    341 func AddCopyrightToHtml() {
    342 	year := strconv.Itoa(time.Now().Year())
    343 	yearInBytes := []byte("&copy; " + year + " ")
    344 	yearReg := `&copy;`
    345 	AddRegexToFile("index.html", yearReg, yearInBytes)
    346 }
    347 
    348 func AddDateToRSS(useRSS bool) {
    349 	if useRSS {
    350 		AddCopyrightToRSS()
    351 		AddPubDateToRSS()
    352 		AddBuildDateToRSS()
    353 	}
    354 }
    355 
    356 func AddCopyrightToRSS() {
    357 	year := strconv.Itoa(time.Now().Year())
    358 	yearInBytes := []byte("<copyright>" + year + " ___RSS-COPYRIGHT___</copyright>")
    359 	yearReg := `<copyright></copyright>`
    360 	AddRegexToFile("rss.xml", yearReg, yearInBytes)
    361 }
    362 
    363 func AddRegexToFile(filename string, regStr string, replacementStr []byte) {
    364 	bytesRead, err := ioutil.ReadFile(filename)
    365 	if err != nil {
    366 		fmt.Fprintf(os.Stderr, "%s", err)
    367 		os.Exit(1)
    368 	}
    369 	os.Remove(filename)
    370 	yearReg := regexp.MustCompile(regStr)
    371 	yearInserted := yearReg.ReplaceAll(bytesRead, replacementStr)
    372 	err = ioutil.WriteFile(filename, yearInserted, 0644)
    373 	if err != nil {
    374 		fmt.Fprintf(os.Stderr, "%s", err)
    375 		os.Exit(1)
    376 	}
    377 }
    378 
    379 func AddPubDateToRSS() {
    380 	reg := `<lastBuildDate></lastBuildDate>`
    381 	now := time.Now().Format(time.RFC1123)
    382 	replacement := []byte(`<lastBuildDate>` + now + `</lastBuildDate>`)
    383 	AddRegexToFile("rss.xml", reg, replacement)
    384 }
    385 
    386 func AddBuildDateToRSS() {
    387 	reg := `<pubDate></pubDate>`
    388 	now := time.Now().Format(time.RFC1123)
    389 	replacement := []byte(`<pubDate>` + now + `</pubDate>`)
    390 	AddRegexToFile("rss.xml", reg, replacement)
    391 }