~zethra/sasha-fetch

ref: df6351698e0d7313fa22ff7cb531f2a866117c9b sasha-fetch/sasha-fetch.py -rwxr-xr-x 3.9 KiB
df635169Sashanoraa Fix typo a month ago
                                                                                
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/env python3

message = '''
Sashanoraa
----------
Pronouns:   fae|she|they
Gender:     Non-binary Trans Fem
Matrix:     @zethra:matrix.org
Email:      sasha@noraa.gay
Mastodon:   @zethra@fosstodon.org
Website:    sashanoraa.gay
Protonmail: sashanoraa@protonmail.com
Code:       sr.ht/~zethra
'''.splitlines()

import sys
import math
import random
import signal
import argparse
from time import sleep

COLOR_ANSI = (
    (0x00, 0x00, 0x00), (0xcd, 0x00, 0x00),
    (0x00, 0xcd, 0x00), (0xcd, 0xcd, 0x00),
    (0x00, 0x00, 0xee), (0xcd, 0x00, 0xcd),
    (0x00, 0xcd, 0xcd), (0xe5, 0xe5, 0xe5),
    (0x7f, 0x7f, 0x7f), (0xff, 0x00, 0x00),
    (0x00, 0xff, 0x00), (0xff, 0xff, 0x00),
    (0x5c, 0x5c, 0xff), (0xff, 0x00, 0xff),
    (0x00, 0xff, 0xff), (0xff, 0xff, 0xff),
)

class TextColor:
    def __init__(self, mode=256):
        self.mode = mode
        self.os = random.randint(10, 25)
        self.spread = 5.0
        self.freq = 0.1

    def _distance(self, rgb1, rgb2):
        return sum(map(lambda c: (c[0] - c[1]) ** 2,
            zip(rgb1, rgb2)))

    def ansi(self, rgb):
        r, g, b = rgb

        if self.mode in (8, 16):
            colors = COLOR_ANSI[:self.mode]
            matches = [(self._distance(c, map(int, rgb)), i) for i, c in enumerate(colors)]
            matches.sort()
            color = matches[0][1]

            return '3%d' % (color,)
        else:
            gray_possible = True
            sep = 2.5
            gray = 0

            while gray_possible:
                if r < sep or g < sep or b < sep:
                    gray = r < sep and g < sep and b < sep
                    gray_possible = False

                sep += 42.5

            if gray:
                color = 232 + int(float(sum(rgb) / 33.0))
            else:
                color = sum([16]+[int(6 * float(val)/256) * mod
                    for val, mod in zip(rgb, [36, 6, 1])])

            return '38;5;%d' % (color,)

    def wrap(self, *codes):
        return '\x1b[%sm' % (''.join(codes),)

    def rainbow(self, freq, i):
        r = math.sin(freq * i) * 127 + 128
        g = math.sin(freq * i + 2 * math.pi / 3) * 127 + 128
        b = math.sin(freq * i + 4 * math.pi / 3) * 127 + 128
        return [r, g, b]

    def apply_color(self, s):
        output = ""
        for i, c in enumerate(s):
            rgb = self.rainbow(self.freq, self.os + i / self.spread)
            output += ''.join([
                self.wrap(self.ansi(rgb)),
                c
            ])
        return output

def generate(args):
    with open('profile') as f:
        img = f.read().splitlines()

    titles = TextColor()
    data = TextColor()
    # Set the data color seed to something far away from the title seed so they look different
    data.os = ((titles.os - 10 + 7) % 15) + 10

    with open(args.output, 'w') as output:
        output.write('\n')
        for (i, m) in zip(img, message):
            if ':' in m:
                parts = m.split(':')
                output.write(f' {i} {titles.apply_color(parts[0])}: {data.apply_color(":".join(parts[1:]))}\n')
            else:
                output.write(f' {i} {titles.apply_color(m)}\n')

        for i in img[len(message):]:
            output.write(f' {i}\n')

def main():
    parser = argparse.ArgumentParser(description="Generate cool neofetch like card")
    parser.add_argument('output', help='Path to output to')
    parser.add_argument('-d', type=float, help='Run in daemon mode, regenerating output every N minutes')
    args = parser.parse_args()
    if args.d:
        wait_time = int(args.d * 60)
        signal.signal(signal.SIGINT, lambda s, f: sys.exit(0))
        signal.signal(signal.SIGTERM, lambda s, f: sys.exit(0))
        print(f'Generating fetch output in daemon mode every {args.d} minutes')
        while True:
            generate(args)
            sleep(wait_time)
            print('Updating fetch output')
    else:
        print('Generating fetch output')
        generate(args)

if __name__ == '__main__':
    main()