telegem 2.1.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/Readme.md +2 -2
  3. data/Starts_HallofFame.md +65 -0
  4. data/Test-Projects/bot.md +145 -0
  5. data/Test-Projects/bot1.rb +91 -0
  6. data/bin/telegem-ssl +44 -0
  7. data/docs-src/Bot-registration_.PNG +0 -0
  8. data/docs-src/bot.md +349 -180
  9. data/docs-src/ctx.md +399 -0
  10. data/docs-src/webhook.md +341 -0
  11. data/lib/api/client.rb +72 -27
  12. data/lib/core/bot.rb +81 -149
  13. data/lib/telegem.rb +1 -1
  14. data/lib/webhook/server.rb +149 -290
  15. data/public/index.html +481 -0
  16. metadata +32 -24
  17. data/Test-Projects/Movie-tracker-bot/Gemfile +0 -2
  18. data/Test-Projects/Movie-tracker-bot/bot.rb +0 -62
  19. data/Test-Projects/Movie-tracker-bot/handlers/.gitkeep +0 -0
  20. data/Test-Projects/Movie-tracker-bot/handlers/add_1_.rb +0 -160
  21. data/Test-Projects/Movie-tracker-bot/handlers/add_2_.rb +0 -139
  22. data/Test-Projects/Movie-tracker-bot/handlers/premium.rb +0 -13
  23. data/Test-Projects/Movie-tracker-bot/handlers/report.rb +0 -31
  24. data/Test-Projects/Movie-tracker-bot/handlers/search.rb +0 -150
  25. data/Test-Projects/Movie-tracker-bot/handlers/sponsor.rb +0 -14
  26. data/Test-Projects/Movie-tracker-bot/handlers/start.rb +0 -48
  27. data/Test-Projects/Movie-tracker-bot/handlers/watch.rb +0 -210
  28. data/Test-Projects/Test-submitted-by-marvel/.gitkeep +0 -0
  29. data/Test-Projects/Test-submitted-by-marvel/Marvel-bot.md +0 -3
  30. data/Test-Projects/bot_test1.rb +0 -75
  31. data/Test-Projects/pizza_test_bot_guide.md +0 -163
  32. data/docs-src/understanding-ctx.md +0 -581
  33. /data/{Test-Projects → bin}/.gitkeep +0 -0
  34. /data/{Test-Projects/Movie-tracker-bot → public}/.gitkeep +0 -0
@@ -1,210 +0,0 @@
1
- class WatchHandler
2
- def initialize(bot, db)
3
- @bot = bot
4
- @db = db
5
- setup_watch_commands
6
- setup_inline_handlers
7
- end
8
-
9
- def setup_watch_commands
10
- # Command: /watch - Show all subscribed shows with inline buttons
11
- @bot.command("watch") do |ctx|
12
- show_watch_menu(ctx)
13
- end
14
-
15
- # Command: /watched <show_id> s<season>e<episode>
16
- @bot.command("watched") do |ctx|
17
- handle_watched_command(ctx)
18
- end
19
- end
20
-
21
- def show_watch_menu(ctx)
22
- user_id = ctx.from.id
23
-
24
- # Get user's shows with their current progress
25
- shows = @db.execute(<<-SQL, [user_id])
26
- SELECT
27
- movies.id,
28
- movies.title,
29
- watched.season as current_season,
30
- watched.episode as current_episode
31
- FROM watched
32
- JOIN movies ON movies.id = watched.movie_id
33
- WHERE watched.telegram_id = ?
34
- ORDER BY movies.title
35
- SQL
36
-
37
- if shows.empty?
38
- ctx.reply("📭 You're not tracking any shows yet!\nUse /search to find shows, then /add <id>")
39
- return
40
- end
41
-
42
- # Create message with inline keyboard
43
- message = "📺 *Mark Episodes Watched*\n\n"
44
- message += "Click a show to mark episodes:\n\n"
45
-
46
- shows.each do |id, title, season, episode|
47
- message += "🎬 *#{title}*\n"
48
- message += " Current: S#{season}E#{episode}\n"
49
- message += " Next: S#{season}E#{episode + 1}\n\n"
50
- end
51
-
52
- # Create inline keyboard with ONE button per show
53
- inline = Telegem.inline do
54
- shows.each do |id, title, season, episode|
55
- # Button shows: "Stranger Things (S1E3)"
56
- row button "#{title} (S#{season}E#{episode})",
57
- callback_data: "select_show:#{id}:#{season}:#{episode}"
58
- end
59
- # Add a "Mark All Caught Up" button
60
- row button "✅ Mark All As Caught Up", callback_data: "catchup_all"
61
- end
62
-
63
- ctx.reply(message, reply_markup: inline, parse_mode: 'Markdown')
64
- end
65
-
66
- def setup_inline_handlers
67
- @bot.on(:callback_query) do |ctx|
68
- case ctx.data
69
- when /^select_show:(\d+):(\d+):(\d+)$/
70
- handle_show_selection(ctx, $1.to_i, $2.to_i, $3.to_i)
71
- when /^mark_episode:(\d+):(\d+):(\d+)$/
72
- handle_mark_episode(ctx, $1.to_i, $2.to_i, $3.to_i)
73
- when "catchup_all"
74
- handle_catchup_all(ctx)
75
- when "back_to_shows"
76
- show_watch_menu(ctx)
77
- end
78
- end
79
- end
80
-
81
- def handle_show_selection(ctx, show_id, current_season, current_episode)
82
- # Get show title
83
- show = @db.execute(
84
- "SELECT title FROM movies WHERE id = ?",
85
- [show_id]
86
- ).first
87
-
88
- return unless show
89
-
90
- show_title = show[0]
91
-
92
- # Create episode selection buttons
93
- message = "🎬 *#{show_title}*\n"
94
- message += "Mark which episode you watched:\n\n"
95
- message += "Current: S#{current_season}E#{current_episode}\n\n"
96
-
97
- # Create buttons for next 5 episodes
98
- inline = Telegem.inline do
99
- # Show 5 episodes: current+1 to current+5
100
- (1..5).each do |offset|
101
- ep_num = current_episode + offset
102
- row button "✅ S#{current_season}E#{ep_num}",
103
- callback_data: "mark_episode:#{show_id}:#{current_season}:#{ep_num}"
104
- end
105
-
106
- # Next season button
107
- row button "➡️ Next Season (S#{current_season + 1}E1)",
108
- callback_data: "mark_episode:#{show_id}:#{current_season + 1}:1"
109
-
110
- # Back button
111
- row button "🔙 Back to Shows", callback_data: "back_to_shows"
112
- end
113
-
114
- # Edit the message with new buttons
115
- ctx.edit_message_text(message, reply_markup: inline, parse_mode: 'Markdown')
116
- ctx.answer_callback_query(text: "Select episode for #{show_title}")
117
- end
118
-
119
- def handle_mark_episode(ctx, show_id, season, episode)
120
- user_id = ctx.from.id
121
-
122
- # Update watched table
123
- @db.execute(<<-SQL, [season, episode, user_id, show_id])
124
- UPDATE watched
125
- SET season = ?, episode = ?, updated_at = CURRENT_TIMESTAMP
126
- WHERE telegram_id = ? AND movie_id = ?
127
- SQL
128
-
129
- # Get show title for response
130
- show = @db.execute(
131
- "SELECT title FROM movies WHERE id = ?",
132
- [show_id]
133
- ).first
134
-
135
- show_title = show[0] if show
136
-
137
- # Show confirmation
138
- ctx.answer_callback_query(
139
- text: "✅ Marked #{show_title} S#{season}E#{episode} as watched!"
140
- )
141
-
142
- # Update message to show new status
143
- message = "✅ *Updated!*\n\n"
144
- message += "🎬 #{show_title}\n"
145
- message += "Now watching: S#{season}E#{episode}\n"
146
- message += "Next alert: S#{season}E#{episode + 1}\n\n"
147
- message += "Click another show or use /watch again."
148
-
149
- # Keep back button
150
- inline = Telegem.inline do
151
- row button "🔙 Back to Shows", callback_data: "back_to_shows"
152
- end
153
-
154
- ctx.edit_message_text(message, reply_markup: inline, parse_mode: 'Markdown')
155
- end
156
-
157
- def handle_catchup_all(ctx)
158
- user_id = ctx.from.id
159
-
160
- # For each show, set episode to a high number (like 999 to mark as "caught up")
161
- shows_updated = @db.execute(<<-SQL, [user_id])
162
- UPDATE watched
163
- SET episode = 999, updated_at = CURRENT_TIMESTAMP
164
- WHERE telegram_id = ? AND episode < 999
165
- SQL
166
-
167
- ctx.answer_callback_query(
168
- text: "✅ Marked all shows as caught up!"
169
- )
170
-
171
- # Go back to show list
172
- show_watch_menu(ctx)
173
- end
174
-
175
- def handle_watched_command(ctx)
176
- # Text command version: /watched 1 s1e3
177
- args = ctx.message.text.split
178
-
179
- if args.size != 3
180
- ctx.reply("Usage: /watched <show_id> <episode>\nExample: /watched 1 s1e3")
181
- return
182
- end
183
-
184
- show_id = args[1].to_i
185
- episode_str = args[2]
186
-
187
- match = episode_str.match(/s(\d+)e(\d+)/i)
188
- unless match
189
- ctx.reply("❌ Invalid format. Use: s1e3, s2e5, etc.")
190
- return
191
- end
192
-
193
- season = match[1].to_i
194
- episode = match[2].to_i
195
- user_id = ctx.from.id
196
-
197
- # Update database
198
- @db.execute(<<-SQL, [season, episode, user_id, show_id])
199
- UPDATE watched
200
- SET season = ?, episode = ?, updated_at = CURRENT_TIMESTAMP
201
- WHERE telegram_id = ? AND movie_id = ?
202
- SQL
203
-
204
- if @db.changes > 0
205
- ctx.reply("✅ Updated! You've watched up to S#{season}E#{episode}")
206
- else
207
- ctx.reply("❌ You're not tracking that show. Use /add first.")
208
- end
209
- end
210
- end
File without changes
@@ -1,3 +0,0 @@
1
- #marvel
2
-
3
- - https://gitlab.com/ynwghosted/bot-test/-/tree/main/editor/src
@@ -1,75 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # Test-Projects/bot_test1.rb
3
- require 'telegem'
4
-
5
- puts "🚀 Starting Bot Test 1..."
6
- puts "Ruby: #{RUBY_VERSION}"
7
- puts "Telegem: #{Telegem::VERSION rescue 'Not loaded'}"
8
-
9
- begin
10
- # 1. Create bot with your token
11
- bot = Telegem.new('8013082846:AAEnG0T1pnLhOpjwpF3I-A4DX4aQy_HPsAc')
12
- puts "✅ Bot object created"
13
-
14
- # 2. Add a command
15
- bot.command('start') do |ctx|
16
- ctx.reply "🤖 Test Bot 1 is working!"
17
- puts "✅ Command '/start' would reply"
18
- end
19
-
20
- bot.command('ping') do |ctx|
21
- ctx.reply "🏓 Pong! #{Time.now}"
22
- puts "✅ Command '/ping' would reply"
23
- end
24
-
25
- puts "✅ Commands registered"
26
-
27
- # 3. Try a simple API call (getMe)
28
- puts "📡 Testing API connection..."
29
- me = bot.api.call('getMe') rescue nil
30
-
31
- if me
32
- puts "✅ API Connected! Bot: @#{me['username']} (#{me['first_name']})"
33
- else
34
- puts "⚠️ API test failed (might be network/CI issue)"
35
- end
36
-
37
- # 4. Start polling for 10 seconds
38
- puts "🔄 Starting bot polling (10 seconds test)..."
39
-
40
- # Run polling in a thread with timeout
41
- polling_thread = Thread.new do
42
- begin
43
- bot.start_polling(timeout: 5, limit: 1)
44
- rescue => e
45
- puts "⚠️ Polling error (normal in CI): #{e.message}"
46
- end
47
- end
48
-
49
- # Wait 10 seconds then stop
50
- sleep 10
51
- puts "⏱️ 10 seconds passed, stopping bot..."
52
-
53
- # Try to stop gracefully
54
- bot.shutdown rescue nil
55
- polling_thread.kill if polling_thread.alive?
56
-
57
- puts "🎉 Test completed successfully!"
58
- puts "✅ Bot framework works!"
59
- puts "✅ Commands work!"
60
- puts "✅ Async system works!"
61
-
62
- rescue LoadError => e
63
- puts "❌ LOAD ERROR: #{e.message}"
64
- puts "Backtrace:"
65
- puts e.backtrace.first(5)
66
- exit 1
67
-
68
- rescue => e
69
- puts "❌ ERROR: #{e.class}: #{e.message}"
70
- puts "Backtrace (first 3 lines):"
71
- puts e.backtrace.first(3)
72
- exit 1
73
- end
74
-
75
- puts "✨ All tests passed!"
@@ -1,163 +0,0 @@
1
-
2
- ```ruby
3
- require 'telegem'
4
-
5
- # 1. Create bot
6
- bot = Telegem.new(ENV['PIZZA_BOT_TOKEN'])
7
-
8
- # 2. Welcome command
9
- bot.command('start') do |ctx|
10
- ctx.reply "🍕 Welcome to PizzaBot!"
11
- ctx.reply "Use /order to start ordering"
12
- ctx.reply "Use /menu to see options"
13
- end
14
-
15
- # 3. Menu command
16
- bot.command('menu') do |ctx|
17
- menu = <<~MENU
18
- *Our Menu:*
19
-
20
- 🍕 Pizzas:
21
- - Margherita: $10
22
- - Pepperoni: $12
23
- - Veggie: $11
24
-
25
- 🥤 Drinks:
26
- - Cola: $2
27
- - Water: $1
28
-
29
- Use /order to order!
30
- MENU
31
-
32
- ctx.reply menu, parse_mode: 'Markdown'
33
- end
34
-
35
- # 4. Order command - Starts a scene
36
- bot.scene :ordering do
37
- step :choose_pizza do |ctx|
38
- keyboard = ctx.keyboard do
39
- row "Margherita", "Pepperoni"
40
- row "Veggie", "Cancel"
41
- end
42
-
43
- ctx.reply "Choose your pizza:", reply_markup: keyboard
44
- end
45
-
46
- step :save_pizza do |ctx|
47
- ctx.session[:pizza] = ctx.message.text
48
- ctx.reply "Great! #{ctx.session[:pizza]} selected."
49
- ctx.reply "What's your address?"
50
- end
51
-
52
- step :save_address do |ctx|
53
- ctx.session[:address] = ctx.message.text
54
-
55
- # Show summary
56
- summary = <<~SUMMARY
57
- *Order Summary:*
58
-
59
- Pizza: #{ctx.session[:pizza]}
60
- Address: #{ctx.session[:address]}
61
-
62
- Confirm? (Yes/No)
63
- SUMMARY
64
-
65
- ctx.reply summary, parse_mode: 'Markdown'
66
- end
67
-
68
- step :confirm do |ctx|
69
- if ctx.message.text.downcase == 'yes'
70
- ctx.reply "✅ Order placed! Delivery in 30 minutes."
71
- ctx.reply "Use /track to track your order"
72
- else
73
- ctx.reply "❌ Order cancelled."
74
- end
75
- ctx.leave_scene
76
- end
77
-
78
- # Handle "Cancel" at any step
79
- on_enter do |ctx|
80
- ctx.session[:order_id] = rand(1000..9999)
81
- end
82
- end
83
-
84
- # 5. Start the order scene
85
- bot.command('order') do |ctx|
86
- ctx.enter_scene(:ordering)
87
- end
88
-
89
- # 6. Track order (simple version)
90
- bot.command('track') do |ctx|
91
- if ctx.session[:order_id]
92
- ctx.reply "Order ##{ctx.session[:order_id]} is being prepared!"
93
- else
94
- ctx.reply "No active order. Use /order to start."
95
- end
96
- end
97
-
98
- # 7. Handle keyboard button presses
99
- bot.on(:message) do |ctx|
100
- # Skip if it's a command or in scene
101
- next if ctx.message.command? || ctx.scene
102
-
103
- text = ctx.message.text
104
-
105
- case text
106
- when "Margherita", "Pepperoni", "Veggie"
107
- ctx.reply "Use /order to order a #{text} pizza!"
108
- when "Cancel"
109
- ctx.reply "Cancelled."
110
- end
111
- end
112
-
113
- # 8. Start bot
114
- if ENV['WEBHOOK']
115
- bot.webhook_server(port: ENV['PORT'] || 3000).run
116
- else
117
- puts "🍕 PizzaBot starting..."
118
- bot.start_polling
119
- end
120
- ```
121
-
122
- ---
123
-
124
- 🧪 Let's Test It!
125
-
126
- Create the file:
127
-
128
- ```bash
129
- mkdir -p examples
130
- touch examples/pizza_bot.rb
131
- ```
132
-
133
- Run it:
134
-
135
- ```bash
136
- # Set your token
137
- export PIZZA_BOT_TOKEN="123456:your_token_here"
138
-
139
- # Run the bot
140
- ruby examples/pizza_bot.rb
141
- ```
142
-
143
- Test the flow:
144
-
145
- 1. /start → Shows welcome
146
- 2. /menu → Shows pizza menu
147
- 3. /order → Starts ordering scene
148
- 4. Choose "Margherita" → Asks for address
149
- 5. Type your address → Shows summary
150
- 6. Type "yes" → Order confirmed!
151
- 7. /track → Shows order status
152
-
153
- ---
154
-
155
- 🏗️ Your Homework:
156
-
157
- Can you add:
158
-
159
- 1. A /help command showing all commands?
160
- 2. A "size" step in the scene (Small/Medium/Large)?
161
- 3. A middleware that logs all orders to a file?
162
-
163
- This is how you learn: Build, break, fix, improve. You now understand then library enough to code without AI help!