Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
GeopJr committed Sep 8, 2020
0 parents commit 1209db4
Show file tree
Hide file tree
Showing 17 changed files with 737 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*.cr]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
trim_trailing_whitespace = true
3 changes: 3 additions & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
ko_fi: geopjr
liberapay: GeopJr
custom: ["https://www.paypal.me/GeopJr"]
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/docs/
/lib/
/bin/
/.shards/
*.dwarf
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2020 GeopJr

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
131 changes: 131 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<div align="center">
<br />
<p>
<img src="https://i.imgur.com/eS2ugrZ.png"/>
</p>
<br />
<p>
<a href="https://ko-fi.com/GeopJr" title="Donate to this project using Ko-Fi"><img src="https://img.shields.io/badge/Buy%20me%20a-KoFi-white.svg" alt="Ko-Fi donate button" /></a>
<a href="https://liberapay.com/GeopJr"><img src="https://img.shields.io/liberapay/patrons/GeopJr.svg?logo=liberapay" alt="liberapay" ></a>
<a href="https://github.com/GeopJr/Crycord/blob/master/LICENSE"><img src="https://img.shields.io/badge/LICENSE-MIT-000000.svg" alt="MIT" /></a>
</p>
</div>

# crycord

Crycord is a modular Discord Client Mod written in Crystal.

Uses [asar-cr](https://github.com/GeopJr/asar-cr).

## Installation

You can download the *statically* linked build from the releases page!

## Building

1. `shards install`
2. `crystal build --release`

*Note:* Static builds can only be built in AlpineLinux

## Usage

```
$ ./crycord -h
<== [Crycord] ==>
-v, --version Show version
-h, --help Show help
-gs, --groups Lists all available plugin groups
-p, --plugins Lists all available plugins
-c CSS_PATH, --css=CSS_PATH Sets CSS location
-f CORE_ASAR_PATH, --force=CORE_ASAR_PATH
Forces an asar path
-g PLUGIN_GROUP, --group=PLUGIN_GROUP
Selects the plugin group(s) to install. Split multiple groups with commas(,).
```

```
$ ./crycord -c ./Downloads/css.css
Flatpak Detected:
Make sure it has access to your CSS file
Usually ~/Downloads is accessible
Extracting core.asar...
Installing enable_css...
Installing enable_https...
Packing core.asar...
Done!
Restart Discord to see the results!
```

## Benchmarks

Crycord:
```
$time ./crycord -c ~/Downloads/css.css
...
real 0m2,942s
user 0m2,932s
sys 0m0,462s
```

BeautifulDiscord:
```
$ time python3 -m beautifuldiscord --css ~/Downloads/css.css
...
real 0m4,593s
user 0m2,026s
sys 0m2,381s
```

## (Laggy) Gifs

![install](https://i.imgur.com/gf6Sa8i.gif)
![restore](https://i.imgur.com/1ooO8me.gif)
![hotreload](https://i.imgur.com/q6nAvhT.gif)

## WARNING

- Any Discord Client modification is against their T.O.S.
- I am not responsible if your account gets terminated.
- Using a client mod such as this (and all others), deactivates many electron security functions.
- If a Discord Staff happens to stumble upon this, I don't use this tool on my account and it's made for educational purposes.

## Goals

As I also wrote the shard that manages the asar pack/extract (these 2 functions at least),
my main goal is to achieve max speed and max compatibility. Using Crystal only tools like Path, File, Dir etc.
is one way to reach it. However, since I don't have access to a Mac and Windows doesn't have proper support, some
paths (Discord config) are made specifically for linux.

## How is it different than BeautifulDiscord?

First of all, it's written, well... in Crystal!

That alone makes it a lot faster!

Crycord also has a plugin(?) system!

Lastly, it can patch the flatpak version.

## TODO

- Use a cross-platform way to find Discord's pid
- Clean the module collector
- GitHub action using docker in an attempt to build static builds automatically

## Contributing

1. Fork it (<https://github.com/your-github-user/crycord/fork>)
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Add some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create a new Pull Request

## Contributors

- [GeopJr](https://github.com/GeopJr) - creator and maintainer
- [leovoel](https://github.com/leovoel) - CSS injector
17 changes: 17 additions & 0 deletions shard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: crycord
version: 1.0.0

authors:
- GeopJr <[email protected]>

targets:
crycord:
main: src/crycord.cr

dependencies:
asar-cr:
github: GeopJr/asar-cr

crystal: 0.34.0

license: MIT
153 changes: 153 additions & 0 deletions src/crycord.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
require "option_parser"
require "asar-cr"
require "./version.cr"
require "./functions/*"
require "./locators/*"
require "./plugins/core/*"
require "./plugins/extra/*"

module Crycord
extend self
@@plugins : Array(String)
@@available_groups : Array(String)

@@plugins = Crycord::PLUGINS.keys.reject! { |x| Crycord::PLUGINS[x].disabled }
@@available_groups = @@plugins.map { |x| x = Crycord::PLUGINS[x].category }.uniq
css_path = ""
asar_path = ""
groups = ["core"]
should_revert = false

def get_paths : String
path = flatpak
if path.nil?
path = linux
else
puts "Flatpak Detected:"
puts "Make sure it has access to your CSS file"
puts "Usually ~/Downloads is accessible"
end
if path.nil?
puts "ERROR: couldn't find core.asar, try manually setting it using the -f flag."
exit
end
return path.to_s
end

def group_list
puts "Available plugin groups:"
puts @@available_groups.join("\n")
puts "Note: core is being installed by default"
end

# CLI options
OptionParser.parse do |parser|
parser.banner = "<== [Crycord] ==>"

parser.on "-v", "--version", "Show version" do
puts "Crycord"
puts "Version: #{VERSION}"
exit
end
parser.on "-h", "--help", "Show help" do
puts parser
exit
end
parser.on "-gs", "--groups", "Lists all available plugin groups" do
group_list
exit
end
parser.on "-r", "--revert", "Reverts back to original asar" do
should_revert = true
end
parser.on "-p", "--plugins", "Lists all available plugins" do
available_plugins = Crycord::PLUGINS.keys.map { |x| x = Crycord::PLUGINS[x].name + " | " + Crycord::PLUGINS[x].category + " | " + Crycord::PLUGINS[x].desc }.uniq
puts "Available plugins:"
puts "NAME | GROUP | DESCRIPTION"
puts available_plugins.reject! { |x| Crycord::PLUGINS[x].disabled }.join("\n")
puts "Note: Disabled plugins are omitted"
exit
end
parser.on "-c CSS_PATH", "--css=CSS_PATH", "Sets CSS location" do |path|
css = Path[path].expand(home: true)
unless File.exists?(css)
puts "ERROR: CSS file not found"
exit
end
css_path = css.to_s
end
parser.on "-f CORE_ASAR_PATH", "--force=CORE_ASAR_PATH", "Forces an asar path" do |path|
asar_path = Path[path].expand(home: true).to_s
unless File.exists?(asar_path)
puts "ERROR: core.asar not found"
exit
end
end
parser.on "-g PLUGIN_GROUP", "--group=PLUGIN_GROUP", "Selects the plugin group(s) to install. Split multiple groups with commas(,)." do |input|
if input == "" || input.nil?
group_list
end
groups.concat(input.downcase.gsub(" ", "").split(","))
groups.uniq!
groups.each do |item|
unless @@available_groups.includes?(item)
puts "ERROR: unknown group, use the -gs flag to list all groups."
exit
end
end
end

parser.missing_option do |option_flag|
STDERR.puts "ERROR: #{option_flag} is missing something."
STDERR.puts ""
STDERR.puts parser
exit(1)
end
parser.invalid_option do |option_flag|
STDERR.puts "ERROR: #{option_flag} is not a valid option."
STDERR.puts parser
exit(1)
end
end

# Check revert
if should_revert
asar_path = get_paths if asar_path == ""
res = revert(Path[asar_path])
puts "Restore was #{res.nil? ? "un" : ""}successful"
exit
end

# Check options
if css_path == ""
puts "ERROR: -c option is missing"
exit
end

# Check discord and get paths
asar_path = get_paths if asar_path == ""

# Extract asar
puts "Extracting core.asar..."
path = extract(Path[asar_path])
if path.nil?
puts "ERROR: couldn't extract core.asar"
exit
end

# See collector.cr
modules = Crycord::Plugins.collected_modules
selected_plugins = @@plugins.reject! { |x| !groups.includes?(Crycord::PLUGINS[x].category) }

selected_plugins.each do |plugin|
plugin_module = modules.find { |i| i.to_s == "Crycord::Plugins::#{plugin.upcase}" }
css = Crycord::PLUGINS[plugin].css ? css_path : nil
puts "Installing #{plugin}..."
plugin_module.try &.execute(path, css)
end

puts "Packing core.asar..."
pack(Path[path])
puts "Done!"
puts "Restart Discord to see the results!"
end
45 changes: 45 additions & 0 deletions src/functions/asar.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
require "file_utils"

module Crycord
# extract and pack require a significant amount of RAM

# Asar to path
def extract(path : Path) : Path | Nil
output = path.parent.join("core").to_s
return if Dir.exists?(output)
asar = Asar::Extract.new path.to_s
asar.extract output
Path[output]
end

# Path to asar
def pack(path : Path) : Path | Nil
return unless Dir.exists?(path)
core = path.parent.join("core.asar")
backup(core) unless File.exists?(path.parent.join("core.asar.bak"))
File.delete(core) if File.exists?(core)
asar = Asar::Pack.new path.to_s
asar.pack core.to_s
delete_unpacked(path)
core
end

def delete_unpacked(path : Path) : Bool
FileUtils.rm_rf(path.to_s)
true
end

def backup(path : Path) : Bool
File.rename(path.to_s, path.parent.join("core.asar.bak").to_s)
return true
end

def revert(path : Path) : Bool | Nil
parent = path.parent
bak = parent.join("core.asar.bak")
return unless File.exists?(path) && File.exists?(bak)
File.delete(path.to_s)
File.rename(bak.to_s, path.to_s)
true
end
end
Loading

0 comments on commit 1209db4

Please sign in to comment.