mirror of
https://github.com/iyear/tdl
synced 2025-01-09 04:17:35 +08:00
feat(users): enhance output
This commit is contained in:
parent
e345ba4a3e
commit
081d4273b6
@ -8,10 +8,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/go-faster/jx"
|
||||
"github.com/gotd/contrib/middleware/ratelimit"
|
||||
"github.com/gotd/td/telegram/peers"
|
||||
"github.com/gotd/td/telegram/query"
|
||||
"github.com/gotd/td/telegram/query/channels/participants"
|
||||
"github.com/gotd/td/tg"
|
||||
"github.com/jedib0t/go-pretty/v6/progress"
|
||||
@ -32,65 +32,36 @@ type UsersOptions struct {
|
||||
|
||||
type User struct {
|
||||
ID int64 `json:"id"`
|
||||
Bot bool `json:"bot"`
|
||||
Username string `json:"username"`
|
||||
Phone string `json:"phone"`
|
||||
FirstName string `json:"firstName"`
|
||||
LastName string `json:"lastName"`
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
}
|
||||
|
||||
func Users(ctx context.Context, opts *UsersOptions) error {
|
||||
func Users(ctx context.Context, opts UsersOptions) error {
|
||||
c, kvd, err := tgc.NoLogin(ctx, ratelimit.New(rate.Every(rateInterval), rateBucket))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tgc.RunWithAuth(ctx, c, func(ctx context.Context) (rerr error) {
|
||||
var peer peers.Peer
|
||||
|
||||
manager := peers.Options{Storage: storage.NewPeers(kvd)}.Build(c.API())
|
||||
if opts.Chat == "" { // defaults to me(saved messages)
|
||||
if opts.Chat == "" {
|
||||
return fmt.Errorf("missing domain id")
|
||||
}
|
||||
|
||||
peer, err = utils.Telegram.GetInputPeer(ctx, manager, opts.Chat)
|
||||
peer, err := utils.Telegram.GetInputPeer(ctx, manager, opts.Chat)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get peer: %w", err)
|
||||
}
|
||||
|
||||
color.Cyan("Occasional suspensions are due to Telegram rate limitations, please wait a moment.")
|
||||
fmt.Println()
|
||||
|
||||
pw := prog.New(progress.FormatNumber)
|
||||
pw.SetUpdateFrequency(200 * time.Millisecond)
|
||||
pw.Style().Visibility.TrackerOverall = false
|
||||
pw.Style().Visibility.ETA = false
|
||||
pw.Style().Visibility.Percentage = false
|
||||
|
||||
tracker := prog.AppendTracker(pw, progress.FormatNumber, fmt.Sprintf("%s-%d", peer.VisibleName(), peer.ID()), 0)
|
||||
|
||||
go pw.Render()
|
||||
|
||||
ch, ok := peer.(peers.Channel)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid type of chat. channels are supported only")
|
||||
}
|
||||
usersList := []*tg.User{}
|
||||
|
||||
iter := participants.NewIterator(query.NewQuery(c.API()).GetParticipants(ch.InputChannel()), 100)
|
||||
for iter.Next(ctx) {
|
||||
el := iter.Value()
|
||||
us, ok := el.User()
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
usersList = append(usersList, us)
|
||||
return fmt.Errorf("invalid type of chat. channels/groups are supported only")
|
||||
}
|
||||
|
||||
if err = iter.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
color.Cyan("Occasional suspensions are due to Telegram rate limitations, please wait a moment.")
|
||||
fmt.Println()
|
||||
|
||||
f, err := os.Create(opts.Output)
|
||||
if err != nil {
|
||||
@ -105,34 +76,98 @@ func Users(ctx context.Context, opts *UsersOptions) error {
|
||||
defer enc.ObjEnd()
|
||||
enc.Field("id", func(e *jx.Encoder) { e.Int64(peer.ID()) })
|
||||
|
||||
enc.FieldStart("users")
|
||||
var output any = usersList
|
||||
if !opts.Raw {
|
||||
users := make([]User, len(usersList))
|
||||
for i := 0; i < len(usersList); i++ {
|
||||
convertTelegramUser(&users[i], usersList[i])
|
||||
pw := prog.New(progress.FormatNumber)
|
||||
pw.SetUpdateFrequency(200 * time.Millisecond)
|
||||
pw.Style().Visibility.TrackerOverall = false
|
||||
pw.Style().Visibility.ETA = false
|
||||
pw.Style().Visibility.Percentage = false
|
||||
|
||||
go pw.Render()
|
||||
|
||||
builder := func() *participants.GetParticipantsQueryBuilder {
|
||||
return participants.NewQueryBuilder(c.API()).
|
||||
GetParticipants(ch.InputChannel()).
|
||||
BatchSize(100)
|
||||
}
|
||||
|
||||
fields := map[string]*participants.GetParticipantsQueryBuilder{
|
||||
"users": builder(),
|
||||
"admins": builder().Admins(),
|
||||
"kicked": builder().Kicked(""),
|
||||
"banned": builder().Banned(""),
|
||||
"bots": builder().Bots(),
|
||||
}
|
||||
|
||||
for field, query := range fields {
|
||||
iter := query.Iter()
|
||||
if err = outputUsers(ctx, pw, peer, enc, field, iter, opts.Raw); err != nil {
|
||||
return fmt.Errorf("failed to output %s: %w", field, err)
|
||||
}
|
||||
|
||||
output = users
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(output)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to marshal message: %w", err)
|
||||
}
|
||||
enc.Raw(buf)
|
||||
|
||||
tracker.MarkAsDone()
|
||||
prog.Wait(pw)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func convertTelegramUser(dstUser *User, tgUser *tg.User) {
|
||||
dstUser.ID = tgUser.ID
|
||||
dstUser.Bot = tgUser.Bot
|
||||
dstUser.FirstName = tgUser.FirstName
|
||||
dstUser.LastName = tgUser.LastName
|
||||
dstUser.Phone = tgUser.Phone
|
||||
dstUser.Username = tgUser.Username
|
||||
func outputUsers(ctx context.Context,
|
||||
pw progress.Writer,
|
||||
peer peers.Peer,
|
||||
enc *jx.Encoder,
|
||||
field string,
|
||||
iter *participants.Iterator,
|
||||
raw bool,
|
||||
) error {
|
||||
total, err := iter.Total(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "get total count")
|
||||
}
|
||||
|
||||
tracker := prog.AppendTracker(pw,
|
||||
progress.FormatNumber,
|
||||
fmt.Sprintf("%s-%d-%s", peer.VisibleName(), peer.ID(), field),
|
||||
int64(total))
|
||||
|
||||
enc.FieldStart(field)
|
||||
enc.ArrStart()
|
||||
defer enc.ArrEnd()
|
||||
|
||||
for iter.Next(ctx) {
|
||||
el := iter.Value()
|
||||
u, ok := el.User()
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
var output any = u
|
||||
if !raw {
|
||||
output = convertTelegramUser(u)
|
||||
}
|
||||
|
||||
buf, err := json.Marshal(output)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "marshal user")
|
||||
}
|
||||
|
||||
enc.Raw(buf)
|
||||
|
||||
tracker.Increment(1)
|
||||
}
|
||||
|
||||
if err = iter.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tracker.MarkAsDone()
|
||||
return nil
|
||||
}
|
||||
|
||||
func convertTelegramUser(u *tg.User) User {
|
||||
var dst User
|
||||
dst.ID = u.ID
|
||||
dst.Username = u.Username
|
||||
dst.Phone = u.Phone
|
||||
dst.FirstName = u.FirstName
|
||||
dst.LastName = u.LastName
|
||||
return dst
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ func NewChatUsers() *cobra.Command {
|
||||
Use: "users",
|
||||
Short: "export users from (protected) channels",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
return chat.Users(logger.Named(cmd.Context(), "users"), &opts)
|
||||
return chat.Users(logger.Named(cmd.Context(), "users"), opts)
|
||||
},
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user