aboutsummaryrefslogtreecommitdiff
path: root/steam/steam.go
blob: ff0ce5afa86c107a878e0c4ac6197697d4e71663 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Package steam is designed to be a rather simplistic library to help pull
// information from a local steam library and run basic operations like
// archiving, restore and deleting games
package steam

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"regexp"
	"strings"
)

// Library is used to represent the steam library, the Games map is populated
// by NewLibrary when called or when ProcessLibrary is called directly
type Library struct {
	Folder string
	Games  map[string]Game
}

// Game represents an actual game in the steam Library, allowing you to perform
// a delete, package, and such.
type Game struct {
	Name        string
	LibraryPath string
	Size        int64
}

var slugregexp = regexp.MustCompile(`[^-0-9A-Za-z_:.]`)

// Slug returns a safer version of the name with spaces and other chars
// transformed into dashes for use in HTML element ids and such.
func (g Game) Slug() string {
	return slugregexp.ReplaceAllString(g.Name, "-")
}

// NewLibrary returns a pointer to a processed library and an error
// if any
func NewLibrary(path string) (*Library, error) {
	l := &Library{}
	err := l.ProcessLibrary(path)
	if err != nil {
		return nil, err
	}
	return l, err
}

// NewLibraryMust is the same as NewLibrary but calls panic if there
// is any error
func NewLibraryMust(path string) *Library {
	l, err := NewLibrary(path)
	if err != nil {
		panic(err)
	}
	return l
}

// ProcessLibrary Populates the "Folder" and "Games" fields based on the
// provided directory.
func (s *Library) ProcessLibrary(r string) error {
	if !hasCommon(r) {
		return fmt.Errorf("No common directory in: %s", r)
	}

	s.Games = make(map[string]Game)

	dirs, err := ioutil.ReadDir(r + "/common")
	if err != nil {
		return err
	}
	s.Folder = r
	for _, f := range dirs {
		if f.IsDir() {
			g := &Game{
				Name:        f.Name(),
				LibraryPath: r,
			}
			g.setSizeInfo()

			s.Games[f.Name()] = *g
		}
	}

	return nil
}

// FindACF will return the filename of the ACF file for a given `game`
func FindACF(libraryPath, game string) (string, error) {
	files, err := filepath.Glob(filepath.Join(libraryPath, "*.acf"))
	if err != nil {
		return "", err
	}
	for _, fn := range files {
		info, err := os.Lstat(fn)
		if err != nil {
			return "", err
		}
		// We don't want it if it's a directory
		if info.IsDir() {
			continue
		}

		// Open up the file
		f, err := os.Open(fn)
		if err != nil {
			return "", err
		}
		defer f.Close()

		scanner := bufio.NewScanner(f)
		for scanner.Scan() {
			if strings.Contains(scanner.Text(), game) {
				return fn, nil
			}
		}

	}
	return "", fmt.Errorf("Couldn't find ACF file related to Game: %s", game)
}

func (s *Library) String() (str string) {
	str = fmt.Sprintf("Library: %s\n", s.Folder)
	str = str + "----\n"
	for _, v := range s.Games {
		str = str + fmt.Sprintf("%s\n", v.Name)
	}
	return
}

func hasCommon(d string) bool {
	dirs, err := ioutil.ReadDir(d)
	if err != nil {
		return false
	}
	for _, f := range dirs {
		if f.Name() == "common" && f.IsDir() {
			return true
		}
	}
	return false
}