1

Тема: wtr — простий скрипт перевіряти погоду в терміналі

Не супер-проект, а простий bash shell сценарій, котрий базується на curl і wttr.in.

По-перше, мав на меті навчитися пакувати .deb — і навчився, тож маєте змогу швидко встановити й видалити скрипт для всіх користувачів, не морочачися з локальною директорією сценаріїв.

По-друге, весь час забував і плутав формати wttr.in, тому написав людські команди під це діло. Користуюся сам.

Раптом комусь ліньки вводити аж curl wttr.in/?format=1 — встановіть і вводіть wtr:

wget https://github.com/bebyx/wtr/blob/master/wtr_1.0_all.deb
dpkg -i wtr*.deb

Репозиторій: github.com/bebyx/wtr

2

Re: wtr — простий скрипт перевіряти погоду в терміналі

нікому не цікавий термінал. час червонооких вичерпаний. в лінух йдуть домогосподарки...

3

Re: wtr — простий скрипт перевіряти погоду в терміналі

ur_naz написав:

в лінух йдуть домогосподарки

Ви так кажете, ніби це шось погане і треба бути не домогосподарем, а наймитом-безхатьком.

4

Re: wtr — простий скрипт перевіряти погоду в терміналі

не перекручуйте

5

Re: wtr — простий скрипт перевіряти погоду в терміналі

я собі колись просто alias робив до curl команди

6 Востаннє редагувалося P.Y. (15.09.2020 17:38:21)

Re: wtr — простий скрипт перевіряти погоду в терміналі

Як латентний лінуксоїд, переглядаю wttr.in з віндового консольного вікна. Що можна робити й просто з допомогою wget чи curl (віндові порти яких знайти не проблема), але для додаткових зручностей довелось дописати деякі скрипти.
По-перше, хотілось би бачити юнікодівські символи (особливо якщо я переглядаю погоду українською мовою) — для цього підійде простий скрипт на nodeJS, що працює подібно до cat — завдяки тому, що node при виводі в консоль використовує звернення до WinAPI, а також уміє обробляти ANSI-послідовності, ми можемо бачити все розмаїття символів, підтримуваних поточних шрифтом.
По-друге, кольори. Як було сказано вище, ANSI-послідовності (з допомогою яких при виводі в термінал кодуються кольори) підтримуються, але проблема в тому, що віндова консоль розрахована на 4-бітні кольори, тоді як у wttr.in використовуються 8-бітні, ANSI-послідовності для яких у node не підтримуються. Довелось написати конвертер, що замінює 8-бітні кольори найближчими 4-бітними — набір кольорів збіднюється, але я їх бачу. (У найпростішому випадку, кольори можна просто відключити через параметри wttr, але так не цікаво).
Потім, заміна символів, відсутніх у консольних шрифтах, доступними аналогами (напр., косі стрілки, що показують напрям вітру, замінюються парами з двох прямих) та деякі інші косметичні дрібнички.
Також інколи треба вказати місце, для якого я хочу подивитись погоду — якщо для цього використовуються кириличні назви, то їх треба попередньо перекодувати в URL-кодування.

Багато нецікавого коду

wttr.bat

::xxxx ; /.*/!a\
@setlocal&set a=%*&                                @rem\
@if defined a @(                                    rem\
    @for /f "delims=" %%i in ('u2url %a%') do @(rem\
        @set a=%%i))&                      @rem\
@wget -O - -q "http://uk.wttr.in/%a%?M"|sed -f "%~f0"|lesscolor|unicon2 & goto :eof
# :mode=perl:
# :: замінити косі стрілки (несумісні з lucida console, consolas):
s/\(↖\|↗\|↘\|↙\)\([^│]* \) /\1 \2/g
s/↖ /↑←/g; s/↗ /↑→/g; s/↘ /↓→/g; s/↙ /↓←/g
s/↖/╔/g; s/↗/╗/g; s/↘/╝/g; s/↙/╚/g
# заміни міжнародних позначень на українські:
s/km/км/g
s!m/s!м/с!g; s/mm/мм/g
# Корекція графіки (замінити рідкісні символи доступними в консольних шрифтах):
s/⚡/ ↯/g
# або s/⚡/☇/g — в обох випадках, заміна доступна лише у FreeMono :(
# блимання не підтримується, а те, що замість нього, псує кольори — позбудьмось його:
s/;5m/m/g

unicon2.bat

@if exist "%~f0.js" goto run
@(echo /*
@type "%~f0")>"%~f0.js"
:run
@node "%~f0.js" %*
@goto :eof
  :mode=javascript:
*/
// Ввід з консолі/вивід у консоль довільних символів utf8 в/з перенаправлення.
// ПРОГРАМА|unicon2 — вивід у консоль
// unicon2|ПРОГРАМА — ввід з консолі (не підтримується)

processLine=function(s)
    {
    process.stdout.write(s+'\n');
    }

process.stdin.resume();
process.stdin.setEncoding('utf8');

var lingeringLine = "";

process.stdin.on('data', function(chunk) 
    {
    lines = chunk.split("\n");
    
    lines[0] = lingeringLine + lines[0];
    lingeringLine = lines.pop();
    
    lines.forEach(processLine);
    });

process.stdin.on('end', function() 
    {
    if(lingeringLine!=='')
        processLine(lingeringLine);
    });

lesscolor.bat

@rem=qw{ 
@perl "%~f0" %* 
@goto :eof 
}; #:mode=perl:#

# https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
# Перетворити розширені 8-бітні кольори:
    # ESC[ 38;5;⟨n⟩ m Select foreground color
    # ESC[ 48;5;⟨n⟩ m Select background color
      # 0-  7:    standard colors (as in ESC [ 30–37 m)
      # 8- 15:    high intensity colors (as in ESC [ 90–97 m)
      # 16-231:   6 × 6 × 6 cube (216 colors): 16 + 36×r + 6×g + b (0 ≤ r, g, b ≤ 5)
      # 232-255:  grayscale from black to white in 24 steps
# на прості:
    # 30    foreground black    # 1    bold (foreground is intense)
    # 31    foreground red      # 4    underline (background is intense)
    # 32    foreground green    # 5    blink (background is intense)
    # 33    foreground yellow    # 22    bold off (foreground is not intense)
    # 34    foreground blue     # 24    underline off (background is not intense)
    # 35    foreground magenta    # 25    blink off (background is not intense)
    # 36    foreground cyan
    # 37    foreground white    # 40-47 background black...white
    
# яскраві кольори (90-97,100-107) підтримує node(pet-apl, unicon2), але ansicon та gnuwin32 не підтримують — краще використати атрибути жирного/підкресленого. Можливо, перетворити яскравий колір на колір+атрибут
# З іншого боку, colorama не підтримує атрибут яскравості тла, хоча підтримує яскраві кольори тла та літер. Додати опцію вибору передачі яскравості...

# TODO: 24-бітні RGB-кольори.....
    # ESC[ 38;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB foreground color
    # ESC[ 48;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB background color
# шукати, перетвориши в 8-бітні, чи окремо? Або ж перетворювати 8-бітні в 24-бітні?.....
    
# \033[(38|48);5;Nm => \033[(1|4|5|22|24|25);(30-37|40-47)m
# 0-7, 8-15: просто конвертувати
# 16-231: підібрати найближчий колір (з основних, включаючи яскраві):
    # осн. кольори в 256х256х256:
    # 30: 0,0,0;       31: 128,0,0; 32: 0,128,0; 33: 128,128,0; 34: 0,0,128; 35: 128,0,128; 36: 0,128,128; 37: 192,192,192
    # 90: 128,128,128; 91: 255,0,0; 92: 0,255,0; 93: 255,255,0; 94: 0,0,255; 95: 255,0,255; 96: 0,255,255; 97: 255,255,255
    # (конвертувати в 6х6х6):
    # 0:0, 128:3, 192:4, 255:5
%colors=(30=>0, 31=>3*36, 32=>3*6, 33=>3*(36+6), 34=>3, 35=>3*(36+1), 36=>3*(6+1), 37=>4*(36+6+1),
 90=>3*(36+6+1), 91=>5*36, 92=>5*6, 93=>5*(36+6), 94=>5, 95=>5*(36+1), 96=>5*(6+1), 97=>5*(36+6+1));
$colors{$_}+=16 for(keys(%colors));
$extcolors{$colors{$_}}=$_ for(keys(%colors));
#$extcolors{0..15}:
for(0..7)
    {
    $extcolors{$_}  =30+$_;
    $extcolors{$_+8}=90+$_;
    }
    
sub cmpcolor # відстань між парою кольорів (як між 3-вимірними коорд.):
    {
    my($res, @t, @a);
    @a=@_;
    for(0,1){
        $a[$_]-=16;
        }
    $res=0;
    for(1..3)
        {
        @t=@a;
        for(0,1){
            $t[$_]%=6;
            $a[$_]-=$t[$_];
            $a[$_]/=6;
            }
        $res+=($t[0]-$t[1])**2;
        }
    return $res;#квадрат відстані
    }
    
sub findcolor # пошук (і кешування) найближчих
    {
    my $extcolor=$_[0];
    my $res=$extcolors{$extcolor};
    return $res if($res ne ''); # 0...15 та кольори, знайдені раніше    
    if($extcolor>231)
        { # 232-355: підібрати найближчий з яскраво-білого, темно-білого, яскраво-чорного, темно-чорного
        $res=(30,90,37,97)[int(($extcolor-232)/6)];
        }
    else    {# Якщо колір у діапазоні 16..231
        my $d=1000000;
        my $d0;
        for(keys %colors)
            {
            $d0=cmpcolor($colors{$_},$extcolor);
            if($d0<$d)
                {
                $d=$d0;
                $res=$_;
                }
            }
        }
    $extcolors{$extcolor}=$res;
    return $res;
    }

%attr=(3=>22, 4=>25, 9=>1, 10=>5);
sub lesscolor
    {
    my($g,$c)=@_;
    $c=findcolor($c);
    $c+=($g==48 && 10);
    # можливо, перетворити на атрибут яскравості+неяскравий колір:
    $c=$attr{int($c/10)}.';'.$c % 60;
    return $c;
    }

for(<>)    {
    s<\033\[([34]8);5;([0-9]+)([;m])>("\033[".lesscolor($1,$2).$3)ge;
    print;
    }

u2url.bat

@type # >nul 2>&1 & goto start
def ____():
    '''
    :start
    @py -3 "%~f0" %*
    @goto :eof
    '''
    pass
#:mode=python:#
def str2urlcode(s):
    return ''.join((('%c' if (b'%c'%c).isalnum()else '%%%02X')%c for c in s.encode())).replace('%20', '+')

if __name__=='__main__':
    import sys
    # перетворити вхідні параметри (якщо є) або вхідний потік (якщо параметрів нема) з юнікоду на url-кодування й вивести на друк:
    s=' '.join(sys.argv[1:])
    if s:
        print(str2urlcode(s))
    else:
        for s in sys.stdin:
            print(str2urlcode(s.replace('\n','')))

Для роботи всього цього потрібні встановлені wget, sed, perl, python (3.x), node.

Подякували: leofun011

7 Востаннє редагувалося bebyk (15.09.2020 17:38:03)

Re: wtr — простий скрипт перевіряти погоду в терміналі

Прихований текст
P.Y. написав:

Як латентний лінуксоїд, переглядаю wttr.in з віндового консольного вікна. Що можна робити й просто з допомогою wget чи curl (віндові порти яких знайти не проблема), але для додаткових зручностей довелось дописати деякі скрипти.
По-перше, хотілось би бачити юнікодівські символи (особливо якщо я переглядаю погоду українською мовою) — для цього підійде простий скрипт на nodeJS, що працює подібно до cat — завдяки тому, що node при виводі в консоль використовує звернення до WinAPI, а також уміє обробляти ANSI-послідовності, ми можемо бачити все розмаїття символів, підтримуваних поточних шрифтом.
По-друге, кольори. Як було сказано вище, ANSI-послідовності (з допомогою яких при виводі в термінал кодуються кольори) підтримуються, але проблема в тому, що віндова консоль розрахована на 4-бітні кольори, тоді як у wttr.in використовуються 8-бітні, ANSI-послідовності для яких у node не підтримуються. Довелось написати конвертер, що замінює 8-бітні кольори найближчими 4-бітними — набір кольорів збіднюється, але я їх бачу. (У найпростішому випадку, кольори можна просто відключити через параметри wttr, але так не цікаво).
Потім, заміна символів, відсутніх у консольних шрифтах, доступними аналогами (напр., косі стрілки, що показують напрям вітру, замінюються парами з двох прямих) та деякі інші косметичні дрібнички.
Також інколи треба вказати місце, для якого я хочу подивитись погоду — якщо для цього використовуються кириличні назви, то їх треба попередньо перекодувати в URL-кодування.

Багато нецікавого коду

wttr.bat

::xxxx ; /.*/!a\
@setlocal&set a=%*&                                @rem\
@if defined a @(                                    rem\
    @for /f "delims=" %%i in ('u2url %a%') do @(rem\
        @set a=%%i))&                      @rem\
@wget -O - -q "http://uk.wttr.in/%a%?M"|sed -f "%~f0"|lesscolor|unicon2 & goto :eof
# :mode=perl:
# :: замінити косі стрілки (несумісні з lucida console, consolas):
s/\(↖\|↗\|↘\|↙\)\([^│]* \) /\1 \2/g
s/↖ /↑←/g; s/↗ /↑→/g; s/↘ /↓→/g; s/↙ /↓←/g
s/↖/╔/g; s/↗/╗/g; s/↘/╝/g; s/↙/╚/g
# заміни міжнародних позначень на українські:
s/km/км/g
s!m/s!м/с!g; s/mm/мм/g
# Корекція графіки (замінити рідкісні символи доступними в консольних шрифтах):
s/⚡/ ↯/g
# або s/⚡/☇/g — в обох випадках, заміна доступна лише у FreeMono :(
# блимання не підтримується, а те, що замість нього, псує кольори — позбудьмось його:
s/;5m/m/g

unicon2.bat

@if exist "%~f0.js" goto run
@(echo /*
@type "%~f0")>"%~f0.js"
:run
@node "%~f0.js" %*
@goto :eof
  :mode=javascript:
*/
// Ввід з консолі/вивід у консоль довільних символів utf8 в/з перенаправлення.
// ПРОГРАМА|unicon2 — вивід у консоль
// unicon2|ПРОГРАМА — ввід з консолі (yt gslnhbve'nmcz)

processLine=function(s)
    {
    process.stdout.write(s+'\n');
    }

process.stdin.resume();
process.stdin.setEncoding('utf8');

var lingeringLine = "";

process.stdin.on('data', function(chunk) 
    {
    lines = chunk.split("\n");
    
    lines[0] = lingeringLine + lines[0];
    lingeringLine = lines.pop();
    
    lines.forEach(processLine);
    });

process.stdin.on('end', function() 
    {
    if(lingeringLine!=='')
        processLine(lingeringLine);
    });

lesscolor.bat

@rem=qw{ 
@perl "%~f0" %* 
@goto :eof 
}; #:mode=perl:#

# https://en.wikipedia.org/wiki/ANSI_escape_code#Colors
# Перетворити розширені 8-бітні кольори:
    # ESC[ 38;5;⟨n⟩ m Select foreground color
    # ESC[ 48;5;⟨n⟩ m Select background color
      # 0-  7:    standard colors (as in ESC [ 30–37 m)
      # 8- 15:    high intensity colors (as in ESC [ 90–97 m)
      # 16-231:   6 × 6 × 6 cube (216 colors): 16 + 36×r + 6×g + b (0 ≤ r, g, b ≤ 5)
      # 232-255:  grayscale from black to white in 24 steps
# на прості:
    # 30    foreground black    # 1    bold (foreground is intense)
    # 31    foreground red      # 4    underline (background is intense)
    # 32    foreground green    # 5    blink (background is intense)
    # 33    foreground yellow    # 22    bold off (foreground is not intense)
    # 34    foreground blue     # 24    underline off (background is not intense)
    # 35    foreground magenta    # 25    blink off (background is not intense)
    # 36    foreground cyan
    # 37    foreground white    # 40-47 background black...white
    
# яскраві кольори (90-97,100-107) підтримує node(pet-apl, unicon2), але ansicon та gnuwin32 не підтримують — краще використати атрибути жирного/підкресленого. Можливо, перетворити яскравий колір на колір+атрибут
# З іншого боку, colorama не підтримує атрибут яскравості тла, хоча підтримує яскраві кольори тла та літер. Додати опцію вибору передачі яскравості...

# TODO: 24-бітні RGB-кольори.....
    # ESC[ 38;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB foreground color
    # ESC[ 48;2;⟨r⟩;⟨g⟩;⟨b⟩ m Select RGB background color
# шукати, перетвориши в 8-бітні, чи окремо? Або ж перетворювати 8-бітні в 24-бітні?.....
    
# \033[(38|48);5;Nm => \033[(1|4|5|22|24|25);(30-37|40-47)m
# 0-7, 8-15: просто конвертувати
# 16-231: підібрати найближчий колір (з основних, включаючи яскраві):
    # осн. кольори в 256х256х256:
    # 30: 0,0,0;       31: 128,0,0; 32: 0,128,0; 33: 128,128,0; 34: 0,0,128; 35: 128,0,128; 36: 0,128,128; 37: 192,192,192
    # 90: 128,128,128; 91: 255,0,0; 92: 0,255,0; 93: 255,255,0; 94: 0,0,255; 95: 255,0,255; 96: 0,255,255; 97: 255,255,255
    # (конвертувати в 6х6х6):
    # 0:0, 128:3, 192:4, 255:5
%colors=(30=>0, 31=>3*36, 32=>3*6, 33=>3*(36+6), 34=>3, 35=>3*(36+1), 36=>3*(6+1), 37=>4*(36+6+1),
 90=>3*(36+6+1), 91=>5*36, 92=>5*6, 93=>5*(36+6), 94=>5, 95=>5*(36+1), 96=>5*(6+1), 97=>5*(36+6+1));
$colors{$_}+=16 for(keys(%colors));
$extcolors{$colors{$_}}=$_ for(keys(%colors));
#$extcolors{0..15}:
for(0..7)
    {
    $extcolors{$_}  =30+$_;
    $extcolors{$_+8}=90+$_;
    }
    
sub cmpcolor # відстань між парою кольорів (як між 3-вимірними коорд.):
    {
    my($res, @t, @a);
    @a=@_;
    for(0,1){
        $a[$_]-=16;
        }
    $res=0;
    for(1..3)
        {
        @t=@a;
        for(0,1){
            $t[$_]%=6;
            $a[$_]-=$t[$_];
            $a[$_]/=6;
            }
        $res+=($t[0]-$t[1])**2;
        }
    return $res;#квадрат відстані
    }
    
sub findcolor # пошук (і кешування) найближчих
    {
    my $extcolor=$_[0];
    my $res=$extcolors{$extcolor};
    return $res if($res ne ''); # 0...15 та кольори, знайдені раніше    
    if($extcolor>231)
        { # 232-355: підібрати найближчий з яскраво-білого, темно-білого, яскраво-чорного, темно-чорного
        $res=(30,90,37,97)[int(($extcolor-232)/6)];
        }
    else    {# Якщо колір у діапазоні 16..231
        my $d=1000000;
        my $d0;
        for(keys %colors)
            {
            $d0=cmpcolor($colors{$_},$extcolor);
            if($d0<$d)
                {
                $d=$d0;
                $res=$_;
                }
            }
        }
    $extcolors{$extcolor}=$res;
    return $res;
    }

%attr=(3=>22, 4=>25, 9=>1, 10=>5);
sub lesscolor
    {
    my($g,$c)=@_;
    $c=findcolor($c);
    $c+=($g==48 && 10);
    # можливо, перетворити на атрибут яскравості+неяскравий колір:
    $c=$attr{int($c/10)}.';'.$c % 60;
    return $c;
    }

for(<>)    {
    s<\033\[([34]8);5;([0-9]+)([;m])>("\033[".lesscolor($1,$2).$3)ge;
    print;
    }

u2url.bat

@type # >nul 2>&1 & goto start
def ____():
    '''
    :start
    @py -3 "%~f0" %*
    @goto :eof
    '''
    pass
#:mode=python:#
def str2urlcode(s):
    return ''.join((('%c' if (b'%c'%c).isalnum()else '%%%02X')%c for c in s.encode())).replace('%20', '+')

if __name__=='__main__':
    import sys
    # перетворити вхідні параметри (якщо є) або вхідний потік (якщо параметрів нема) з юнікоду на url-кодування й вивести на друк:
    s=' '.join(sys.argv[1:])
    if s:
        print(str2urlcode(s))
    else:
        for s in sys.stdin:
            print(str2urlcode(s.replace('\n','')))

Для роботи всього цього потрібні встановлені wget, sed, perl, python (3.x), node.

Вінда — боль.

8

Re: wtr — простий скрипт перевіряти погоду в терміналі

Вінда — це така штука, де я вже маю налагоджений спосіб робити все, що мені треба. Власне, якби не це, то вже б став лінуксоїдом. А так треба портувати купу батників, що назбирались за довгі роки, дописати скриптець, що конвертує мої саморобні клавіатурні розкладки у щось-там лінуксове (з чим іще треба розібратись), і т.д., і т.п.