├── .github
└── ISSUE_TEMPLATE
│ └── custom.md
├── .gitignore
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── args
└── cli.go
├── backup.go
├── badger.go
├── balance.go
├── board.go
├── bulk.go
├── buysell.go
├── diamond.go
├── display
└── cli.go
├── draw
├── buy.go
├── diamond.go
├── infinity.go
├── peace.go
├── pie.go
├── size.go
└── users.go
├── emoji.go
├── enrich.go
├── files
├── home.go
└── stdin.go
├── follow.go
├── global.go
├── go.mod
├── gui.go
├── infinity.go
├── inspect.go
├── keys
├── hdkey.go
├── jwt.go
└── v8.go
├── like.go
├── long_thread.go
├── machine.go
├── main.go
├── message.go
├── models
├── coin.go
├── follow.go
├── hodler.go
├── image.go
├── message.go
├── notification.go
├── post.go
├── profile.go
├── rate.go
├── submit_post.go
├── tx.go
└── user.go
├── network
├── api.go
└── http.go
├── notification.go
├── post.go
├── profile.go
├── reclout.go
├── samples
├── burn_bitcoin.list
├── burn_bitcoin.req
├── buy_or_sell.req
├── create_follow_txn_stateless.req
├── create_like_stateless.req
├── get_diamonds_for_key.list
├── get_diamonds_for_key.req
├── get_follows_stateless.list
├── get_follows_stateless.req
├── get_hodlers.list
├── get_hodlers.req
├── get_messages_stateless.list
├── get_messages_stateless.req
├── get_notifications.list
├── get_notifications.req
├── get_posts_for_public_key.list
├── get_posts_for_public_key.req
├── get_posts_stateless.list
├── get_posts_stateless.req
├── get_single_post.list
├── get_single_post.req
├── get_single_profile.list
├── get_single_profile.req
├── get_tx.req
├── get_users_stateless.list
├── get_users_stateless.req
├── send_bitclout.req
├── send_diamonds.req
├── send_message.req
├── submit_post.req
├── submit_tx.req
├── transfer_coin.req
├── update_profile.req
└── upload_image.req
├── scripts
└── stop_core_copy_sync.sh
├── send.go
├── session
├── account.go
├── backup.go
├── baseline.go
├── cache.go
├── encryption.go
├── login.go
├── logout.go
├── session.go
├── short.go
└── whoami.go
├── sync
├── create.go
├── list.go
├── schema.go
└── sync.go
├── tags.go
├── unfollow.go
├── upload.go
├── wallet.go
├── words.go
└── youtube.go
/.github/ISSUE_TEMPLATE/custom.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Custom issue template
3 | about: Describe this issue template's purpose here.
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | clout
2 | .DS_Store
3 | go.sum
4 | vendor
5 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | submit pull requests
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Andrew Arrow
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # clout-cli
2 |
3 | 
4 |
5 | Welcome to the [cloutcli](https://bitclout.com/u/cloutcli) project.
6 |
7 | This repo slowly moving over to:
8 |
9 | [github.com/andrewarrow/cloutcli](https://github.com/andrewarrow/cloutcli)
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 | [7 Minute Video Talk About This Project](https://vimeo.com/559521458)
35 |
36 | There WAS a [bounty](https://stackoverflow.com/questions/67661276/how-do-i-properly-sign-a-bitclout-tx-in-golang-vs-typescript) for how to fix our tx signing to not need javascript. It was claimed by https://stackoverflow.com/users/589259/maarten-bodewes thanks!
37 |
38 | To understand the code start with the big if else in main.go for each menu option. Many things are still in the package `main` but slowly moving into various packages.
39 |
40 | [they own your coin](https://andrewarrow.substack.com/p/they-own-your-coin) is a blog article I wrote about bc in general.
41 |
42 | # Entering your secret words
43 |
44 | Everything cloutcli stores on your local drive it stores in `~/clout-cli-data` so when you want to remove everything just run:
45 |
46 | ```
47 | $ rm -rf ~/clout-cli-data
48 | ```
49 |
50 | And any secret you entered has been deleted.
51 |
52 | # You can login with multiple accounts
53 |
54 | ```
55 | $ ./clout login
56 | ~/clout-cli $ ./clout login
57 | Enter mnenomic: lorem ipsum dolor sit amet consectetur adipiscing elit aenean ac mauris sit
58 | Secret stored at: /Users/andrewarrow/clout-cli-data/secrets.txt
59 |
60 | $ ./clout login
61 | ~/clout-cli $ ./clout login
62 | Enter mnenomic: these are twelve different words from the words above this line done
63 | Secret stored at: /Users/andrewarrow/clout-cli-data/secrets.txt
64 | ```
65 |
66 | Each time you login the words are appened to that `secrets.txt` file.
67 |
68 | ```
69 | $ ./clout accounts
70 |
71 | andrewarrow
72 | cloutcli
73 |
74 | To select account, run `clout account [username]`
75 | ```
76 |
77 | When I run the `accounts` command I see all my logged in accounts.
78 |
79 | # Backup
80 |
81 | `export CLOUT_PHRASE='these are some nice words and stuff.'`
82 |
83 | If you set a `CLOUT_PHRASE` you can run `./clout backup` to
84 | place your secrets.txt file with ALL your words into a encrypted file
85 | that can only be read with your CLOUT_PHRASE.
86 |
87 | Backup this one file, and it can get you into all your accounts.
88 |
89 |
90 | # Building
91 |
92 | If you don't have gcc installed [install it first](https://www.guru99.com/c-gcc-install.html).
93 |
94 | Then run `go mod vendor` and then `go build`
95 |
96 | See this [blog post](https://andrewarrow.substack.com/p/how-to-clone-build-and-run-clout).
97 |
98 | # Linux (Fedora)
99 |
100 | sudo dnf groupinstall "Development Tools"
101 | sudo dnf install g++
102 | sudo dnf install bzr
103 | sudo dnf install gtk3-devel
104 | sudo dnf install webkit2gtk3-devel.x86_64
105 | sudo dnf install ImageMagick
106 |
107 | # Examples
108 |
109 | ```
110 | ~/clout-cli $ ./clout
111 |
112 | clout accounts # list your various accounts
113 | clout backup # encrypt and copy secrets
114 | clout balances # list available $bitclout
115 | clout boards # list boards you are on
116 | clout buy # buy creator coin
117 | clout diamond [username] # award 1 diamond to last post
118 | clout follow [username] # toggle follow
119 | clout followers # who follows you
120 | clout following # who you follow
121 | clout help # this menu
122 | clout like --hash=x # like a post
123 | clout ls # list global posts
124 | clout ls --follow # filter by follow
125 | clout ls --hash=x # show single post
126 | clout login # enter secret phrase
127 | clout logout # delete secret from drive
128 | clout messages # list messages
129 | clout notifications # list notifications
130 | clout post --reply=x # post or reply
131 | clout reclout [username] # reclout last post
132 | clout sync # fill local hard drive with data
133 | clout update # update profile description
134 | clout wallet # list what you own
135 | clout whoami # base58 pubkey logged in
136 | clout [username] # username's profile & posts
137 | ```
138 |
139 | ```
140 | ~/clout-cli $ ./clout ls --body
141 | hash username body
142 | ---- -------- ----
143 | b7cded5 MemeGod Where are those people now? Probably buying BitClo
144 | 0d10064 RajLahoti We just on-boarded the photographer here at #Clout
145 | 98da010 InURfeelz2 How are you going to celebrate the deflation bomb
146 | 28a5805 HIKIMBERLY Deflation Bomb countdown
147 | 76af117 VishalGulia Lmao 😂🤣
148 | 6b51d65 thorsten 🧐 I foresee a huge increase of sightings of the
149 | 34c30e2 BitCloutBuffett @diamondhands walking around Miami tonight..
150 | 6bf58b3 DeflationBomb Top 20 before 💣 detonation? We have until appro
151 | dc9873c YasminBcreative I can’t get over how clear the water in Portugue
152 | 3ef8b62 Yellowredsparks Is it just me or are your parents using more emoji
153 | ec2430c MemeGod This is the moment we've all been waiting for! Get
154 | 9a9de37 pamelaanderson It's amazing that we get to witness this first han
155 | c36f4db NotInMiami Something for those of us #NotInMiami
156 | 8d3d91a Klesh Keep Calm and Carry On!
157 | 0539682 tijn Bomb Block: 33783 Current Block: 31113 To go: 2670
158 | 08659a4 connormitchell wow you get on a plane to Miami and suddenly there
159 | 067d4f5 Tetono Bitclout Deflation 💣 The total supply currentl
160 | a21b9e9 Abhiandnow This is going to bring so many changes to the scen
161 | 447e613 nigeleccles Release the bomb!
162 | 84f51d1 Tetono I see this as 📈
163 | 2ba1aac CloutStreetBets We knew this was all going to happen. Time to 🚀
164 | d3f5bd3 Mirina Change is coming! I don't quite understand what.
165 | ```
166 |
167 | ```
168 | ~/clout-cli $ ./clout ls
169 | username ago likes replies reclouts cap hash
170 | -------- --- ----- ------- -------- ------- -------
171 | MemeGod 13 minutes 12 5 0 77.82 b7cded5
172 | RajLahoti 14 minutes 33 5 2 5058.26 0d10064
173 | InURfeelz2 15 minutes 5 3 0 34.50 98da010
174 | HIKIMBERLY 16 minutes 5 1 1 123.22 28a5805
175 | VishalGulia 17 minutes 8 2 1 14.39 76af117
176 | thorsten 17 minutes 6 1 0 80.09 6b51d65
177 | BitCloutBuffett 19 minutes 15 5 0 1290.88 34c30e2
178 | DeflationBomb 28 minutes 10 6 1 163.06 6bf58b3
179 | YasminBcreative 28 minutes 16 5 1 20.46 dc9873c
180 | Yellowredsparks 31 minutes 14 6 0 37.78 3ef8b62
181 | MemeGod 35 minutes 24 10 14 77.82 ec2430c
182 | pamelaanderson 36 minutes 33 10 4 3361.05 9a9de37
183 | NotInMiami 37 minutes 9 0 0 2.56 c36f4db
184 | Klesh 42 minutes 17 3 2 48.31 8d3d91a
185 | tijn 42 minutes 15 6 0 572.18 0539682
186 | connormitchell 42 minutes 14 2 0 981.33 08659a4
187 | Tetono about 1 hour 14 5 5 120.07 067d4f5
188 | Abhiandnow about 1 hour 11 2 1 9.23 a21b9e9
189 | nigeleccles about 1 hour 22 6 2 595.68 447e613
190 | Tetono about 1 hour 15 5 0 120.07 84f51d1
191 | CloutStreetBets about 1 hour 20 4 0 54.23 2ba1aac
192 | Mirina about 1 hour 20 9 1 25.00 d3f5bd3
193 | ```
194 |
195 | ```
196 | ~/clout-cli $ ./clout accounts
197 |
198 | 01. andrewarrow
199 | 02. cloutcli
200 | 03. cloutfactory
201 | 04. wolfschedule
202 | 05. imitate
203 |
204 | To select account, run `clout account [username or i]`
205 | ```
206 |
207 | ```
208 | clout-cli $ ./clout diamondhands
209 | 0 Sounds awesome. Quintuple 💎💎💎💎💎 from me for the first person who does this.
210 | 3 days
211 |
212 | 0 Today, we take the decentralization of social media further than any other project has in the past.
213 | 2 Today, BitClout does to social media what Bitcoin is doing to the traditional financial system.
214 | 4 Today, 100% of the BitClout code goes public.
215 | 6 https://github.com/bitclout/core
216 | 4 days
217 |
218 | 0 The more feedback you give us, the better the product gets. And the shipping never stops, not even on a beautiful sunny Saturday.
219 | 2 Click to learn about some important upgrades to your Wallet and Creator Coin pages that we hope will promote HODLing and minimize scams. 👇
220 | 13 days
221 | ```
222 |
223 |
--------------------------------------------------------------------------------
/args/cli.go:
--------------------------------------------------------------------------------
1 | package args
2 |
3 | import (
4 | "os"
5 | "strings"
6 | )
7 |
8 | func ToMap() map[string]string {
9 | m := map[string]string{}
10 | if len(os.Args) == 1 {
11 | return m
12 | }
13 |
14 | for _, a := range os.Args[1:] {
15 | if strings.HasPrefix(a, "--") {
16 | tokens := strings.Split(a, "=")
17 | key := strings.Split(tokens[0], "--")
18 | if len(tokens) == 2 {
19 | m[key[1]] = tokens[1]
20 | } else {
21 | m[key[1]] = "true"
22 | }
23 | } else if strings.Contains(a, "=") {
24 | tokens := strings.Split(a, "=")
25 | if len(tokens) == 2 {
26 | m[tokens[0]] = tokens[1]
27 | }
28 | }
29 | }
30 | return m
31 | }
32 |
--------------------------------------------------------------------------------
/backup.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "clout/session"
5 | "fmt"
6 | "os"
7 | )
8 |
9 | func HandleBackup(argMap map[string]string) {
10 | words := os.Getenv("CLOUT_PHRASE")
11 | if len(words) < 36 {
12 | fmt.Println("")
13 | fmt.Println("Backup allows you to have just one list of words to unlock")
14 | fmt.Println("many other lists of words for N number of accounts.")
15 | fmt.Println("")
16 | fmt.Println("export CLOUT_PHRASE='these are some nice words and stuff.'")
17 | fmt.Println("")
18 | fmt.Println("Set an envionment variable called CLOUT_PHRASE with your words.")
19 | fmt.Println("The string must be >= 36.")
20 | fmt.Println("")
21 | return
22 | }
23 | if argMap["restore"] != "" {
24 | session.SecretsFromBackup(words)
25 | return
26 | }
27 | fmt.Println("")
28 | fmt.Println("Found CLOUT_PHRASE size is", len(words))
29 | fmt.Println("")
30 | session.BackupSecrets(words)
31 | fmt.Println("")
32 | }
33 |
--------------------------------------------------------------------------------
/badger.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "clout/sync"
5 |
6 | badger "github.com/dgraph-io/badger/v3"
7 | )
8 |
9 | func HandleBadger() {
10 | db, _ := badger.Open(badger.DefaultOptions(argMap["dir"]))
11 | defer db.Close()
12 |
13 | //PrefixPostHashToPostEntry := byte(17)
14 | PrefixPKIDToProfileEntry := byte(23)
15 | sync.EnumerateKeysForPrefix(db, []byte{PrefixPKIDToProfileEntry})
16 | }
17 |
--------------------------------------------------------------------------------
/balance.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "clout/display"
5 | "clout/keys"
6 | "clout/models"
7 | "clout/network"
8 | "clout/session"
9 | "encoding/json"
10 | "fmt"
11 | "sort"
12 | )
13 |
14 | func HandleBalances(argMap map[string]string) {
15 | list := session.ReadAccountsSorted()
16 | m := session.ReadAccounts()
17 | fields := []string{"username", "% owned", "co-owner1", "co-owner2", "balance", "price"}
18 | sizes := []int{15, 10, 15, 15, 10, 10}
19 | display.Header(sizes, fields...)
20 | for _, username := range list {
21 | s := m[username]
22 | pub58, _ := keys.ComputeKeysFromSeed(session.SeedBytes(s))
23 | js := network.GetHodlers(username)
24 | var hw models.HodlersWrap
25 | json.Unmarshal([]byte(js), &hw)
26 | user := session.Pub58ToUser(pub58)
27 | //points := user.ProfileEntryResponse.CoinEntry.CreatorBasisPoints
28 | total := user.ProfileEntryResponse.CoinEntry.CoinsInCirculationNanos
29 | price := user.ProfileEntryResponse.CoinPriceBitCloutNanos
30 |
31 | holdMap := map[string]string{}
32 | sort.SliceStable(hw.Hodlers, func(i, j int) bool {
33 | return hw.Hodlers[i].BalanceNanos >
34 | hw.Hodlers[j].BalanceNanos
35 | })
36 | topThree := []string{}
37 | for _, friend := range hw.Hodlers {
38 | username := friend.ProfileEntryResponse.Username
39 | if username == "" {
40 | username = "anonymous" //friend.HODLerPublicKeyBase58Check
41 | }
42 |
43 | perString := fmt.Sprintf("%d",
44 | int(100*(float64(friend.BalanceNanos)/float64(total))))
45 | holdMap[username] = perString
46 |
47 | if len(topThree) < 3 {
48 | topThree = append(topThree, username)
49 | }
50 | }
51 |
52 | others := []string{}
53 | for _, u := range topThree {
54 | if u == username {
55 | continue
56 | }
57 | others = append(others, u)
58 | }
59 |
60 | co1 := ""
61 | co2 := ""
62 |
63 | if len(others) == 2 {
64 | co1 = others[0] + " " + holdMap[others[0]]
65 | co2 = others[1] + " " + holdMap[others[1]]
66 | } else if len(others) == 1 {
67 | co1 = others[0] + " " + holdMap[others[0]]
68 | }
69 |
70 | display.Row(sizes, username, holdMap[username], co1, co2,
71 | display.OneE9(user.BalanceNanos), display.OneE9(price))
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/board.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "clout/display"
5 | "clout/keys"
6 | "clout/models"
7 | "clout/network"
8 | "clout/session"
9 | "encoding/json"
10 | "fmt"
11 | )
12 |
13 | func HandleBoards() {
14 |
15 | fmt.Println("")
16 | fmt.Println("Boards are coins where you are one of the few significant")
17 | fmt.Println("owners and have some responsibilities.")
18 | fmt.Println("")
19 |
20 | m := session.ReadAccounts()
21 | for username, s := range m {
22 | fmt.Println("")
23 | fmt.Println("===========")
24 | fmt.Println(username)
25 | fmt.Println("===========")
26 | pub58, _ := keys.ComputeKeysFromSeed(session.SeedBytes(s))
27 | Pub58ToBoards(pub58)
28 | }
29 | fmt.Println("")
30 | }
31 |
32 | func Pub58ToBoards(key string) {
33 | js := network.GetUsersStateless(key)
34 | var us models.UsersStateless
35 | json.Unmarshal([]byte(js), &us)
36 | for _, thing := range us.UserList[0].UsersYouHODL {
37 | coins := float64(thing.BalanceNanos) / 1000000000.0
38 | if coins < 1 {
39 | continue
40 | }
41 | fmt.Printf("%s %0.2f\n",
42 | display.LeftAligned(thing.ProfileEntryResponse.Username, 30), coins)
43 |
44 | js := network.GetHodlers(thing.ProfileEntryResponse.Username)
45 | var hw models.HodlersWrap
46 | json.Unmarshal([]byte(js), &hw)
47 | for _, friend := range hw.Hodlers {
48 | if friend.ProfileEntryResponse.PublicKeyBase58Check == key {
49 | continue
50 | }
51 | coins := float64(friend.BalanceNanos) / 1000000000.0
52 | if coins < 1 {
53 | continue
54 | }
55 | username := friend.ProfileEntryResponse.Username
56 | if username == "" {
57 | username = "anonymous"
58 | }
59 | fmt.Printf(" %s %0.2f\n",
60 | display.LeftAligned(username, 30), coins)
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/bulk.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "clout/network"
5 | "clout/session"
6 | "encoding/json"
7 | "fmt"
8 | "io/ioutil"
9 | "os"
10 | "strings"
11 | "time"
12 | )
13 |
14 | func HandleBulk() {
15 |
16 | file := argMap["file"]
17 | if file != "" {
18 | b, _ := ioutil.ReadFile(file)
19 | s := string(b)
20 | lines := strings.Split(s, "\n")
21 | for _, line := range lines {
22 | fmt.Println(line)
23 | //os.Args = []string{"", "diamond", line}
24 | //HandleDiamond()
25 | }
26 | return
27 | }
28 |
29 | query := argMap["query"]
30 | if query == "" {
31 | return
32 | }
33 |
34 | //changeme := ""
35 | for _, username := range session.GetAccountsForTag(query) {
36 | fmt.Println(username)
37 | session.WriteSelected(username)
38 |
39 | //name, url := VideoFromVimeo(username)
40 | //m := map[string]string{"text": name, "video": url}
41 | //Post(m)
42 |
43 | //m := map[string]string{"percent": "3333"}
44 | //HandleUpdateProfile(m)
45 | //os.Args = []string{"", "follow", ""}
46 | //HandleFollow()
47 | //os.Args = []string{"", "reclout", changeme}
48 | //HandleReclout()
49 | //m := map[string]string{"text": "everyone? even me?", "reply": changeme}
50 | //Post(m)
51 | //m := map[string]string{"hash": "changeme"}
52 | //HandleLike(m)
53 | time.Sleep(time.Second * 1)
54 | }
55 |
56 | }
57 |
58 | type VimeoReply struct {
59 | Data []VimeoRecord
60 | }
61 |
62 | type VimeoRecord struct {
63 | Uri string
64 | Name string
65 | }
66 |
67 | func VideoFromVimeo(query string) (string, string) {
68 | pat := os.Getenv("VIMEO_PAT")
69 | url := "https://api.vimeo.com/videos?query=" + query
70 | js := network.DoGetWithPat(pat, url)
71 | var vr VimeoReply
72 | json.Unmarshal([]byte(js), &vr)
73 |
74 | fmt.Println(vr.Data[0].Uri)
75 | fmt.Println(vr.Data[0].Name)
76 |
77 | tokens := strings.Split(vr.Data[0].Uri, "/")
78 | id := tokens[len(tokens)-1]
79 |
80 | return vr.Data[0].Name, "https://player.vimeo.com/video/" + id
81 | }
82 |
--------------------------------------------------------------------------------
/buysell.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "clout/keys"
5 | "clout/models"
6 | "clout/network"
7 | "clout/session"
8 | "encoding/json"
9 | "fmt"
10 | "os"
11 | )
12 |
13 | func HandleBuy() {
14 | if len(os.Args) < 4 {
15 | fmt.Println("missing username or amount")
16 | return
17 | }
18 | username := os.Args[2]
19 | //amountString := os.Args[3]
20 | theirPub58 := session.UsernameToPub58(username)
21 |
22 | mnemonic := session.ReadLoggedInWords()
23 | if mnemonic == "" {
24 | return
25 | }
26 | pub58, priv := keys.ComputeKeysFromSeed(session.SeedBytes(mnemonic))
27 | user := session.Pub58ToUser(pub58)
28 | amount := user.BalanceNanos - 100318
29 | // 604713
30 | // 504395
31 | //amount, _ := strconv.ParseInt(amountString, 10, 64)
32 | bigString := network.SubmitBuyCoin(pub58, theirPub58, amount, 0)
33 | var tx models.TxReady
34 | json.Unmarshal([]byte(bigString), &tx)
35 | fmt.Println(user.BalanceNanos, amount, tx.ExpectedCreatorCoinReturnedNanos)
36 |
37 | bigString = network.SubmitBuyCoin(pub58, theirPub58, amount, tx.ExpectedCreatorCoinReturnedNanos)
38 | json.Unmarshal([]byte(bigString), &tx)
39 |
40 | jsonString := network.SubmitTx(tx.TransactionHex, priv)
41 | if jsonString != "" {
42 | fmt.Println("Success.")
43 | }
44 | }
45 | func HandleSell() {
46 | if len(os.Args) < 4 {
47 | fmt.Println("missing username or amount")
48 | return
49 | }
50 | username := os.Args[2]
51 | //amountString := os.Args[3]
52 | theirPub58 := session.UsernameToPub58(username)
53 |
54 | mnemonic := session.ReadLoggedInWords()
55 | if mnemonic == "" {
56 | return
57 | }
58 | pub58, priv := keys.ComputeKeysFromSeed(session.SeedBytes(mnemonic))
59 | user := session.Pub58ToUser(pub58)
60 | amount := int64(0)
61 | for _, item := range user.UsersYouHODL {
62 | if username != item.ProfileEntryResponse.Username {
63 | continue
64 | }
65 | fmt.Println(item.BalanceNanos)
66 | amount = item.BalanceNanos
67 | break
68 | }
69 | bigString := network.SubmitSellCoin(pub58, theirPub58, amount, 0)
70 | var tx models.TxReady
71 | json.Unmarshal([]byte(bigString), &tx)
72 | fmt.Println(user.BalanceNanos, amount, tx.ExpectedBitCloutReturnedNanos)
73 |
74 | bigString = network.SubmitSellCoin(pub58, theirPub58, amount, tx.ExpectedBitCloutReturnedNanos)
75 | json.Unmarshal([]byte(bigString), &tx)
76 |
77 | jsonString := network.SubmitTx(tx.TransactionHex, priv)
78 | if jsonString != "" {
79 | fmt.Println("Success.")
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/diamond.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "clout/keys"
5 | "clout/models"
6 | "clout/network"
7 | "clout/session"
8 | "encoding/json"
9 | "fmt"
10 | "os"
11 | )
12 |
13 | func HandleDiamond() {
14 | if len(os.Args) < 3 {
15 | fmt.Println("missing username")
16 | return
17 | }
18 | level := "1"
19 | if argMap["level"] != "" {
20 | level = argMap["level"]
21 | }
22 | username := os.Args[2]
23 | theirPub58 := session.UsernameToPub58(username)
24 | js := network.GetPostsForPublicKey(username)
25 | var ppk models.PostsPublicKey
26 | json.Unmarshal([]byte(js), &ppk)
27 | if len(ppk.Posts) == 0 {
28 | return
29 | }
30 | lastPost := ppk.Posts[0].PostHashHex
31 |
32 | mnemonic := session.ReadLoggedInWords()
33 | if mnemonic == "" {
34 | return
35 | }
36 | pub58, priv := keys.ComputeKeysFromSeed(session.SeedBytes(mnemonic))
37 | bigString := network.SubmitDiamond(level, pub58, theirPub58, lastPost)
38 |
39 | var tx models.TxReady
40 | json.Unmarshal([]byte(bigString), &tx)
41 |
42 | jsonString := network.SubmitTx(tx.TransactionHex, priv)
43 | if jsonString != "" {
44 | fmt.Println("Success.")
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/display/cli.go:
--------------------------------------------------------------------------------
1 | package display
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 | )
7 |
8 | func Float(val float64) string {
9 | return fmt.Sprintf("%.02f", val)
10 | }
11 | func OneE9(val int64) string {
12 | return fmt.Sprintf("%.02f", OneE9Float(val))
13 | }
14 | func OneE9Float(val int64) float64 {
15 | return float64(val) / 1000000000.0
16 | }
17 |
18 | func Header(sizes []int, fields ...string) {
19 | for i, field := range fields {
20 | fmt.Printf("%s ", LeftAligned(field, sizes[i]))
21 | }
22 | fmt.Printf("\n")
23 | for i, field := range fields {
24 | dashes := []string{}
25 | for i := 0; i < len(field); i++ {
26 | dashes = append(dashes, "-")
27 | }
28 | fmt.Printf("%s ", LeftAligned(strings.Join(dashes, ""), sizes[i]))
29 | }
30 | fmt.Printf("\n")
31 | }
32 | func Row(sizes []int, items ...interface{}) {
33 | for i, item := range items {
34 | fmt.Printf("%s ", LeftAligned(item, sizes[i]))
35 | }
36 | fmt.Printf("\n")
37 | }
38 |
39 | func LeftAligned(thing interface{}, size int) string {
40 | s := fmt.Sprintf("%v", thing)
41 |
42 | if len(s) >= size {
43 | return s[0:size-1] + " "
44 | }
45 | fill := size - len(s)
46 | spaces := []string{}
47 | for {
48 | spaces = append(spaces, " ")
49 | if len(spaces) >= fill {
50 | break
51 | }
52 | }
53 | return s + strings.Join(spaces, "")
54 | }
55 |
--------------------------------------------------------------------------------
/draw/buy.go:
--------------------------------------------------------------------------------
1 | package draw
2 |
3 | import (
4 | "clout/network"
5 | "clout/session"
6 | "fmt"
7 |
8 | "github.com/fogleman/gg"
9 | )
10 |
11 | var files = []string{}
12 | var coinX = -220
13 | var buyerX = 600
14 |
15 | func DrawBuyFrame(i int, usd float64) {
16 | dc := gg.NewContext(600, 400)
17 | dc.SetRGB(0, 0, 0)
18 | dc.Clear()
19 | dc.SetRGB(0, 1, 0)
20 | im, _ := gg.LoadPNG("coin.png")
21 | dc.DrawImage(im, coinX, 20)
22 | im, _ = gg.LoadPNG("buyer.png")
23 | dc.DrawImage(im, buyerX, 20)
24 | dc.LoadFontFace("arial.ttf", 72)
25 | dc.DrawStringAnchored(fmt.Sprintf("BUY $%0.2f", usd), 300, 300, 0.5, 0.5)
26 | file := fmt.Sprintf("frames/%d.png", i)
27 | dc.SavePNG(file)
28 | files = append(files, file)
29 | }
30 | func BuyPoster(coin, buyer string, usd float64) {
31 | GetProfilePicAndEnlarge(coin, "coin")
32 | GetProfilePicAndEnlarge(buyer, "buyer")
33 |
34 | files = []string{}
35 | for i := 1; i < 50; i++ {
36 | DrawBuyFrame(i, usd)
37 | coinX += 6
38 | buyerX -= 6
39 | }
40 | for i := 50; i < 100; i++ {
41 | DrawBuyFrame(i, usd)
42 | coinX -= 6
43 | buyerX += 6
44 | }
45 | MakeVideoFromImages(files)
46 | }
47 |
48 | func GetProfilePicAndEnlarge(username, flavor string) {
49 | pub58 := session.UsernameToPub58(username)
50 | actorBytes := network.GetSingleProfilePicture(pub58)
51 | SavePic(flavor, actorBytes)
52 | ResizeImage(flavor + ".png")
53 | }
54 |
--------------------------------------------------------------------------------
/draw/diamond.go:
--------------------------------------------------------------------------------
1 | package draw
2 |
3 | import (
4 | "clout/network"
5 | "clout/session"
6 |
7 | "github.com/fogleman/gg"
8 | )
9 |
10 | var sizeX, sizeY float64
11 |
12 | func DrawDiamondImage(argMap map[string]string) {
13 | if argMap["pie"] != "" {
14 | DrawPieImage()
15 | return
16 | }
17 | if argMap["pic"] != "" {
18 | UserPoster(argMap["pic"])
19 | return
20 | }
21 | if argMap["peace"] != "" {
22 | DrawPeaceVideo()
23 | return
24 | }
25 | dc := gg.NewContext(600, 600)
26 | dc.SetRGB(1, 1, 1)
27 | dc.Clear()
28 | dc.SetRGB(0, 0, 0)
29 | //im, _ := gg.LoadPNG("actor.png")
30 | //dc.DrawImage(im, 0, 0)
31 |
32 | username := argMap["username"]
33 | if username != "" {
34 | pub58 := session.UsernameToPub58(username)
35 | actorBytes := network.GetSingleProfilePicture(pub58)
36 | SavePic("actor", actorBytes)
37 | ResizeImage("actor.png")
38 | }
39 |
40 | dc.SetLineWidth(4)
41 | sizeX = float64(100)
42 | sizeY = float64(50)
43 | DrawDiamond(dc, 150.0, 100.0+sizeY+sizeY+(sizeY/2.0))
44 | DrawDiamond(dc, 150.0, 100.0)
45 | dc.SavePNG("001.png")
46 | }
47 |
48 | func DrawDiamond(dc *gg.Context, startX, startY float64) {
49 | im, _ := gg.LoadPNG("water.png")
50 | pattern := gg.NewSurfacePattern(im, gg.RepeatBoth)
51 | dc.MoveTo(startX, startY)
52 | dc.LineTo(startX+sizeX, startY+sizeY)
53 | dc.LineTo(startX+sizeX+sizeX, startY)
54 | dc.LineTo(startX+sizeX, startY-sizeY)
55 | dc.LineTo(startX, startY)
56 | dc.ClosePath()
57 | dc.SetFillStyle(pattern)
58 | dc.Fill()
59 | im, _ = gg.LoadPNG("actor.png")
60 | pattern = gg.NewSurfacePattern(im, gg.RepeatBoth)
61 | dc.MoveTo(startX, startY)
62 | dc.LineTo(startX+sizeX, startY+sizeY+sizeY+(sizeY/2.0))
63 | dc.LineTo(startX+sizeX+sizeX, startY)
64 | dc.LineTo(startX+sizeX, startY+sizeY)
65 | dc.LineTo(startX, startY)
66 | dc.ClosePath()
67 | dc.SetFillStyle(pattern)
68 | dc.Fill()
69 |
70 | dc.DrawLine(startX, startY, startX+sizeX, startY+sizeY)
71 | dc.DrawLine(startX+sizeX, startY+sizeY, startX+sizeX+sizeX, startY)
72 | dc.DrawLine(startX+sizeX+sizeX, startY, startX+sizeX, startY-sizeY)
73 | dc.DrawLine(startX+sizeX, startY-sizeY, startX, startY)
74 | dc.DrawLine(startX, startY, startX+sizeX, startY+sizeY+sizeY+(sizeY/2.0))
75 | dc.DrawLine(startX+sizeX, startY+sizeY+sizeY+(sizeY/2.0), startX+sizeX+sizeX, startY)
76 | dc.Stroke()
77 | }
78 |
--------------------------------------------------------------------------------
/draw/infinity.go:
--------------------------------------------------------------------------------
1 | package draw
2 |
3 | import (
4 | "fmt"
5 | "os/exec"
6 | "strconv"
7 | "strings"
8 |
9 | "github.com/fogleman/gg"
10 | )
11 |
12 | func MakeVideoFromImages(files []string) {
13 | /*
14 |
15 | ffmpeg -f image2 -framerate 1 -i img_%02d.png -filter_complex "drawtext=enable='between(t,0,1)':text='word1':fontsize=24:fontcolor=white:x=w-tw:y=0,drawtext=enable='between(t,0,0.9)':text='word2':fontsize=24:fontcolor=white:x=w-tw:y=0" out.gif
16 | */
17 | //b, err := exec.Command("ffmpeg", "-y", "-framerate", "1/2", "-i", "frames/%03d.png", "-loop", "0", "output.gif").CombinedOutput()
18 | params := []string{"-o", "output.gif", "-r", "16", "-Q", "80"}
19 | b, err := exec.Command("gifski", append(params, files...)...).CombinedOutput()
20 | fmt.Println(string(b), err)
21 | }
22 | func DrawInfinities() {
23 | one := 1
24 | three := 3
25 | nine := 9
26 | files := []string{}
27 | for i := 1; i < 20; i++ {
28 | dc := gg.NewContext(600, 400)
29 | dc.SetRGB(0, 0, 0)
30 | dc.Clear()
31 | dc.SetRGB(0, 1, 0)
32 | file := fmt.Sprintf("%03d.png", i)
33 | DrawInfinityFrame(dc, file, one, three, nine)
34 | files = append(files, "frames/"+file)
35 | one = one * 2
36 | three = three * 2
37 | nine = nine * 2
38 | }
39 | MakeVideoFromImages(files)
40 | }
41 | func DrawInfinityFrame(dc *gg.Context, filename string, one, three, nine int) {
42 | font := "arial.ttf"
43 | dc.LoadFontFace(font, 18)
44 | dc.DrawStringAnchored(fmt.Sprintf("%d", one), 100, 100, 0.5, 0.5)
45 | dc.DrawStringAnchored(fmt.Sprintf("%d", three), 100+200, 100, 0.5, 0.5)
46 | dc.DrawStringAnchored(fmt.Sprintf("%d", nine), 100+400, 100, 0.5, 0.5)
47 |
48 | lines := []string{}
49 | lines = AsciiByteAddition(lines, fmt.Sprintf("%d", one))
50 | dc.LoadFontFace(font, 14)
51 | for i, line := range lines {
52 | dc.DrawStringAnchored(line, 100, float64(150+(i*25)), 0.5, 0.5)
53 | }
54 | dc.DrawStringAnchored("1,2,4,8,7,5", 100, float64(150+(len(lines)*25)), 0.5, 0.5)
55 |
56 | lines = []string{}
57 | lines = AsciiByteAddition(lines, fmt.Sprintf("%d", three))
58 | dc.LoadFontFace(font, 14)
59 | for i, line := range lines {
60 | dc.DrawStringAnchored(line, 100+200, float64(150+(i*25)), 0.5, 0.5)
61 | }
62 | dc.DrawStringAnchored("3,6", 100+200, float64(150+(len(lines)*25)), 0.5, 0.5)
63 |
64 | lines = []string{}
65 | lines = AsciiByteAddition(lines, fmt.Sprintf("%d", nine))
66 | dc.LoadFontFace(font, 14)
67 | for i, line := range lines {
68 | dc.DrawStringAnchored(line, 100+400, float64(150+(i*25)), 0.5, 0.5)
69 | }
70 | dc.DrawStringAnchored("9", 100+400, float64(150+(len(lines)*25)), 0.5, 0.5)
71 |
72 | dc.SavePNG("frames/" + filename)
73 | }
74 | func AsciiByteAddition(lines []string, a string) []string {
75 |
76 | sum := byte(0)
77 | buff := []string{}
78 | for i := range a {
79 |
80 | word := a[i : i+1]
81 | t, _ := strconv.Atoi(word)
82 | buff = append(buff, fmt.Sprintf("%d", t))
83 |
84 | sum += byte(t)
85 | }
86 | strSum := fmt.Sprintf("%d", sum)
87 | lines = append(lines, strings.Join(buff, "+")+"="+strSum)
88 | if len(strSum) > 1 {
89 | return AsciiByteAddition(lines, strSum)
90 | }
91 | lines = append(lines, strSum)
92 | return lines
93 | }
94 |
--------------------------------------------------------------------------------
/draw/peace.go:
--------------------------------------------------------------------------------
1 | package draw
2 |
3 | import (
4 | "fmt"
5 | "strings"
6 |
7 | "github.com/fogleman/gg"
8 | )
9 |
10 | func DrawPeaceVideo() {
11 | lines := strings.Split(text, "\n")
12 | j := 0
13 | total := 0
14 | for i := 1; i < 2309; i += 10 {
15 | total++
16 | file := fmt.Sprintf("/Users/andrewarrow/youtube/foo/%04d.png", i)
17 | ResizeImageBy(file, "50")
18 | files = append(files, file)
19 | dc := gg.NewContext(960, 540)
20 | im, _ := gg.LoadPNG(file)
21 | dc.DrawImage(im, 0, 0)
22 | dc.LoadFontFace("arial.ttf", 48)
23 | dc.SetRGB(1, 1, 1)
24 | dc.DrawStringAnchored(lines[j], 482, 402, 0.5, 0.5)
25 | dc.SetRGB(0, 1, 0)
26 | dc.DrawStringAnchored(lines[j], 480, 400, 0.5, 0.5)
27 | dc.SavePNG(file)
28 | fmt.Println(i, total, total%10, j, lines[j])
29 | if total%10 == 0 && total != 0 && j != len(lines)-1 {
30 | j++
31 | }
32 | }
33 | for i := 1; i < 2309; i += 10 {
34 | file := fmt.Sprintf("/Users/andrewarrow/youtube/foo/%04d.png", i)
35 | files = append(files, file)
36 | }
37 | MakeVideoFromImages(files)
38 | }
39 |
40 | var text = `But peace is what you want most of the time.
41 | That's interesting.
42 | You can convert peace to happiness
43 | anytime you want.
44 | If you're a peaceful person,
45 | anything you do will be a happy activity.
46 | And by the way, being on social media,
47 | engaging in politics, will not bring you peace.
48 | There is nothing less peaceful.
49 | Right.
50 | In today's day and age?
51 | The way we think you get peace is by
52 | resolving all your external problems.
53 | But there is unlimited external problems.
54 | So the only way to actually get peace on
55 | the inside by giving up this idea of problems.
56 | Who thinks you can get peace by resolving
57 | external problems other than politicians?
58 | Everybody.
59 | Yeah?
60 | That's what everybody struggling to do, right?
61 | Why are you trying to make money?
62 | To solve all your money problems.`
63 |
--------------------------------------------------------------------------------
/draw/pie.go:
--------------------------------------------------------------------------------
1 | package draw
2 |
3 | import (
4 | "fmt"
5 | "os"
6 |
7 | "github.com/fogleman/gg"
8 | "github.com/wcharczuk/go-chart"
9 | )
10 |
11 | type CreatorCoin struct {
12 | Username string
13 | Supply int64
14 | Price int64
15 | CapTable map[string]int64
16 | History []int64
17 | Rewards []int64
18 | }
19 |
20 | func (cc *CreatorCoin) ToChartMap() map[string]int {
21 | chartMap := map[string]int{}
22 | sum := int64(0)
23 | for k, v := range cc.CapTable {
24 | val := int((float64(v) / float64(cc.Supply)) * 100)
25 | chartMap[fmt.Sprintf("%s_%d", k, val)] = val
26 | sum += v
27 | }
28 | chartMap["other"] = int((float64(cc.Supply-sum) / float64(cc.Supply)) * 100)
29 | return chartMap
30 | }
31 | func (cc *CreatorCoin) Buy(who string, amount int64, rate float64) int64 {
32 | fr := int64(float64(amount) * rate)
33 | fixed := amount - fr
34 | cc.History = append(cc.History, fixed)
35 | cc.Rewards = append(cc.Rewards, fr)
36 | cc.Supply += fixed
37 | cc.CapTable[who] += fixed
38 | return fr
39 | }
40 | func (cc *CreatorCoin) BuyNoFR(who string, amount int64) {
41 | cc.Supply += amount
42 | cc.CapTable[who] += amount
43 | }
44 | func (cc *CreatorCoin) DrawChartWithBuys(filename string) {
45 | dc := gg.NewContext(600, 600)
46 | dc.SetRGB(1, 1, 1)
47 | dc.Clear()
48 | dc.SetRGB(0, 0, 0)
49 | DrawChart(cc.ToChartMap(), "chart.png")
50 | im, _ := gg.LoadPNG("chart.png")
51 | dc.DrawImage(im, 0, 0)
52 | font := "arial.ttf"
53 | dc.LoadFontFace(font, 18)
54 | for i, buy := range cc.History {
55 | dc.DrawStringAnchored(fmt.Sprintf("%d", buy), 500, float64(50+(i*50)), 0.5, 0.5)
56 | }
57 | for i, reward := range cc.Rewards {
58 | y := len(cc.History) * 50
59 | y += 50
60 | dc.DrawStringAnchored(fmt.Sprintf("%d", reward), 500, float64(y+50+(i*50)), 0.5, 0.5)
61 | }
62 | dc.SavePNG(filename)
63 | }
64 |
65 | func DrawPieImage() {
66 | cc := CreatorCoin{}
67 | cc.Username = "andrewarrow"
68 | cc.Supply = 15950600000
69 | cc.CapTable = map[string]int64{}
70 | cc.History = []int64{}
71 | cc.Rewards = []int64{}
72 | cc.CapTable["andrewarrow"] = 8370500000
73 | cc.CapTable["donhardman"] = 1940800000
74 | cc.CapTable["Clout_Cast"] = 1711100000
75 | cc.CapTable["JasonDevlin"] = 1523500000
76 | cc.CapTable["clayoglesby"] = 663300000
77 | cc.CapTable["Salvo"] = 500700000
78 |
79 | fr := 0.50
80 | cc.DrawChartWithBuys("001.png")
81 | val := cc.Buy("Clout_Cast", 1711100000, fr)
82 | cc.BuyNoFR("andrewarrow", val)
83 | cc.DrawChartWithBuys("002.png")
84 | val = cc.Buy("Clout_Cast", 1711100000*4, fr)
85 | cc.BuyNoFR("andrewarrow", val)
86 | cc.DrawChartWithBuys("003.png")
87 | val = cc.Buy("Clout_Cast", 1711100000*4, fr)
88 | cc.BuyNoFR("andrewarrow", val)
89 | cc.DrawChartWithBuys("004.png")
90 | val = cc.Buy("Clout_Cast", 1711100000*8, fr)
91 | cc.BuyNoFR("andrewarrow", val)
92 | cc.DrawChartWithBuys("005.png")
93 | }
94 |
95 | func DrawChart(m map[string]int, filename string) {
96 | items := []chart.Value{}
97 | for k, v := range m {
98 | items = append(items, chart.Value{Value: float64(v), Label: k})
99 | }
100 |
101 | pie := chart.PieChart{
102 | Width: 400,
103 | Height: 400,
104 | Values: items,
105 | }
106 |
107 | f, _ := os.Create(filename)
108 | defer f.Close()
109 | pie.Render(chart.PNG, f)
110 | }
111 |
--------------------------------------------------------------------------------
/draw/size.go:
--------------------------------------------------------------------------------
1 | package draw
2 |
3 | import (
4 | "io/ioutil"
5 | "os"
6 | "os/exec"
7 | )
8 |
9 | func ResizeImage(filename string) {
10 | exec.Command("convert", filename, "-resize", "200%", filename).Output()
11 | }
12 | func ResizeImageBy(filename, percent string) {
13 | exec.Command("convert", filename, "-resize", percent+"%", filename).Output()
14 | }
15 | func SavePic(flavor string, data []byte) {
16 | os.Remove(flavor + ".webp")
17 | ioutil.WriteFile(flavor+".webp", data, 0755)
18 | exec.Command("convert", flavor+".webp", flavor+".png").Output()
19 | }
20 | func SavePicWithPath(imageKind, path, flavor string, data []byte) {
21 | os.Remove(path + "/" + flavor + "." + imageKind)
22 | ioutil.WriteFile(path+"/"+flavor+"."+imageKind, data, 0755)
23 | exec.Command("convert", path+"/"+flavor+"."+imageKind, path+"/"+flavor+".png").CombinedOutput()
24 | os.Remove(path + "/" + flavor + "." + imageKind)
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/draw/users.go:
--------------------------------------------------------------------------------
1 | package draw
2 |
3 | import (
4 | "fmt"
5 | "io/ioutil"
6 | "math/rand"
7 |
8 | "github.com/fogleman/gg"
9 | )
10 |
11 | func DrawUserFrame(i int, list []string) {
12 | dc := gg.NewContext(600, 400)
13 | dc.SetRGB(0, 0, 0)
14 | dc.Clear()
15 | dc.SetRGB(0, 1, 0)
16 | x := rand.Intn(600)
17 | y := rand.Intn(400)
18 | for _, image := range list {
19 | im, _ := gg.LoadPNG(image)
20 | dc.DrawImage(im, x, y)
21 | x = rand.Intn(650) - 50
22 | y = rand.Intn(350) - 50
23 | }
24 | file := fmt.Sprintf("frames/%d.png", i)
25 | dc.SavePNG(file)
26 | files = append(files, file)
27 | }
28 | func UserPoster(pic string) {
29 | if true {
30 | for i := 0; i < 93; i++ {
31 | file := fmt.Sprintf("frames/%d.png", i)
32 | files = append(files, file)
33 | }
34 | MakeVideoFromImages(files)
35 | return
36 | }
37 |
38 | files, _ := ioutil.ReadDir(pic)
39 | all := []string{}
40 | for _, file := range files {
41 | all = append(all, pic+"/"+file.Name())
42 | }
43 |
44 | j := 0
45 | for {
46 | if j*1000 > 92100 {
47 | break
48 | }
49 | list := []string{}
50 | for i, file := range all {
51 | if i < j*1000 {
52 | continue
53 | }
54 | list = append(list, file)
55 | if i > (j*1000)+1000 {
56 | break
57 | }
58 | }
59 |
60 | DrawUserFrame(j, list)
61 | j++
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/emoji.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "clout/keys"
5 | "clout/models"
6 | "clout/network"
7 | "clout/session"
8 | "encoding/json"
9 | "fmt"
10 | "html"
11 | "math/rand"
12 | "strconv"
13 | "strings"
14 | )
15 |
16 | func RandomEmo(n int) {
17 | for i := 0; i < n; i++ {
18 | items := ParseEmojiFromString()
19 | item := items[rand.Intn(len(items))]
20 | val, _ := strconv.ParseInt(item, 16, 64)
21 | s := html.UnescapeString(string(val))
22 | fmt.Println(s)
23 | }
24 | }
25 |
26 | func HandleClown() {
27 | items := ParseEmojiFromString()
28 | item1 := items[rand.Intn(len(items))]
29 | item2 := items[rand.Intn(len(items))]
30 | item3 := items[rand.Intn(len(items))]
31 |
32 | val1, _ := strconv.ParseInt(item1, 16, 64)
33 | val2, _ := strconv.ParseInt(item2, 16, 64)
34 | val3, _ := strconv.ParseInt(item3, 16, 64)
35 | str1 := html.UnescapeString(string(val1))
36 | str2 := html.UnescapeString(string(val2))
37 | str3 := html.UnescapeString(string(val3))
38 | text := fmt.Sprintf("%s%s%s = $%d", str1, str2, str3, SumIt(item1)+SumIt(item2)+SumIt(item3))
39 |
40 | fmt.Println(text)
41 |
42 | mnemonic := session.ReadLoggedInWords()
43 | if mnemonic == "" {
44 | return
45 | }
46 | pub58, priv := keys.ComputeKeysFromSeed(session.SeedBytes(mnemonic))
47 |
48 | longHash := "a167e616c33047f73ce386bb877b0044b275ca59aa12af1a5a0312b10c3a756b"
49 | bigString := network.SubmitPost(pub58, text, longHash, "")
50 |
51 | var tx models.TxReady
52 | json.Unmarshal([]byte(bigString), &tx)
53 |
54 | jsonString := network.SubmitTx(tx.TransactionHex, priv)
55 | if jsonString != "" {
56 | fmt.Println("Success.")
57 | }
58 | }
59 |
60 | func SumIt(item string) int64 {
61 | sum := int64(0)
62 | for i, _ := range item {
63 | thing := item[i : i+1]
64 | val, _ := strconv.ParseInt(thing, 16, 64)
65 | sum += val
66 | }
67 | return sum
68 | }
69 |
70 | func ParseEmojiFromString() []string {
71 | tokens := strings.Split(emojiTableString, ",")
72 | return tokens
73 | }
74 | func ParseEmojiFromHTML() map[string]bool {
75 | m := map[string]bool{}
76 | tokens := strings.Split(emojiTableString, "