GithubHelp home page GithubHelp logo

nanotodon's Introduction

nanotodon

CLI Mastodon Client

注意

現在かなり大規模に開発中です。安定利用はできない可能性があります

依存ライブラリ

  • cURL
  • pthread

ビルド

pkgsrc環境

CFLAGS="-I/usr/pkg/include" LDFLAGS="-L/usr/pkg/lib -Wl,-R/usr/pkg/lib" make

OpenBSD

CFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib" make

その他

make

オプション

  • -mono

    • 色付け無効化(太字のみ有効)(for 1bpp framebuffer)
  • -unlock

    • 公開範囲が PRIVATE/DIRECT の投稿を表示する
  • -noemoji

    • ReblogやFavourite、公開範囲表示などのUI要素に絵文字を利用しない
  • -profile <name>

    • プロファイル <name> を利用する
  • -timeline <public|local|home>

    • (WIP)流すタイムラインの選択

投稿方法

  1. TLが流れているときにEnterを押す
  2. > とプロンプトが出るのでToot内容を入力(\n\\が利用できます)
  3. Enterを押すと投稿
  • Toot入力中はTLの更新がブロックされます
  • 以前のVerにあった/private等も利用できます

詳しいガイド

TBW

動いてるっぽい環境(24/06/11)

  • WSL2 + VSCode Terminal(w/ Sixel)
  • WSL2 + Windows Terminal
  • OpenBSD/amd64
  • NetBSD/i386 10.0
  • NetBSD/evbppc 10.0 (on Nintendo Wii)

テスト済み環境(0.1.x-0.3.x)

  • NetBSD/luna68k + mlterm
  • NetBSD/x68k + mlterm
  • NetBSD/sun3 + mlterm
  • ArchLinux + xfce terminal
  • WSL1 + mintty(wsl-terminal)
  • WSL2 + mintty(wsltty)
  • WSL1 + Windows Terminal

Thanks

nanotodon's People

Contributors

gomasy avatar kr4dio avatar shibafu528 avatar taka-tuos avatar tsutsui avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

nanotodon's Issues

丁寧なMakefileにする

  • OpenBSDへの対応を行う もしくは パッチ無しで容易にビルドできるようにする
  • cmakeは絶対に利用してはならない(gcc3)
  • できるだけ依存ツールを少なくする

Auto refresh does not work

Hi
I use archlinux and when I run this client. It does not refresh my feed automatically. Is it a bug?

json_object_get_string() の警告

#2 で記載した initialization discards 'const' qualifier from pointer target type の警告の修正です。
<json-c/json_object.h> によれば
json_object_get_string() は const を返すようなのでコピーするようにしてみましたが、他のやり方もあるような気がします……。

diff --git a/nanotodon.c b/nanotodon.c
index a3a2227..9e88bc8 100755
--- a/nanotodon.c
+++ b/nanotodon.c
@@ -124,12 +124,13 @@ void stream_event_notify(struct json_object *jobj_from_string)
 	//fputs("\n\n", fp);
 	//fclose(fp);
 	
-	char *t = json_object_get_string(notify_type);
+	char *t = strdup(json_object_get_string(notify_type));
 	t[0] = toupper(t[0]);
 	
 	wattron(scr, COLOR_PAIR(4));
 	waddstr(scr, strcmp(t, "Follow") == 0 ? "👥" : strcmp(t, "Favourite") == 0 ? "💕" : strcmp(t, "Reblog") == 0 ? "🔃" : strcmp(t, "Mention") == 0 ? "🗨" : "");
 	waddstr(scr, t);
+	free(t);
 	waddstr(scr, " from ");
 	waddstr(scr, json_object_get_string(screen_name));
 	waddstr(scr, " (");

導入ガイドの作成

最低限必要なもの

  • NetBSD, OpenBSD, Debian, Arch Linuxにおけるclone ~ tootまでのガイド
    • NetBSD:i386, amd64, evbarm(armv6 RPi)で通用するガイド
    • OpenBSD:(TBD)
    • Debian:amd64, Raspbianで通用するガイド
    • Arch Linux:amd64で通用するガイド

あると嬉しい

  • 複数プロファイルの利用方法
  • token類の移行方法

トゥートで改行が2つ連続した場合に改行が表示されない

表題の通りで、トゥート内で改行が2つ連続している場合、
nanotodon 上ではそれらが表示されません。
https://social.mikutter.hachune.net/@tsutsuii/103393307270448434

内部的には、改行が2つ続いた場合 <br> が連続するのではなく
markdown 的に段落区切りとして

<p>nanotodon</p><p>改行が2つ続くと消えちゃう感</p>

という感じになっているようなので、そこをハンドリングしないといけないっぽいです

本文の ' (ASCIIコード 39 の文字) が #39; と表示される

mastodon 投稿のトゥート本文に ' (ASCIIコード 39) が含まれると nanotodon 上では #39; と表示されます。
0.2.0, 0.3.0 のいずれでも発生します。

mastodon の仕様がわかりませんが、 &apos ; とエンコードされるわけではないようです。
また、単純に #39; を置換するようにすると、本文に #39; の文字列が含まれる場合も置換されてしまうので、
本文の元データがどうなっているのかから見る必要がありそうです。

いろいろが壊れている(ビルド不能)

on ArchLinux

wget_wchや、str系関数、timegm/strptime等が定義されていないと怒られる
define不足が原因?

nanotodon.c:289:9: エラー: implicit declaration of function ‘strptime’; did you mean ‘strftime’? [-Wimplicit-function-declaration]
  289 |         strptime(created_at->string_, "%Y-%m-%dT%H:%M:%S", &tm);
      |         ^~~~~~~~
      |         strftime
nanotodon.c:1191:17: エラー: implicit declaration of function ‘wget_wch’; did you mean ‘wgetch’? [-Wimplicit-function-declaration]
 1191 |                 wget_wch(pad, &c);
      |                 ^~~~~~~~
      |
sjson.h: 関数 ‘sjson_find_member_nocase’ 内:
sjson.h:394:50: エラー: 関数 ‘strcasecmp’ の暗黙的な宣言です [-Wimplicit-function-declaration]
  394 | #               define sjson_stricmp(_a, _b)     strcasecmp(_a, _b)
      |                                                  ^~~~~~~~~~
sjson.h:1198:13: 備考: in expansion of macro ‘sjson_stricmp’
 1198 |         if (sjson_stricmp(member->key, name) == 0)
      |             ^~~~~~~~~~~~~
nanotodon.c: 関数 ‘read_json_fom_path’ 内:
nanotodon.c:147:21: エラー: 関数 ‘strdup’ の暗黙的な宣言です [-Wimplicit-function-declaration]
  147 |         char *dup = strdup(path);       // strtokは破壊するので複製
      |                     ^~~~~~
nanotodon.c:147:21: 警告: 組み込み関数 ‘strdup’ の互換性がない暗黙的な宣言です [-Wbuiltin-declaration-mismatch]
nanotodon.c: 関数 ‘stream_event_notify’ 内:
nanotodon.c:234:19: 警告: 組み込み関数 ‘strdup’ の互換性がない暗黙的な宣言です [-Wbuiltin-declaration-mismatch]
  234 |         char *t = strdup(notify_type->string_);
      |                   ^~~~~~
nanotodon.c: 関数 ‘stream_event_update’ 内:
nanotodon.c:290:16: エラー: implicit declaration of function ‘timegm’; did you mean ‘time’? [-Wimplicit-function-declaration]
  290 |         time = timegm(&tm);
      |                ^~~~~~
      |
  • 修正後の*BSDでの動作確認

設定ファイルをホームディレクトリ等の固定場所に置くようにしたい

現状の nanotodon の仕様では .nanotter .nanotter2 の設定ファイルが
nanotodon の実行ファイルと同じディレクトリにあることを想定していると思います。

しかし、汎用的に全ユーザーで使用する場合(およびパッケージシステム等に入れる場合)は
バイナリが /usr/pkg/bin 等の一般ユーザー書き込み不可の場所に置かれるため
複数ユーザーが設定ファイルを書き込むということができません。

同様の CUIクライアントだと以下のような感じです
tw: ~/.tw.yml に保管
sayaka: ~/.sayaka/ 以下に各ファイルで保管

従来との互換性を考えると、起動時は

  • 実行ファイルと同じ場所(もしくはカレントディレクトリ)を見る
  • ~/.nanotodon/ 以下、もしくは ~/.nanotter ~/.nanotter2 を見る

認証時は今後は ~/.nanotodon/ 以下、もしくは ~/.nanotter ~/.nanotter2 を使う、
とすればよい?

トゥート表示の改善

プルリクにしようかとも思ったのですが、コードが雑すぎるのでいったん issue で投げてみます。

  • トゥート日付表示(右寄せ)追加
  • スクリーンネームと名前の表示の間にスペース追加
  • via クライアントの表示の修正
    • UTF-8単位での表示幅カウント
    • wrap抑制のため右端のマージン1文字追加

日付用に色を足してるので #3 のプルリクとコンフリクトします。

diff --git a/nanotodon.c b/nanotodon.c
index b1db163..a3a2227 100755
--- a/nanotodon.c
+++ b/nanotodon.c
@@ -28,6 +28,19 @@ char domain_string[256];
 int term_w, term_h;
 int pad_x = 0, pad_y = 0;
 
+int ustrwidth(const char *str)
+{
+	int size, width;
+
+	width = 0;
+	while (*str != '\0') {
+		size = (((uint8_t)*str & 0xf0) == 0xe0) ? 3 : 1;
+		width += (size == 1) ? 1 : 2;
+		str += size;
+	}
+	return width;
+}
+
 char *create_uri_string(char *api)
 {
 	char *s = malloc(256);
@@ -119,7 +132,7 @@ void stream_event_notify(struct json_object *jobj_from_string)
 	waddstr(scr, t);
 	waddstr(scr, " from ");
 	waddstr(scr, json_object_get_string(screen_name));
-	waddstr(scr, "(");
+	waddstr(scr, " (");
 	waddstr(scr, json_object_get_string(display_name));
 	waddstr(scr, ")\n");
 	wattroff(scr, COLOR_PAIR(4));
@@ -139,15 +152,28 @@ void stream_event_notify(struct json_object *jobj_from_string)
 	wrefresh(pad);
 }
 
+#define DATEBUFLEN	40
+
 void stream_event_update(struct json_object *jobj_from_string)
 {
 	struct json_object *content, *screen_name, *display_name, *reblog;
 	//struct json_object *jobj_from_string = json_tokener_parse(json);
+	struct json_object *created_at;
+	struct tm tm;
+	time_t time;
+	char datebuf[DATEBUFLEN];
+	int x, y, date_w;
+
 	if(!jobj_from_string) return;
 	read_json_fom_path(jobj_from_string, "content", &content);
 	read_json_fom_path(jobj_from_string, "account/acct", &screen_name);
 	read_json_fom_path(jobj_from_string, "account/display_name", &display_name);
 	read_json_fom_path(jobj_from_string, "reblog", &reblog);
+	read_json_fom_path(jobj_from_string, "created_at", &created_at);
+	memset(&tm, 0, sizeof(tm));
+	strptime(json_object_get_string(created_at), "%Y-%m-%dT%H:%M:%S", &tm);
+	time = timegm(&tm);
+	strftime(datebuf, sizeof(datebuf), "%x(%a) %X", localtime(&time));
 	
 	//FILE *fp = fopen("json.log", "a+");
 	
@@ -163,7 +189,7 @@ void stream_event_update(struct json_object *jobj_from_string)
 		wattron(scr, COLOR_PAIR(3));
 		waddstr(scr, "🔃 Reblog by ");
 		waddstr(scr, json_object_get_string(screen_name));
-		waddstr(scr, "(");
+		waddstr(scr, " (");
 		waddstr(scr, json_object_get_string(display_name));
 		waddstr(scr, ")\n");
 		wattroff(scr, COLOR_PAIR(3));
@@ -175,10 +201,21 @@ void stream_event_update(struct json_object *jobj_from_string)
 	waddstr(scr, json_object_get_string(screen_name));
 	wattroff(scr, COLOR_PAIR(1));
 	wattron(scr, COLOR_PAIR(2));
-	waddstr(scr, "(");
+	waddstr(scr, " (");
 	waddstr(scr, json_object_get_string(display_name));
 	waddstr(scr, ")");
 	wattroff(scr, COLOR_PAIR(2));
+	date_w = ustrwidth(datebuf) + 1;
+	getyx(scr, y, x);
+	if (x < term_w - date_w) {
+		for(int i = 0; i < term_w - x - date_w; i++) waddstr(scr, " ");
+	} else {
+		for(int i = 0; i < x - (term_w - date_w); i++) waddstr(scr, "\b");
+		waddstr(scr, "\b ");
+	}
+	wattron(scr, COLOR_PAIR(5));
+	waddstr(scr, datebuf);
+	wattroff(scr, COLOR_PAIR(5));
 	waddstr(scr, "\n");
 	
 	const char *src = json_object_get_string(content);
@@ -245,16 +282,16 @@ void stream_event_update(struct json_object *jobj_from_string)
 		type = json_object_get_type(application_name);
 		
 		if(type != json_type_null) {
-			int l = strlen(json_object_get_string(application_name));
+			int l = ustrwidth(json_object_get_string(application_name));
 		
-			for(int i = 0; i < term_w - (l + 4); i++) waddstr(scr, " ");
+			for(int i = 0; i < term_w - (l + 4 + 1); i++) waddstr(scr, " ");
 			
 			wattron(scr, COLOR_PAIR(1));
 			waddstr(scr, "via ");
 			wattroff(scr, COLOR_PAIR(1));
 			wattron(scr, COLOR_PAIR(2));
 			waddstr(scr, json_object_get_string(application_name));
-			//waddstr(scr, "\n");
+			waddstr(scr, "\n");
 			wattroff(scr, COLOR_PAIR(2));
 		}
 	}
@@ -722,11 +759,14 @@ retry1:
 	WINDOW *term = initscr();
 	
 	start_color();
+
+	use_default_colors();
 	
-	init_pair(1, COLOR_GREEN, COLOR_BLACK);
-	init_pair(2, COLOR_CYAN, COLOR_BLACK);
-	init_pair(3, COLOR_YELLOW, COLOR_BLACK);
-	init_pair(4, COLOR_RED, COLOR_BLACK);
+	init_pair(1, COLOR_GREEN, -1);
+	init_pair(2, COLOR_CYAN, -1);
+	init_pair(3, COLOR_YELLOW, -1);
+	init_pair(4, COLOR_RED, -1);
+	init_pair(5, COLOR_BLUE, -1);
 	
 	getmaxyx(term, term_h, term_w);
 	

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.