Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
SpoilerRules committed Mar 4, 2025
0 parents commit 70d9c33
Show file tree
Hide file tree
Showing 22 changed files with 2,631 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Folders
.idea/
Pipsi Installations/
workspace/
dist/

# Files
cheat_catalog.yaml
installation_data.yaml
41 changes: 41 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
# vim: set ts=2 sw=2 tw=0 fo=jcroql
version: 2

before:
hooks:
- go mod tidy

builds:
- id: windows
goos:
- windows
goarch:
# - "386"
- amd64
# - arm64
mod_timestamp: "{{ .CommitTimestamp }}"
flags:
- -trimpath
ldflags:
- -s -w -X main.version={{.Version}} -X main.commit={{.Commit}} -X main.date={{ .CommitDate }} -X main.builtBy=goreleaser -X main.treeState={{ .IsGitDirty }}
env:
- CGO_ENABLED=0

archives:
- name_template: >-
{{- .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end -}}
release:
disable: true

changelog:
disable: true

checksum:
disable: true
Binary file added Game Icons/Pipsi-HI3.ico
Binary file not shown.
Binary file added Game Icons/Pipsi-HSR.ico
Binary file not shown.
Binary file added Game Icons/Pipsi-WuWa.ico
Binary file not shown.
Binary file added Game Icons/Pipsi-ZZZ.ico
Binary file not shown.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

129 changes: 129 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<a id="readme-top"></a>
<!--suppress HtmlDeprecatedAttribute -->
<h1 align="center">
<b>Pipsi Utilities</b>
</h1>

<p align="center">
<a href="https://www.codefactor.io/repository/github/SpoilerRules/pipsi-utils">
<img src="https://www.codefactor.io/repository/github/SpoilerRules/pipsi-utils/badge" alt="CodeFactor">
</a>
<a href="https://github.com/SpoilerRules/pipsi-utils/releases">
<img src="https://img.shields.io/github/downloads/SpoilerRules/pipsi-utils/total" alt="GitHub Downloads">
</a>
<a href="LICENSE">
<img src="https://img.shields.io/badge/license-GPL--3.0-blue.svg" alt="GPL-3.0 License">
</a>
</p>

<!--suppress HtmlDeprecatedAttribute -->
<p align="center">
Pipsi Utils is a command-line app that automates Pipsi installations and updates with an interactive interface.
</p>

<p align="center">
<img src="https://i.imgur.com/6XMGQqN.gif" alt="Pipsi Utilities Showcase" style="max-width: 100%; height: auto;">
</p>

<details>
<summary>Table of Contents</summary>
<ul>
<li><a href="#getting-started">Getting Started</a></li>
<li><a href="#building-from-source">Building from Source</a>
<ul>
<li><a href="#prerequisites">Prerequisites</a></li>
<li><a href="#build-instructions">Build Instructions</a></li>
<li><a href="#notes">Notes</a></li>
</ul>
</li>
<li><a href="#contributing">Contributing</a></li>
<li><a href="#license">License</a></li>
</ul>
</details>

## Getting Started

1. **Download the Latest Binary**
Visit the [releases page](https://github.com/SpoilerRules/pipsi-utils/releases/latest) and download the latest binary for your system.

2. **Install the Binary**
Move the executable to your desired installation directory (e.g., `C:\Desktop\Favorite Apps\pipsi-utils`).
**Note**: The tool will create supporting files/folders (e.g., Pipsi installations) in this directory. Ensure it has write permissions.

3. **Run the Tool**
You can run the tool in one of the following ways:
- **Via Terminal/Powershell**:
Open a terminal or PowerShell window and execute:
```powershell
.\pipsi-utils.exe
```
- **Via Right-Click**:
Right-click on the executable and select **Open** from the context menu.
- **Via Double-Click**:
Double-click the executable file to run it directly.
<p align="right">(<a href="#readme-top">back to top</a>)</p>
## Building from Source
### Prerequisites
- **Go 1.24 (64-bit)** installed on Windows ([download](https://go.dev/dl/))
- **Git** for repository cloning
### Build Instructions
1. **Clone the Repository**
```powershell
git clone https://github.com/SpoilerRules/pipsi-utils.git
cd pipsi-utils
```
2. **Build the Binary**

Dependencies will be automatically fetched by Go Modules. Run:
```powershell
go build -o pipsi-utils.exe
```
This generates `pipsi-utils.exe` in the project root.

3. **Run the Application**
Launch the application to verify the build:
```powershell
.\pipsi-utils.exe
```

<p align="right">(<a href="#readme-top">back to top</a>)</p>

### Notes
Ensure your Go environment is properly configured (`GOPATH`, `GOROOT`, etc.).

If you encounter issues, check your Go version (`go version`) and ensure it matches the prerequisite (Go 1.24).

<p align="right">(<a href="#readme-top">back to top</a>)</p>

## Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
Don't forget to give the project a star! Thanks again!

1. Fork the Project
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
4. Push to the Branch (`git push origin feature/AmazingFeature`)
5. Open a Pull Request

<p align="right">(<a href="#readme-top">back to top</a>)</p>

### Top contributors:

<a href="https://github.com/SpoilerRules/pipsi-utils/graphs/contributors">
<img src="https://contrib.rocks/image?repo=SpoilerRules/pipsi-utils" alt="contrib.rocks image" />
</a>

## License

Distributed under the [GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html). See the [LICENSE](LICENSE) file for more information.

<p align="right">(<a href="#readme-top">back to top</a>)</p>
14 changes: 14 additions & 0 deletions accessibility.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import (
"os"
"strconv"
)

func IsAccessible() bool {
accessible, err := strconv.ParseBool(os.Getenv("ACCESSIBLE"))
if err != nil {
return false
}
return accessible
}
78 changes: 78 additions & 0 deletions cheat_catalog_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package main

import (
"fmt"
"gopkg.in/yaml.v3"
"io"
"net/http"
)

type GameCheat struct {
GameTitle string `yaml:"game_title"`
CheatInstallationLink string `yaml:"cheat_installation_link"`
InstallationFolder string `yaml:"installation_folder"`
IsDiscontinued bool `yaml:"is_discontinued"`
}

type Config struct {
Cheats []GameCheat `yaml:"cheat_catalog"`
}

var config Config

func loadCheatCatalogFromURL(url string) error {
response, err := http.Get(url)
if err != nil {
return fmt.Errorf("failed to fetch configuration from URL %s: %w", url, err)
}
defer func() {
if closeErr := response.Body.Close(); closeErr != nil {
err = fmt.Errorf("failed to close response body: %w", closeErr)
}
}()

if response.StatusCode != http.StatusOK {
return fmt.Errorf("failed to fetch configuration: received status %d", response.StatusCode)
}

body, err := io.ReadAll(response.Body)
if err != nil {
return fmt.Errorf("failed to read response body: %w", err)
}

if err := yaml.Unmarshal(body, &config); err != nil {
return fmt.Errorf("failed to decode YAML from URL: %w", err)
}

return nil
}

func (cfg *Config) getSupportedGameTitles() []string {
var titles []string
for _, cheat := range cfg.Cheats {
if !cheat.IsDiscontinued {
titles = append(titles, cheat.GameTitle)
}
}
return titles
}

func (cfg *Config) getInstallationLink(title string) string {
for _, cheat := range cfg.Cheats {
if cheat.GameTitle == title {
return cheat.CheatInstallationLink
}
}
fmt.Printf("Error: InstallationData title '%s' not found. The installation link could not be retrieved.\n", title)
return ""
}

func (cfg *Config) getInstallationFolder(title string) string {
for _, cheat := range cfg.Cheats {
if cheat.GameTitle == title {
return cheat.InstallationFolder
}
}
fmt.Printf("Error: InstallationData title '%s' not found. The installation folder could not be retrieved.\n", title)
return ""
}
13 changes: 13 additions & 0 deletions colors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import "github.com/charmbracelet/lipgloss"

var (
WarningText = lipgloss.NewStyle().Foreground(lipgloss.Color("3")) // yellow
HighlightText = lipgloss.NewStyle().Foreground(lipgloss.Color("11")) // bright yellow
// NoticePrefix = lipgloss.NewStyle().Foreground(lipgloss.Color("3"))
BoldCyan = lipgloss.NewStyle().Foreground(lipgloss.Color("6"))
StatusText = lipgloss.NewStyle().
Bold(true).
Foreground(lipgloss.Color("#00C853")) // bold green adhering to fluent 2 theme
)
87 changes: 87 additions & 0 deletions defender_exclusion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package main

import (
"bytes"
"fmt"
"github.com/charmbracelet/log"
"os"
"os/exec"
"path/filepath"
"strings"
)

func manageDefenderExclusion() {
if !isDefenderActive() {
log.Warnf("Windows Defender is not active.\nExternal antivirus software may flag or delete Pipsi installations.\nWe are proceeding to add exclusions, but please ensure your antivirus software allows Pipsi by setting the necessary exclusions manually.")
}

currentDir, err := os.Getwd()
if err != nil {
log.Errorf("Unable to get current directory: %v", err)
return
}
pipsiFolderPath := filepath.Join(currentDir, "Pipsi Installations")

if _, err := os.Stat(pipsiFolderPath); os.IsNotExist(err) {
if err := os.Mkdir(pipsiFolderPath, 0755); err != nil {
log.Errorf("Unable to create Pipsi Installations folder: %v", err)
return
}
}

checkCmd := exec.Command(
"powershell", "-Command", fmt.Sprintf(
`$exclusions = Get-MpPreference | Select -ExpandProperty ExclusionPath; $exclusions -contains "%s"`,
pipsiFolderPath,
),
)
var checkOutput bytes.Buffer
var checkStderr bytes.Buffer
checkCmd.Stdout = &checkOutput
checkCmd.Stderr = &checkStderr

if err := checkCmd.Run(); err != nil {
log.Errorf("Failed to check Windows Defender exclusions.\nError: %v", checkStderr.String())
return
}

if strings.TrimSpace(checkOutput.String()) == "True" {
log.Debugf("'%s' is already in Windows Defender exclusions.", pipsiFolderPath)
return
}

log.Debugf("Attempting to add '%s' to Windows Defender exclusions...", pipsiFolderPath)

addCmd := exec.Command(
"powershell", "-Command", fmt.Sprintf(`Add-MpPreference -ExclusionPath "%s"`, pipsiFolderPath),
)
var addStderr bytes.Buffer
addCmd.Stderr = &addStderr

if err := addCmd.Run(); err != nil {
log.Errorf(
"Failed to add folder to Windows Defender exclusions.\nConsider disabling real-time protection or manually adding the folder.\nError: %v",
addStderr.String(),
)
return
}

log.Infof("Successfully added '%s' to Windows Defender exclusions.", pipsiFolderPath)
}

func isDefenderActive() bool {
cmd := exec.Command(
"powershell", "-Command", "Get-MpPreference | Select-Object -ExpandProperty DisableRealtimeMonitoring",
)
var output bytes.Buffer
cmd.Stdout = &output

if err := cmd.Run(); err != nil {
log.Warnf("Error checking Windows Defender status: %v\n", err)
pauseAndExit()
}

trimmedOutput := strings.TrimSpace(output.String())

return trimmedOutput == "False"
}
Loading

0 comments on commit 70d9c33

Please sign in to comment.