├── .editorconfig
├── .github
├── CODEOWNERS
├── dependabot.yml
├── labels.yml
└── workflows
│ ├── build.yml
│ ├── labels.yml
│ └── released.yml
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── assets
└── assets.go
├── build.properties
├── build.xml
├── go.mod
├── go.sum
├── main.go
├── res
├── Franz.lnk
├── app.ico
├── papp.ico
├── papp.manifest
├── papp.png
├── run.iss
└── setup-mini.bmp
└── tools
└── tools.go
/.editorconfig:
--------------------------------------------------------------------------------
1 | # This file is for unifying the coding style for different editors and IDEs.
2 | # More information at http://editorconfig.org
3 |
4 | root = true
5 |
6 | [*]
7 | charset = utf-8
8 | indent_size = 2
9 | indent_style = space
10 | end_of_line = lf
11 | insert_final_newline = true
12 | trim_trailing_whitespace = true
13 |
14 | [*.md]
15 | trim_trailing_whitespace = false
16 |
17 | [*.go]
18 | indent_style = tab
19 |
--------------------------------------------------------------------------------
/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @crazy-max
2 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: "gomod"
4 | directory: "/"
5 | schedule:
6 | interval: "daily"
7 | time: "08:00"
8 | timezone: "Europe/Paris"
9 | labels:
10 | - ":game_die: dependencies"
11 | - ":robot: bot"
12 | - package-ecosystem: "github-actions"
13 | directory: "/"
14 | schedule:
15 | interval: "daily"
16 | time: "08:00"
17 | timezone: "Europe/Paris"
18 | labels:
19 | - ":game_die: dependencies"
20 | - ":robot: bot"
21 |
--------------------------------------------------------------------------------
/.github/labels.yml:
--------------------------------------------------------------------------------
1 | ## more info https://github.com/crazy-max/ghaction-github-labeler
2 | - # bot
3 | name: ":robot: bot"
4 | color: "69cde9"
5 | description: ""
6 | - # broken
7 | name: ":zap: broken"
8 | color: "a3090e"
9 | description: ""
10 | - # bug
11 | name: ":bug: bug"
12 | color: "b60205"
13 | description: ""
14 | - # dependencies
15 | name: ":game_die: dependencies"
16 | color: "0366d6"
17 | description: ""
18 | - # documentation
19 | name: ":memo: documentation"
20 | color: "c5def5"
21 | description: ""
22 | - # duplicate
23 | name: ":busts_in_silhouette: duplicate"
24 | color: "cccccc"
25 | description: ""
26 | - # enhancement
27 | name: ":sparkles: enhancement"
28 | color: "0054ca"
29 | description: ""
30 | - # feature request
31 | name: ":bulb: feature request"
32 | color: "0e8a16"
33 | description: ""
34 | - # feedback
35 | name: ":mega: feedback"
36 | color: "03a9f4"
37 | description: ""
38 | - # future maybe
39 | name: ":rocket: future maybe"
40 | color: "fef2c0"
41 | description: ""
42 | - # good first issue
43 | name: ":hatching_chick: good first issue"
44 | color: "7057ff"
45 | description: ""
46 | - # help wanted
47 | name: ":pray: help wanted"
48 | color: "4caf50"
49 | description: ""
50 | - # hold
51 | name: ":hand: hold"
52 | color: "24292f"
53 | description: ""
54 | - # invalid
55 | name: ":no_entry_sign: invalid"
56 | color: "e6e6e6"
57 | description: ""
58 | - # maybe bug
59 | name: ":interrobang: maybe bug"
60 | color: "ff5722"
61 | description: ""
62 | - # needs more info
63 | name: ":thinking: needs more info"
64 | color: "795548"
65 | description: ""
66 | - # question
67 | name: ":question: question"
68 | color: "3f51b5"
69 | description: ""
70 | - # trademark violation
71 | name: ":construction: trademark violation"
72 | color: "cfe524"
73 | description: ""
74 | - # upstream
75 | name: ":eyes: upstream"
76 | color: "fbca04"
77 | description: ""
78 | - # wontfix
79 | name: ":coffin: wontfix"
80 | color: "ffffff"
81 | description: ""
82 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: build
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | tags:
7 | - '*'
8 | pull_request:
9 |
10 | jobs:
11 | build:
12 | uses: portapps/.github/.github/workflows/app-build.yml@master
13 |
--------------------------------------------------------------------------------
/.github/workflows/labels.yml:
--------------------------------------------------------------------------------
1 | name: labels
2 |
3 | on:
4 | push:
5 | branches:
6 | - 'master'
7 | paths:
8 | - '.github/labels.yml'
9 | - '.github/workflows/labels.yml'
10 |
11 | jobs:
12 | labeler:
13 | runs-on: ubuntu-latest
14 | steps:
15 | -
16 | name: Checkout
17 | uses: actions/checkout@v4
18 | -
19 | name: Run Labeler
20 | uses: crazy-max/ghaction-github-labeler@v5
21 |
--------------------------------------------------------------------------------
/.github/workflows/released.yml:
--------------------------------------------------------------------------------
1 | name: released
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | jobs:
8 | virustotal:
9 | uses: portapps/.github/.github/workflows/app-virustotal.yml@master
10 | secrets:
11 | vt_api_key: ${{ secrets.VT_API_KEY }}
12 | vt_monitor_api_key: ${{ secrets.VT_MONITOR_API_KEY }}
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Intellij
2 | /.idea
3 | /*.iml
4 |
5 | # App
6 | /.dev
7 | /bin
8 | /vendor
9 | /*.syso
10 | /*.exe
11 | /versioninfo.json
12 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## 5.9.1-12 (2021/05/08)
4 |
5 | * Franz 5.9.1
6 | * Portapps 3.5.0
7 |
8 | ## 5.6.1-11 (2021/01/06)
9 |
10 | * Franz 5.6.1
11 | * Portapps 3.1.0
12 |
13 | ## 5.5.0-10 (2020/05/07)
14 |
15 | * Franz 5.5.0
16 | * Portapps 2.2.4
17 |
18 | ## 5.4.1-9 (2020/02/01)
19 |
20 | * Add `cleanup` config
21 | * Portapps 1.31.0
22 |
23 | ## 5.4.1-8 (2019/11/03)
24 |
25 | * Franz 5.4.1
26 |
27 | ## 5.4.0-7 (2019/10/23)
28 |
29 | * Franz 5.4.0
30 | * Franz is now based on Electron 6
31 | * Portapps 1.28.0
32 |
33 | ## 5.3.3-6 (2019/09/17)
34 |
35 | * Franz 5.3.3
36 |
37 | ## 5.3.1-5 (2019/09/09)
38 |
39 | * Franz 5.3.1
40 | * Portapps 1.26.1
41 |
42 | ## 5.2.0-4 (2019/07/24)
43 |
44 | * Add option to disable delay (Issue #2)
45 |
46 | ## 5.2.0-3 (2019/07/21)
47 |
48 | * Franz 5.2.0
49 |
50 | ## 5.1.0-2 (2019/05/17)
51 |
52 | * Disable launch on startup (Issue #1)
53 |
54 | ## 5.1.0-1 (2019/05/08)
55 |
56 | * Initial version based on Franz 5.1.0
57 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019-2023 CrazyMax
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 |

2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | ## Notice of Non-Affiliation and Disclaimer
13 |
14 | Portapps is not affiliated, associated, authorized, endorsed by, or in any way officially connected with Franz™, or any of its subsidiaries or its affiliates.
15 |
16 | The official Franz™ website can be found at https://meetfranz.com/.
17 |
18 | The name Franz™ as well as related names, marks, emblems and images are registered trademarks of their respective owners.
19 |
20 | ## About
21 |
22 | Franz™ portable app made with 🚀 [Portapps](https://portapps.io).
23 | Documentation and downloads can be found on https://portapps.io/app/franz-portable/
24 |
25 | ## Contributing
26 |
27 | Want to contribute? Awesome! The most basic way to show your support is to star the project, or to raise issues. If
28 | you want to open a pull request, please read the [contributing guidelines](https://portapps.io/doc/contribute/).
29 |
30 | You can also support this project by [**becoming a sponsor on GitHub**](https://github.com/sponsors/crazy-max) or by
31 | making a [Paypal donation](https://www.paypal.me/crazyws) to ensure this journey continues indefinitely!
32 |
33 | Thanks again for your support, it is much appreciated! :pray:
34 |
35 | ## License
36 |
37 | MIT. See `LICENSE` for more details.
38 | Rocket icon credit to [Squid Ink](http://thesquid.ink).
39 |
--------------------------------------------------------------------------------
/assets/assets.go:
--------------------------------------------------------------------------------
1 | // Code generated by go-bindata. DO NOT EDIT.
2 | // sources:
3 | // res/Franz.lnk (2.371kB)
4 |
5 | package assets
6 |
7 | import (
8 | "bytes"
9 | "compress/gzip"
10 | "crypto/sha256"
11 | "fmt"
12 | "io"
13 | "os"
14 | "path/filepath"
15 | "strings"
16 | "time"
17 | )
18 |
19 | func bindataRead(data []byte, name string) ([]byte, error) {
20 | gz, err := gzip.NewReader(bytes.NewBuffer(data))
21 | if err != nil {
22 | return nil, fmt.Errorf("read %q: %w", name, err)
23 | }
24 |
25 | var buf bytes.Buffer
26 | _, err = io.Copy(&buf, gz)
27 | clErr := gz.Close()
28 |
29 | if err != nil {
30 | return nil, fmt.Errorf("read %q: %w", name, err)
31 | }
32 | if clErr != nil {
33 | return nil, err
34 | }
35 |
36 | return buf.Bytes(), nil
37 | }
38 |
39 | type asset struct {
40 | bytes []byte
41 | info os.FileInfo
42 | digest [sha256.Size]byte
43 | }
44 |
45 | type bindataFileInfo struct {
46 | name string
47 | size int64
48 | mode os.FileMode
49 | modTime time.Time
50 | }
51 |
52 | func (fi bindataFileInfo) Name() string {
53 | return fi.name
54 | }
55 | func (fi bindataFileInfo) Size() int64 {
56 | return fi.size
57 | }
58 | func (fi bindataFileInfo) Mode() os.FileMode {
59 | return fi.mode
60 | }
61 | func (fi bindataFileInfo) ModTime() time.Time {
62 | return fi.modTime
63 | }
64 | func (fi bindataFileInfo) IsDir() bool {
65 | return false
66 | }
67 | func (fi bindataFileInfo) Sys() interface{} {
68 | return nil
69 | }
70 |
71 | var _franzLnk = []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xec\x95\x6f\x68\x5b\xd5\x1b\xc7\x3f\xb7\x7f\x18\xdd\x5e\xac\xfb\xfd\xca\xd4\x52\x69\x50\x5b\x26\x9a\x4b\xda\x25\x6d\x93\x29\xb6\xe6\x4f\x53\x9b\xae\x31\x59\xb4\x1b\xd7\xe2\x25\xbd\x4d\x4b\x9a\x26\xbb\xc9\xb0\x89\xa2\x74\xa0\xb3\xc3\x29\x38\xfc\x33\x7d\xd1\x0e\x84\x55\xd0\xa2\x22\x0a\x6e\x8e\xbe\xb0\x08\xa2\x43\xb1\x7d\x53\xa1\x65\x03\x05\x45\x57\xd8\x10\xa7\x8e\x21\xe7\x24\x8d\x69\x2c\x28\xa8\x20\xe2\x03\xc9\xf9\xf7\x9c\xcf\xf3\xbd\xcf\x73\xee\x3d\x01\x40\xa9\xab\x40\xd8\xbc\xfc\xc7\xb7\xda\x09\x16\x60\xf6\xca\x43\x5b\x97\xab\x97\x94\x95\xe5\xc1\x6d\xa2\x65\xc7\xd3\x57\x26\x7f\x5e\x54\x9e\x6c\x7f\xa9\x5a\x38\x2a\x6c\xb4\xba\x0a\x17\x8d\x9e\xee\xfa\xca\xfd\xe6\x5d\xa7\x3c\x53\x0b\x91\xe7\xae\xc5\x6d\x17\x9b\x51\x68\x66\xed\x6c\x2d\xe0\xba\x56\xad\x5e\x78\x7c\x51\xb9\xf4\xc1\xc8\xb7\x2b\xca\x52\xb1\xad\xe3\x30\x19\x1a\x70\xfb\xc2\xbe\x9d\xb4\x48\x5a\xae\x6f\xfe\xfd\xff\xd1\x95\x4a\x79\xf4\x8c\x0e\x64\xea\xf7\x0f\x3e\xbf\xfa\xb9\xff\x58\xec\xba\xdd\x67\x2e\xee\x7a\x6f\xe1\x93\x9f\x56\xa7\x63\xf7\x75\x4d\x75\x2f\x7c\x18\x9f\x7f\xe7\xb1\x4e\x6a\xa8\x62\xed\xac\xd8\x27\x7e\x2a\xe0\xed\x17\x1a\x2b\xcb\x74\xbe\xfb\x72\x8d\xd2\x45\x8a\x14\x1e\x74\x32\x08\xfa\xdd\x04\x0b\x71\x67\xf7\x76\x9f\xac\x25\x90\x8c\xea\x63\xdc\x51\xc2\x14\xf3\x82\x39\xb0\x29\x73\x70\x4f\x9c\x00\x49\xa2\xe8\x8c\x89\x5c\x70\xa0\xc8\xf3\x9e\xac\x25\x68\x26\x63\xa6\x9e\x48\x8b\x48\x79\xe6\xc3\x7d\x7b\xde\x10\x6b\x82\x69\xbf\x57\x78\x56\x94\xe7\xf3\xab\x0a\x25\x88\x49\x92\x18\x26\x3a\x09\xd2\xc0\xf5\x65\x4a\x87\x4d\x7d\x3c\x57\x54\x2a\x88\xeb\x4a\xbf\x79\x40\x10\x6b\xcb\xa8\xee\xc3\x37\x31\x2c\x79\xe3\xe4\xa4\x52\x8d\x56\x44\x4d\x4f\xec\xfd\x6c\xd2\x82\x4f\xf0\x54\x63\xc2\xc0\x53\x64\xfa\x8a\xcc\xed\xdf\x8b\xd2\x57\xf3\x5b\xf3\x15\x99\x2a\x06\x13\x18\x52\x2b\x32\x1b\x0d\x85\xd3\x22\x5a\x47\xc1\x3f\x0e\xdc\x50\xc8\xa4\xfb\x74\x83\x26\x74\x7a\x46\x6f\x39\x78\xc8\xb0\xb8\x71\xbb\xb4\x48\xda\x30\xd3\x5a\xd4\xd4\x73\x59\xad\x70\x0a\x34\x59\x15\x6d\x3d\x97\x9a\x7c\x74\xed\x57\xc1\x84\xe8\xc3\x20\x4d\x1a\x9d\x18\xa3\x8c\x13\xc3\x82\x2e\x6b\x6d\x61\x98\x24\x26\x16\xee\x67\x44\xd6\x3d\x4d\xfe\x14\xdc\x8e\x85\x30\x63\xe8\x44\x89\xcb\xd1\x3e\x0c\xc6\x30\x8a\x79\x17\x73\x7e\x46\x49\xe1\x2e\xec\xcd\xcf\xe8\x32\x42\x92\x43\x92\x66\x91\xe3\x21\x2c\x24\x64\x2f\x5b\xd6\x13\xd1\x0d\x54\x6e\x45\x45\x45\x63\xe3\x19\xd4\x4a\xce\x8f\x46\x79\xdd\xb5\x92\x9a\x69\x9b\xe4\xfa\x36\xdc\xb8\xd0\x88\x90\xc6\xc0\x94\x3b\xa2\xd2\x2b\x47\xf6\x4f\xc4\x72\xfc\x4d\xdc\xcd\x9e\xa1\xae\x12\xb6\xc0\x4c\x53\x24\xec\x0d\x05\x43\xfd\xbe\x9e\x80\xb7\xe9\x0f\xd7\xfe\xdf\x65\x4d\x44\x08\xe3\x25\x44\x90\x10\xfd\xf8\xe8\x21\x80\x97\xa6\xbf\x38\xe7\xff\xd9\x3f\xdb\xc4\x17\x73\x1b\xcc\x3c\xb2\xfd\xdc\x65\xa5\xe7\xe3\x7b\x9e\xf0\x2f\x2d\xf6\x56\xad\x3d\xe3\x02\x1e\xcc\x7f\x3d\x67\x06\x0a\xbe\xa9\xa8\x75\x44\x1f\x32\xd2\xeb\x7b\x87\xe6\xe6\x32\xd9\x4b\xaf\x79\x9f\x9d\xfc\xf2\xd5\xe5\xd9\x23\x55\x3f\x84\xaf\x1e\x78\xfb\xe0\xd7\x3b\x4e\x1c\xdf\xf7\x56\xe5\xd6\xa3\x81\xdf\x5b\xbf\x59\x81\x1a\x98\x99\x02\x5a\xc2\xc1\xf0\x85\xa3\x03\xbe\x33\x81\x0e\xf7\xe9\xab\xff\x3f\xde\xfc\x62\xe2\x5c\x02\xa8\x12\x81\x1a\x01\x71\x39\x84\xb1\xd2\x82\x15\x07\x56\x5a\x65\x6f\x37\xed\x38\xb1\x63\xc7\x89\x93\x36\x3a\x68\x93\x6b\x4e\x1c\xd8\xb0\xcb\x71\x2b\x1d\xd2\xd3\x81\x1d\x1b\x36\x5a\x68\x97\x3b\xda\x24\x2d\x3f\x93\xb7\x48\x41\x48\x64\x57\x60\x3a\x3b\xed\xec\x9d\xfd\xf4\xfc\xa2\xf5\xfc\xd2\x65\xe7\xfa\x95\xd4\x28\xef\x33\x88\x92\x24\x81\x4a\x02\x03\x83\x4c\xc9\x3b\xa0\x6e\xb8\xfb\x84\x39\x0b\xd0\x37\x77\x26\x3c\xaf\x1f\x4b\xf9\x4f\xf9\x3b\xd5\x57\xee\x9c\x78\xea\x46\x60\x44\x38\xf8\x81\xd5\x95\xfa\xef\x8e\xfc\xb8\xe6\x7f\x61\xee\x8b\xde\x2d\x1f\x3d\x6a\x2b\x2d\xd1\x2f\x01\x00\x00\xff\xff\x27\xd0\x90\x1e\x43\x09\x00\x00")
72 |
73 | func franzLnkBytes() ([]byte, error) {
74 | return bindataRead(
75 | _franzLnk,
76 | "Franz.lnk",
77 | )
78 | }
79 |
80 | func franzLnk() (*asset, error) {
81 | bytes, err := franzLnkBytes()
82 | if err != nil {
83 | return nil, err
84 | }
85 |
86 | info := bindataFileInfo{name: "Franz.lnk", size: 2371, mode: os.FileMode(0666), modTime: time.Unix(1557346214, 0)}
87 | a := &asset{bytes: bytes, info: info, digest: [32]uint8{0x20, 0xa4, 0x6, 0x39, 0x2c, 0x53, 0xf9, 0x4a, 0x54, 0x22, 0x3d, 0x9a, 0x78, 0x61, 0xb0, 0x38, 0x9b, 0x68, 0xb, 0x62, 0xdb, 0xc, 0xfb, 0xeb, 0x90, 0x2c, 0x79, 0x77, 0xc6, 0xd6, 0x67, 0x80}}
88 | return a, nil
89 | }
90 |
91 | // Asset loads and returns the asset for the given name.
92 | // It returns an error if the asset could not be found or
93 | // could not be loaded.
94 | func Asset(name string) ([]byte, error) {
95 | canonicalName := strings.Replace(name, "\\", "/", -1)
96 | if f, ok := _bindata[canonicalName]; ok {
97 | a, err := f()
98 | if err != nil {
99 | return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
100 | }
101 | return a.bytes, nil
102 | }
103 | return nil, fmt.Errorf("Asset %s not found", name)
104 | }
105 |
106 | // AssetString returns the asset contents as a string (instead of a []byte).
107 | func AssetString(name string) (string, error) {
108 | data, err := Asset(name)
109 | return string(data), err
110 | }
111 |
112 | // MustAsset is like Asset but panics when Asset would return an error.
113 | // It simplifies safe initialization of global variables.
114 | func MustAsset(name string) []byte {
115 | a, err := Asset(name)
116 | if err != nil {
117 | panic("asset: Asset(" + name + "): " + err.Error())
118 | }
119 |
120 | return a
121 | }
122 |
123 | // MustAssetString is like AssetString but panics when Asset would return an
124 | // error. It simplifies safe initialization of global variables.
125 | func MustAssetString(name string) string {
126 | return string(MustAsset(name))
127 | }
128 |
129 | // AssetInfo loads and returns the asset info for the given name.
130 | // It returns an error if the asset could not be found or
131 | // could not be loaded.
132 | func AssetInfo(name string) (os.FileInfo, error) {
133 | canonicalName := strings.Replace(name, "\\", "/", -1)
134 | if f, ok := _bindata[canonicalName]; ok {
135 | a, err := f()
136 | if err != nil {
137 | return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
138 | }
139 | return a.info, nil
140 | }
141 | return nil, fmt.Errorf("AssetInfo %s not found", name)
142 | }
143 |
144 | // AssetDigest returns the digest of the file with the given name. It returns an
145 | // error if the asset could not be found or the digest could not be loaded.
146 | func AssetDigest(name string) ([sha256.Size]byte, error) {
147 | canonicalName := strings.Replace(name, "\\", "/", -1)
148 | if f, ok := _bindata[canonicalName]; ok {
149 | a, err := f()
150 | if err != nil {
151 | return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s can't read by error: %v", name, err)
152 | }
153 | return a.digest, nil
154 | }
155 | return [sha256.Size]byte{}, fmt.Errorf("AssetDigest %s not found", name)
156 | }
157 |
158 | // Digests returns a map of all known files and their checksums.
159 | func Digests() (map[string][sha256.Size]byte, error) {
160 | mp := make(map[string][sha256.Size]byte, len(_bindata))
161 | for name := range _bindata {
162 | a, err := _bindata[name]()
163 | if err != nil {
164 | return nil, err
165 | }
166 | mp[name] = a.digest
167 | }
168 | return mp, nil
169 | }
170 |
171 | // AssetNames returns the names of the assets.
172 | func AssetNames() []string {
173 | names := make([]string, 0, len(_bindata))
174 | for name := range _bindata {
175 | names = append(names, name)
176 | }
177 | return names
178 | }
179 |
180 | // _bindata is a table, holding each asset generator, mapped to its name.
181 | var _bindata = map[string]func() (*asset, error){
182 | "Franz.lnk": franzLnk,
183 | }
184 |
185 | // AssetDebug is true if the assets were built with the debug flag enabled.
186 | const AssetDebug = false
187 |
188 | // AssetDir returns the file names below a certain
189 | // directory embedded in the file by go-bindata.
190 | // For example if you run go-bindata on data/... and data contains the
191 | // following hierarchy:
192 | //
193 | // data/
194 | // foo.txt
195 | // img/
196 | // a.png
197 | // b.png
198 | //
199 | // then AssetDir("data") would return []string{"foo.txt", "img"},
200 | // AssetDir("data/img") would return []string{"a.png", "b.png"},
201 | // AssetDir("foo.txt") and AssetDir("notexist") would return an error, and
202 | // AssetDir("") will return []string{"data"}.
203 | func AssetDir(name string) ([]string, error) {
204 | node := _bintree
205 | if len(name) != 0 {
206 | canonicalName := strings.Replace(name, "\\", "/", -1)
207 | pathList := strings.Split(canonicalName, "/")
208 | for _, p := range pathList {
209 | node = node.Children[p]
210 | if node == nil {
211 | return nil, fmt.Errorf("Asset %s not found", name)
212 | }
213 | }
214 | }
215 | if node.Func != nil {
216 | return nil, fmt.Errorf("Asset %s not found", name)
217 | }
218 | rv := make([]string, 0, len(node.Children))
219 | for childName := range node.Children {
220 | rv = append(rv, childName)
221 | }
222 | return rv, nil
223 | }
224 |
225 | type bintree struct {
226 | Func func() (*asset, error)
227 | Children map[string]*bintree
228 | }
229 |
230 | var _bintree = &bintree{nil, map[string]*bintree{
231 | "Franz.lnk": {franzLnk, map[string]*bintree{}},
232 | }}
233 |
234 | // RestoreAsset restores an asset under the given directory.
235 | func RestoreAsset(dir, name string) error {
236 | data, err := Asset(name)
237 | if err != nil {
238 | return err
239 | }
240 | info, err := AssetInfo(name)
241 | if err != nil {
242 | return err
243 | }
244 | err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
245 | if err != nil {
246 | return err
247 | }
248 | err = os.WriteFile(_filePath(dir, name), data, info.Mode())
249 | if err != nil {
250 | return err
251 | }
252 | return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
253 | }
254 |
255 | // RestoreAssets restores an asset under the given directory recursively.
256 | func RestoreAssets(dir, name string) error {
257 | children, err := AssetDir(name)
258 | // File
259 | if err != nil {
260 | return RestoreAsset(dir, name)
261 | }
262 | // Dir
263 | for _, child := range children {
264 | err = RestoreAssets(dir, filepath.Join(name, child))
265 | if err != nil {
266 | return err
267 | }
268 | }
269 | return nil
270 | }
271 |
272 | func _filePath(dir, name string) string {
273 | canonicalName := strings.Replace(name, "\\", "/", -1)
274 | return filepath.Join(append([]string{dir}, strings.Split(canonicalName, "/")...)...)
275 | }
276 |
--------------------------------------------------------------------------------
/build.properties:
--------------------------------------------------------------------------------
1 | # Portapps
2 | core.dir = ../portapps
3 |
4 | # App
5 | app = franz
6 | app.name = Franz
7 | app.type = archive
8 | app.version = 5.9.1
9 | app.release = 12
10 | app.homepage = https://meetfranz.com/
11 |
12 | # Portable app
13 | papp.id = ${app}-portable
14 | papp.guid = {3AD7920B-9BE4-4E5F-BB6B-D79A4F913D8B}
15 | papp.name = ${app.name} Portable
16 | papp.desc = ${app.name} portable on Windows by Portapps
17 | papp.url = https://github.com/portapps/${papp.id}
18 | papp.folder = app
19 |
20 | # Electron
21 | electron.appasar.file = electron/ipc-api/index.js
22 | electron.appasar.search = var _autoUpdate=_interopRequireDefault(require("./autoUpdate")),
23 | electron.appasar.replace = var
24 | electron.appasar.search2 = ,(0,_autoUpdate.default)(e),
25 | electron.appasar.replace2 = ,
26 | electron.appasar2.file = components/settings/settings/EditSettingsForm.js
27 | electron.appasar2.search = field:t.$("autoLaunchOnStart")
28 | electron.appasar2.replace = field:t.$("autoLaunchOnStart"),disabled:true
29 | electron.appasar3.file = containers/settings/EditSettingsScreen.js
30 | electron.appasar3.search = enable:e.autoLaunchOnStart
31 | electron.appasar3.replace = enable:false
32 | electron.appasar4.file = features/delayApp/index.js
33 | electron.appasar4.search = if(t){
34 | electron.appasar4.replace = if(t && process.env.FRANZ_DELAY == "true"){
35 |
36 | # Official artifacts
37 | atf.id = franz
38 | atf.win32.filename = franz-setup-${app.version}
39 | atf.win32.ext = .exe
40 | atf.win32.url = https://github.com/meetfranz/franz/releases/download/v${app.version}/franz-setup-${app.version}.exe
41 | atf.win32.assertextract = $PLUGINSDIR/app-32.7z
42 | atf.win64.filename = franz-setup-${app.version}
43 | atf.win64.ext = .exe
44 | atf.win64.url = https://github.com/meetfranz/franz/releases/download/v${app.version}/franz-setup-${app.version}.exe
45 | atf.win64.assertextract = $PLUGINSDIR/app-64.7z
46 |
--------------------------------------------------------------------------------
/build.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
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 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/portapps/franz-portable
2 |
3 | go 1.23
4 |
5 | require (
6 | github.com/kevinburke/go-bindata/v4 v4.0.2
7 | github.com/portapps/portapps/v3 v3.14.1
8 | )
9 |
10 | require (
11 | github.com/akavel/rsrc v0.10.2 // indirect
12 | github.com/go-ole/go-ole v1.3.0 // indirect
13 | github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
14 | github.com/ilya1st/rotatewriter v0.0.0-20171126183947-3df0c1a3ed6d // indirect
15 | github.com/josephspurrier/goversioninfo v1.4.1 // indirect
16 | github.com/mattn/go-colorable v0.1.13 // indirect
17 | github.com/mattn/go-isatty v0.0.19 // indirect
18 | github.com/pkg/errors v0.9.1 // indirect
19 | github.com/rs/zerolog v1.33.0 // indirect
20 | golang.org/x/sys v0.27.0 // indirect
21 | gopkg.in/yaml.v3 v3.0.1 // indirect
22 | )
23 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw=
2 | github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
3 | github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
6 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7 | github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
8 | github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
9 | github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
10 | github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
11 | github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
12 | github.com/ilya1st/rotatewriter v0.0.0-20171126183947-3df0c1a3ed6d h1:OGuVAVny/97zsQ5BWg0mOjzTBBD9zR+Lug1co144+rU=
13 | github.com/ilya1st/rotatewriter v0.0.0-20171126183947-3df0c1a3ed6d/go.mod h1:S1q6q+21PRGd0WRX+fHjQ+TOe3CgpSv7zgCWnZcbxCs=
14 | github.com/josephspurrier/goversioninfo v1.4.1 h1:5LvrkP+n0tg91J9yTkoVnt/QgNnrI1t4uSsWjIonrqY=
15 | github.com/josephspurrier/goversioninfo v1.4.1/go.mod h1:JWzv5rKQr+MmW+LvM412ToT/IkYDZjaclF2pKDss8IY=
16 | github.com/kevinburke/go-bindata/v4 v4.0.2 h1:6qQI0nNTL27wM1En8zQHGBEPp3ETzgFU6hVdSjlkrfE=
17 | github.com/kevinburke/go-bindata/v4 v4.0.2/go.mod h1:M/CkBqw2qCZ1Ztv5JyKgocGYWyUkYlDqkqXS1ktLe5c=
18 | github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
19 | github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
20 | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
21 | github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
22 | github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
23 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
24 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
25 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
26 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
27 | github.com/portapps/portapps/v3 v3.14.1 h1:/MD+QBSq64KIg82hZ/hMQHxW+UZ/Th9TWMRkY5danfY=
28 | github.com/portapps/portapps/v3 v3.14.1/go.mod h1:PJTha9WxFuumcnCd+TjHDdam5wH5b5akiKyF/HZieco=
29 | github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
30 | github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
31 | github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
32 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
33 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
34 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
35 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
36 | golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
37 | golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
38 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
39 | golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
40 | golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
41 | golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
42 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
43 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
44 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
45 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
46 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
47 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | //go:generate go install -v github.com/kevinburke/go-bindata/v4/go-bindata
2 | //go:generate go-bindata -prefix res/ -pkg assets -o assets/assets.go res/Franz.lnk
3 | //go:generate go install -v github.com/josephspurrier/goversioninfo/cmd/goversioninfo
4 | //go:generate goversioninfo -icon=res/papp.ico -manifest=res/papp.manifest
5 | package main
6 |
7 | import (
8 | "os"
9 | "path"
10 |
11 | "github.com/portapps/franz-portable/assets"
12 | "github.com/portapps/portapps/v3"
13 | "github.com/portapps/portapps/v3/pkg/log"
14 | "github.com/portapps/portapps/v3/pkg/shortcut"
15 | "github.com/portapps/portapps/v3/pkg/utl"
16 | )
17 |
18 | type config struct {
19 | Cleanup bool `yaml:"cleanup" mapstructure:"cleanup"`
20 | DisableDelay bool `yaml:"disable_delay" mapstructure:"disable_delay"`
21 | }
22 |
23 | var (
24 | app *portapps.App
25 | cfg *config
26 | )
27 |
28 | func init() {
29 | var err error
30 |
31 | // Default config
32 | cfg = &config{
33 | Cleanup: false,
34 | DisableDelay: false,
35 | }
36 |
37 | // Init app
38 | if app, err = portapps.NewWithCfg("franz-portable", "Franz", cfg); err != nil {
39 | log.Fatal().Err(err).Msg("Cannot initialize application. See log file for more info.")
40 | }
41 | }
42 |
43 | func main() {
44 | utl.CreateFolder(app.DataPath)
45 | app.Process = utl.PathJoin(app.AppPath, "Franz.exe")
46 | app.Args = []string{
47 | "--user-data-dir=" + app.DataPath,
48 | }
49 |
50 | // Data dir
51 | os.Setenv("FRANZ_APPDATA_DIR", app.DataPath)
52 |
53 | // Cleanup on exit
54 | if cfg.Cleanup {
55 | defer func() {
56 | utl.Cleanup([]string{
57 | path.Join(os.Getenv("APPDATA"), "Franz"),
58 | })
59 | }()
60 | }
61 |
62 | // Copy default shortcut
63 | shortcutPath := path.Join(os.Getenv("APPDATA"), "Microsoft", "Windows", "Start Menu", "Programs", "Franz Portable.lnk")
64 | defaultShortcut, err := assets.Asset("Franz.lnk")
65 | if err != nil {
66 | log.Error().Err(err).Msg("Cannot load asset Franz.lnk")
67 | }
68 | err = os.WriteFile(shortcutPath, defaultShortcut, 0644)
69 | if err != nil {
70 | log.Error().Err(err).Msg("Cannot write default shortcut")
71 | }
72 |
73 | // Check delay
74 | if cfg.DisableDelay {
75 | os.Setenv("FRANZ_DELAY", "false")
76 | } else {
77 | os.Setenv("FRANZ_DELAY", "true")
78 | }
79 |
80 | // Update default shortcut
81 | err = shortcut.Create(shortcut.Shortcut{
82 | ShortcutPath: shortcutPath,
83 | TargetPath: app.Process,
84 | Arguments: shortcut.Property{Clear: true},
85 | Description: shortcut.Property{Value: "Franz Portable by Portapps"},
86 | IconLocation: shortcut.Property{Value: app.Process},
87 | WorkingDirectory: shortcut.Property{Value: app.AppPath},
88 | })
89 | if err != nil {
90 | log.Error().Err(err).Msg("Cannot create shortcut")
91 | }
92 | defer func() {
93 | if err := os.Remove(shortcutPath); err != nil {
94 | log.Error().Err(err).Msg("Cannot remove shortcut")
95 | }
96 | }()
97 |
98 | defer app.Close()
99 | app.Launch(os.Args[1:])
100 | }
101 |
--------------------------------------------------------------------------------
/res/Franz.lnk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/portapps/franz-portable/b00868fb5875ecfe168a8ae160d4c1a7f0d62142/res/Franz.lnk
--------------------------------------------------------------------------------
/res/app.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/portapps/franz-portable/b00868fb5875ecfe168a8ae160d4c1a7f0d62142/res/app.ico
--------------------------------------------------------------------------------
/res/papp.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/portapps/franz-portable/b00868fb5875ecfe168a8ae160d4c1a7f0d62142/res/papp.ico
--------------------------------------------------------------------------------
/res/papp.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/res/papp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/portapps/franz-portable/b00868fb5875ecfe168a8ae160d4c1a7f0d62142/res/papp.png
--------------------------------------------------------------------------------
/res/run.iss:
--------------------------------------------------------------------------------
1 | [Run]
2 | Filename: {app}\{#pappId}.exe; Description: Run {#pappName}; Flags: nowait postinstall skipifsilent unchecked
3 |
--------------------------------------------------------------------------------
/res/setup-mini.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/portapps/franz-portable/b00868fb5875ecfe168a8ae160d4c1a7f0d62142/res/setup-mini.bmp
--------------------------------------------------------------------------------
/tools/tools.go:
--------------------------------------------------------------------------------
1 | //go:build tools
2 | // +build tools
3 |
4 | // Package tools tracks dependencies on binaries not referenced in this codebase.
5 | // https://github.com/golang/go/wiki/Modules#how-can-i-track-tool-dependencies-for-a-module
6 | package tools
7 |
8 | import (
9 | _ "github.com/kevinburke/go-bindata/v4"
10 | _ "github.com/portapps/portapps/v3/tools"
11 | )
12 |
--------------------------------------------------------------------------------