Skip to content

Commit 0bb2e8e

Browse files
new: add ezytel gRPC service for Telegram public-channel viewer
Port the ezytel.zip PHP app into a v2 gRPC service. Routes t.me traffic through the translate.goog domain front so it reaches users behind GFW-style filters, mirrors the original HTML rewriting (image proxy, Persian/Jalali date conversion, channels.txt parser) and exposes four RPCs: GetChannelInfo, GetChannelMessages, ProxyImage, ParseChannels. Service is wired into both StartGrpcServer("ezytel") and the mTLS StartGrpcServerByMode path, alongside hello. Includes unit tests for the str_find walker, channels parser, Jalali date conversion, image-URL rewriting, and ProxyImage input validation.
1 parent 5223abc commit 0bb2e8e

8 files changed

Lines changed: 1765 additions & 0 deletions

File tree

v2/ezytel/ezytel.pb.go

Lines changed: 606 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

v2/ezytel/ezytel.proto

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
syntax = "proto3";
2+
3+
package ezytel;
4+
option go_package = "github.com/hiddify/hiddify-core/v2/ezytel";
5+
option java_package = "com.hiddify.core.api.v2.ezytel";
6+
7+
// Request the metadata card of a Telegram public channel
8+
// (name, description preview, avatar, last-post timestamp, unread badge).
9+
message ChannelInfoRequest {
10+
// Channel id, e.g. "durov" — without "@" or "t.me/".
11+
string channel_id = 1;
12+
// Last post id the client has already read; used to compute the
13+
// unread badge (newmsg). 0 means "everything is unread".
14+
int64 last_read = 2;
15+
}
16+
17+
message ChannelInfo {
18+
string name = 1;
19+
// Plain-text preview of the most recent post, or "فایل" if it is a media post.
20+
string description = 2;
21+
// Local cache path of the avatar JPEG, relative to the cache dir
22+
// returned by GetCacheDir(). Empty if the avatar could not be fetched.
23+
string avatar_path = 3;
24+
// Unix epoch seconds of the most recent post.
25+
int64 date = 4;
26+
// Persian-calendar formatted "MM-DD HH:mm" string for the most recent post.
27+
string date_str = 5;
28+
// Unread badge, e.g. "+12" or "+99" (capped). Empty when caught up.
29+
string newmsg = 6;
30+
// Last post id observed on the channel page (server-side cookie replacement).
31+
int64 last_post_id = 7;
32+
// True when the channel page was reachable and parsed; false if served
33+
// from stale cache (newmsg is then forced to "OFF").
34+
bool ok = 8;
35+
}
36+
37+
// Request a slab of HTML for the channel timeline.
38+
message ChannelMessagesRequest {
39+
string channel_id = 1;
40+
// 0 = latest page; otherwise the "before" cursor returned by Telegram
41+
// (the data-before attribute of messages_more_wrap).
42+
int64 before = 2;
43+
}
44+
45+
message ChannelMessagesResponse {
46+
// Pre-rendered HTML fragment ready to be injected into .main_block.
47+
// Image URLs have been rewritten to call ProxyImage; dates have been
48+
// converted to the Persian calendar.
49+
string html = 1;
50+
// Channel avatar URL embedded in the header (only set when before == 0).
51+
string channel_avatar = 2;
52+
// Last post id seen on the page (mirrors the lastread_<chid> cookie).
53+
int64 last_post_id = 3;
54+
}
55+
56+
// Fetch a Telegram-hosted image through the translate.goog domain front
57+
// and cache it locally. Mirrors proxy.php?url=<hex>.
58+
message ProxyImageRequest {
59+
// Hex-encoded source URL without the "https://" prefix, exactly as the
60+
// PHP version expected (bin2hex of the host+path).
61+
string hex_url = 1;
62+
}
63+
64+
message ProxyImageResponse {
65+
bytes data = 1;
66+
string content_type = 2;
67+
// Local cache filename (md5(url) + ".jpg") for clients that prefer to
68+
// reload from disk instead of holding the bytes.
69+
string cache_name = 3;
70+
}
71+
72+
// Parse the operator-supplied newline-separated channel list into the
73+
// normalised ids the other RPCs accept.
74+
message ParseChannelsRequest {
75+
string raw = 1;
76+
}
77+
78+
message ParseChannelsResponse {
79+
repeated string channel_ids = 1;
80+
}

v2/ezytel/ezytel_service.pb.go

Lines changed: 84 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

v2/ezytel/ezytel_service.proto

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
syntax = "proto3";
2+
3+
package ezytel;
4+
option go_package = "github.com/hiddify/hiddify-core/v2/ezytel";
5+
option java_package = "com.hiddify.core.api.v2.ezytel";
6+
import "v2/ezytel/ezytel.proto";
7+
8+
// Ezytel exposes the Telegram public-channel viewer originally shipped as
9+
// the ezytel.zip PHP app. Traffic to t.me is routed through Google's
10+
// translate.goog domain front so it reaches users behind GFW-style filters.
11+
service Ezytel {
12+
rpc GetChannelInfo (ChannelInfoRequest) returns (ChannelInfo);
13+
rpc GetChannelMessages (ChannelMessagesRequest) returns (ChannelMessagesResponse);
14+
rpc ProxyImage (ProxyImageRequest) returns (ProxyImageResponse);
15+
rpc ParseChannels (ParseChannelsRequest) returns (ParseChannelsResponse);
16+
}

0 commit comments

Comments
 (0)