diff --git a/go.mod b/go.mod index 142be4f..d46f5a0 100644 --- a/go.mod +++ b/go.mod @@ -5,63 +5,19 @@ go 1.24.0 toolchain go1.24.11 require ( - github.com/celestix/gotgproto v1.0.0-beta22 github.com/joho/godotenv v1.5.1 github.com/xelaj/mtproto v1.0.0 ) require ( - github.com/AnimeKaizoku/cacher v1.0.3-0.20250508132714-ddc7471efeef // indirect - github.com/cenkalti/backoff/v4 v4.3.0 // indirect - github.com/coder/websocket v1.8.14 // indirect - github.com/dlclark/regexp2 v1.11.5 // indirect - github.com/dustin/go-humanize v1.0.1 // indirect - github.com/fatih/color v1.18.0 // indirect github.com/fatih/structtag v1.2.0 // indirect - github.com/ghodss/yaml v1.0.0 // indirect - github.com/glebarez/go-sqlite v1.22.0 // indirect - github.com/glebarez/sqlite v1.11.0 // indirect - github.com/go-faster/errors v0.7.1 // indirect - github.com/go-faster/jx v1.2.0 // indirect - github.com/go-faster/xor v1.0.0 // indirect - github.com/go-faster/yaml v0.4.6 // indirect - github.com/google/uuid v1.6.0 // indirect - github.com/gotd/ige v0.2.2 // indirect - github.com/gotd/neo v0.1.5 // indirect - github.com/gotd/td v0.135.0 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect github.com/k0kubun/pp v3.0.1+incompatible // indirect - github.com/klauspost/compress v1.18.2 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/ogen-go/ogen v1.16.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect - github.com/segmentio/asm v1.2.1 // indirect - github.com/shopspring/decimal v1.4.0 // indirect + github.com/stretchr/testify v1.11.1 // indirect github.com/xelaj/errs v0.0.0-20200831133608-d1c11863e019 // indirect github.com/xelaj/go-dry v0.0.0-20201104165138-61a25872c05a // indirect - go.opentelemetry.io/otel v1.38.0 // indirect - go.opentelemetry.io/otel/metric v1.38.0 // indirect - go.opentelemetry.io/otel/trace v1.38.0 // indirect - go.uber.org/atomic v1.11.0 // indirect - go.uber.org/multierr v1.11.0 // indirect - go.uber.org/zap v1.27.1 // indirect golang.org/x/crypto v0.45.0 // indirect - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect - golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.47.0 // indirect - golang.org/x/sync v0.18.0 // indirect golang.org/x/sys v0.38.0 // indirect - golang.org/x/text v0.31.0 // indirect - golang.org/x/tools v0.39.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect - gorm.io/gorm v1.25.12 // indirect - modernc.org/libc v1.61.8 // indirect - modernc.org/mathutil v1.7.1 // indirect - modernc.org/memory v1.8.2 // indirect - modernc.org/sqlite v1.34.4 // indirect - rsc.io/qr v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index eb06e9c..9deed24 100644 --- a/go.sum +++ b/go.sum @@ -1,89 +1,24 @@ -github.com/AnimeKaizoku/cacher v1.0.3-0.20250508132714-ddc7471efeef h1:y8llZexgesBazUg/zdIlrZKHPFJ2zk9YxlLAJ5x4DpQ= -github.com/AnimeKaizoku/cacher v1.0.3-0.20250508132714-ddc7471efeef/go.mod h1:jw0de/b0K6W7Y3T9rHCMGVKUf6oG7hENNcssxYcZTCc= -github.com/celestix/gotgproto v1.0.0-beta22 h1:Iu78cFA08nV8+flmxKs9CJ3W73+HG30fx0nLOs5A6fI= -github.com/celestix/gotgproto v1.0.0-beta22/go.mod h1:JYC9Js/5KLUhFR5M2RslQi2DFAcF7EdrgJMXo0YrzGQ= -github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= -github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/coder/websocket v1.8.14 h1:9L0p0iKiNOibykf283eHkKUHHrpG7f65OE3BhhO7v9g= -github.com/coder/websocket v1.8.14/go.mod h1:NX3SzP+inril6yawo5CQXx8+fk145lPDC6pumgx0mVg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= -github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= -github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= -github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= -github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= -github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= -github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/glebarez/go-sqlite v1.22.0 h1:uAcMJhaA6r3LHMTFgP0SifzgXg46yJkgxqyuyec+ruQ= -github.com/glebarez/go-sqlite v1.22.0/go.mod h1:PlBIdHe0+aUEFn+r2/uthrWq4FxbzugL0L8Li6yQJbc= -github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw= -github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ= -github.com/go-faster/errors v0.7.1 h1:MkJTnDoEdi9pDabt1dpWf7AA8/BaSYZqibYyhZ20AYg= -github.com/go-faster/errors v0.7.1/go.mod h1:5ySTjWFiphBs07IKuiL69nxdfd5+fzh1u7FPGZP2quo= -github.com/go-faster/jx v1.2.0 h1:T2YHJPrFaYu21fJtUxC9GzmluKu8rVIFDwwGBKTDseI= -github.com/go-faster/jx v1.2.0/go.mod h1:UWLOVDmMG597a5tBFPLIWJdUxz5/2emOpfsj9Neg0PE= -github.com/go-faster/xor v0.3.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= -github.com/go-faster/xor v1.0.0 h1:2o8vTOgErSGHP3/7XwA5ib1FTtUsNtwCoLLBjl31X38= -github.com/go-faster/xor v1.0.0/go.mod h1:x5CaDY9UKErKzqfRfFZdfu+OSTfoZny3w5Ak7UxcipQ= -github.com/go-faster/yaml v0.4.6 h1:lOK/EhI04gCpPgPhgt0bChS6bvw7G3WwI8xxVe0sw9I= -github.com/go-faster/yaml v0.4.6/go.mod h1:390dRIvV4zbnO7qC9FGo6YYutc+wyyUSHBgbXL52eXk= -github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= -github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= -github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo= -github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gotd/ige v0.2.2 h1:XQ9dJZwBfDnOGSTxKXBGP4gMud3Qku2ekScRjDWWfEk= -github.com/gotd/ige v0.2.2/go.mod h1:tuCRb+Y5Y3eNTo3ypIfNpQ4MFjrnONiL2jN2AKZXmb0= -github.com/gotd/neo v0.1.5 h1:oj0iQfMbGClP8xI59x7fE/uHoTJD7NZH9oV1WNuPukQ= -github.com/gotd/neo v0.1.5/go.mod h1:9A2a4bn9zL6FADufBdt7tZt+WMhvZoc5gWXihOPoiBQ= -github.com/gotd/td v0.135.0 h1:RuVWPxiy2WoaJdLklIIKmVTowe7NOBJTM7diV9lgjmE= -github.com/gotd/td v0.135.0/go.mod h1:mStcqs/9FXhNhWnPTguptSwqkQbRIwXLw3SCSpzPJxM= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM= github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= -github.com/klauspost/compress v1.18.2 h1:iiPHWW0YrcFgpBYhsA6D1+fqHssJscY/Tm/y2Uqnapk= -github.com/klauspost/compress v1.18.2/go.mod h1:R0h/fSBs8DE4ENlcrlib3PsXS61voFxhIs2DeRhCvJ4= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/ogen-go/ogen v1.16.0 h1:fKHEYokW/QrMzVNXId74/6RObRIUs9T2oroGKtR25Iw= -github.com/ogen-go/ogen v1.16.0/go.mod h1:s3nWiMzybSf8fhxckyO+wtto92+QHpEL8FmkPnhL3jI= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= -github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= -github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0= -github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= -github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= @@ -95,36 +30,11 @@ github.com/xelaj/go-dry v0.0.0-20201104165138-61a25872c05a h1:xb1eHQRUPQyg8Du+uv github.com/xelaj/go-dry v0.0.0-20201104165138-61a25872c05a/go.mod h1:GqU1xy36iXfKYraEQQ0JYqKbLowkiSSk+OVwkNFfIq8= github.com/xelaj/mtproto v1.0.0 h1:7mGbOJtaArIEZXtJ0FJbIVx5BM6S01t7vly0tBEW3Qc= github.com/xelaj/mtproto v1.0.0/go.mod h1:/l6djr+c//gLeTTZtprPugLSGguEeL6l3WioKotVcg0= -go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= -go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8= -go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM= -go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA= -go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI= -go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE= -go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs= -go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= -go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= -go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= -go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc= -go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= -golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= -golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= -golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -134,47 +44,9 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= -golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= -golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= -gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= -modernc.org/cc/v4 v4.24.4 h1:TFkx1s6dCkQpd6dKurBNmpo+G8Zl4Sq/ztJ+2+DEsh0= -modernc.org/cc/v4 v4.24.4/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.23.12 h1:UF08a38c4B+K3VoGipBrVWLFUCHd8+X20QZtFAIlQNk= -modernc.org/ccgo/v4 v4.23.12/go.mod h1:vdN4h2WR5aEoNondUx26K7G8X+nuBscYnAEWSRmN2/0= -modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE= -modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ= -modernc.org/gc/v2 v2.6.1 h1:+Qf6xdG8l7B27TQ8D8lw/iFMUj1RXRBOuMUWziJOsk8= -modernc.org/gc/v2 v2.6.1/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= -modernc.org/libc v1.61.8 h1:50KrjlFFoKq9ABh+bNVUf5SfVfQ4NY7CEyFBh65qc60= -modernc.org/libc v1.61.8/go.mod h1:XloulGc0yIRM+91kbwrp7jNi/mfYPAvDOD2qwzWEij0= -modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= -modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= -modernc.org/memory v1.8.2 h1:cL9L4bcoAObu4NkxOlKWBWtNHIsnnACGF/TbqQ6sbcI= -modernc.org/memory v1.8.2/go.mod h1:ZbjSvMO5NQ1A2i3bWeDiVMxIorXwdClKE/0SZ+BMotU= -modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= -modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= -modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= -modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.34.4 h1:sjdARozcL5KJBvYQvLlZEmctRgW9xqIZc2ncN7PU0P8= -modernc.org/sqlite v1.34.4/go.mod h1:3QQFCG2SEMtc2nv+Wq4cQCH7Hjcg+p/RMlS1XK+zwbk= -modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= -modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= -modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= -modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -nhooyr.io/websocket v1.8.17 h1:KEVeLJkUywCKVsnLIDlD/5gtayKp8VoCkksHCGGfT9Y= -nhooyr.io/websocket v1.8.17/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= -rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= -rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs= diff --git a/main.go b/main.go index 7dde28b..ec8914d 100644 --- a/main.go +++ b/main.go @@ -6,10 +6,9 @@ import ( "fmt" "log" "os" + "path/filepath" "time" - "github.com/celestix/gotgproto" - "github.com/celestix/gotgproto/ext" "github.com/xelaj/mtproto" "github.com/xelaj/mtproto/telegram" "github.com/joho/godotenv" @@ -21,10 +20,6 @@ type GroupMember struct { Username string `json:"username"` FirstName string `json:"first_name"` LastName string `json:"last_name"` - IsBot bool `json:"is_bot,omitempty"` - IsScam bool `json:"is_scam,omitempty"` - IsFake bool `json:"is_fake,omitempty"` - PhoneNumber string `json:"phone_number,omitempty"` } // ExportConfiguration settings that define the export parameters @@ -34,9 +29,6 @@ type ExportConfiguration struct { PhoneNumber string `env:"PHONE"` GroupID int64 `env:"GROUP_ID"` OutputDir string `env:"OUTPUT_DIR"` - ProxyHost string `env:"PROXY_HOST"` - ProxyPort int `env:"PROXY_PORT"` - ProxySecret string `env:"PROXY_SECRET"` Verbose bool `env:"VERBOSE"` } @@ -46,10 +38,6 @@ type ExportOptions struct { IncludeUsername bool IncludeFirstName bool IncludeLastName bool - IncludeIsBot bool - IncludeIsScam bool - IncludeIsFake bool - IncludePhoneNumber bool } // ExportResult represents the result of an export operation @@ -70,10 +58,6 @@ func LoadExportOptions() ExportOptions { IncludeUsername: getBoolEnv("INCLUDE_USERNAME", true), IncludeFirstName: getBoolEnv("INCLUDE_FIRST_NAME", true), IncludeLastName: getBoolEnv("INCLUDE_LAST_NAME", true), - IncludeIsBot: getBoolEnv("INCLUDE_IS_BOT", false), // Default to false for privacy - IncludeIsScam: getBoolEnv("INCLUDE_IS_SCAM", false), // Default to false - IncludeIsFake: getBoolEnv("INCLUDE_IS_FAKE", false), // Default to false - IncludePhoneNumber: getBoolEnv("INCLUDE_PHONE_NUMBER", false), // Default to false for privacy } } @@ -103,9 +87,6 @@ func LoadConfig() (*ExportConfiguration, error) { PhoneNumber: getEnv("PHONE", ""), GroupID: getInt64Env("GROUP_ID", 0), OutputDir: getEnv("OUTPUT_DIR", "out"), - ProxyHost: getEnv("PROXY_HOST", ""), - ProxyPort: getIntEnv("PROXY_PORT", 0), - ProxySecret: getEnv("PROXY_SECRET", ""), Verbose: getBoolEnv("VERBOSE", false), } @@ -158,29 +139,25 @@ func getInt64Env(key string, defaultValue int64) int64 { return defaultValue } -// InitializeTelegramClient initializes Telegram client using gotgproto with configuration values -func InitializeTelegramClient(config *ExportConfiguration) (*gotgproto.Client, error) { - // Create device config with timeout settings - deviceConfig := &mtproto.DeviceConfig{ - DeviceModel: "Go Telegram Exporter", - SystemVersion: "1.0.0", - AppVersion: "1.0.0", - SystemLangCode: "en", - LangCode: "en", +// InitializeTelegramClient initializes Telegram client using xelaj/mtproto with configuration values +func InitializeTelegramClient(config *ExportConfiguration) (*telegram.Client, error) { + // Setup storage paths + appStorage := os.TempDir() // Use temp directory for session storage + sessionFile := filepath.Join(appStorage, fmt.Sprintf("session_%s.json", config.PhoneNumber)) + publicKeysFile := filepath.Join(appStorage, "tg_public_keys.pem") + + // Create client config + clientConfig := telegram.ClientConfig{ + SessionFile: sessionFile, + ServerHost: "149.154.167.50:443", // Telegram production server + PublicKeysFile: publicKeysFile, + AppID: int32(config.APIID), + AppHash: config.APIHash, + InitWarnChannel: true, } - // Create MTProto config with timeout settings - mtprotoConfig := &mtproto.Config{ - AppID: config.APIID, - AppHash: config.APIHash, - Device: deviceConfig, - Timeout: 30 * time.Second, // 30 second timeout for network requests - } - - client, err := gotgproto.NewClient( - mtprotoConfig, - gotgproto.ClientTypeUser(config.PhoneNumber), - ) + // Initialize the client + client, err := telegram.NewClient(clientConfig) if err != nil { return nil, fmt.Errorf("failed to create Telegram client: %v", err) } @@ -189,11 +166,11 @@ func InitializeTelegramClient(config *ExportConfiguration) (*gotgproto.Client, e } // AuthenticateTelegram handles the authentication flow with code request and sign-in -func AuthenticateTelegram(client *gotgproto.Client, config *ExportConfiguration) error { +func AuthenticateTelegram(client *telegram.Client, config *ExportConfiguration) error { // Send code request - sendCodeErr := client.SendCode(config.PhoneNumber) - if sendCodeErr != nil { - return fmt.Errorf("failed to send authentication code to %s. Please check your phone number and API credentials: %v", config.PhoneNumber, sendCodeErr) + codeResult, err := client.AuthSendCode(config.PhoneNumber, int32(config.APIID), config.APIHash, &telegram.CodeSettings{}) + if err != nil { + return fmt.Errorf("failed to send authentication code to %s. Please check your phone number and API credentials: %v", config.PhoneNumber, err) } // Ask user for the code they received @@ -202,20 +179,33 @@ func AuthenticateTelegram(client *gotgproto.Client, config *ExportConfiguration) fmt.Scanln(&code) // Sign in with the code - authResult, signInErr := client.SignIn(config.PhoneNumber, code) - if signInErr != nil { - // If 2FA is enabled, we need to handle password - if authResult.RequiredAuth == gotgproto.AuthTypePassword { + authResult, err := client.AuthSignIn(config.PhoneNumber, codeResult.PhoneCodeHash, code) + if err != nil { + // Check if 2FA is needed + if authErr, ok := err.(*mtproto.ErrResponseCode); ok && authErr.Message == "SESSION_PASSWORD_NEEDED" { fmt.Print("2FA Password required. Enter password: ") var password string fmt.Scanln(&password) - _, signInErr = client.AuthWithPassword(password) - if signInErr != nil { - return fmt.Errorf("failed to authenticate with 2FA password. Please check your password and try again: %v", signInErr) + // Get password information + passwordData, err := client.AccountGetPassword() + if err != nil { + return fmt.Errorf("failed to get password information: %v", err) + } + + // Create input check for password + inputCheck, err := telegram.GetInputCheckPassword(password, passwordData) + if err != nil { + return fmt.Errorf("failed to create password input: %v", err) + } + + // Sign in with password + authResult, err = client.AuthCheckPassword(inputCheck) + if err != nil { + return fmt.Errorf("failed to authenticate with 2FA password. Please check your password and try again: %v", err) } } else { - return fmt.Errorf("failed to sign in with the provided code. Please check the code and try again: %v", signInErr) + return fmt.Errorf("failed to sign in with the provided code. Please check the code and try again: %v", err) } } @@ -224,121 +214,109 @@ func AuthenticateTelegram(client *gotgproto.Client, config *ExportConfiguration) } // GetGroupMembers retrieves all members from specified group ID using Telegram client -func GetGroupMembers(client *gotgproto.Client, groupID int64) ([]GroupMember, error) { - // Convert group ID to input peer - inputPeer := &telegram.InputPeerChat{ - ChatId: int32(groupID), - } +func GetGroupMembers(client *telegram.Client, groupID int64) ([]GroupMember, error) { + var inputChannel telegram.InputChannel - // Check if it's a supergroup (negative ID) + // Check if it's a supergroup/channel (negative ID) if groupID < 0 { - inputPeer = &telegram.InputPeerChannel{ - ChannelId: int32(-groupID), // Channels use positive IDs - AccessHash: 0, // Will be retrieved if needed - } - } - - // Get full channel info to retrieve access hash and other details - // We'll try to get it first to see if it's a channel - result, err := callWithRetry(func() (interface{}, error) { - return client.API().ChannelsGetChannels(&telegram.ChannelsGetChannels{ - ID: []telegram.InputChannel{ - &telegram.InputChannel{ - ChannelId: int32(-groupID), + // Get channel info to retrieve access hash + channelsResult, err := callWithRetry(func() (interface{}, error) { + return client.ChannelsGetChannels([]telegram.InputChannel{ + telegram.InputChannelObj{ + ChannelID: int32(-groupID), AccessHash: 0, }, - }, - }) - }, 3) - - if err == nil && result != nil { - channel := result.(*telegram.MessagesChats) - if len(channel.Chats) > 0 { - chat := channel.Chats[0] - if chatChannel, ok := chat.(*telegram.Channel); ok { - // It's a supergroup/channel - inputPeer = &telegram.InputPeerChannel{ - ChannelId: int32(chatChannel.Id), - AccessHash: chatChannel.AccessHash, - } - } + }) + }, 3) + if err != nil { + return nil, fmt.Errorf("failed to get channel info: %v", err) } + + channelsData := channelsResult.(*telegram.MessagesChatsObj) + if len(channelsData.Chats) == 0 { + return nil, fmt.Errorf("channel not found or access denied") + } + + channel := channelsData.Chats[0].(*telegram.ChannelObj) + inputChannel = telegram.InputChannelObj{ + ChannelID: channel.ID, + AccessHash: channel.AccessHash, + } + } else { + // Regular chat + return nil, fmt.Errorf("regular chats (positive IDs) are not supported with this API. Only supergroups/channels (negative IDs) are supported") } - // Get participants from the group/channel + // Get participants from the channel var allMembers []GroupMember - var offset int32 = 0 - const limit int32 = 200 // Telegram's limit for one request + offset := 0 + const limit = 200 // Telegram's limit for one request // Track progress totalRetrieved := 0 for { // Get participants in batches - var participants *telegram.ChannelsChannelParticipants - var err error - - switch peer := inputPeer.(type) { - case *telegram.InputPeerChannel: - req := &telegram.ChannelsGetParticipants{ - Channel: &telegram.InputChannel{ - ChannelId: peer.ChannelId, - AccessHash: peer.AccessHash, - }, - Filter: &telegram.ChannelParticipantsRecent{}, - Offset: offset, - Limit: limit, - Hash: 0, - } - - // Make the API call with retry logic - result, err := callWithRetry(func() (interface{}, error) { - return client.API().ChannelsGetParticipants(req) - }, 3) - if err != nil { - return nil, fmt.Errorf("failed to get channel participants after retries: %v", err) - } - participants = result.(*telegram.ChannelsChannelParticipants) - default: - return nil, fmt.Errorf("unsupported peer type for getting members") + result, err := callWithRetry(func() (interface{}, error) { + return client.ChannelsGetParticipants( + inputChannel, + telegram.ChannelParticipantsFilterObj{}, + limit, + int32(offset), + 0, // hash + ) + }, 3) + if err != nil { + return nil, fmt.Errorf("failed to get channel participants after retries: %v", err) } - // Convert telegram users to GroupMember - for _, participant := range participants.Participants { - var user *telegram.User + // Process the response + participantsData := result.(*telegram.ChannelsChannelParticipantsObj) - // Find the user in the users list - for _, u := range participants.Users { - if u.GetId() == participant.GetUserId() { - user = u + // Process channel participants + for _, participant := range participantsData.Participants { + // We need to extract user ID from participant + var userID int32 + switch participant := participant.(type) { + case *telegram.ChannelParticipantSelf: + userID = participant.UserID + case *telegram.ChannelParticipant: + userID = participant.UserID + case *telegram.ChannelParticipantAdmin: + userID = participant.UserID + case *telegram.ChannelParticipantCreator: + userID = participant.UserID + } + + // Find the corresponding user in the users list + var user *telegram.UserObj + for _, u := range participantsData.Users { + if uUser, ok := u.(*telegram.UserObj); ok && uUser.ID == userID { + user = uUser break } } if user != nil { groupMember := GroupMember{ - ID: int64(user.GetId()), - Username: user.GetUsername(), - FirstName: user.GetFirstName(), - LastName: user.GetLastName(), - IsBot: user.GetBot(), - IsScam: user.GetScam(), - IsFake: user.GetFake(), - PhoneNumber: user.GetPhone(), + ID: int64(user.ID), + Username: user.Username, + FirstName: user.FirstName, + LastName: user.LastName, } allMembers = append(allMembers, groupMember) } } // Update progress - totalRetrieved += len(participants.Participants) - totalParticipants := totalRetrieved // Approximate total since Telegram doesn't give exact count upfront + count := len(participantsData.Participants) + totalRetrieved += count - // For a more accurate progress, we'll just show current progress based on what we've retrieved + // Show progress fmt.Printf("Retrieved %d members so far...\n", totalRetrieved) // Check if we've retrieved all members - if int32(len(participants.Participants)) < limit { + if count < limit { break } @@ -472,18 +450,6 @@ func FilterMembersByOptions(members []GroupMember, options ExportOptions) []map[ if options.IncludeLastName { filteredMember["last_name"] = member.LastName } - if options.IncludeIsBot { - filteredMember["is_bot"] = member.IsBot - } - if options.IncludeIsScam { - filteredMember["is_scam"] = member.IsScam - } - if options.IncludeIsFake { - filteredMember["is_fake"] = member.IsFake - } - if options.IncludePhoneNumber { - filteredMember["phone_number"] = member.PhoneNumber - } filteredMembers = append(filteredMembers, filteredMember) } @@ -532,16 +498,13 @@ func ExportToJSON(members []GroupMember, filePath string, options ExportOptions) return nil } -// GenerateFilePath generates file path using group name and current date in format 'groupname_members_YYYYMMDD.json' -func GenerateFilePath(groupName string, outputDir string) string { - // Sanitize group name by removing special characters that might cause issues in filenames - sanitizedGroupName := sanitizeFileName(groupName) - +// GenerateFilePath generates file path using group ID and current date in format 'group_ID_members_YYYYMMDD.json' +func GenerateFilePath(groupID int64, outputDir string) string { // Get current date in YYYYMMDD format currentDate := time.Now().Format("20060102") // Create filename - filename := fmt.Sprintf("%s_members_%s.json", sanitizedGroupName, currentDate) + filename := fmt.Sprintf("group_%d_members_%s.json", groupID, currentDate) // Create full path return fmt.Sprintf("%s/%s", outputDir, filename) @@ -577,7 +540,7 @@ func replaceAll(str, old, new string) string { } // ValidateGroupAccess checks if the user has access to the specified group -func ValidateGroupAccess(client *gotgproto.Client, groupID int64) error { +func ValidateGroupAccess(client *telegram.Client, groupID int64) error { _, err := GetGroupName(client, groupID) if err != nil { return fmt.Errorf("user does not have access to group with ID %d: %v", groupID, err) @@ -586,63 +549,33 @@ func ValidateGroupAccess(client *gotgproto.Client, groupID int64) error { } // GetGroupName retrieves the name of a group or channel by its ID -func GetGroupName(client *gotgproto.Client, groupID int64) (string, error) { - // Convert group ID to input peer - var inputPeer telegram.InputPeer - +func GetGroupName(client *telegram.Client, groupID int64) (string, error) { // Check if it's a supergroup/channel (negative ID) if groupID < 0 { - inputPeer = &telegram.InputPeerChannel{ - ChannelId: int32(-groupID), - AccessHash: 0, // Will be retrieved if needed - } - } else { - inputPeer = &telegram.InputPeerChat{ - ChatId: int32(groupID), - } - } - - // Get full channel/chat info to retrieve the name - var err error - var chats *telegram.MessagesChats - var isChannel = groupID < 0 - - if isChannel { - channelsReq := &telegram.ChannelsGetChannels{ - ID: []telegram.InputChannel{ - &telegram.InputChannel{ - ChannelId: int32(-groupID), - AccessHash: 0, - }, + // For channels/supergroups + resp, err := client.ChannelsGetChannels([]telegram.InputChannel{ + telegram.InputChannelObj{ + ChannelID: int32(-groupID), + AccessHash: 0, // Will be retrieved if needed }, - } - resp, err := client.API().ChannelsGetChannels(channelsReq) + }) if err != nil { return "", fmt.Errorf("failed to get channel info: %v", err) } - chats = resp.(*telegram.MessagesChats) + + chatsData := resp.(*telegram.MessagesChatsObj) + if len(chatsData.Chats) == 0 { + return "", fmt.Errorf("no channel found with ID: %d", groupID) + } + + chat := chatsData.Chats[0] + if channel, ok := chat.(*telegram.ChannelObj); ok { + return channel.Title, nil + } else { + return fmt.Sprintf("group_%d", groupID), nil + } } else { - chatsReq := &telegram.MessagesGetChats{ - ID: []int32{int32(groupID)}, - } - resp, err := client.API().MessagesGetChats(chatsReq) - if err != nil { - return "", fmt.Errorf("failed to get chat info: %v", err) - } - chats = resp.(*telegram.MessagesChats) - } - - if len(chats.Chats) == 0 { - return "", fmt.Errorf("no chat found with ID: %d", groupID) - } - - chat := chats.Chats[0] - switch c := chat.(type) { - case *telegram.Chat: - return c.Title, nil - case *telegram.Channel: - return c.Title, nil - default: + // For regular chats - not supported with this API approach return fmt.Sprintf("group_%d", groupID), nil } } @@ -658,7 +591,7 @@ func ExportWorkflow(config *ExportConfiguration) (*ExportResult, error) { ErrorMessage: fmt.Sprintf("Failed to initialize client: %v", err), }, err } - defer client.Stop() + // Note: mtproto client doesn't have a Stop() method like gotgproto // Authenticate with Telegram if err := AuthenticateTelegram(client, config); err != nil { @@ -694,7 +627,7 @@ func ExportWorkflow(config *ExportConfiguration) (*ExportResult, error) { options := LoadExportOptions() // Generate output file path - outputFilePath := GenerateFilePath(groupName, config.OutputDir) + outputFilePath := GenerateFilePath(config.GroupID, config.OutputDir) // Export members to JSON if err := ExportToJSON(members, outputFilePath, options); err != nil { @@ -708,7 +641,7 @@ func ExportWorkflow(config *ExportConfiguration) (*ExportResult, error) { // Create successful export result result := &ExportResult{ GroupID: config.GroupID, - GroupName: groupName, + GroupName: fmt.Sprintf("group_%d", config.GroupID), // Using group ID format for consistency MemberCount: len(members), OutputFilePath: outputFilePath, ExportTime: time.Now(), @@ -751,36 +684,35 @@ func (l *Logger) Error(message string) { } // GetAccessibleGroups retrieves all groups accessible to the authenticated user -func GetAccessibleGroups(client *gotgproto.Client) ([]*telegram.Chat, []*telegram.Channel, error) { +func GetAccessibleGroups(client *telegram.Client) ([]*telegram.ChatObj, []*telegram.ChannelObj, error) { // Get dialogs (chats and channels the user is part of) - dialogs, err := client.API().MessagesGetDialogs(&telegram.MessagesGetDialogs{ - OffsetDate: 0, - OffsetID: 0, - OffsetPeer: &telegram.InputPeerEmpty{}, - Limit: 100, // Limit for the first request - Hash: 0, - }) + dialogs, err := client.MessagesGetDialogs( + 0, // offset date + 0, // offset ID + telegram.InputPeerObj{}, // offset peer + 100, // limit + 0, // hash + ) if err != nil { return nil, nil, fmt.Errorf("failed to get dialogs: %v", err) } - var chats []*telegram.Chat - var channels []*telegram.Channel + var chats []*telegram.ChatObj + var channels []*telegram.ChannelObj - switch d := dialogs.(type) { - case *telegram.MessagesDialogs: - for _, chat := range d.Chats { - switch c := chat.(type) { - case *telegram.Chat: - // Only include chats that are groups (not one-to-one conversations) - if c.GetParticipantsCount() > 2 { - chats = append(chats, c) - } - case *telegram.Channel: - // Include channels and supergroups - if c.GetMegaGroup() || !c.GetBroadcast() { // MegaGroup = supergroup, !Broadcast = not a channel - channels = append(channels, c) - } + dialogsData := dialogs.(*telegram.MessagesDialogsObj) + + for _, chat := range dialogsData.Chats { + switch c := chat.(type) { + case *telegram.ChatObj: + // Only include chats that are groups (not one-to-one conversations) + if c.ParticipantsCount > 2 { + chats = append(chats, c) + } + case *telegram.ChannelObj: + // Include channels and supergroups + if c.Megagroup || !c.Broadcast { // Megagroup = supergroup, !Broadcast = not a channel + channels = append(channels, c) } } } @@ -801,7 +733,7 @@ func FormatChatName(chat interface{}) string { } // SelectGroupByUser prompts user to select a group from available groups -func SelectGroupByUser(client *gotgproto.Client) (int64, error) { +func SelectGroupByUser(client *telegram.Client) (int64, error) { fmt.Println("Fetching accessible groups...") chats, channels, err := GetAccessibleGroups(client) if err != nil { @@ -838,10 +770,10 @@ func SelectGroupByUser(client *gotgproto.Client) (int64, error) { // Determine which group was selected if selection < len(chats) { - return int64(chats[selection].Id), nil + return int64(chats[selection].ID), nil } else { channelIndex := selection - len(chats) - return -int64(channels[channelIndex].Id), nil // Negative for channels/supergroups + return -int64(channels[channelIndex].ID), nil // Negative for channels/supergroups } } @@ -871,7 +803,7 @@ func main() { log.Printf("[ERROR] Error initializing client: %v\n", err) return } - defer client.Stop() + // Note: mtproto client doesn't have a Stop() method like gotgproto logger.Info("Starting authentication process") // Authenticate with Telegram