Skip to content

Commit b9ff278

Browse files
Added command to set a custom delay in seconds for each entry
Added command to capture a specific HTML element of the website changed screenshot tool to capture-website-cli
1 parent 710de0f commit b9ff278

File tree

13 files changed

+168
-88
lines changed

13 files changed

+168
-88
lines changed

NotifierBot/Sources/Notifier/Commands/AddCommand.swift

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,39 +19,36 @@ struct AddCommand: Command {
1919
func run(update: Update, context: BotContext?) throws {
2020
let chatID = try update.chatID()
2121
let args = try update.args()
22-
guard args.count > 0 else {
22+
guard args.count >= 2 else {
2323
try showUsage(chatID)
2424
return
2525
}
2626

27+
// Parse the arguments
28+
let name = args[0]
29+
let url = args[1]
30+
2731
// Check if there is a valid URL
28-
guard let urlIndex = args.lastIndex(where: { $0.starts(with: "http") }) else {
32+
guard url.starts(with: "http") else {
2933
// No valid URL found
3034
try bot.sendMessage("Please enter a valid URL, starting with 'http://' or 'https://'", to: chatID)
3135
return
3236
}
33-
// The first argument should be the name, not the URL
34-
if urlIndex == 0 {
35-
try showUsage(chatID)
36-
return
37-
}
38-
// Parse the arguments
39-
let name = args[0..<urlIndex].joined(separator: " ")
40-
let url = args[urlIndex]
4137

4238
let area: Rectangle!
43-
if args.count == urlIndex + 5 {
39+
// If we have name, url, x, y, width, height (6 arguments)
40+
if args.count == 6 {
4441
// If a cropping area was supplied
45-
let x = Int(args[urlIndex + 1])
46-
let y = Int(args[urlIndex + 2])
47-
let width = Int(args[urlIndex + 3])
48-
let height = Int(args[urlIndex + 4])
42+
let x = Int(args[2])
43+
let y = Int(args[3])
44+
let width = Int(args[4])
45+
let height = Int(args[5])
4946
guard x != nil && y != nil && width != nil && height != nil else {
5047
try bot.sendMessage("Please enter a valid Offset and Size", to: chatID)
5148
return
5249
}
5350
area = Rectangle(x: x!, y: y!, width: width!, height: height!)
54-
} else if args.count == urlIndex + 1 {
51+
} else if args.count == 2 {
5552
// No cropping area
5653
area = .zero
5754
} else {

NotifierBot/Sources/Notifier/Commands/DiffCommand.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ struct DiffCommand: Command {
1919
func run(update: Update, context: BotContext?) throws {
2020
let chatID = try update.chatID()
2121
let args = try update.args()
22-
guard args.count > 0 else {
22+
guard args.count == 1 else {
2323
try showUsage(chatID)
2424
return
2525
}
26-
let name = args.joined(separator: " ")
26+
let name = args[0]
2727
// Check if an entry with this name exists
2828
let config = try ConfigParser.getConfig()
2929
guard let entry = config.first(where: { $0.name.lowercased() == name.lowercased() && $0.chatID == chatID }) else {

NotifierBot/Sources/Notifier/Commands/FetchCommand.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ struct FetchCommand: Command {
1919
func run(update: Update, context: BotContext?) throws {
2020
let chatID = try update.chatID()
2121
let args = try update.args()
22-
guard args.count > 0 else {
22+
guard args.count == 1 else {
2323
try showUsage(chatID)
2424
return
2525
}
26-
let name = args.joined(separator: " ")
26+
let name = args[0]
2727
// Get the settings
2828
let config = try ConfigParser.getConfig()
2929
let entry = config.first(where: { $0.name.lowercased() == name.lowercased() && $0.chatID == chatID })

NotifierBot/Sources/Notifier/Commands/RemoveCommand.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@ struct RemoveCommand: Command {
1919
func run(update: Update, context: BotContext?) throws {
2020
let chatID = try update.chatID()
2121
let args = try update.args()
22-
guard args.count > 0 else {
22+
guard args.count == 1 else {
2323
try showUsage(chatID)
2424
return
2525
}
2626

27-
let name = args.joined(separator: " ")
27+
let name = args[0]
2828
var config = try ConfigParser.getConfig()
2929
// Use .firstIndex instead of .removeAll(where:) to check if there even was an entry that got removed
3030
let index = config.firstIndex(where: { $0.name.lowercased() == name.lowercased() && $0.chatID == chatID })
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//
2+
// SetDelayCommand.swift
3+
//
4+
//
5+
// Created by Jonas Frey on 03.06.21.
6+
//
7+
8+
import Foundation
9+
import Telegrammer
10+
11+
struct SetDelayCommand: Command {
12+
13+
let name = "Set Delay"
14+
let commands = ["/setdelay"]
15+
let syntax = "/setdelay <name> <delay>"
16+
let description = "Specifies a delay in seconds to wait after the website has been loaded"
17+
let permission = BotPermission.mod
18+
19+
func run(update: Update, context: BotContext?) throws {
20+
let chatID = try update.chatID()
21+
let args = try update.args()
22+
guard args.count == 2 else {
23+
try showUsage(chatID)
24+
return
25+
}
26+
let name = args[0]
27+
let delay = Int(args[1])
28+
guard delay != nil else {
29+
try bot.sendMessage("Please specify a valid integer delay value", to: chatID)
30+
return
31+
}
32+
// Get the settings
33+
var config = try ConfigParser.getConfig()
34+
let entryIndex = config.firstIndex(where: { $0.name.lowercased() == name.lowercased() && $0.chatID == chatID })
35+
guard entryIndex != nil else {
36+
try bot.sendMessage("There is no entry with the name '\(name)'", to: chatID)
37+
return
38+
}
39+
// Reset the element property
40+
config[entryIndex!].delay = delay!
41+
// Save the entry
42+
try ConfigParser.saveConfig(config)
43+
44+
try bot.sendMessage("Successfully updated the delay of \(name)", to: chatID)
45+
}
46+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//
2+
// SetElementCommand.swift
3+
//
4+
//
5+
// Created by Jonas Frey on 03.06.21.
6+
//
7+
8+
import Foundation
9+
import Telegrammer
10+
11+
struct SetElementCommand: Command {
12+
13+
let name = "Set Element"
14+
let commands = ["/setelement"]
15+
let syntax = "/setelement <name> [html element]"
16+
let description = "Specifies which HTML element to capture"
17+
let permission = BotPermission.mod
18+
19+
func run(update: Update, context: BotContext?) throws {
20+
let chatID = try update.chatID()
21+
let args = try update.args()
22+
guard args.count >= 1 else {
23+
try showUsage(chatID)
24+
return
25+
}
26+
let name = args[0]
27+
// Get the settings
28+
var config = try ConfigParser.getConfig()
29+
let entryIndex = config.firstIndex(where: { $0.name.lowercased() == name.lowercased() && $0.chatID == chatID })
30+
guard entryIndex != nil else {
31+
try bot.sendMessage("There is no entry with the name '\(name)'", to: chatID)
32+
return
33+
}
34+
// Reset the element property
35+
config[entryIndex!].element = ""
36+
if args.count > 1 {
37+
let element = args[1...].joined(separator: " ")
38+
guard !element.contains(",") else {
39+
try bot.sendMessage("Please specify a HTML element that does not contain ','", to: chatID)
40+
return
41+
}
42+
// If there was a new element supplied, set it
43+
config[entryIndex!].element = element
44+
}
45+
// Save the entry
46+
try ConfigParser.saveConfig(config)
47+
48+
if args.count == 1 {
49+
try bot.sendMessage("Successfully removed capture element of \(name)", to: chatID)
50+
} else {
51+
try bot.sendMessage("Successfully updated capture element of \(name)", to: chatID)
52+
}
53+
}
54+
}

NotifierBot/Sources/Notifier/Commands/UpdateCommand.swift

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,17 @@ struct UpdateCommand: Command {
1919
func run(update: Update, context: BotContext?) throws {
2020
let chatID = try update.chatID()
2121
let args = try update.args()
22-
guard args.count >= 5 else {
22+
guard args.count == 5 else {
2323
try showUsage(chatID)
2424
return
2525
}
26-
// Modifiable copy
27-
var arguments = args
28-
let height = Int(arguments.removeLast())
29-
let width = Int(arguments.removeLast())
30-
let y = Int(arguments.removeLast())
31-
let x = Int(arguments.removeLast())
32-
// Remaining arguments must be the name
33-
let name = arguments.joined(separator: " ")
26+
let name = args[0]
27+
let x = Int(args[1])
28+
let y = Int(args[2])
29+
let width = Int(args[3])
30+
let height = Int(args[4])
3431

32+
// Check if parsing to integer worked
3533
guard x != nil && y != nil && width != nil && height != nil else {
3634
try bot.sendMessage("Please enter a valid Offset and Size.", to: chatID)
3735
return
@@ -48,6 +46,6 @@ struct UpdateCommand: Command {
4846
entry.area = Rectangle(x: x!, y: y!, width: width!, height: height!)
4947
config[entryIndex!] = entry
5048
try ConfigParser.saveConfig(config)
51-
try bot.sendMessage("Successfully updated '\(entry.name)'", to: chatID)
49+
try bot.sendMessage("Successfully updated \(entry.name)", to: chatID)
5250
}
5351
}

NotifierBot/Sources/Notifier/ConfigParser.swift

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,24 @@ class ConfigParser {
2727
}
2828
let components = line.components(separatedBy: ",")
2929
// Name, x, y, width, height, url (url may contain comma)
30-
guard components.count >= 7 else {
30+
guard components.count >= 9 else {
3131
throw JFBotError.malformedLineSegments(line)
3232
}
3333
let name = components[0].trimmingCharacters(in: .whitespaces)
3434
let x = Int(components[1].trimmingCharacters(in: .whitespaces))
3535
let y = Int(components[2].trimmingCharacters(in: .whitespaces))
3636
let width = Int(components[3].trimmingCharacters(in: .whitespaces))
3737
let height = Int(components[4].trimmingCharacters(in: .whitespaces))
38-
let chatID = Int64(components[5].trimmingCharacters(in: .whitespaces))
39-
let url = components[6...].joined(separator: ",").trimmingCharacters(in: .whitespaces)
38+
let delay = Int(components[5].trimmingCharacters(in: .whitespaces))
39+
let element = components[6].trimmingCharacters(in: .whitespaces)
40+
let chatID = Int64(components[7].trimmingCharacters(in: .whitespaces))
41+
let url = components[8...].joined(separator: ",").trimmingCharacters(in: .whitespaces)
4042

41-
guard x != nil && y != nil && width != nil && height != nil && chatID != nil else {
43+
guard x != nil && y != nil && width != nil && height != nil && chatID != nil, delay != nil else {
4244
throw JFBotError.malformedIntegers(line)
4345
}
4446

45-
entries.append(URLEntry(name: name, url: url, area: Rectangle(x: x!, y: y!, width: width!, height: height!), chatID: chatID!))
47+
entries.append(URLEntry(name: name, url: url, area: Rectangle(x: x!, y: y!, width: width!, height: height!), chatID: chatID!, delay: delay!, element: element))
4648
}
4749

4850
return entries
@@ -52,7 +54,7 @@ class ConfigParser {
5254
static func saveConfig(_ config: Config) throws {
5355
var configString = ""
5456
for l in config {
55-
configString += "\(l.name),\(l.area.x),\(l.area.y),\(l.area.width),\(l.area.height),\(l.chatID),\(l.url)\n"
57+
configString += "\(l.name),\(l.area.x),\(l.area.y),\(l.area.width),\(l.area.height),\(l.delay),\(l.element),\(l.chatID),\(l.url)\n"
5658
}
5759
// Remove the trailing line break
5860
configString.removeLast()
@@ -108,6 +110,8 @@ struct URLEntry {
108110
var url: String
109111
var area: Rectangle
110112
var chatID: Int64
113+
var delay: Int = 0
114+
var element: String = ""
111115

112116
}
113117

NotifierBot/Sources/Notifier/main.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ let diffFile = "diff.png"
4545
// The order defines the order of commands in the /help list
4646
let allCommands: [Command] = [
4747
HelpCommand(), ListCommand(), ListURLsCommand(), MyIDCommand(),
48-
AddCommand(), RemoveCommand(), UpdateCommand(), FetchCommand(), FetchURLCommand(), DiffCommand(),
48+
AddCommand(), RemoveCommand(), UpdateCommand(), SetDelayCommand(), SetElementCommand(), FetchCommand(), FetchURLCommand(), DiffCommand(),
4949
ListAllCommand(), CheckCommand(), GetPermissionsCommand(), SetPermissionsCommand()
5050
]
5151

README.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ Adds a new website with an optional screenshot area to the list
1919
Removes an entry from the list
2020
`/update <name> <x> <y> <width> <height>`
2121
Updates the screenshot area of an entry
22+
`/setdelay <name> <delay>`
23+
Specifies a delay in seconds to wait after the website has been loaded
24+
`/setelement <name> [html element]`
25+
Specifies which HTML element to capture
2226
`/fetch <name>`
2327
Takes a screenshot with the stored settings and sends it into this chat
2428
`/fetchurl <URL> [x y width height]`
@@ -36,10 +40,8 @@ Sets the permission level of the author of the message, replied to or the user i
3640

3741
### Prerequisites
3842
For the bot to work, you first need the following things:
39-
- ImageMagick (for cropping the screenshot using the `convert` tool and comparing the screenshots using `identify`)
40-
- Selenium for taking the screenshots (install using pip)
41-
- [Geckodriver](https://github.com/mozilla/geckodriver/releases) (installed in one of these directories: `/usr/local/sbin`, `/usr/local/bin`, `/sbin`, `/bin`, `/usr/sbin` or `/usr/bin`)
42-
- Firefox (install using apt-get)
43+
- ImageMagick (for cropping the screenshot using the `convert` tool and comparing the screenshots using `compare`)
44+
- [`capture-website-cli`](https://github.com/sindresorhus/capture-website-cli) to take the screenshots
4345

4446

4547
1. Clone the repository: `git clone https://github.com/iComputerfreak/NotifierBot`
@@ -64,7 +66,7 @@ $ tree -L 2
6466
│   └── Tests
6567
├── README.md
6668
├── tools
67-
│   ├── screenshot.py
69+
│   ├── screenshot.sh
6870
│   └── telegram.sh
6971
└── urlwatcher
7072
└── urlwatcher.sh
@@ -86,6 +88,16 @@ For the scripts and the bot to work, you have to put your bot token in a file ca
8688
1. `cd` to your installation directory
8789
2. Create the file: `echo YOUR_BOT_TOKEN > BOT_TOKEN`
8890

91+
### Give yourself admin permissions
92+
1. Start the bot
93+
2. Run the command `/myid` to retrieve your ID
94+
3. Stop the bot
95+
4. Add your ID to the permissions file: `echo "YOUR_ID: admin" > /path/to/your/install/directory/permissions.txt`
96+
5. Start the bot again and make sure, it worked by checking your permissions with the bot: `/getpermissions YOUR_ID`
97+
6. If the bot returned your permission level as **admin**, everything worked and you now have admin permissions
98+
99+
**Note**: Modifying the permissions file requires a restart of the bot, but using `/setpermissions <level> <userid>` does not.
100+
89101
### (Optional) Create a systemd service for the bot
90102
1. Create the unit file: `sudo nano /etc/systemd/system/notifier.service`
91103
2. Paste the following content (replace `YOUR_USER_ACCOUNT` with your user account name):
@@ -107,14 +119,3 @@ WantedBy=multi-user.target
107119
```
108120
3. Start the service: `sudo service Notifier start`
109121
4. Optional: Enable automatic start on boot: `sudo service Notifier enable`
110-
111-
112-
### Give yourself admin permissions
113-
1. Start the bot
114-
2. Run the command `/myid` to retrieve your ID
115-
3. Stop the bot
116-
4. Add your ID to the permissions file: `echo "YOUR_ID: admin" > /path/to/your/install/directory/permissions.txt`
117-
5. Start the bot again and make sure, it worked by checking your permissions with the bot: `/getpermissions YOUR_ID`
118-
6. If the bot returned your permission level as **admin**, everything worked and you now have admin permissions
119-
120-
**Note**: Modifying the permissions file requires a restart of the bot, but using `/setpermissions <level> <userid>` does not.

0 commit comments

Comments
 (0)