Skip to content

Commit

Permalink
Release of version 0.2.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ChriZ982 authored Apr 17, 2020
2 parents e3dd7a6 + 71f390d commit cde5930
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 28 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"mode": "auto",
"program": "${workspaceFolder}/src/main.go",
"env": {"CGO_ENABLED":1},
"args": ["-level", "DEBUG", "-layoutWidth", "4", "-groupName", "GOG Galaxy 2.0 Games", "-y"]
"args": ["-level", "DEBUG", "-width", "4", "-tileSize", "2", "-groupName", "GOG Galaxy 2.0 Games", "-y", "-tagName", "INSTALLED", "-hideName"]
}
]
}
30 changes: 22 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,21 @@
# <img height="25" src="https://simpleicons.org/icons/gog-dot-com.svg"/> WIP: GOG Galaxy 2.0 Start Menu Tiles
[![GOG Galaxy 2.0](https://img.shields.io/badge/GOG-Galaxy%202.0-86328A?logo=data:https://simpleicons.org/icons/gog-dot-com.svg)](https://www.gogalaxy.com/en/) ![Build status](https://travis-ci.org/ChriZ982/gog-galaxy-2.0-start-menu-tiles.svg?branch=master) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/ChriZ982/gog-galaxy-2.0-start-menu-tiles) ![GitHub stars](https://img.shields.io/github/stars/ChriZ982/gog-galaxy-2.0-start-menu-tiles) ![GitHub top language](https://img.shields.io/github/languages/top/ChriZ982/gog-galaxy-2.0-start-menu-tiles) [![PayPal.Me ChriZ98](https://img.shields.io/badge/PayPal.Me-ChriZ98-00457C?logo=paypal)](https://www.paypal.me/ChriZ98)
# <img height="25" src="https://simpleicons.org/icons/gog-dot-com.svg"/> GOG Galaxy 2.0 Start Menu Tiles
[![GOG Galaxy 2.0](https://img.shields.io/badge/GOG-Galaxy%202.0-86328A?logo=data:https://simpleicons.org/icons/gog-dot-com.svg)](https://www.gogalaxy.com/en/) [![Build status](https://travis-ci.org/ChriZ982/gog-galaxy-2.0-start-menu-tiles.svg?branch=master)](https://travis-ci.org/github/ChriZ982/gog-galaxy-2.0-start-menu-tiles/branches) [![GitHub release (latest by date)](https://img.shields.io/github/v/release/ChriZ982/gog-galaxy-2.0-start-menu-tiles)](https://github.com/ChriZ982/gog-galaxy-2.0-start-menu-tiles/releases) ![GitHub stars](https://img.shields.io/github/stars/ChriZ982/gog-galaxy-2.0-start-menu-tiles) ![GitHub top language](https://img.shields.io/github/languages/top/ChriZ982/gog-galaxy-2.0-start-menu-tiles) [![PayPal.Me ChriZ98](https://img.shields.io/badge/PayPal.Me-ChriZ98-00457C?logo=paypal)](https://www.paypal.me/ChriZ98)

## **Disclaimer: This is in a highly experimental stage and might break your Start Menu or your Windows Registry! Use at own risk!**
This script lets you create Start Menu Tiles of your favourite games in Windows 10! :video_game:

This script lets you create Start Menu Tiles of your favourite games in Windows 10! :video_game:
Simply download the `GOG_Galaxy_Start_Menu.exe` from the Releases section. Your GOG Galaxy 2.0 database will be read and a shortcut will be created in the Programs section. Additionally tiles can be automatically added to the Start Menu, providing a stylish and easy access.

**Disclaimer: If you have applied a Start Menu Layout previosly, all changes will be reverted and all tiles will be deleted! This can be the case for computers managed by organizations.**

#### Examples:
<table>
<tr>
<td><img alt="Startmenu Picture" src="examples/startmenu1.jpeg" /></td>
<td><img alt="Startmenu Picture" src="examples/startmenu2.jpeg" /></td>
<td><img alt="Startmenu Picture 1" src="examples/startmenu1.jpeg" /></td>
<td><img alt="Startmenu Picture 2" src="examples/startmenu2.jpeg" /></td>
</tr>
<tr>
<td><img alt="Startmenu Picture 3" src="examples/startmenu3.jpeg" /></td>
<td></td>
</tr>
</table>

Expand All @@ -25,16 +31,24 @@ This script lets you create Start Menu Tiles of your favourite games in Windows
Usage of GOG_Galaxy_Start_Menu.exe:
-database string
Path to GOG Galaxy 2.0 database. (default "C:/ProgramData/GOG.com/Galaxy/storage/galaxy-2.0.db")
-force
Force re-download of images.
-groupName string
Name of the Start Menu group.
-layoutWidth int
Defines the tile count per row in the Start Menu Layout (3 or 4). (default 3)
-height int
Defines the rows per group Start Menu Layout. (default 7)
-hideName
Show name of game on Start Menu Tile.
-level string
Defines log level. (default "INFO")
-startFolder string
Path for game shortcuts and image data. (default "/Appdata/Roaming/Microsoft/Windows/Start Menu/Programs/GOG.com/GameTiles/")
-tagName string
Define a custom tag that defines games to be added to the Start Menu. You can also set it to INSTALLED or ALL to add installed or all games to the StartMenu. (default "StartMenuTiles")
-tileSize int
Size of the individual game tiles (1 or 2). (default 2)
-width int
Defines the tile count per row in the Start Menu Layout (3 or 4). (default 3)
-y Always confirm creation of Start Layout.
```

Expand Down
Binary file modified examples/startmenu1.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/startmenu2.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/startmenu3.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
102 changes: 83 additions & 19 deletions src/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,29 @@ import (
const sqlTaggedGames = `SELECT UserReleaseTags.releaseKey, WebCacheResources.filename, GamePieces.value FROM UserReleaseTags
LEFT JOIN WebCacheResources ON UserReleaseTags.releaseKey = WebCacheResources.releaseKey
LEFT JOIN GamePieces ON UserReleaseTags.releaseKey = GamePieces.releaseKey
WHERE UserReleaseTags.tag = 'StartMenuTiles' AND WebCacheResources.webCacheResourceTypeId = 2 AND GamePieces.gamePieceTypeId = 11 AND GamePieces.userId <> 0`
WHERE UserReleaseTags.tag = ? AND WebCacheResources.webCacheResourceTypeId = 2 AND GamePieces.gamePieceTypeId = 11 AND GamePieces.userId <> 0`

const sqlInstalledGames = `SELECT Installed.releaseKey, WebCacheResources.filename, GamePieces.value FROM
(SELECT 'gog_' || productId as releaseKey FROM InstalledBaseProducts
UNION ALL
SELECT Platforms.name || '_' || productId as releaseKey FROM InstalledExternalProducts
JOIN Platforms ON InstalledExternalProducts.platformId = Platforms.id) as Installed
LEFT JOIN WebCacheResources ON Installed.releaseKey = WebCacheResources.releaseKey
LEFT JOIN GamePieces ON Installed.releaseKey = GamePieces.releaseKey
WHERE WebCacheResources.webCacheResourceTypeId = 2 AND GamePieces.gamePieceTypeId = 11 AND GamePieces.userId <> 0`

const sqlAllGames = `SELECT OwnedGames.releaseKey, WebCacheResources.filename, GamePieces.value FROM OwnedGames
LEFT JOIN WebCacheResources ON OwnedGames.releaseKey = WebCacheResources.releaseKey
LEFT JOIN GamePieces ON OwnedGames.releaseKey = GamePieces.releaseKey
WHERE WebCacheResources.webCacheResourceTypeId = 2 AND GamePieces.gamePieceTypeId = 11 AND OwnedGames.userId <> 0 AND GamePieces.userId <> 0`

// Uses a partial Start Layout (https://docs.microsoft.com/en-us/windows/configuration/customize-and-export-start-layout#configure-a-partial-start-layout)
const partialStartLayoutBegin = `<LayoutModificationTemplate xmlns:defaultlayout="http://schemas.microsoft.com/Start/2014/FullDefaultLayout" xmlns:start="http://schemas.microsoft.com/Start/2014/StartLayout" Version="1" xmlns="http://schemas.microsoft.com/Start/2014/LayoutModification">
<LayoutOptions StartTileGroupCellWidth="8" />
<DefaultLayoutOverride LayoutCustomizationRestrictionType="OnlySpecifiedGroups">
<StartLayoutCollection>
<defaultlayout:StartLayout GroupCellWidth="8">
<start:Group Name="%s">`
<defaultlayout:StartLayout GroupCellWidth="8">
<start:Group Name="%s">`

const startLayoutTile = `
<start:DesktopApplicationTile Size="%[1]dx%[1]d" Column="%[2]d" Row="%[3]d" DesktopApplicationLinkPath="%%APPDATA%%\Microsoft\Windows\Start Menu\Programs\GOG.com\GameTiles\%[4]s.lnk" />`
Expand All @@ -41,26 +55,34 @@ const partialStartLayoutEnd = `
</DefaultLayoutOverride>
</LayoutModificationTemplate>`

const powershellCreateShortcut = `Invoke-WebRequest -Uri https://images.gog.com/%s?namespace=gamesdb -OutFile "%s.png"
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut("%s.lnk")
const newGroup = `
</start:Group>
<start:Group Name="%s">`

const powershellDownloadImage = `Invoke-WebRequest -Uri https://images.gog.com/%s?namespace=gamesdb -OutFile "%s.png"`

const powershellCreateShortcut = `$Shortcut = $WScriptShell.CreateShortcut("%s.lnk")
$Shortcut.TargetPath = "%s.bat"
$Shortcut.Save()`

const visualElements = `<?xml version="1.0" encoding="utf-8"?>
<Application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<VisualElements ShowNameOnSquare150x150Logo="on" Square150x150Logo="VisualElements\MediumIcon%[1]s.png" Square70x70Logo="VisualElements\MediumIcon%[1]s.png" ForegroundText="light" BackgroundColor="#5A391B" />
<VisualElements ShowNameOnSquare150x150Logo="%[2]s" Square150x150Logo="VisualElements\MediumIcon%[1]s.png" Square70x70Logo="VisualElements\MediumIcon%[1]s.png" ForegroundText="light" BackgroundColor="#5A391B" />
</Application>`

var alphanum = regexp.MustCompile("[^A-Za-z0-9 ]+")
var disallowedChars = regexp.MustCompile("[^A-Za-z0-9 +_#!()=-]+")

var loglevel = flag.String("level", "INFO", "Defines log level.")
var databaseFile = flag.String("database", "C:/ProgramData/GOG.com/Galaxy/storage/galaxy-2.0.db", "Path to GOG Galaxy 2.0 database.")
var startMenuDir = flag.String("startFolder", "/Appdata/Roaming/Microsoft/Windows/Start Menu/Programs/GOG.com/GameTiles/", "Path for game shortcuts and image data.")
var width = flag.Int("layoutWidth", 3, "Defines the tile count per row in the Start Menu Layout (3 or 4).")
var width = flag.Int("width", 3, "Defines the tile count per row in the Start Menu Layout (3 or 4).")
var height = flag.Int("height", 7, "Defines the rows per group Start Menu Layout.")
var tileSize = flag.Int("tileSize", 2, "Size of the individual game tiles (1 or 2).")
var yes = flag.Bool("y", false, "Always confirm creation of Start Layout.")
var groupName = flag.String("groupName", "", "Name of the Start Menu group.")
var tagName = flag.String("tagName", "StartMenuTiles", "Define a custom tag that defines games to be added to the Start Menu. You can also set it to INSTALLED or ALL to add installed or all games to the StartMenu.")
var hideName = flag.Bool("hideName", false, "Show name of game on Start Menu Tile.")
var force = flag.Bool("force", false, "Force re-download of images.")

func main() {
flag.Parse()
Expand Down Expand Up @@ -96,7 +118,14 @@ func listGames() *map[string]map[string]string {
if err != nil {
log.Fatalf("Error while trying to open GOG Galaxy 2.0 database at '%s'. %s", *databaseFile, err)
}
rows, err := database.Query(sqlTaggedGames)
var rows *sql.Rows
if *tagName == "INSTALLED" {
rows, err = database.Query(sqlInstalledGames)
} else if *tagName == "ALL" {
rows, err = database.Query(sqlAllGames)
} else {
rows, err = database.Query(sqlTaggedGames, *tagName)
}
if err != nil {
log.Fatal("Error while running query on database. ", err)
}
Expand All @@ -109,7 +138,7 @@ func listGames() *map[string]map[string]string {
var title string
for rows.Next() {
rows.Scan(&releaseKey, &iconFileName, &title)
extractedTitle := alphanum.ReplaceAllString(strings.Split(title, ":")[1], "")
extractedTitle := disallowedChars.ReplaceAllString(strings.Split(title, ":")[1], "")
alreadyExisting := false
for _, val := range games {
if val["title"] == extractedTitle {
Expand All @@ -126,6 +155,15 @@ func listGames() *map[string]map[string]string {
games[releaseKey]["iconFileName"] = strings.ReplaceAll(iconFileName, ".webp", ".png")
games[releaseKey]["title"] = extractedTitle
}
if len(games) == 0 {
log.Fatal("No games found.")
}
if len(games) > 150 {
log.Fatalf("Adding too many tiles causes unexpected behaviour. %d tiles can not be created safely.", len(games))
}
if len(games) > 80 {
log.Warnf("Adding too many tiles causes unexpected behaviour. %d tiles will be added.", len(games))
}
return &games
}

Expand All @@ -144,27 +182,52 @@ func createStartMenu(games *map[string]map[string]string) {
log.Info("Creating Start Menu layout...")
partialStartLayout := fmt.Sprintf(partialStartLayoutBegin, *groupName)
tileCount := 0
maxTiles := *width * (3 - *tileSize) * *height * (3 - *tileSize)
actualWidth := *width * (3 - *tileSize)
nameOnLogo := "on"
if *hideName {
nameOnLogo = "off"
}
allPowershellCreateShortcut := "$WScriptShell = New-Object -ComObject WScript.Shell\n"
allPowershellDownloadImage := ""
for key, val := range *games {
partialStartLayout += fmt.Sprintf(startLayoutTile,
*tileSize,
(tileCount%actualWidth)*(*tileSize),
(tileCount-(tileCount%actualWidth))/actualWidth*(*tileSize),
val["title"])
tileCount++
writeFile(startMenuPath+key+".bat",
`"C:\Program Files (x86)\GOG Galaxy\GalaxyClient.exe" /command=runGame /gameId=`+key)
writeFile(startMenuPath+key+".VisualElementsManifest.xml", fmt.Sprintf(visualElements, key))

execPowershell(powershellCreateShortcut,
val["iconFileName"], startMenuPath+"VisualElements\\MediumIcon"+key, startMenuPath+val["title"], startMenuPath+key)
if tileCount >= maxTiles {
tileCount = 0
partialStartLayout += fmt.Sprintf(newGroup, *groupName)
}
plainKey := disallowedChars.ReplaceAllString(key, "")
writeFile(startMenuPath+plainKey+".bat", `"C:\Program Files (x86)\GOG Galaxy\GalaxyClient.exe" /command=runGame /gameId=`+key)
writeFile(startMenuPath+plainKey+".VisualElementsManifest.xml", fmt.Sprintf(visualElements, plainKey, nameOnLogo))
if !fileExists(startMenuPath+"VisualElements\\MediumIcon"+plainKey+".png") || *force {
allPowershellDownloadImage += fmt.Sprintf(powershellDownloadImage+"\n", val["iconFileName"], startMenuPath+"VisualElements\\MediumIcon"+plainKey)
}
allPowershellCreateShortcut += fmt.Sprintf(powershellCreateShortcut+"\n", startMenuPath+val["title"], startMenuPath+plainKey)
}
if len(allPowershellDownloadImage) > 0 {
execPowershell(allPowershellDownloadImage)
}
execPowershell(allPowershellCreateShortcut)

partialStartLayout += partialStartLayoutEnd
writeFile("PartialStartLayout.xml", partialStartLayout)
}

func fileExists(filename string) bool {
info, err := os.Stat(filename)
if os.IsNotExist(err) {
return false
}
return !info.IsDir()
}

func updateRegistry() {
time.Sleep(8 * time.Second) // Wait for shortcuts to be recoginzed
log.Info("Updating Start Menu...")
execPowershell("Export-StartLayout -Path StartLayoutBackup.xml")
key, _, err := registry.CreateKey(registry.CURRENT_USER, `Software\Policies\Microsoft\Windows\Explorer`, registry.ALL_ACCESS)
Expand All @@ -180,7 +243,7 @@ func updateRegistry() {
log.Warn("Registry Value 'StartLayoutFile' or 'LockedStartLayout' exists. There might have been a Start Layout previously applied! This would be removed entirely!")
}
if !*yes {
log.Warning("The script will now create registry values to modify the Start Menu. The groups in your Start Menu will probably be reordered. If there was a custom Start Layout .xml file applied before, all tiles will be removed! Use at own risk!\nDo you want to proceed? [yN]")
log.Warn("The script will now create registry values to modify the Start Menu. The groups in your Start Menu will probably be reordered. If there was a custom Start Layout .xml file applied before, all tiles will be removed! Use at own risk!\nDo you want to proceed? [yN]")
var proceed string
fmt.Scanln(&proceed)
if proceed != "y" {
Expand Down Expand Up @@ -226,7 +289,8 @@ func execPowershell(cmdText string, args ...interface{}) {
}
for _, line := range strings.Split(stderr.String(), "\r\n") {
if len(line) > 0 {
log.Warn(strings.TrimRight(line, " "))
log.Error(strings.TrimRight(line, " "))
log.Warn("Script: ", fmt.Sprintf(cmdText, args...))
}
}
for _, line := range strings.Split(stdout.String(), "\r\n") {
Expand Down

0 comments on commit cde5930

Please sign in to comment.