inat-channel 0.8.2 → 0.9.2
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.
- checksums.yaml +4 -4
- data/README.md +327 -94
- data/bin/inat-channel +14 -15
- data/lib/inat-channel/api.rb +53 -30
- data/lib/inat-channel/config.rb +52 -13
- data/lib/inat-channel/data.rb +267 -36
- data/lib/inat-channel/data_convert.rb +27 -11
- data/lib/inat-channel/data_types.rb +53 -81
- data/lib/inat-channel/icons.rb +21 -0
- data/lib/inat-channel/lock.rb +6 -6
- data/lib/inat-channel/logger.rb +10 -2
- data/lib/inat-channel/message.rb +18 -3
- data/lib/inat-channel/telegram.rb +30 -12
- data/lib/inat-channel/template.rb +25 -9
- data/lib/inat-channel/version.rb +7 -2
- data/lib/inat-channel.rb +0 -1
- metadata +1 -29
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4eb7d2097a0e7dfa5bb82a35bb44a2760796b60a2b7bc9e2005b40de25cb2eb4
|
|
4
|
+
data.tar.gz: 1e853788786d2e9a4c2dd260a3a1fd133be1e5ace65bf79f8866dbdb45b2bb59
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 07ba71faf1531c5048799439424d335ee066371e55d7c09ae412a33f11b10b55c81e3cdcc71c2f1c705bf0f1c3c25a2210c55048096a3767a27ad302f2ec9f3e
|
|
7
|
+
data.tar.gz: d30cec087845059eb8a8ae0b8fb1a4ce804942900101262b5bb5d3c4173046bdfe5a286e5824066f8c0db078323ef2f8d25c421c49b42de05c230ef27a989773
|
data/README.md
CHANGED
|
@@ -1,150 +1,383 @@
|
|
|
1
|
-
|
|
1
|
+
| **EN** | [ru](README-ru.md) |
|
|
2
|
+
|----------|----------|
|
|
3
|
+
|
|
4
|
+
# inat-channel — automatic posting of observations
|
|
2
5
|
|
|
3
6
|
[](LICENSE)
|
|
4
|
-
[](https://badge.fury.io/rb/inat-channel)
|
|
5
8
|
[](https://github.com/inat-get/inat-channel/actions/workflows/ruby.yml)
|
|
6
9
|

|
|
7
10
|
|
|
8
|
-
|
|
11
|
+
A script that sends a random iNaturalist observation from a selected sample to Telegram.
|
|
12
|
+
|
|
13
|
+
## What does it do?
|
|
14
|
+
|
|
15
|
+
+ Obtains a sample via the [iNaturalist API](https://api.inaturalist.org/v2/docs/#/Observations/get_observations) based on an arbitrary query (supported by the API).
|
|
16
|
+
|
|
17
|
+
+ Sends a random observation from the sample to a specified Telegram channel, excluding those already sent. If there are no new observations in the fresh sample, it takes from a saved pool.
|
|
18
|
+
|
|
19
|
+
+ Saves unsent observations obtained via the query into the pool.
|
|
20
|
+
|
|
21
|
+
+ Taxon uniqueness and pool depth are configurable.
|
|
22
|
+
|
|
23
|
+
+ Sends a message to the administrator in case of failures.
|
|
24
|
+
|
|
25
|
+
## Installation and running
|
|
26
|
+
|
|
27
|
+
### Using Bundler
|
|
28
|
+
|
|
29
|
+
Create a `Gemfile` with the single line:
|
|
30
|
+
```
|
|
31
|
+
gem 'inat-channel', '~> 0.9.0'
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Run:
|
|
35
|
+
```
|
|
36
|
+
$ bundle install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Then use:
|
|
40
|
+
```
|
|
41
|
+
$ bundle exec inat-channel [options]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Manually
|
|
45
|
+
|
|
46
|
+
Install:
|
|
47
|
+
```
|
|
48
|
+
$ gem install inat-channel
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Run:
|
|
52
|
+
```
|
|
53
|
+
$ inat-channel [options]
|
|
54
|
+
```
|
|
9
55
|
|
|
10
|
-
|
|
56
|
+
There are few command line parameters, and all are optional:
|
|
11
57
|
|
|
12
|
-
|
|
58
|
+
```
|
|
59
|
+
$ inat-channel --help
|
|
60
|
+
Usage: inat-channel [options]
|
|
61
|
+
-c, --config FILE Config file (default: inat-channel.yml)
|
|
62
|
+
-l, --log-level LEVEL Log level (default: warn)
|
|
63
|
+
--debug Set log level to debug
|
|
64
|
+
--version Show version info and exit
|
|
65
|
+
-h, --help Show help and exit
|
|
66
|
+
```
|
|
13
67
|
|
|
14
|
-
##
|
|
68
|
+
## Configuration
|
|
15
69
|
|
|
16
|
-
|
|
17
|
-
- Очередь публикаций с приоритетом свежих наблюдений, затем пулом и архивом отправленных (без дубликатов).
|
|
18
|
-
- Поддержка до 10 фотографий и геолокационных ссылок в одном посте.
|
|
19
|
-
- Вывод эмодзи и хештегов, соответствующих иерархии таксонов.
|
|
20
|
-
- Автоматическая генерация ссылок на проекты и места из настройки.
|
|
21
|
-
- Механизм блокировки для безопасного параллельного запуска.
|
|
22
|
-
- Автоматические повторы запросов, уведомления администратору, логирование.
|
|
70
|
+
Main settings are described in a YAML configuration file. Optionally, you can specify an ERB message template and extract the `places` group of settings (see below) into a separate YAML file.
|
|
23
71
|
|
|
24
|
-
|
|
72
|
+
Most settings have default values and may be omitted, but some are mandatory.
|
|
25
73
|
|
|
26
|
-
|
|
27
|
-
# 1. Установка
|
|
28
|
-
bundle install
|
|
74
|
+
### Environment variables
|
|
29
75
|
|
|
30
|
-
|
|
31
|
-
|
|
76
|
+
Additionally, **two mandatory parameters** must be set **in environment variables**: `TELEGRAM_BOT_TOKEN` is responsible for the Telegram bot token,
|
|
77
|
+
which is issued during creation via [@BotFather](https://t.me/BotFather) — you need to add this bot (your bot) to your channel as an admin
|
|
78
|
+
and give it rights to post messages; in the `ADMIN_TELEGRAM_ID` variable, specify your personal ID — notifications will be sent to it.
|
|
79
|
+
You can find this ID using the bot [@Getmyid_bot](https://t.me/Getmyid_bot). These parameters cannot be set in the config file for security reasons.
|
|
80
|
+
|
|
81
|
+
### Configuration file
|
|
82
|
+
|
|
83
|
+
Example:
|
|
84
|
+
```
|
|
32
85
|
base_query:
|
|
33
|
-
project_id:
|
|
86
|
+
project_id: 175821
|
|
87
|
+
locale: ru
|
|
34
88
|
popular: true
|
|
89
|
+
photo_license: 'cc-by,cc-by-nc,cc-by-nd,cc-by-sa,cc-by-nc-nd,cc-by-nc-sa,cc0'
|
|
35
90
|
quality_grade: research
|
|
91
|
+
|
|
92
|
+
days_back:
|
|
93
|
+
fresh: 30
|
|
94
|
+
pool: 180
|
|
95
|
+
sent: 181
|
|
96
|
+
used: 360
|
|
97
|
+
|
|
98
|
+
unique_taxon: priority
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
lock_file:
|
|
102
|
+
path: data/data.lock
|
|
103
|
+
ttl: 300
|
|
104
|
+
|
|
105
|
+
data_files:
|
|
106
|
+
root: data
|
|
107
|
+
pool: data/pool.json
|
|
108
|
+
sent: data/sent.json
|
|
109
|
+
used: data/used.json
|
|
110
|
+
|
|
111
|
+
api:
|
|
112
|
+
retries: 5
|
|
113
|
+
interval: 1.0
|
|
114
|
+
randomness: 0.5
|
|
115
|
+
backoff: 2
|
|
116
|
+
page_delay: 1.0
|
|
117
|
+
per_page: 200
|
|
118
|
+
|
|
119
|
+
tg_bot:
|
|
120
|
+
retries: 5
|
|
121
|
+
interval: 1.0
|
|
122
|
+
randomness: 0.5
|
|
123
|
+
backoff: 2
|
|
124
|
+
chat_id: '@<my_test_channel>'
|
|
125
|
+
template: message.erb
|
|
126
|
+
desc_limit: 512
|
|
127
|
+
link_zoom: 12
|
|
128
|
+
|
|
129
|
+
log_level: info
|
|
130
|
+
notify_level: warn
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
places: places.yml
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
This is a fully working (if you fix `tg_bot.chat_id`) but somewhat verbose config. Let's break down the parameters.
|
|
137
|
+
|
|
138
|
+
#### API query parameters
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
base_query:
|
|
142
|
+
project_id: 175821
|
|
36
143
|
locale: ru
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
144
|
+
popular: true
|
|
145
|
+
photo_license: 'cc-by,cc-by-nc,cc-by-nd,cc-by-sa,cc-by-nc-nd,cc-by-nc-sa,cc0'
|
|
146
|
+
quality_grade: research
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The composition of these parameters can be arbitrary but at least one must be specified. Some notes:
|
|
150
|
+
|
|
151
|
+
+ As `project_id` you can specify not only a numeric ID but also the project `slug`, which is easier to obtain — part of its URL.
|
|
41
152
|
|
|
42
|
-
|
|
43
|
-
export TELEGRAM_BOT_TOKEN="ваш_токен_бота"
|
|
44
|
-
export ADMIN_TELEGRAM_ID="ID_администратора_в_Telegram"
|
|
153
|
+
+ Locale affects taxon names; without it, English names are returned.
|
|
45
154
|
|
|
46
|
-
|
|
47
|
-
|
|
155
|
+
+ *It is strongly recommended to specify photo licenses*, otherwise the script may collect observations whose photos you do not have rights to redistribute.
|
|
156
|
+
|
|
157
|
+
+ Observations on iNaturalist vary in quality. The parameters `quality_grade: research` and `popular: true` do not guarantee anything but tend to improve the sample on average.
|
|
158
|
+
|
|
159
|
+
#### Recency parameters
|
|
48
160
|
|
|
49
|
-
# 5. Настройте cron для ежедневного запуска
|
|
50
|
-
echo "0 9 * * * cd /путь/к/проекту && bin/inat-channel -c config.yaml >> log/cron.log 2>&1" | crontab -
|
|
51
161
|
```
|
|
162
|
+
days_back:
|
|
163
|
+
fresh: 30
|
|
164
|
+
pool: 180
|
|
165
|
+
sent: 181
|
|
166
|
+
used: 360
|
|
52
167
|
|
|
53
|
-
|
|
168
|
+
unique_taxon: priority
|
|
169
|
+
```
|
|
54
170
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
171
|
+
Group of parameters controlling recency and data lifetime.
|
|
172
|
+
|
|
173
|
+
+ `days_back.fresh` is *mandatory* and defines how many days of data are requested each run.
|
|
174
|
+
You might want to reduce it according to the script run frequency, but keep in mind that to achieve `research` status,
|
|
175
|
+
and especially to be counted as popular (means at least one user favorited the observation), some extra time is needed.
|
|
176
|
+
Though 30 days may be too much, at least a week is recommended.
|
|
177
|
+
|
|
178
|
+
+ `days_back.pool` controls the age of observations in the pool. The pool is used if no fresh observations are available or all are already sent.
|
|
179
|
+
Observations older (in days) than this are removed from the pool. Default is `days_back.fresh * 3`. This parameter also controls initial pool fill on first run.
|
|
180
|
+
|
|
181
|
+
+ `days_back.sent` controls how long the list of sent observations is kept. Age is counted from the send date. It is recommended to set it equal
|
|
182
|
+
to `days_back.pool` or one day more, to avoid duplicates (they shouldn't get into the pool but just in case...). Default is `days_back.pool + 1`.
|
|
183
|
+
|
|
184
|
+
+ `days_back.used` controls how long information about *used taxa* is kept. Default is `365` days (1 year).
|
|
185
|
+
|
|
186
|
+
+ `unique_taxon` manages taxon uniqueness. Possible values:
|
|
64
187
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
188
|
+
+ `strict` — observations with the same taxon are not sent (and removed from pool);
|
|
189
|
+
|
|
190
|
+
+ `priority` — observations with taxa never sent before get priority;
|
|
191
|
+
|
|
192
|
+
+ `ignore` — uniqueness is ignored; taxon data is not saved.
|
|
193
|
+
|
|
194
|
+
Default is `ignore`.
|
|
195
|
+
|
|
196
|
+
#### File parameters
|
|
197
|
+
|
|
198
|
+
Data is stored across runs in several JSON files. Also, to avoid concurrent runs corrupting data, parallel execution is forbidden, controlled by a lock file.
|
|
69
199
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
200
|
+
```
|
|
201
|
+
lock_file:
|
|
202
|
+
path: data/data.lock
|
|
203
|
+
ttl: 300
|
|
204
|
+
|
|
205
|
+
data_files:
|
|
206
|
+
root: data
|
|
207
|
+
pool: data/pool.json
|
|
208
|
+
sent: data/sent.json
|
|
209
|
+
used: data/used.json
|
|
76
210
|
```
|
|
77
211
|
|
|
78
|
-
|
|
212
|
+
The `lock_file` group defines the lock file name and its TTL in seconds — after that, the lock file is considered expired, allowing a new run. This prevents permanent blocking in case of crashes (though most errors should delete the lock file anyway).
|
|
79
213
|
|
|
80
|
-
|
|
214
|
+
The `data_files` group sets data file locations. `data_files.root` can specify a root folder for all data files without individual paths. In the example, `root` is unused since absolute paths are given.
|
|
81
215
|
|
|
82
|
-
|
|
83
|
-
config/
|
|
84
|
-
├── moscow.yaml # данные: data/moscow_pool.json + moscow.lock
|
|
85
|
-
└── spb.yaml # данные: data/spb_pool.json + spb.lock
|
|
216
|
+
#### Service parameters
|
|
86
217
|
|
|
87
|
-
bin/inat-channel -c config/moscow.yaml &
|
|
88
|
-
bin/inat-channel -c config/spb.yaml &
|
|
89
218
|
```
|
|
219
|
+
api:
|
|
220
|
+
retries: 5
|
|
221
|
+
interval: 1.0
|
|
222
|
+
randomness: 0.5
|
|
223
|
+
backoff: 2
|
|
224
|
+
page_delay: 1.0
|
|
225
|
+
per_page: 200
|
|
226
|
+
|
|
227
|
+
tg_bot:
|
|
228
|
+
retries: 5
|
|
229
|
+
interval: 1.0
|
|
230
|
+
randomness: 0.5
|
|
231
|
+
backoff: 2
|
|
232
|
+
chat_id: '@<my_test_channel>'
|
|
233
|
+
template: message.erb
|
|
234
|
+
desc_limit: 512
|
|
235
|
+
link_zoom: 12
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
These two groups control interaction with **[iNaturalist API v2](https://api.inaturalist.org/v2/docs/)** and **[Telegram Bot API](https://core.telegram.org/bots/api)**.
|
|
239
|
+
|
|
240
|
+
The first four keys in each group are identical and configure [`faraday-retry`](https://github.com/lostisland/faraday-retry), handling retries on errors. Defaults shown above can be changed for fine tuning but usually aren't needed.
|
|
241
|
+
|
|
242
|
+
iNaturalist API has rate limits; `api.page_delay` adds a delay between normal requests (not retries). Parameter `api.per_page` sets the number of items per request; 200 is the maximum. Adjust these only if iNaturalist changes API conditions.
|
|
243
|
+
|
|
244
|
+
Additional parameters in `tg_bot`:
|
|
90
245
|
|
|
91
|
-
|
|
246
|
+
+ `chat_id` — channel ID where messages will be sent.
|
|
92
247
|
|
|
93
|
-
|
|
248
|
+
+ `template` — [ERB](https://docs.ruby-lang.org/en/3.4/ERB.html) message template, explained below.
|
|
249
|
+
|
|
250
|
+
+ `desc_limit` — limits the `description` field length to fit Telegram limits. Reduce it if your template adds more text.
|
|
251
|
+
|
|
252
|
+
+ `link_zoom` — zoom level applied in map service links.
|
|
253
|
+
|
|
254
|
+
#### Logging and notifications
|
|
255
|
+
|
|
256
|
+
Two parameters:
|
|
94
257
|
|
|
95
258
|
```
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
│ ├── pool.json # Кэш новых UUID объектов для публикации
|
|
99
|
-
│ ├── sent.json # UUID уже опубликованных объектов + id сообщений Telegram
|
|
100
|
-
│ └── bot.lock # Лок-файл блокировки работы бота
|
|
101
|
-
├── log/ # Логи запуска бота
|
|
102
|
-
└── bin/inat-channel # Основной исполняемый файл бота
|
|
259
|
+
log_level: info
|
|
260
|
+
notify_level: warn
|
|
103
261
|
```
|
|
104
262
|
|
|
105
|
-
|
|
263
|
+
+ `log_level` replicates command line `--log-level` (command line has priority).
|
|
106
264
|
|
|
107
|
-
|
|
108
|
-
- Автоудаление устаревших блокировок.
|
|
109
|
-
- Завершение по сигналам INT и TERM (graceful shutdown).
|
|
110
|
-
- Ошибка, если бот уже запущен с тем же конфигом.
|
|
265
|
+
+ `notify_level` similarly controls admin notification levels. Currently not implemented; notification cases are hardcoded.
|
|
111
266
|
|
|
112
|
-
|
|
267
|
+
#### Places
|
|
113
268
|
|
|
114
|
-
```bash
|
|
115
|
-
$ bin/inat-channel -c config.yaml # PID 12345 захватил lock
|
|
116
|
-
$ bin/inat-channel -c config.yaml # Ошибка: процесс с PID 12345 уже запущен
|
|
117
269
|
```
|
|
270
|
+
places: places.yml
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
In the example, places are extracted to a separate file. This is handy because place settings can be large and reusable across configs.
|
|
118
274
|
|
|
119
|
-
|
|
275
|
+
Example `places.yml` looks like:
|
|
120
276
|
|
|
121
277
|
```
|
|
122
|
-
|
|
278
|
+
regions:
|
|
279
|
+
- place_ids: [ 139490 ]
|
|
280
|
+
link: https://www.inaturalist.org/places/139490
|
|
281
|
+
text: Sverdlovsk Oblast
|
|
282
|
+
tag: SV
|
|
283
|
+
- place_ids: [ 139365 ]
|
|
284
|
+
link: https://www.inaturalist.org/places/139365
|
|
285
|
+
text: Republic of Bashkortostan
|
|
286
|
+
tag: BK
|
|
287
|
+
- place_ids: [ 139506 ]
|
|
288
|
+
link: https://www.inaturalist.org/places/139506
|
|
289
|
+
text: Chelyabinsk Oblast
|
|
290
|
+
tag: CL
|
|
291
|
+
- place_ids: [ 139361 ]
|
|
292
|
+
link: https://www.inaturalist.org/places/139361
|
|
293
|
+
text: Perm Krai
|
|
294
|
+
tag: PE
|
|
295
|
+
- place_ids: [ 139358 ]
|
|
296
|
+
link: https://www.inaturalist.org/places/139358
|
|
297
|
+
text: Orenburg Oblast
|
|
298
|
+
tag: OB
|
|
299
|
+
- place_ids: [ 12867 ]
|
|
300
|
+
link: https://www.inaturalist.org/places/12867
|
|
301
|
+
text: Khanty-Mansi Autonomous Okrug
|
|
302
|
+
tag: KM
|
|
303
|
+
- place_ids: [ 11809 ]
|
|
304
|
+
link: https://www.inaturalist.org/places/11809
|
|
305
|
+
text: Komi Republic
|
|
306
|
+
tag: KO
|
|
307
|
+
- place_ids: [ 13219 ]
|
|
308
|
+
link: https://www.inaturalist.org/places/13219
|
|
309
|
+
text: Yamalo-Nenets Autonomous Okrug
|
|
310
|
+
tag: YN
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
A few words on why this is needed. iNaturalist defines many territories, each observation belongs to several. These places vary in quality and purpose of tagging, so it's uninteresting to show them all. But some are worth highlighting. For that, we specify a selected list.
|
|
314
|
+
|
|
315
|
+
The list is split into groups. The example has one group — `regions`, but there can be several: e.g., one for administrative/municipal units, another for protected areas, parks, etc. Options vary.
|
|
123
316
|
|
|
124
|
-
|
|
317
|
+
The script iterates over this list and, if it finds an intersection between the observation's `place_ids` and the list's `place_ids`, it adds a corresponding item (with `link`, `text`, and `tag`) internally for the template. From each group, only one place max is added; groups are independent. So the max places listed equals the number of groups configured.
|
|
125
318
|
|
|
126
|
-
|
|
319
|
+
If you do not use a separate file, the whole structure should be nested under the `places` parameter with proper indentation.
|
|
127
320
|
|
|
128
|
-
|
|
321
|
+
## Message template
|
|
322
|
+
|
|
323
|
+
As mentioned, you can specify an ERB message template in the config. If not provided, a builtin default template is used:
|
|
129
324
|
|
|
130
|
-
#Animalia • #Aves • #Pyrrhula_pyrrhula
|
|
131
325
|
```
|
|
326
|
+
<%= taxon.icon %> <a href="<%= taxon.url %>"><%= taxon.title %></a>
|
|
327
|
+
|
|
132
328
|
|
|
133
|
-
|
|
329
|
+
<%= observation.icon %> <%= observation.url %>
|
|
330
|
+
<%= datetime.icon %> <%= datetime %>
|
|
331
|
+
<%= user.icon %> <a href="<%= user.url %>"><%= user.title %></a>
|
|
332
|
+
<% if observation.description -%>
|
|
333
|
+
<blockquote><%= observation.description.text %></blockquote>
|
|
334
|
+
<% end -%>
|
|
134
335
|
|
|
135
|
-
```bash
|
|
136
|
-
bin/inat-channel --help
|
|
137
336
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
#
|
|
337
|
+
<%= location.icon %> <%= location.dms %> - <a href="<%= location.google %>">G</a> <a href="<%= location.osm %>">OSM</a>
|
|
338
|
+
<% if places && places.size > 0 -%>
|
|
339
|
+
<% places.each do |place| -%>
|
|
340
|
+
<%= place.icon %> <a href="<%= place.link %>"><%= place.text %></a> <%= '• #' + place.tag if place.tag %>
|
|
341
|
+
<% end -%>
|
|
342
|
+
<% else -%>
|
|
343
|
+
<%= icons[:place] %> <%= observation.place_guess %>
|
|
344
|
+
<% end -%>
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
<%= taxon.to_tags&.join(' • ') %>
|
|
142
348
|
```
|
|
143
349
|
|
|
144
|
-
|
|
350
|
+
[<img align="right" width="40%" src="example.png">](example.png)
|
|
351
|
+
|
|
352
|
+
This template uses many emojis, which may look gaudy but makes it language-independent. You will most likely want to use your own template for your channel.
|
|
353
|
+
[An example](https://github.com/inat-get/channel-ural/blob/main/message.erb) is available in the [`channel-ural`](https://github.com/inat-get/channel-ural) project.
|
|
354
|
+
|
|
355
|
+
The template variables (standard or immutable data classes) are:
|
|
356
|
+
|
|
357
|
+
+ `observation`: `Observation`
|
|
358
|
+
+ `datetime`: `DateTime` = `observation.datetime`
|
|
359
|
+
+ `date`: `Date` = `observation.date` (= `datetime.to_date`)
|
|
360
|
+
+ `location`: `Location` = `observation.location`
|
|
361
|
+
+ `places`: `Array<Place>` = `observation.places`
|
|
362
|
+
+ `taxon`: `Taxon` = `observation.taxon`
|
|
363
|
+
+ `user`: `User` = `observation.user`
|
|
364
|
+
+ `icons`: `Hash` — emoji set for icons
|
|
365
|
+
+ `taxa_icons`: `Hash` — emoji set for taxon icons, selected bottom-up by hierarchy
|
|
366
|
+
+ `data`: `Hash` — template data — you can specify front-matter in YAML format for your custom template, passed here; you can also override `icons` and `taxa_icons`.
|
|
367
|
+
+ `config`: `Hash` — configuration data
|
|
368
|
+
|
|
369
|
+
Data class definitions are in [`data_types.rb`](https://github.com/inat-get/inat-channel/blob/next/lib/inat-channel/data_types.rb).
|
|
370
|
+
|
|
371
|
+
## Usage example
|
|
372
|
+
|
|
373
|
+
The script fully supports GitHub Actions. See how it works in the [`inat-get/channel-ural`](https://github.com/inat-get/channel-ural) project.
|
|
374
|
+
It contains four configs and four workflows that run them, to post different observation categories at different times.
|
|
375
|
+
|
|
376
|
+
## Version
|
|
377
|
+
|
|
378
|
+
+ **0.9.0** can be considered a beta or pre-release version. After some improvements, version 1.0 will be released.
|
|
145
379
|
|
|
146
|
-
|
|
147
|
-
- [Faraday HTTP Client](https://github.com/lostisland/faraday)
|
|
380
|
+
## License
|
|
148
381
|
|
|
149
|
-
|
|
382
|
+
+ **[GNU GPL v3+](LICENSE)**,
|
|
150
383
|
|
data/bin/inat-channel
CHANGED
|
@@ -1,29 +1,28 @@
|
|
|
1
1
|
#!/usr/bin/ruby
|
|
2
2
|
require_relative '../lib/inat-channel'
|
|
3
|
-
include
|
|
3
|
+
include IC
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
logger.info "=== iNatChannel Run ==="
|
|
6
6
|
|
|
7
|
-
news =
|
|
8
|
-
|
|
7
|
+
news = load_news
|
|
8
|
+
logger.info "Found #{ news.size } fresh UUIDs (days_back=#{ CONFIG.dig :days_back, :fresh })"
|
|
9
9
|
|
|
10
|
-
uuid =
|
|
10
|
+
uuid = select_uuid news
|
|
11
11
|
|
|
12
12
|
if uuid
|
|
13
|
-
obs =
|
|
13
|
+
obs = load_observation(uuid)
|
|
14
14
|
if obs
|
|
15
|
-
msg_id =
|
|
16
|
-
|
|
17
|
-
INCh::LOGGER.info "Posted #{obs[:id]} (#{INCh::Message::list_photos(obs).size} photos)" # очень плохо, не должно быть тут вызова list_photos
|
|
15
|
+
msg_id = send_observation(obs)
|
|
16
|
+
IC::confirm_sending! msg_id
|
|
18
17
|
else
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
18
|
+
IC::revert_sending!
|
|
19
|
+
logger.warn "Failed to load #{uuid} — returning to pool"
|
|
20
|
+
notify_admin "Failed to load #{uuid} — returning to pool"
|
|
22
21
|
end
|
|
23
22
|
|
|
24
|
-
|
|
23
|
+
save_data
|
|
25
24
|
else
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
notify_admin 'No observation to send.'
|
|
26
|
+
logger.warn 'No observation to send.'
|
|
28
27
|
end
|
|
29
28
|
|