WIP
This commit is contained in:
commit
d7f0a68b08
|
@ -0,0 +1 @@
|
|||
Output
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/fmartingr/games-screenshot-mananger
|
||||
|
||||
go 1.15
|
|
@ -0,0 +1,7 @@
|
|||
package main
|
||||
|
||||
import "github.com/fmartingr/games-screenshot-mananger/pkg/cli"
|
||||
|
||||
func main() {
|
||||
cli.Start()
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package cli
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"github.com/fmartingr/games-screenshot-mananger/pkg/games"
|
||||
"github.com/fmartingr/games-screenshot-mananger/pkg/helpers"
|
||||
"github.com/fmartingr/games-screenshot-mananger/pkg/providers/steam"
|
||||
)
|
||||
|
||||
var AllowedProviders = [...]string{"steam"}
|
||||
|
||||
const OutputPath string = "~/Developer/games-screenshot-manager/Output"
|
||||
|
||||
func main() {
|
||||
Start()
|
||||
}
|
||||
|
||||
func Start() {
|
||||
var provider = flag.String("provider", "steam", "steam")
|
||||
flag.Parse()
|
||||
if helpers.SliceContainsString(AllowedProviders[:], *provider, nil) {
|
||||
games := getGamesFromProvider(*provider)
|
||||
processGames(games)
|
||||
} else {
|
||||
log.Printf("Provider %s not found!", *provider)
|
||||
}
|
||||
}
|
||||
|
||||
func getGamesFromProvider(provider string) []games.Game {
|
||||
var games []games.Game
|
||||
if provider == "steam" {
|
||||
games = append(games, steam.GetGames()...)
|
||||
}
|
||||
return games
|
||||
}
|
||||
|
||||
func processGames(games []games.Game) {
|
||||
dryRun := false
|
||||
|
||||
for _, game := range games {
|
||||
destinationPath := path.Join(helpers.ExpandUser(OutputPath), game.Platform)
|
||||
if len(game.Name) > 0 {
|
||||
destinationPath = path.Join(destinationPath, game.Name)
|
||||
} else {
|
||||
log.Printf("[IMPORTANT] Game ID %d has no name!", game.ID)
|
||||
destinationPath = path.Join(destinationPath, strconv.FormatUint(game.ID, 10))
|
||||
}
|
||||
|
||||
// Check if folder exists
|
||||
if _, err := os.Stat(destinationPath); os.IsNotExist(err) {
|
||||
os.MkdirAll(destinationPath, 0711)
|
||||
}
|
||||
|
||||
log.Printf("=> Proceesing screenshots for %s", game.Name)
|
||||
for _, screenshot := range game.Screenshots {
|
||||
fileStat, statErr := os.Stat(screenshot.Path)
|
||||
if statErr != nil {
|
||||
log.Fatal(statErr)
|
||||
}
|
||||
|
||||
destinationPath := path.Join(destinationPath, fileStat.ModTime().Format("2006-01-02_15-04-05")+path.Ext(screenshot.Path))
|
||||
|
||||
if _, err := os.Stat(destinationPath); !os.IsNotExist(err) {
|
||||
sourceMd5, err := helpers.Md5File(screenshot.Path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
continue
|
||||
}
|
||||
destinationMd5, err := helpers.Md5File(destinationPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
continue
|
||||
}
|
||||
|
||||
if bytes.Compare(sourceMd5, destinationMd5) != 0 {
|
||||
// Images are not equal, we should copy it anyway, but how?
|
||||
log.Println("Found different screenshot with equal timestamp for game ", game.Name, screenshot.Path)
|
||||
}
|
||||
|
||||
} else {
|
||||
if !dryRun {
|
||||
helpers.CopyFile(screenshot.Path, destinationPath)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package games
|
||||
|
||||
type Game struct {
|
||||
ID uint64
|
||||
Name string
|
||||
Platform string
|
||||
Provider string
|
||||
Screenshots []Screenshot
|
||||
}
|
||||
|
||||
type Screenshot struct {
|
||||
Path string
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package helpers
|
||||
|
||||
import (
|
||||
"os/user"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func ExpandUser(providedPath string) string {
|
||||
var path string
|
||||
usr, _ := user.Current()
|
||||
dir := usr.HomeDir
|
||||
|
||||
if providedPath == "~" {
|
||||
path = dir
|
||||
} else if strings.HasPrefix(providedPath, "~/") {
|
||||
path = filepath.Join(dir, providedPath[2:])
|
||||
}
|
||||
return path
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package helpers
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func CopyFile(src, dst string) (int64, error) {
|
||||
sourceFileStat, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !sourceFileStat.Mode().IsRegular() {
|
||||
return 0, fmt.Errorf("%s is not a regular file", src)
|
||||
}
|
||||
|
||||
source, err := os.Open(src)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer source.Close()
|
||||
|
||||
// Check if destination exists
|
||||
if _, err := os.Stat(dst); !os.IsNotExist(err) {
|
||||
log.Printf("- %s already exists, skipping...", dst)
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
destination, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer destination.Close()
|
||||
nBytes, err := io.Copy(destination, source)
|
||||
return nBytes, err
|
||||
}
|
||||
|
||||
func Md5File(src string) ([]byte, error) {
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
h := md5.New()
|
||||
if _, err := io.Copy(h, f); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return h.Sum(nil), nil
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package helpers
|
||||
|
||||
func SliceContainsString(slice []string, s string, modifier func(s string) string) bool {
|
||||
for _, item := range slice {
|
||||
if item == s {
|
||||
return true
|
||||
}
|
||||
if modifier != nil && modifier(item) == s {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
package steam
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fmartingr/games-screenshot-mananger/pkg/games"
|
||||
"github.com/fmartingr/games-screenshot-mananger/pkg/helpers"
|
||||
)
|
||||
|
||||
const providerName string = "steam"
|
||||
|
||||
type SteamApp struct {
|
||||
AppID uint64 `json:"appid"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type SteamAppList struct {
|
||||
Apps []SteamApp `json:"apps"`
|
||||
}
|
||||
|
||||
func (appList SteamAppList) FindID(id uint64) (SteamApp, error) {
|
||||
GameIDNotFound := errors.New("Game ID not found")
|
||||
for _, game := range appList.Apps {
|
||||
if game.AppID == id {
|
||||
return game, nil
|
||||
}
|
||||
}
|
||||
return SteamApp{}, GameIDNotFound
|
||||
}
|
||||
|
||||
type SteamAppListResponse struct {
|
||||
AppList SteamAppList `json:"applist"`
|
||||
}
|
||||
|
||||
func GetSteamAppsList(c chan SteamAppList) {
|
||||
log.Println("Updating steam game list...")
|
||||
steamGetAppListURL, _ := url.Parse("https://api.steampowered.com/ISteamApps/GetAppList/v2/")
|
||||
request := http.Request{
|
||||
Method: "GET",
|
||||
URL: steamGetAppListURL,
|
||||
Header: map[string][]string{
|
||||
"User-Agent": {"games-screenshot-manager/0.0.1"},
|
||||
},
|
||||
ProtoMajor: 2,
|
||||
ProtoMinor: 1,
|
||||
}
|
||||
response, err := http.DefaultClient.Do(&request)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if response.Body != nil {
|
||||
defer response.Body.Close()
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
steamListResponse := SteamAppListResponse{}
|
||||
jsonErr := json.Unmarshal(body, &steamListResponse)
|
||||
if jsonErr != nil {
|
||||
log.Fatal(jsonErr)
|
||||
}
|
||||
|
||||
log.Printf("Updated Steam game list. Found %d games.", len(steamListResponse.AppList.Apps))
|
||||
|
||||
c <- steamListResponse.AppList
|
||||
}
|
||||
|
||||
func GuessUsers() []string {
|
||||
var users []string
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
if _, err := os.Stat(helpers.ExpandUser("~/.local/share/Steam/userdata")); !os.IsNotExist(err) {
|
||||
files, err := ioutil.ReadDir(helpers.ExpandUser("~/.local/share/Steam/userdata"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if _, err := strconv.ParseInt(file.Name(), 10, 64); err == nil {
|
||||
log.Printf("Found local install Steam user: %s", file.Name())
|
||||
users = append(users, file.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
func GetGamesFromUser(user string) []uint64 {
|
||||
log.Println("Getting Steam games for user: " + user)
|
||||
var userGames []uint64
|
||||
path := helpers.ExpandUser("~/.local/share/Steam/userdata/" + user + "/760/remote")
|
||||
|
||||
if runtime.GOOS == "linux" {
|
||||
if _, err := os.Stat(path); !os.IsNotExist(err) {
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
// len(file.Name()) == 20 -> Custom added Game to steam
|
||||
gameID, err := strconv.ParseUint(file.Name(), 10, 64)
|
||||
if err == nil {
|
||||
userGames = append(userGames, gameID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return userGames
|
||||
}
|
||||
|
||||
func GetScreenshotsForGame(user string, game *games.Game) {
|
||||
path := helpers.ExpandUser("~/.local/share/Steam/userdata/" + user + "/760/remote/" + strconv.FormatUint(game.ID, 10) + "/screenshots")
|
||||
files, err := ioutil.ReadDir(path)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
if strings.Contains(file.Name(), ".jpg") {
|
||||
game.Screenshots = append(game.Screenshots, games.Screenshot{Path: path + "/" + file.Name()})
|
||||
// log.Printf("Found screenshot for user %s and game %d: %s", user, game.ID, path+"/"+file.Name())
|
||||
}
|
||||
}
|
||||
|
||||
if len(game.Screenshots) > 0 {
|
||||
log.Printf("Found %d screenshots", len(game.Screenshots))
|
||||
}
|
||||
}
|
||||
|
||||
func GetGames() []games.Game {
|
||||
var localGames []games.Game
|
||||
c := make(chan SteamAppList)
|
||||
go GetSteamAppsList(c)
|
||||
users := GuessUsers()
|
||||
steamApps := <-c
|
||||
for _, userID := range users {
|
||||
userGames := GetGamesFromUser(userID)
|
||||
for _, userGameID := range userGames {
|
||||
steamGame, err := steamApps.FindID(userGameID)
|
||||
if err != nil {
|
||||
log.Print("[ERROR] Steam game ID not found: ", userGameID)
|
||||
}
|
||||
userGame := games.Game{ID: userGameID, Name: steamGame.Name, Provider: providerName, Platform: "PC"}
|
||||
log.Printf("Found Steam game for user %s: %s (%d)", userID, userGame.Name, userGame.ID)
|
||||
GetScreenshotsForGame(userID, &userGame)
|
||||
localGames = append(localGames, userGame)
|
||||
}
|
||||
}
|
||||
return localGames
|
||||
}
|
Loading…
Reference in New Issue