+24
.github/workflows/ci.yml
+24
.github/workflows/ci.yml
···
1
+
# Do not edit this file directly. It is generated by https://deno.land/x/fluent_github_actions
2
+
3
+
name: ci
4
+
on:
5
+
push:
6
+
branches:
7
+
- master
8
+
pull_request:
9
+
branches:
10
+
- master
11
+
jobs:
12
+
tests:
13
+
runs-on: ubuntu-22.04
14
+
steps:
15
+
- uses: actions/checkout@v2
16
+
- name: Install build dependencies
17
+
run: |
18
+
sudo apt-get update
19
+
sudo apt-get install -y build-essential libasound2-dev protobuf-compiler
20
+
- name: Setup Fluent CI
21
+
uses: fluentci-io/setup-fluentci@v5
22
+
- name: Run tests
23
+
run: |
24
+
fluentci run --wasm rust test
+1
-1
.github/workflows/release-for-mac.yml
+1
-1
.github/workflows/release-for-mac.yml
+1
-1
.github/workflows/release.yml
+1
-1
.github/workflows/release.yml
+818
-112
Cargo.lock
+818
-112
Cargo.lock
···
1
1
# This file is automatically @generated by Cargo.
2
2
# It is not intended for manual editing.
3
-
version = 3
3
+
version = 4
4
4
5
5
[[package]]
6
6
name = "aead"
···
69
69
]
70
70
71
71
[[package]]
72
+
name = "aho-corasick"
73
+
version = "1.1.3"
74
+
source = "registry+https://github.com/rust-lang/crates.io-index"
75
+
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
76
+
dependencies = [
77
+
"memchr",
78
+
]
79
+
80
+
[[package]]
72
81
name = "allocator-api2"
73
82
version = "0.2.16"
74
83
source = "registry+https://github.com/rust-lang/crates.io-index"
···
97
106
]
98
107
99
108
[[package]]
109
+
name = "android-tzdata"
110
+
version = "0.1.1"
111
+
source = "registry+https://github.com/rust-lang/crates.io-index"
112
+
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
113
+
114
+
[[package]]
115
+
name = "android_system_properties"
116
+
version = "0.1.5"
117
+
source = "registry+https://github.com/rust-lang/crates.io-index"
118
+
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
119
+
dependencies = [
120
+
"libc",
121
+
]
122
+
123
+
[[package]]
100
124
name = "anyhow"
101
125
version = "1.0.69"
102
126
source = "registry+https://github.com/rust-lang/crates.io-index"
···
115
139
checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
116
140
117
141
[[package]]
142
+
name = "async-attributes"
143
+
version = "1.1.2"
144
+
source = "registry+https://github.com/rust-lang/crates.io-index"
145
+
checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5"
146
+
dependencies = [
147
+
"quote",
148
+
"syn 1.0.107",
149
+
]
150
+
151
+
[[package]]
118
152
name = "async-channel"
119
153
version = "1.8.0"
120
154
source = "registry+https://github.com/rust-lang/crates.io-index"
···
162
196
"blocking",
163
197
"futures-lite",
164
198
"once_cell",
199
+
"tokio",
165
200
]
166
201
167
202
[[package]]
···
195
230
"parking",
196
231
"polling",
197
232
"slab",
198
-
"socket2",
233
+
"socket2 0.4.7",
199
234
"waker-fn",
200
235
"windows-sys 0.42.0",
201
236
]
···
211
246
]
212
247
213
248
[[package]]
249
+
name = "async-process"
250
+
version = "1.7.0"
251
+
source = "registry+https://github.com/rust-lang/crates.io-index"
252
+
checksum = "7a9d28b1d97e08915212e2e45310d47854eafa69600756fc735fb788f75199c9"
253
+
dependencies = [
254
+
"async-io",
255
+
"async-lock",
256
+
"autocfg",
257
+
"blocking",
258
+
"cfg-if",
259
+
"event-listener",
260
+
"futures-lite",
261
+
"rustix",
262
+
"signal-hook",
263
+
"windows-sys 0.48.0",
264
+
]
265
+
266
+
[[package]]
214
267
name = "async-std"
215
268
version = "1.12.0"
216
269
source = "registry+https://github.com/rust-lang/crates.io-index"
217
270
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
218
271
dependencies = [
272
+
"async-attributes",
219
273
"async-channel",
220
274
"async-global-executor",
221
275
"async-io",
222
276
"async-lock",
277
+
"async-process",
223
278
"crossbeam-utils",
224
279
"futures-channel",
225
280
"futures-core",
···
237
292
]
238
293
239
294
[[package]]
295
+
name = "async-std-resolver"
296
+
version = "0.24.2"
297
+
source = "registry+https://github.com/rust-lang/crates.io-index"
298
+
checksum = "fa5ee46ec0c518414838d2fdc7dd18f6ba7d934b6e728005c958621da450682d"
299
+
dependencies = [
300
+
"async-std",
301
+
"async-trait",
302
+
"futures-io",
303
+
"futures-util",
304
+
"hickory-resolver",
305
+
"pin-utils",
306
+
"socket2 0.5.8",
307
+
]
308
+
309
+
[[package]]
240
310
name = "async-stream"
241
311
version = "0.3.4"
242
312
source = "registry+https://github.com/rust-lang/crates.io-index"
···
273
343
"futures-core",
274
344
"futures-io",
275
345
"rustls 0.18.1",
276
-
"webpki 0.21.4",
346
+
"webpki",
277
347
"webpki-roots 0.20.0",
278
348
]
279
349
280
350
[[package]]
281
351
name = "async-trait"
282
-
version = "0.1.64"
352
+
version = "0.1.85"
283
353
source = "registry+https://github.com/rust-lang/crates.io-index"
284
-
checksum = "1cd7fce9ba8c3c042128ce72d8b2ddbf3a05747efb67ea0313c635e10bda47a2"
354
+
checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056"
285
355
dependencies = [
286
356
"proc-macro2",
287
357
"quote",
288
-
"syn 1.0.107",
358
+
"syn 2.0.51",
289
359
]
290
360
291
361
[[package]]
···
329
399
"matchit",
330
400
"memchr",
331
401
"mime",
332
-
"percent-encoding 2.2.0",
402
+
"percent-encoding 2.3.1",
333
403
"pin-project-lite",
334
404
"rustversion",
335
405
"serde",
···
506
576
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
507
577
508
578
[[package]]
579
+
name = "chrono"
580
+
version = "0.4.39"
581
+
source = "registry+https://github.com/rust-lang/crates.io-index"
582
+
checksum = "7e36cc9d416881d2e24f9a963be5fb1cd90966419ac844274161d10488b3e825"
583
+
dependencies = [
584
+
"android-tzdata",
585
+
"iana-time-zone",
586
+
"js-sys",
587
+
"num-traits",
588
+
"serde",
589
+
"wasm-bindgen",
590
+
"windows-targets 0.52.6",
591
+
]
592
+
593
+
[[package]]
509
594
name = "cipher"
510
595
version = "0.2.5"
511
596
source = "registry+https://github.com/rust-lang/crates.io-index"
···
620
705
"base64 0.13.1",
621
706
"hkdf",
622
707
"hmac",
623
-
"percent-encoding 2.2.0",
708
+
"percent-encoding 2.3.1",
624
709
"rand 0.8.5",
625
710
"sha2",
626
711
"time",
···
628
713
]
629
714
630
715
[[package]]
716
+
name = "core-foundation"
717
+
version = "0.9.3"
718
+
source = "registry+https://github.com/rust-lang/crates.io-index"
719
+
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
720
+
dependencies = [
721
+
"core-foundation-sys",
722
+
"libc",
723
+
]
724
+
725
+
[[package]]
631
726
name = "core-foundation-sys"
632
727
version = "0.8.3"
633
728
source = "registry+https://github.com/rust-lang/crates.io-index"
···
746
841
]
747
842
748
843
[[package]]
749
-
name = "ctor"
750
-
version = "0.1.26"
751
-
source = "registry+https://github.com/rust-lang/crates.io-index"
752
-
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
753
-
dependencies = [
754
-
"quote",
755
-
"syn 1.0.107",
756
-
]
757
-
758
-
[[package]]
759
844
name = "ctr"
760
845
version = "0.6.0"
761
846
source = "registry+https://github.com/rust-lang/crates.io-index"
···
782
867
"once_cell",
783
868
"parking_lot_core",
784
869
]
870
+
871
+
[[package]]
872
+
name = "data-encoding"
873
+
version = "2.7.0"
874
+
source = "registry+https://github.com/rust-lang/crates.io-index"
875
+
checksum = "0e60eed09d8c01d3cee5b7d30acb059b76614c918fa0f992e0dd6eeb10daad6f"
785
876
786
877
[[package]]
787
878
name = "deadpool"
···
826
917
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
827
918
828
919
[[package]]
920
+
name = "displaydoc"
921
+
version = "0.2.5"
922
+
source = "registry+https://github.com/rust-lang/crates.io-index"
923
+
checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
924
+
dependencies = [
925
+
"proc-macro2",
926
+
"quote",
927
+
"syn 2.0.51",
928
+
]
929
+
930
+
[[package]]
829
931
name = "either"
830
932
version = "1.8.1"
831
933
source = "registry+https://github.com/rust-lang/crates.io-index"
···
841
943
]
842
944
843
945
[[package]]
946
+
name = "enum-as-inner"
947
+
version = "0.6.1"
948
+
source = "registry+https://github.com/rust-lang/crates.io-index"
949
+
checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc"
950
+
dependencies = [
951
+
"heck 0.5.0",
952
+
"proc-macro2",
953
+
"quote",
954
+
"syn 2.0.51",
955
+
]
956
+
957
+
[[package]]
958
+
name = "errno"
959
+
version = "0.3.10"
960
+
source = "registry+https://github.com/rust-lang/crates.io-index"
961
+
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
962
+
dependencies = [
963
+
"libc",
964
+
"windows-sys 0.59.0",
965
+
]
966
+
967
+
[[package]]
844
968
name = "event-listener"
845
969
version = "2.5.3"
846
970
source = "registry+https://github.com/rust-lang/crates.io-index"
···
869
993
870
994
[[package]]
871
995
name = "form_urlencoded"
872
-
version = "1.1.0"
996
+
version = "1.2.1"
873
997
source = "registry+https://github.com/rust-lang/crates.io-index"
874
-
checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
998
+
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
875
999
dependencies = [
876
-
"percent-encoding 2.2.0",
1000
+
"percent-encoding 2.3.1",
877
1001
]
878
1002
879
1003
[[package]]
···
1082
1206
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
1083
1207
1084
1208
[[package]]
1209
+
name = "heck"
1210
+
version = "0.5.0"
1211
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1212
+
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
1213
+
1214
+
[[package]]
1085
1215
name = "hermit-abi"
1086
1216
version = "0.1.19"
1087
1217
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1100
1230
]
1101
1231
1102
1232
[[package]]
1233
+
name = "hermit-abi"
1234
+
version = "0.3.9"
1235
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1236
+
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
1237
+
1238
+
[[package]]
1239
+
name = "hickory-proto"
1240
+
version = "0.24.2"
1241
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1242
+
checksum = "447afdcdb8afb9d0a852af6dc65d9b285ce720ed7a59e42a8bf2e931c67bc1b5"
1243
+
dependencies = [
1244
+
"async-trait",
1245
+
"cfg-if",
1246
+
"data-encoding",
1247
+
"enum-as-inner",
1248
+
"futures-channel",
1249
+
"futures-io",
1250
+
"futures-util",
1251
+
"idna 1.0.3",
1252
+
"ipnet",
1253
+
"once_cell",
1254
+
"rand 0.8.5",
1255
+
"thiserror",
1256
+
"tinyvec",
1257
+
"tracing",
1258
+
"url 2.5.4",
1259
+
]
1260
+
1261
+
[[package]]
1262
+
name = "hickory-resolver"
1263
+
version = "0.24.2"
1264
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1265
+
checksum = "0a2e2aba9c389ce5267d31cf1e4dace82390ae276b0b364ea55630b1fa1b44b4"
1266
+
dependencies = [
1267
+
"cfg-if",
1268
+
"futures-util",
1269
+
"hickory-proto",
1270
+
"ipconfig",
1271
+
"lru-cache",
1272
+
"once_cell",
1273
+
"parking_lot",
1274
+
"rand 0.8.5",
1275
+
"resolv-conf",
1276
+
"smallvec",
1277
+
"thiserror",
1278
+
"tracing",
1279
+
]
1280
+
1281
+
[[package]]
1103
1282
name = "hkdf"
1104
1283
version = "0.10.0"
1105
1284
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1117
1296
dependencies = [
1118
1297
"crypto-mac",
1119
1298
"digest",
1299
+
]
1300
+
1301
+
[[package]]
1302
+
name = "hostname"
1303
+
version = "0.3.1"
1304
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1305
+
checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867"
1306
+
dependencies = [
1307
+
"libc",
1308
+
"match_cfg",
1309
+
"winapi",
1120
1310
]
1121
1311
1122
1312
[[package]]
···
1191
1381
"serde_json",
1192
1382
"serde_qs",
1193
1383
"serde_urlencoded",
1194
-
"url 2.3.1",
1384
+
"url 2.5.4",
1195
1385
]
1196
1386
1197
1387
[[package]]
···
1223
1413
"httpdate",
1224
1414
"itoa",
1225
1415
"pin-project-lite",
1226
-
"socket2",
1416
+
"socket2 0.4.7",
1227
1417
"tokio",
1228
1418
"tower-service",
1229
1419
"tracing",
···
1232
1422
1233
1423
[[package]]
1234
1424
name = "hyper-rustls"
1235
-
version = "0.23.2"
1425
+
version = "0.24.2"
1236
1426
source = "registry+https://github.com/rust-lang/crates.io-index"
1237
-
checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
1427
+
checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
1238
1428
dependencies = [
1429
+
"futures-util",
1239
1430
"http",
1240
1431
"hyper",
1241
-
"rustls 0.20.9",
1432
+
"rustls 0.21.12",
1242
1433
"tokio",
1243
1434
"tokio-rustls",
1244
1435
]
···
1256
1447
]
1257
1448
1258
1449
[[package]]
1450
+
name = "iana-time-zone"
1451
+
version = "0.1.61"
1452
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1453
+
checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220"
1454
+
dependencies = [
1455
+
"android_system_properties",
1456
+
"core-foundation-sys",
1457
+
"iana-time-zone-haiku",
1458
+
"js-sys",
1459
+
"wasm-bindgen",
1460
+
"windows-core",
1461
+
]
1462
+
1463
+
[[package]]
1464
+
name = "iana-time-zone-haiku"
1465
+
version = "0.1.2"
1466
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1467
+
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
1468
+
dependencies = [
1469
+
"cc",
1470
+
]
1471
+
1472
+
[[package]]
1473
+
name = "icu_collections"
1474
+
version = "1.5.0"
1475
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1476
+
checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526"
1477
+
dependencies = [
1478
+
"displaydoc",
1479
+
"yoke",
1480
+
"zerofrom",
1481
+
"zerovec",
1482
+
]
1483
+
1484
+
[[package]]
1485
+
name = "icu_locid"
1486
+
version = "1.5.0"
1487
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1488
+
checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637"
1489
+
dependencies = [
1490
+
"displaydoc",
1491
+
"litemap",
1492
+
"tinystr",
1493
+
"writeable",
1494
+
"zerovec",
1495
+
]
1496
+
1497
+
[[package]]
1498
+
name = "icu_locid_transform"
1499
+
version = "1.5.0"
1500
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1501
+
checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e"
1502
+
dependencies = [
1503
+
"displaydoc",
1504
+
"icu_locid",
1505
+
"icu_locid_transform_data",
1506
+
"icu_provider",
1507
+
"tinystr",
1508
+
"zerovec",
1509
+
]
1510
+
1511
+
[[package]]
1512
+
name = "icu_locid_transform_data"
1513
+
version = "1.5.0"
1514
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1515
+
checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e"
1516
+
1517
+
[[package]]
1518
+
name = "icu_normalizer"
1519
+
version = "1.5.0"
1520
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1521
+
checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f"
1522
+
dependencies = [
1523
+
"displaydoc",
1524
+
"icu_collections",
1525
+
"icu_normalizer_data",
1526
+
"icu_properties",
1527
+
"icu_provider",
1528
+
"smallvec",
1529
+
"utf16_iter",
1530
+
"utf8_iter",
1531
+
"write16",
1532
+
"zerovec",
1533
+
]
1534
+
1535
+
[[package]]
1536
+
name = "icu_normalizer_data"
1537
+
version = "1.5.0"
1538
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1539
+
checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516"
1540
+
1541
+
[[package]]
1542
+
name = "icu_properties"
1543
+
version = "1.5.1"
1544
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1545
+
checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5"
1546
+
dependencies = [
1547
+
"displaydoc",
1548
+
"icu_collections",
1549
+
"icu_locid_transform",
1550
+
"icu_properties_data",
1551
+
"icu_provider",
1552
+
"tinystr",
1553
+
"zerovec",
1554
+
]
1555
+
1556
+
[[package]]
1557
+
name = "icu_properties_data"
1558
+
version = "1.5.0"
1559
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1560
+
checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569"
1561
+
1562
+
[[package]]
1563
+
name = "icu_provider"
1564
+
version = "1.5.0"
1565
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1566
+
checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9"
1567
+
dependencies = [
1568
+
"displaydoc",
1569
+
"icu_locid",
1570
+
"icu_provider_macros",
1571
+
"stable_deref_trait",
1572
+
"tinystr",
1573
+
"writeable",
1574
+
"yoke",
1575
+
"zerofrom",
1576
+
"zerovec",
1577
+
]
1578
+
1579
+
[[package]]
1580
+
name = "icu_provider_macros"
1581
+
version = "1.5.0"
1582
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1583
+
checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
1584
+
dependencies = [
1585
+
"proc-macro2",
1586
+
"quote",
1587
+
"syn 2.0.51",
1588
+
]
1589
+
1590
+
[[package]]
1259
1591
name = "idna"
1260
1592
version = "0.1.5"
1261
1593
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1268
1600
1269
1601
[[package]]
1270
1602
name = "idna"
1271
-
version = "0.3.0"
1603
+
version = "1.0.3"
1604
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1605
+
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
1606
+
dependencies = [
1607
+
"idna_adapter",
1608
+
"smallvec",
1609
+
"utf8_iter",
1610
+
]
1611
+
1612
+
[[package]]
1613
+
name = "idna_adapter"
1614
+
version = "1.2.0"
1272
1615
source = "registry+https://github.com/rust-lang/crates.io-index"
1273
-
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
1616
+
checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71"
1274
1617
dependencies = [
1275
-
"unicode-bidi",
1276
-
"unicode-normalization",
1618
+
"icu_normalizer",
1619
+
"icu_properties",
1277
1620
]
1278
1621
1279
1622
[[package]]
···
1308
1651
]
1309
1652
1310
1653
[[package]]
1654
+
name = "io-lifetimes"
1655
+
version = "1.0.11"
1656
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1657
+
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
1658
+
dependencies = [
1659
+
"hermit-abi 0.3.9",
1660
+
"libc",
1661
+
"windows-sys 0.48.0",
1662
+
]
1663
+
1664
+
[[package]]
1665
+
name = "ipconfig"
1666
+
version = "0.3.2"
1667
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1668
+
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
1669
+
dependencies = [
1670
+
"socket2 0.5.8",
1671
+
"widestring",
1672
+
"windows-sys 0.48.0",
1673
+
"winreg",
1674
+
]
1675
+
1676
+
[[package]]
1311
1677
name = "ipnet"
1312
1678
version = "2.7.1"
1313
1679
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1368
1734
1369
1735
[[package]]
1370
1736
name = "js-sys"
1371
-
version = "0.3.61"
1737
+
version = "0.3.77"
1372
1738
source = "registry+https://github.com/rust-lang/crates.io-index"
1373
-
checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
1739
+
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f"
1374
1740
dependencies = [
1741
+
"once_cell",
1375
1742
"wasm-bindgen",
1376
1743
]
1377
1744
···
1422
1789
1423
1790
[[package]]
1424
1791
name = "libc"
1425
-
version = "0.2.139"
1792
+
version = "0.2.169"
1426
1793
source = "registry+https://github.com/rust-lang/crates.io-index"
1427
-
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
1794
+
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
1428
1795
1429
1796
[[package]]
1430
1797
name = "libloading"
···
1437
1804
]
1438
1805
1439
1806
[[package]]
1807
+
name = "linked-hash-map"
1808
+
version = "0.5.6"
1809
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1810
+
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
1811
+
1812
+
[[package]]
1813
+
name = "linux-raw-sys"
1814
+
version = "0.3.8"
1815
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1816
+
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
1817
+
1818
+
[[package]]
1819
+
name = "litemap"
1820
+
version = "0.7.4"
1821
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1822
+
checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
1823
+
1824
+
[[package]]
1440
1825
name = "lock_api"
1441
1826
version = "0.4.9"
1442
1827
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1448
1833
1449
1834
[[package]]
1450
1835
name = "log"
1451
-
version = "0.4.17"
1836
+
version = "0.4.25"
1452
1837
source = "registry+https://github.com/rust-lang/crates.io-index"
1453
-
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
1838
+
checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f"
1454
1839
dependencies = [
1455
-
"cfg-if",
1456
1840
"value-bag",
1457
1841
]
1458
1842
···
1466
1850
]
1467
1851
1468
1852
[[package]]
1853
+
name = "lru-cache"
1854
+
version = "0.1.2"
1855
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1856
+
checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c"
1857
+
dependencies = [
1858
+
"linked-hash-map",
1859
+
]
1860
+
1861
+
[[package]]
1469
1862
name = "m3u"
1470
1863
version = "1.0.0"
1471
1864
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1484
1877
]
1485
1878
1486
1879
[[package]]
1880
+
name = "match_cfg"
1881
+
version = "0.1.0"
1882
+
source = "registry+https://github.com/rust-lang/crates.io-index"
1883
+
checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4"
1884
+
1885
+
[[package]]
1487
1886
name = "matches"
1488
1887
version = "0.1.10"
1489
1888
source = "registry+https://github.com/rust-lang/crates.io-index"
···
1497
1896
1498
1897
[[package]]
1499
1898
name = "memchr"
1500
-
version = "2.5.0"
1899
+
version = "2.7.4"
1501
1900
source = "registry+https://github.com/rust-lang/crates.io-index"
1502
-
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
1901
+
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
1503
1902
1504
1903
[[package]]
1505
1904
name = "memoffset"
···
1844
2243
1845
2244
[[package]]
1846
2245
name = "percent-encoding"
1847
-
version = "2.2.0"
2246
+
version = "2.3.1"
1848
2247
source = "registry+https://github.com/rust-lang/crates.io-index"
1849
-
checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
2248
+
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
1850
2249
1851
2250
[[package]]
1852
2251
name = "petgraph"
···
1997
2396
checksum = "2c828f93f5ca4826f97fedcbd3f9a536c16b12cff3dbbb4a007f932bbad95b12"
1998
2397
dependencies = [
1999
2398
"bytes",
2000
-
"heck",
2399
+
"heck 0.4.1",
2001
2400
"itertools 0.10.5",
2002
2401
"lazy_static",
2003
2402
"log",
···
2035
2434
]
2036
2435
2037
2436
[[package]]
2437
+
name = "quick-error"
2438
+
version = "1.2.3"
2439
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2440
+
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
2441
+
2442
+
[[package]]
2038
2443
name = "quote"
2039
2444
version = "1.0.35"
2040
2445
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2044
2449
]
2045
2450
2046
2451
[[package]]
2452
+
name = "radiobrowser"
2453
+
version = "0.6.1"
2454
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2455
+
checksum = "763ad5f847e3d2e3221dac4e87370297a970e3f9eb8f2760b915001b9c79023b"
2456
+
dependencies = [
2457
+
"async-std",
2458
+
"async-std-resolver",
2459
+
"chrono",
2460
+
"log",
2461
+
"rand 0.8.5",
2462
+
"reqwest",
2463
+
"serde",
2464
+
]
2465
+
2466
+
[[package]]
2047
2467
name = "rand"
2048
2468
version = "0.7.3"
2049
2469
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2163
2583
2164
2584
[[package]]
2165
2585
name = "regex"
2166
-
version = "1.7.1"
2586
+
version = "1.11.1"
2167
2587
source = "registry+https://github.com/rust-lang/crates.io-index"
2168
-
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
2588
+
checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
2169
2589
dependencies = [
2590
+
"aho-corasick",
2591
+
"memchr",
2592
+
"regex-automata",
2593
+
"regex-syntax",
2594
+
]
2595
+
2596
+
[[package]]
2597
+
name = "regex-automata"
2598
+
version = "0.4.9"
2599
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2600
+
checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
2601
+
dependencies = [
2602
+
"aho-corasick",
2603
+
"memchr",
2170
2604
"regex-syntax",
2171
2605
]
2172
2606
2173
2607
[[package]]
2174
2608
name = "regex-syntax"
2175
-
version = "0.6.28"
2609
+
version = "0.8.5"
2176
2610
source = "registry+https://github.com/rust-lang/crates.io-index"
2177
-
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
2611
+
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
2178
2612
2179
2613
[[package]]
2180
2614
name = "remove_dir_all"
···
2187
2621
2188
2622
[[package]]
2189
2623
name = "reqwest"
2190
-
version = "0.11.14"
2624
+
version = "0.11.27"
2191
2625
source = "registry+https://github.com/rust-lang/crates.io-index"
2192
-
checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9"
2626
+
checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
2193
2627
dependencies = [
2194
2628
"base64 0.21.0",
2195
2629
"bytes",
···
2206
2640
"log",
2207
2641
"mime",
2208
2642
"once_cell",
2209
-
"percent-encoding 2.2.0",
2643
+
"percent-encoding 2.3.1",
2210
2644
"pin-project-lite",
2211
-
"rustls 0.20.9",
2645
+
"rustls 0.21.12",
2212
2646
"rustls-pemfile",
2213
2647
"serde",
2214
2648
"serde_json",
2215
2649
"serde_urlencoded",
2650
+
"sync_wrapper",
2651
+
"system-configuration",
2216
2652
"tokio",
2217
2653
"tokio-rustls",
2218
2654
"tower-service",
2219
-
"url 2.3.1",
2655
+
"url 2.5.4",
2220
2656
"wasm-bindgen",
2221
2657
"wasm-bindgen-futures",
2222
2658
"web-sys",
2223
-
"webpki-roots 0.22.6",
2659
+
"webpki-roots 0.25.4",
2224
2660
"winreg",
2661
+
]
2662
+
2663
+
[[package]]
2664
+
name = "resolv-conf"
2665
+
version = "0.7.0"
2666
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2667
+
checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00"
2668
+
dependencies = [
2669
+
"hostname",
2670
+
"quick-error",
2225
2671
]
2226
2672
2227
2673
[[package]]
···
2312
2758
]
2313
2759
2314
2760
[[package]]
2761
+
name = "rustix"
2762
+
version = "0.37.28"
2763
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2764
+
checksum = "519165d378b97752ca44bbe15047d5d3409e875f39327546b42ac81d7e18c1b6"
2765
+
dependencies = [
2766
+
"bitflags 1.3.2",
2767
+
"errno",
2768
+
"io-lifetimes",
2769
+
"libc",
2770
+
"linux-raw-sys",
2771
+
"windows-sys 0.48.0",
2772
+
]
2773
+
2774
+
[[package]]
2315
2775
name = "rustls"
2316
2776
version = "0.18.1"
2317
2777
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2321
2781
"log",
2322
2782
"ring 0.16.20",
2323
2783
"sct 0.6.1",
2324
-
"webpki 0.21.4",
2784
+
"webpki",
2325
2785
]
2326
2786
2327
2787
[[package]]
2328
2788
name = "rustls"
2329
-
version = "0.20.9"
2789
+
version = "0.21.12"
2330
2790
source = "registry+https://github.com/rust-lang/crates.io-index"
2331
-
checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99"
2791
+
checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e"
2332
2792
dependencies = [
2333
2793
"log",
2334
-
"ring 0.16.20",
2794
+
"ring 0.17.3",
2795
+
"rustls-webpki",
2335
2796
"sct 0.7.1",
2336
-
"webpki 0.22.4",
2337
2797
]
2338
2798
2339
2799
[[package]]
···
2346
2806
]
2347
2807
2348
2808
[[package]]
2809
+
name = "rustls-webpki"
2810
+
version = "0.101.7"
2811
+
source = "registry+https://github.com/rust-lang/crates.io-index"
2812
+
checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
2813
+
dependencies = [
2814
+
"ring 0.17.3",
2815
+
"untrusted 0.9.0",
2816
+
]
2817
+
2818
+
[[package]]
2349
2819
name = "rustversion"
2350
2820
version = "1.0.11"
2351
2821
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2450
2920
source = "registry+https://github.com/rust-lang/crates.io-index"
2451
2921
checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6"
2452
2922
dependencies = [
2453
-
"percent-encoding 2.2.0",
2923
+
"percent-encoding 2.3.1",
2454
2924
"serde",
2455
2925
"thiserror",
2456
2926
]
···
2562
3032
2563
3033
[[package]]
2564
3034
name = "smallvec"
2565
-
version = "1.10.0"
3035
+
version = "1.13.2"
2566
3036
source = "registry+https://github.com/rust-lang/crates.io-index"
2567
-
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
3037
+
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
2568
3038
2569
3039
[[package]]
2570
3040
name = "socket2"
···
2577
3047
]
2578
3048
2579
3049
[[package]]
3050
+
name = "socket2"
3051
+
version = "0.5.8"
3052
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3053
+
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
3054
+
dependencies = [
3055
+
"libc",
3056
+
"windows-sys 0.52.0",
3057
+
]
3058
+
3059
+
[[package]]
2580
3060
name = "spin"
2581
3061
version = "0.5.2"
2582
3062
source = "registry+https://github.com/rust-lang/crates.io-index"
···
2597
3077
"quote",
2598
3078
"syn 1.0.107",
2599
3079
]
3080
+
3081
+
[[package]]
3082
+
name = "stable_deref_trait"
3083
+
version = "1.2.0"
3084
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3085
+
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
2600
3086
2601
3087
[[package]]
2602
3088
name = "standback"
···
2689
3175
source = "registry+https://github.com/rust-lang/crates.io-index"
2690
3176
checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18"
2691
3177
dependencies = [
2692
-
"heck",
3178
+
"heck 0.4.1",
2693
3179
"proc-macro2",
2694
3180
"quote",
2695
3181
"rustversion",
···
2934
3420
version = "0.1.2"
2935
3421
source = "registry+https://github.com/rust-lang/crates.io-index"
2936
3422
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
3423
+
3424
+
[[package]]
3425
+
name = "synstructure"
3426
+
version = "0.13.1"
3427
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3428
+
checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
3429
+
dependencies = [
3430
+
"proc-macro2",
3431
+
"quote",
3432
+
"syn 2.0.51",
3433
+
]
3434
+
3435
+
[[package]]
3436
+
name = "system-configuration"
3437
+
version = "0.5.1"
3438
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3439
+
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
3440
+
dependencies = [
3441
+
"bitflags 1.3.2",
3442
+
"core-foundation",
3443
+
"system-configuration-sys",
3444
+
]
3445
+
3446
+
[[package]]
3447
+
name = "system-configuration-sys"
3448
+
version = "0.5.0"
3449
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3450
+
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
3451
+
dependencies = [
3452
+
"core-foundation-sys",
3453
+
"libc",
3454
+
]
2937
3455
2938
3456
[[package]]
2939
3457
name = "tempfile"
···
3035
3553
]
3036
3554
3037
3555
[[package]]
3556
+
name = "tinystr"
3557
+
version = "0.7.6"
3558
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3559
+
checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f"
3560
+
dependencies = [
3561
+
"displaydoc",
3562
+
"zerovec",
3563
+
]
3564
+
3565
+
[[package]]
3038
3566
name = "tinyvec"
3039
3567
version = "1.6.0"
3040
3568
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3062
3590
"mio",
3063
3591
"num_cpus",
3064
3592
"pin-project-lite",
3065
-
"socket2",
3593
+
"socket2 0.4.7",
3066
3594
"tokio-macros",
3067
3595
"windows-sys 0.42.0",
3068
3596
]
···
3090
3618
3091
3619
[[package]]
3092
3620
name = "tokio-rustls"
3093
-
version = "0.23.4"
3621
+
version = "0.24.1"
3094
3622
source = "registry+https://github.com/rust-lang/crates.io-index"
3095
-
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
3623
+
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
3096
3624
dependencies = [
3097
-
"rustls 0.20.9",
3625
+
"rustls 0.21.12",
3098
3626
"tokio",
3099
-
"webpki 0.22.4",
3100
3627
]
3101
3628
3102
3629
[[package]]
···
3159
3686
"http-body",
3160
3687
"hyper",
3161
3688
"hyper-timeout",
3162
-
"percent-encoding 2.2.0",
3689
+
"percent-encoding 2.3.1",
3163
3690
"pin-project",
3164
3691
"prost",
3165
3692
"prost-derive",
···
3316
3843
3317
3844
[[package]]
3318
3845
name = "tunein"
3319
-
version = "0.1.2"
3846
+
version = "0.1.3"
3320
3847
source = "registry+https://github.com/rust-lang/crates.io-index"
3321
-
checksum = "fbb48ce12eca4db1649e7d311e782e9b8a341c844cec57b5b8d1e332381e323f"
3848
+
checksum = "9d33b9d790869737661ff1f34a95da32a1288373c5b78c66d098cff2df045055"
3322
3849
dependencies = [
3323
3850
"anyhow",
3324
3851
"m3u",
···
3334
3861
version = "0.2.6"
3335
3862
dependencies = [
3336
3863
"anyhow",
3864
+
"async-trait",
3337
3865
"clap",
3338
3866
"cpal",
3339
3867
"crossterm",
···
3346
3874
"owo-colors",
3347
3875
"pls",
3348
3876
"prost",
3877
+
"radiobrowser",
3349
3878
"ratatui",
3879
+
"regex",
3350
3880
"reqwest",
3351
3881
"rodio",
3352
3882
"rustfft",
···
3360
3890
"tonic-build",
3361
3891
"tonic-web",
3362
3892
"tunein",
3363
-
"url 2.3.1",
3893
+
"url 2.5.4",
3364
3894
]
3365
3895
3366
3896
[[package]]
···
3446
3976
3447
3977
[[package]]
3448
3978
name = "url"
3449
-
version = "2.3.1"
3979
+
version = "2.5.4"
3450
3980
source = "registry+https://github.com/rust-lang/crates.io-index"
3451
-
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
3981
+
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
3452
3982
dependencies = [
3453
3983
"form_urlencoded",
3454
-
"idna 0.3.0",
3455
-
"percent-encoding 2.2.0",
3984
+
"idna 1.0.3",
3985
+
"percent-encoding 2.3.1",
3456
3986
"serde",
3457
3987
]
3458
3988
3459
3989
[[package]]
3990
+
name = "utf16_iter"
3991
+
version = "1.0.5"
3992
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3993
+
checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246"
3994
+
3995
+
[[package]]
3996
+
name = "utf8_iter"
3997
+
version = "1.0.4"
3998
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3999
+
checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
4000
+
4001
+
[[package]]
3460
4002
name = "value-bag"
3461
-
version = "1.0.0-alpha.9"
4003
+
version = "1.10.0"
3462
4004
source = "registry+https://github.com/rust-lang/crates.io-index"
3463
-
checksum = "2209b78d1249f7e6f3293657c9779fe31ced465df091bbd433a1cf88e916ec55"
3464
-
dependencies = [
3465
-
"ctor",
3466
-
"version_check",
3467
-
]
4005
+
checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2"
3468
4006
3469
4007
[[package]]
3470
4008
name = "version_check"
···
3513
4051
3514
4052
[[package]]
3515
4053
name = "wasm-bindgen"
3516
-
version = "0.2.84"
4054
+
version = "0.2.100"
3517
4055
source = "registry+https://github.com/rust-lang/crates.io-index"
3518
-
checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
4056
+
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5"
3519
4057
dependencies = [
3520
4058
"cfg-if",
4059
+
"once_cell",
4060
+
"rustversion",
3521
4061
"wasm-bindgen-macro",
3522
4062
]
3523
4063
3524
4064
[[package]]
3525
4065
name = "wasm-bindgen-backend"
3526
-
version = "0.2.84"
4066
+
version = "0.2.100"
3527
4067
source = "registry+https://github.com/rust-lang/crates.io-index"
3528
-
checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
4068
+
checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6"
3529
4069
dependencies = [
3530
4070
"bumpalo",
3531
4071
"log",
3532
-
"once_cell",
3533
4072
"proc-macro2",
3534
4073
"quote",
3535
-
"syn 1.0.107",
4074
+
"syn 2.0.51",
3536
4075
"wasm-bindgen-shared",
3537
4076
]
3538
4077
···
3550
4089
3551
4090
[[package]]
3552
4091
name = "wasm-bindgen-macro"
3553
-
version = "0.2.84"
4092
+
version = "0.2.100"
3554
4093
source = "registry+https://github.com/rust-lang/crates.io-index"
3555
-
checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
4094
+
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407"
3556
4095
dependencies = [
3557
4096
"quote",
3558
4097
"wasm-bindgen-macro-support",
···
3560
4099
3561
4100
[[package]]
3562
4101
name = "wasm-bindgen-macro-support"
3563
-
version = "0.2.84"
4102
+
version = "0.2.100"
3564
4103
source = "registry+https://github.com/rust-lang/crates.io-index"
3565
-
checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
4104
+
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de"
3566
4105
dependencies = [
3567
4106
"proc-macro2",
3568
4107
"quote",
3569
-
"syn 1.0.107",
4108
+
"syn 2.0.51",
3570
4109
"wasm-bindgen-backend",
3571
4110
"wasm-bindgen-shared",
3572
4111
]
3573
4112
3574
4113
[[package]]
3575
4114
name = "wasm-bindgen-shared"
3576
-
version = "0.2.84"
4115
+
version = "0.2.100"
3577
4116
source = "registry+https://github.com/rust-lang/crates.io-index"
3578
-
checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
4117
+
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d"
4118
+
dependencies = [
4119
+
"unicode-ident",
4120
+
]
3579
4121
3580
4122
[[package]]
3581
4123
name = "web-sys"
···
3598
4140
]
3599
4141
3600
4142
[[package]]
3601
-
name = "webpki"
3602
-
version = "0.22.4"
3603
-
source = "registry+https://github.com/rust-lang/crates.io-index"
3604
-
checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53"
3605
-
dependencies = [
3606
-
"ring 0.17.3",
3607
-
"untrusted 0.9.0",
3608
-
]
3609
-
3610
-
[[package]]
3611
4143
name = "webpki-roots"
3612
4144
version = "0.20.0"
3613
4145
source = "registry+https://github.com/rust-lang/crates.io-index"
3614
4146
checksum = "0f20dea7535251981a9670857150d571846545088359b28e4951d350bdaf179f"
3615
4147
dependencies = [
3616
-
"webpki 0.21.4",
4148
+
"webpki",
3617
4149
]
3618
4150
3619
4151
[[package]]
3620
4152
name = "webpki-roots"
3621
-
version = "0.22.6"
4153
+
version = "0.25.4"
3622
4154
source = "registry+https://github.com/rust-lang/crates.io-index"
3623
-
checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
3624
-
dependencies = [
3625
-
"webpki 0.22.4",
3626
-
]
4155
+
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
3627
4156
3628
4157
[[package]]
3629
4158
name = "wepoll-ffi"
···
3644
4173
"libc",
3645
4174
"once_cell",
3646
4175
]
4176
+
4177
+
[[package]]
4178
+
name = "widestring"
4179
+
version = "1.1.0"
4180
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4181
+
checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311"
3647
4182
3648
4183
[[package]]
3649
4184
name = "winapi"
···
3690
4225
]
3691
4226
3692
4227
[[package]]
4228
+
name = "windows-core"
4229
+
version = "0.52.0"
4230
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4231
+
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
4232
+
dependencies = [
4233
+
"windows-targets 0.52.6",
4234
+
]
4235
+
4236
+
[[package]]
3693
4237
name = "windows-sys"
3694
4238
version = "0.42.0"
3695
4239
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3723
4267
]
3724
4268
3725
4269
[[package]]
4270
+
name = "windows-sys"
4271
+
version = "0.52.0"
4272
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4273
+
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
4274
+
dependencies = [
4275
+
"windows-targets 0.52.6",
4276
+
]
4277
+
4278
+
[[package]]
4279
+
name = "windows-sys"
4280
+
version = "0.59.0"
4281
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4282
+
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
4283
+
dependencies = [
4284
+
"windows-targets 0.52.6",
4285
+
]
4286
+
4287
+
[[package]]
3726
4288
name = "windows-targets"
3727
4289
version = "0.42.1"
3728
4290
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3753
4315
]
3754
4316
3755
4317
[[package]]
4318
+
name = "windows-targets"
4319
+
version = "0.52.6"
4320
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4321
+
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
4322
+
dependencies = [
4323
+
"windows_aarch64_gnullvm 0.52.6",
4324
+
"windows_aarch64_msvc 0.52.6",
4325
+
"windows_i686_gnu 0.52.6",
4326
+
"windows_i686_gnullvm",
4327
+
"windows_i686_msvc 0.52.6",
4328
+
"windows_x86_64_gnu 0.52.6",
4329
+
"windows_x86_64_gnullvm 0.52.6",
4330
+
"windows_x86_64_msvc 0.52.6",
4331
+
]
4332
+
4333
+
[[package]]
3756
4334
name = "windows_aarch64_gnullvm"
3757
4335
version = "0.42.1"
3758
4336
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3765
4343
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
3766
4344
3767
4345
[[package]]
4346
+
name = "windows_aarch64_gnullvm"
4347
+
version = "0.52.6"
4348
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4349
+
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
4350
+
4351
+
[[package]]
3768
4352
name = "windows_aarch64_msvc"
3769
4353
version = "0.37.0"
3770
4354
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3783
4367
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
3784
4368
3785
4369
[[package]]
4370
+
name = "windows_aarch64_msvc"
4371
+
version = "0.52.6"
4372
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4373
+
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
4374
+
4375
+
[[package]]
3786
4376
name = "windows_i686_gnu"
3787
4377
version = "0.37.0"
3788
4378
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3801
4391
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
3802
4392
3803
4393
[[package]]
4394
+
name = "windows_i686_gnu"
4395
+
version = "0.52.6"
4396
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4397
+
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
4398
+
4399
+
[[package]]
4400
+
name = "windows_i686_gnullvm"
4401
+
version = "0.52.6"
4402
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4403
+
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
4404
+
4405
+
[[package]]
3804
4406
name = "windows_i686_msvc"
3805
4407
version = "0.37.0"
3806
4408
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3819
4421
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
3820
4422
3821
4423
[[package]]
4424
+
name = "windows_i686_msvc"
4425
+
version = "0.52.6"
4426
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4427
+
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
4428
+
4429
+
[[package]]
3822
4430
name = "windows_x86_64_gnu"
3823
4431
version = "0.37.0"
3824
4432
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3837
4445
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
3838
4446
3839
4447
[[package]]
4448
+
name = "windows_x86_64_gnu"
4449
+
version = "0.52.6"
4450
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4451
+
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
4452
+
4453
+
[[package]]
3840
4454
name = "windows_x86_64_gnullvm"
3841
4455
version = "0.42.1"
3842
4456
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3849
4463
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
3850
4464
3851
4465
[[package]]
4466
+
name = "windows_x86_64_gnullvm"
4467
+
version = "0.52.6"
4468
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4469
+
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
4470
+
4471
+
[[package]]
3852
4472
name = "windows_x86_64_msvc"
3853
4473
version = "0.37.0"
3854
4474
source = "registry+https://github.com/rust-lang/crates.io-index"
···
3867
4487
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
3868
4488
3869
4489
[[package]]
4490
+
name = "windows_x86_64_msvc"
4491
+
version = "0.52.6"
4492
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4493
+
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
4494
+
4495
+
[[package]]
3870
4496
name = "winreg"
3871
-
version = "0.10.1"
4497
+
version = "0.50.0"
3872
4498
source = "registry+https://github.com/rust-lang/crates.io-index"
3873
-
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
4499
+
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
3874
4500
dependencies = [
3875
-
"winapi",
4501
+
"cfg-if",
4502
+
"windows-sys 0.48.0",
4503
+
]
4504
+
4505
+
[[package]]
4506
+
name = "write16"
4507
+
version = "1.0.0"
4508
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4509
+
checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936"
4510
+
4511
+
[[package]]
4512
+
name = "writeable"
4513
+
version = "0.5.5"
4514
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4515
+
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
4516
+
4517
+
[[package]]
4518
+
name = "yoke"
4519
+
version = "0.7.5"
4520
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4521
+
checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40"
4522
+
dependencies = [
4523
+
"serde",
4524
+
"stable_deref_trait",
4525
+
"yoke-derive",
4526
+
"zerofrom",
4527
+
]
4528
+
4529
+
[[package]]
4530
+
name = "yoke-derive"
4531
+
version = "0.7.5"
4532
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4533
+
checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
4534
+
dependencies = [
4535
+
"proc-macro2",
4536
+
"quote",
4537
+
"syn 2.0.51",
4538
+
"synstructure",
3876
4539
]
3877
4540
3878
4541
[[package]]
···
3894
4557
"quote",
3895
4558
"syn 2.0.51",
3896
4559
]
4560
+
4561
+
[[package]]
4562
+
name = "zerofrom"
4563
+
version = "0.1.5"
4564
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4565
+
checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e"
4566
+
dependencies = [
4567
+
"zerofrom-derive",
4568
+
]
4569
+
4570
+
[[package]]
4571
+
name = "zerofrom-derive"
4572
+
version = "0.1.5"
4573
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4574
+
checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
4575
+
dependencies = [
4576
+
"proc-macro2",
4577
+
"quote",
4578
+
"syn 2.0.51",
4579
+
"synstructure",
4580
+
]
4581
+
4582
+
[[package]]
4583
+
name = "zerovec"
4584
+
version = "0.10.4"
4585
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4586
+
checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079"
4587
+
dependencies = [
4588
+
"yoke",
4589
+
"zerofrom",
4590
+
"zerovec-derive",
4591
+
]
4592
+
4593
+
[[package]]
4594
+
name = "zerovec-derive"
4595
+
version = "0.10.3"
4596
+
source = "registry+https://github.com/rust-lang/crates.io-index"
4597
+
checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
4598
+
dependencies = [
4599
+
"proc-macro2",
4600
+
"quote",
4601
+
"syn 2.0.51",
4602
+
]
+4
-1
Cargo.toml
+4
-1
Cargo.toml
···
24
24
25
25
[dependencies]
26
26
anyhow = "1.0.69"
27
+
async-trait = "0.1.85"
27
28
clap = "3.2.20"
28
29
cpal = "0.14.0"
29
30
crossterm = "0.27.0"
···
36
37
owo-colors = "3.5.0"
37
38
pls = "0.2.2"
38
39
prost = "0.11.8"
40
+
radiobrowser = { version = "0.6.1", features = ["default-rustls"], default-features = false }
39
41
ratatui = "0.26.1"
42
+
regex = "1.11.1"
40
43
reqwest = {version = "0.11.14", features = ["blocking", "rustls-tls"], default-features = false}
41
44
rodio = {version = "0.16"}
42
45
rustfft = "6.2.0"
···
48
51
tokio = {version = "1.24.2", features = ["tokio-macros", "macros", "rt", "rt-multi-thread"]}
49
52
tonic = "0.8.3"
50
53
tonic-web = "0.4.0"
51
-
tunein = "0.1.2"
54
+
tunein = "0.1.3"
52
55
url = "2.3.1"
53
56
54
57
[build-dependencies]
+7
-2
README.md
+7
-2
README.md
···
19
19
<a href="LICENSE" target="./LICENSE">
20
20
<img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-blue.svg" />
21
21
</a>
22
+
<a href="https://github.com/tsirysndr/tunein-cli/actions/workflows/ci.yml">
23
+
<img src="https://github.com/tsirysndr/tunein-cli/actions/workflows/ci.yml/badge.svg"
24
+
</a>
22
25
</p>
23
26
24
27
A command line interface for [TuneIn Radio](https://tunein.com).<br />
···
81
84
tunein <SUBCOMMAND>
82
85
83
86
OPTIONS:
84
-
-h, --help Print help information
85
-
-V, --version Print version information
87
+
-h, --help Print help information
88
+
-p, --provider <provider> The radio provider to use, can be 'tunein' or 'radiobrowser'.
89
+
Default is 'tunein' [default: tunein]
90
+
-V, --version Print version information
86
91
87
92
SUBCOMMANDS:
88
93
browse Browse radio stations
+27
-14
src/app.rs
+27
-14
src/app.rs
···
118
118
},
119
119
frame,
120
120
);
121
-
render_line(
122
-
"Now Playing ",
123
-
&state.now_playing,
124
-
Rect {
125
-
x: size.x,
126
-
y: size.y + 2,
127
-
width: size.width,
128
-
height: 1,
129
-
},
130
-
frame,
131
-
);
121
+
122
+
if !state.now_playing.is_empty() {
123
+
render_line(
124
+
"Now Playing ",
125
+
&state.now_playing,
126
+
Rect {
127
+
x: size.x,
128
+
y: size.y + 2,
129
+
width: size.width,
130
+
height: 1,
131
+
},
132
+
frame,
133
+
);
134
+
}
135
+
132
136
render_line(
133
137
"Genre ",
134
138
&state.genre,
135
139
Rect {
136
140
x: size.x,
137
-
y: size.y + 3,
141
+
y: match state.now_playing.is_empty() {
142
+
true => size.y + 2,
143
+
false => size.y + 3,
144
+
},
138
145
width: size.width,
139
146
height: 1,
140
147
},
···
145
152
&state.description,
146
153
Rect {
147
154
x: size.x,
148
-
y: size.y + 4,
155
+
y: match state.now_playing.is_empty() {
156
+
true => size.y + 3,
157
+
false => size.y + 4,
158
+
},
149
159
width: size.width,
150
160
height: 1,
151
161
},
···
156
166
&format!("{} kbps", &state.br),
157
167
Rect {
158
168
x: size.x,
159
-
y: size.y + 5,
169
+
y: match state.now_playing.is_empty() {
170
+
true => size.y + 4,
171
+
false => size.y + 5,
172
+
},
160
173
width: size.width,
161
174
height: 1,
162
175
},
+37
-69
src/browse.rs
+37
-69
src/browse.rs
···
1
-
use std::str::FromStr;
2
-
3
1
use anyhow::Error;
4
2
use owo_colors::OwoColorize;
5
-
use tunein::{types::Category, TuneInClient};
3
+
4
+
use crate::provider::radiobrowser::Radiobrowser;
5
+
use crate::provider::tunein::Tunein;
6
+
use crate::provider::Provider;
6
7
7
-
pub async fn exec(category: Option<&str>) -> Result<(), Error> {
8
-
let client = TuneInClient::new();
8
+
pub async fn exec(
9
+
category: Option<&str>,
10
+
offset: u32,
11
+
limit: u32,
12
+
provider: &str,
13
+
) -> Result<(), Error> {
14
+
let provider: Box<dyn Provider> = match provider {
15
+
"tunein" => Box::new(Tunein::new()),
16
+
"radiobrowser" => Box::new(Radiobrowser::new().await),
17
+
_ => {
18
+
return Err(anyhow::anyhow!(format!(
19
+
"Unsupported provider '{}'",
20
+
provider
21
+
)))
22
+
}
23
+
};
9
24
10
-
if category.is_some() && Category::from_str(category.unwrap_or_default()).is_err() {
11
-
let id = category.unwrap_or_default();
12
-
let results = client
13
-
.browse_by_id(id)
14
-
.await
15
-
.map_err(|e| Error::msg(e.to_string()))?;
16
-
for result in results {
17
-
println!("{}", result.text);
18
-
if let Some(children) = result.children {
19
-
for child in children {
20
-
match child.playing {
25
+
match category {
26
+
Some(category) => {
27
+
let results = provider.browse(category.to_string(), offset, limit).await?;
28
+
for result in results {
29
+
match result.id.is_empty() {
30
+
false => match result.playing {
21
31
Some(playing) => println!(
22
32
" {} | {} | id: {}",
23
-
child.text.magenta(),
33
+
result.name.magenta(),
24
34
playing,
25
-
child.guide_id.unwrap()
35
+
result.id
26
36
),
27
-
None => {
28
-
if let Some(guide_id) = child.guide_id {
29
-
println!(" {} | {}", child.text.magenta(), guide_id);
30
-
}
31
-
}
32
-
}
33
-
}
34
-
}
35
-
}
36
-
return Ok(());
37
-
}
37
+
None => println!(" {} | id: {}", result.name.magenta(), result.id),
38
+
},
38
39
39
-
let results = match category {
40
-
Some(category) => match Category::from_str(category) {
41
-
Ok(category) => client
42
-
.browse(Some(category))
43
-
.await
44
-
.map_err(|e| Error::msg(e.to_string()))?,
45
-
Err(_) => {
46
-
println!("Invalid category");
47
-
return Ok(());
40
+
true => println!("{}", result.name),
41
+
}
48
42
}
49
-
},
50
-
None => client
51
-
.browse(None)
52
-
.await
53
-
.map_err(|e| Error::msg(e.to_string()))?,
54
-
};
55
-
56
-
for result in results {
57
-
match result.guide_id {
58
-
Some(_) => println!(
59
-
"{} | id: {}",
60
-
result.text.magenta(),
61
-
result.guide_id.unwrap()
62
-
),
63
-
None => println!("{}", result.text),
64
43
}
65
-
if let Some(children) = result.children {
66
-
for child in children {
67
-
match child.playing {
68
-
Some(playing) => println!(
69
-
" {} | {} | id: {}",
70
-
child.text.magenta(),
71
-
playing,
72
-
child.guide_id.unwrap()
73
-
),
74
-
None => println!(
75
-
" {} | id: {}",
76
-
child.text.magenta(),
77
-
child.guide_id.unwrap()
78
-
),
79
-
}
44
+
None => {
45
+
let results = provider.categories(offset, limit).await?;
46
+
for result in results {
47
+
println!("{}", result.magenta());
80
48
}
81
49
}
82
-
}
50
+
};
83
51
Ok(())
84
52
}
+23
-4
src/main.rs
+23
-4
src/main.rs
···
10
10
mod music;
11
11
mod play;
12
12
mod player;
13
+
mod provider;
13
14
mod search;
14
15
mod server;
16
+
mod tags;
15
17
mod tui;
18
+
mod types;
16
19
mod visualization;
17
20
18
21
fn cli() -> Command<'static> {
···
29
32
30
33
A simple CLI to listen to radio stations"#,
31
34
)
35
+
.arg(
36
+
arg!(-p --provider "The radio provider to use, can be 'tunein' or 'radiobrowser'. Default is 'tunein'").default_value("tunein")
37
+
)
32
38
.subcommand_required(true)
33
39
.subcommand(
34
40
Command::new("search")
···
43
49
.subcommand(
44
50
Command::new("browse")
45
51
.about("Browse radio stations")
46
-
.arg(arg!([category] "The category (category name or id) to browse")),
52
+
.arg(arg!([category] "The category (category name or id) to browse"))
53
+
.arg(arg!(--offset "The offset to start from").default_value("0"))
54
+
.arg(arg!(--limit "The number of results to show").default_value("100")),
47
55
)
48
56
.subcommand(
49
57
Command::new("server")
···
59
67
match matches.subcommand() {
60
68
Some(("search", args)) => {
61
69
let query = args.value_of("query").unwrap();
62
-
search::exec(query).await?;
70
+
let provider = matches.value_of("provider").unwrap();
71
+
search::exec(query, provider).await?;
63
72
}
64
73
Some(("play", args)) => {
65
74
let station = args.value_of("station").unwrap();
66
-
play::exec(station).await?;
75
+
let provider = matches.value_of("provider").unwrap();
76
+
play::exec(station, provider).await?;
67
77
}
68
78
Some(("browse", args)) => {
69
79
let category = args.value_of("category");
70
-
browse::exec(category).await?;
80
+
let offset = args.value_of("offset").unwrap();
81
+
let limit = args.value_of("limit").unwrap();
82
+
let provider = matches.value_of("provider").unwrap();
83
+
browse::exec(
84
+
category,
85
+
offset.parse::<u32>()?,
86
+
limit.parse::<u32>()?,
87
+
provider,
88
+
)
89
+
.await?;
71
90
}
72
91
Some(("server", args)) => {
73
92
let port = args.value_of("port").unwrap();
+20
-46
src/play.rs
+20
-46
src/play.rs
···
2
2
3
3
use anyhow::Error;
4
4
use hyper::header::HeaderValue;
5
-
use tunein::TuneInClient;
6
5
7
6
use crate::{
8
7
app::{App, State},
9
8
cfg::{SourceOptions, UiOptions},
10
9
decoder::Mp3Decoder,
11
-
extract::{extract_stream_url, get_currently_playing},
10
+
provider::{radiobrowser::Radiobrowser, tunein::Tunein, Provider},
12
11
tui,
13
12
};
14
13
15
-
pub async fn exec(name_or_id: &str) -> Result<(), Error> {
16
-
let client = TuneInClient::new();
17
-
let results = client
18
-
.get_station(name_or_id)
19
-
.await
20
-
.map_err(|e| Error::msg(e.to_string()))?;
21
-
let (url, playlist_type, _, id) = match results.is_empty() {
22
-
true => {
23
-
let results = client
24
-
.search(name_or_id)
25
-
.await
26
-
.map_err(|e| Error::msg(e.to_string()))?;
27
-
match results.first() {
28
-
Some(result) => {
29
-
if result.r#type != Some("audio".to_string()) {
30
-
return Err(Error::msg("No station found"));
31
-
}
32
-
let id = result.guide_id.as_ref().unwrap();
33
-
let station = client
34
-
.get_station(id)
35
-
.await
36
-
.map_err(|e| Error::msg(e.to_string()))?;
37
-
let station = station.first().unwrap();
38
-
(
39
-
station.url.clone(),
40
-
station.playlist_type.clone(),
41
-
station.media_type.clone(),
42
-
id.clone(),
43
-
)
44
-
}
45
-
None => ("".to_string(), None, "".to_string(), "".to_string()),
46
-
}
47
-
}
48
-
false => {
49
-
let result = results.first().unwrap();
50
-
(
51
-
result.url.clone(),
52
-
result.playlist_type.clone(),
53
-
result.media_type.clone(),
54
-
name_or_id.to_string(),
55
-
)
14
+
pub async fn exec(name_or_id: &str, provider: &str) -> Result<(), Error> {
15
+
let _provider = provider;
16
+
let provider: Box<dyn Provider> = match provider {
17
+
"tunein" => Box::new(Tunein::new()),
18
+
"radiobrowser" => Box::new(Radiobrowser::new().await),
19
+
_ => {
20
+
return Err(anyhow::anyhow!(format!(
21
+
"Unsupported provider '{}'",
22
+
provider
23
+
)))
56
24
}
57
25
};
58
-
let now_playing = get_currently_playing(&id).await?;
59
-
let stream_url = extract_stream_url(&url, playlist_type).await?;
60
-
println!("{}", stream_url);
26
+
let station = provider.get_station(name_or_id.to_string()).await?;
27
+
if station.is_none() {
28
+
return Err(Error::msg("No station found"));
29
+
}
30
+
31
+
let station = station.unwrap();
32
+
let stream_url = station.stream_url.clone();
33
+
let id = station.id.clone();
34
+
let now_playing = station.playing.clone().unwrap_or_default();
61
35
62
36
let (cmd_tx, cmd_rx) = tokio::sync::mpsc::unbounded_channel::<State>();
63
37
let (frame_tx, frame_rx) = std::sync::mpsc::channel::<minimp3::Frame>();
+28
src/provider/mod.rs
+28
src/provider/mod.rs
···
1
+
pub mod radiobrowser;
2
+
pub mod tunein;
3
+
4
+
use crate::types::Station;
5
+
use anyhow::Error;
6
+
use async_trait::async_trait;
7
+
use regex::Regex;
8
+
9
+
#[async_trait]
10
+
pub trait Provider {
11
+
async fn search(&self, name: String) -> Result<Vec<Station>, Error>;
12
+
async fn get_station(&self, id: String) -> Result<Option<Station>, Error>;
13
+
async fn browse(
14
+
&self,
15
+
category: String,
16
+
offset: u32,
17
+
limit: u32,
18
+
) -> Result<Vec<Station>, Error>;
19
+
async fn categories(&self, offset: u32, limit: u32) -> Result<Vec<String>, Error>;
20
+
}
21
+
22
+
pub fn is_valid_uuid(uuid: &str) -> bool {
23
+
let uuid_pattern = Regex::new(
24
+
r"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
25
+
).unwrap();
26
+
27
+
uuid_pattern.is_match(uuid)
28
+
}
+161
src/provider/radiobrowser.rs
+161
src/provider/radiobrowser.rs
···
1
+
use crate::types::Station;
2
+
3
+
use super::{is_valid_uuid, Provider};
4
+
use anyhow::Error;
5
+
use async_trait::async_trait;
6
+
use radiobrowser::{ApiStation, RadioBrowserAPI};
7
+
use std::process::exit;
8
+
9
+
pub struct Radiobrowser {
10
+
client: RadioBrowserAPI,
11
+
}
12
+
13
+
impl Radiobrowser {
14
+
pub async fn new() -> Self {
15
+
let client = RadioBrowserAPI::new().await;
16
+
17
+
if client.is_err() {
18
+
eprintln!("Failed to create a RadioBrowserAPI client");
19
+
exit(1);
20
+
}
21
+
22
+
let client = client.unwrap();
23
+
Self { client }
24
+
}
25
+
}
26
+
27
+
#[async_trait]
28
+
impl Provider for Radiobrowser {
29
+
async fn search(&self, name: String) -> Result<Vec<Station>, Error> {
30
+
let stations = self
31
+
.client
32
+
.get_stations()
33
+
.name(&name)
34
+
.send()
35
+
.await
36
+
.map_err(|e| anyhow::anyhow!(format!("{}", e)))?;
37
+
let stations = stations.into_iter().map(|x| Station::from(x)).collect();
38
+
Ok(stations)
39
+
}
40
+
41
+
async fn get_station(&self, name_or_uuid: String) -> Result<Option<Station>, Error> {
42
+
match is_valid_uuid(&name_or_uuid) {
43
+
true => {
44
+
let servers = RadioBrowserAPI::get_default_servers()
45
+
.await
46
+
.map_err(|e| anyhow::anyhow!(format!("{}", e)))?;
47
+
48
+
if servers.is_empty() {
49
+
return Ok(None);
50
+
}
51
+
52
+
let client = reqwest::Client::new();
53
+
let url = format!(
54
+
"https://{}/json/stations/byuuid/{}",
55
+
servers[0], name_or_uuid
56
+
);
57
+
let results = client
58
+
.get(&url)
59
+
.send()
60
+
.await?
61
+
.json::<Vec<ApiStation>>()
62
+
.await?;
63
+
64
+
Ok(results.into_iter().next().map(|x| Station::from(x)))
65
+
}
66
+
false => {
67
+
let stations = self
68
+
.client
69
+
.get_stations()
70
+
.name(&name_or_uuid)
71
+
.name_exact(true)
72
+
.send()
73
+
.await
74
+
.map_err(|e| anyhow::anyhow!(format!("{}", e)))?;
75
+
match stations.len() {
76
+
0 => Ok(None),
77
+
_ => Ok(Some(Station::from(stations[0].clone()))),
78
+
}
79
+
}
80
+
}
81
+
}
82
+
83
+
async fn browse(
84
+
&self,
85
+
category: String,
86
+
offset: u32,
87
+
limit: u32,
88
+
) -> Result<Vec<Station>, Error> {
89
+
let stations = self
90
+
.client
91
+
.get_stations()
92
+
.tag(&category)
93
+
.offset(&format!("{}", offset))
94
+
.limit(&format!("{}", limit))
95
+
.send()
96
+
.await
97
+
.map_err(|e| anyhow::anyhow!(format!("{}", e)))?;
98
+
let stations = stations.into_iter().map(|x| Station::from(x)).collect();
99
+
Ok(stations)
100
+
}
101
+
102
+
async fn categories(&self, offset: u32, limit: u32) -> Result<Vec<String>, Error> {
103
+
let categories = self
104
+
.client
105
+
.get_tags()
106
+
.offset(&format!("{}", offset))
107
+
.limit(&format!("{}", limit))
108
+
.send()
109
+
.await
110
+
.map_err(|e| anyhow::anyhow!(format!("{}", e)))?;
111
+
let categories = categories.into_iter().map(|x| x.name).collect();
112
+
Ok(categories)
113
+
}
114
+
}
115
+
116
+
#[cfg(test)]
117
+
mod tests {
118
+
use super::*;
119
+
120
+
#[tokio::test]
121
+
pub async fn test_search() {
122
+
let provider = Radiobrowser::new().await;
123
+
let name = "alternativeradio";
124
+
let stations = provider.search(name.to_string()).await.unwrap();
125
+
assert!(stations.len() == 1)
126
+
}
127
+
128
+
#[tokio::test]
129
+
pub async fn test_get_station() {
130
+
let provider = Radiobrowser::new().await;
131
+
let name = "AlternativeRadio.us".to_string();
132
+
let station = provider.get_station(name).await.unwrap();
133
+
assert!(station.is_some())
134
+
}
135
+
136
+
#[tokio::test]
137
+
pub async fn test_get_station_by_uuid() {
138
+
let provider = Radiobrowser::new().await;
139
+
let name = "964da563-0601-11e8-ae97-52543be04c81".to_string();
140
+
let station = provider.get_station(name).await.unwrap();
141
+
assert!(station.is_some())
142
+
}
143
+
144
+
#[tokio::test]
145
+
pub async fn test_browse() {
146
+
let provider = Radiobrowser::new().await;
147
+
let stations = provider.browse("music".to_string(), 0, 100).await.unwrap();
148
+
let stations = stations
149
+
.into_iter()
150
+
.map(|x| Station::from(x))
151
+
.collect::<Vec<Station>>();
152
+
assert!(stations.len() == 100)
153
+
}
154
+
155
+
#[tokio::test]
156
+
pub async fn test_categories() {
157
+
let provider = Radiobrowser::new().await;
158
+
let categories = provider.categories(0, 100).await.unwrap();
159
+
assert!(categories.len() > 0)
160
+
}
161
+
}
+181
src/provider/tunein.rs
+181
src/provider/tunein.rs
···
1
+
use crate::types::Station;
2
+
3
+
use super::Provider;
4
+
use anyhow::Error;
5
+
use async_trait::async_trait;
6
+
use tunein::TuneInClient;
7
+
8
+
pub struct Tunein {
9
+
client: TuneInClient,
10
+
}
11
+
12
+
impl Tunein {
13
+
pub fn new() -> Self {
14
+
Self {
15
+
client: TuneInClient::new(),
16
+
}
17
+
}
18
+
}
19
+
20
+
#[async_trait]
21
+
impl Provider for Tunein {
22
+
async fn search(&self, name: String) -> Result<Vec<Station>, Error> {
23
+
let results = self
24
+
.client
25
+
.search(&name)
26
+
.await
27
+
.map_err(|e| Error::msg(e.to_string()))?;
28
+
let stations = results.into_iter().map(|x| Station::from(x)).collect();
29
+
Ok(stations)
30
+
}
31
+
32
+
async fn get_station(&self, id: String) -> Result<Option<Station>, Error> {
33
+
let stations = self
34
+
.client
35
+
.get_station(&id)
36
+
.await
37
+
.map_err(|e| Error::msg(e.to_string()))?;
38
+
match stations.len() {
39
+
0 => {
40
+
let results = self.search(id.clone()).await?;
41
+
let station = results.first().cloned();
42
+
match station {
43
+
Some(st) => {
44
+
let stations = self
45
+
.client
46
+
.get_station(&st.id)
47
+
.await
48
+
.map_err(|e| Error::msg(e.to_string()))?;
49
+
let mut station = Station::from(stations[0].clone());
50
+
station.id = st.id.clone();
51
+
station.name = st.name.clone();
52
+
station.playing = st.playing.clone();
53
+
return Ok(Some(station));
54
+
}
55
+
None => Ok(None),
56
+
}
57
+
}
58
+
_ => Ok(Some(Station::from(stations[0].clone()))),
59
+
}
60
+
}
61
+
62
+
async fn browse(
63
+
&self,
64
+
category: String,
65
+
_offset: u32,
66
+
_limit: u32,
67
+
) -> Result<Vec<Station>, Error> {
68
+
let guide_id = category.clone();
69
+
let category = match category.to_lowercase().as_str() {
70
+
"by location" => Some(tunein::types::Category::ByLocation),
71
+
"by language" => Some(tunein::types::Category::ByLanguage),
72
+
"sports" => Some(tunein::types::Category::Sports),
73
+
"talk" => Some(tunein::types::Category::Talk),
74
+
"music" => Some(tunein::types::Category::Music),
75
+
"local radio" => Some(tunein::types::Category::LocalRadio),
76
+
"podcasts" => Some(tunein::types::Category::Podcasts),
77
+
_ => None,
78
+
};
79
+
80
+
if category.is_none() {
81
+
let category_stations = self
82
+
.client
83
+
.browse_by_id(&guide_id)
84
+
.await
85
+
.map_err(|e| Error::msg(e.to_string()))?;
86
+
87
+
let mut stations = vec![];
88
+
89
+
for st in category_stations {
90
+
if let Some(children) = st.clone().children {
91
+
stations = [stations, vec![Box::new(st.clone())], children].concat();
92
+
}
93
+
}
94
+
95
+
let stations = stations.into_iter().map(|x| Station::from(x)).collect();
96
+
return Ok(stations);
97
+
}
98
+
99
+
let category_stations = self
100
+
.client
101
+
.browse(category)
102
+
.await
103
+
.map_err(|e| Error::msg(e.to_string()))?;
104
+
105
+
let stations = category_stations
106
+
.clone()
107
+
.into_iter()
108
+
.map(|x| Station::from(x))
109
+
.collect::<Vec<Station>>();
110
+
111
+
let mut _stations = vec![];
112
+
for st in category_stations {
113
+
if let Some(children) = st.children {
114
+
_stations = [_stations, children].concat();
115
+
}
116
+
}
117
+
let _stations = _stations
118
+
.into_iter()
119
+
.map(|x| Station::from(x))
120
+
.collect::<Vec<Station>>();
121
+
122
+
Ok([stations, _stations].concat())
123
+
}
124
+
125
+
async fn categories(&self, _offset: u32, _limit: u32) -> Result<Vec<String>, Error> {
126
+
let categories = self
127
+
.client
128
+
.browse(None)
129
+
.await
130
+
.map_err(|e| Error::msg(e.to_string()))?;
131
+
let categories = categories.into_iter().map(|x| x.text).collect();
132
+
Ok(categories)
133
+
}
134
+
}
135
+
136
+
#[cfg(test)]
137
+
mod tests {
138
+
use super::*;
139
+
140
+
#[tokio::test]
141
+
pub async fn test_search() {
142
+
let provider = Tunein::new();
143
+
let name = "alternativeradio";
144
+
let stations = provider.search(name.to_string()).await.unwrap();
145
+
println!("Search: {:#?}", stations);
146
+
assert!(stations.len() > 0)
147
+
}
148
+
149
+
#[tokio::test]
150
+
pub async fn test_get_station() {
151
+
let provider = Tunein::new();
152
+
let name = "s288303".to_string();
153
+
let station = provider.get_station(name).await.unwrap();
154
+
println!("Station: {:#?}", station);
155
+
assert!(station.is_some())
156
+
}
157
+
158
+
#[tokio::test]
159
+
pub async fn test_browse() {
160
+
let provider = Tunein::new();
161
+
let stations = provider.browse("music".to_string(), 0, 100).await.unwrap();
162
+
println!("Browse: {:#?}", stations);
163
+
assert!(stations.len() > 0)
164
+
}
165
+
166
+
#[tokio::test]
167
+
pub async fn test_browse_by_id() {
168
+
let provider = Tunein::new();
169
+
let stations = provider.browse("c57942".to_string(), 0, 100).await.unwrap();
170
+
println!("Browse by category id: {:#?}", stations);
171
+
assert!(stations.len() > 0)
172
+
}
173
+
174
+
#[tokio::test]
175
+
pub async fn test_categories() {
176
+
let provider = Tunein::new();
177
+
let categories = provider.categories(0, 100).await.unwrap();
178
+
println!("Categories: {:#?}", categories);
179
+
assert!(categories.len() > 0)
180
+
}
181
+
}
+21
-18
src/search.rs
+21
-18
src/search.rs
···
1
1
use anyhow::Error;
2
2
use owo_colors::OwoColorize;
3
-
use tunein::TuneInClient;
4
3
5
-
pub async fn exec(query: &str) -> Result<(), Error> {
6
-
let client = TuneInClient::new();
7
-
let results = client
8
-
.search(query)
9
-
.await
10
-
.map_err(|e| Error::msg(e.to_string()))?;
4
+
use crate::provider::{radiobrowser::Radiobrowser, tunein::Tunein, Provider};
5
+
6
+
pub async fn exec(query: &str, provider: &str) -> Result<(), Error> {
7
+
let provider: Box<dyn Provider> = match provider {
8
+
"tunein" => Box::new(Tunein::new()),
9
+
"radiobrowser" => Box::new(Radiobrowser::new().await),
10
+
_ => {
11
+
return Err(anyhow::anyhow!(format!(
12
+
"Unsupported provider '{}'",
13
+
provider
14
+
)))
15
+
}
16
+
};
17
+
let results = provider.search(query.to_string()).await?;
11
18
let query = format!("\"{}\"", query);
12
19
println!("Results for {}:", query.bright_green());
13
20
14
-
let results = results
15
-
.into_iter()
16
-
.filter(|r| Some("audio".to_string()) == r.r#type)
17
-
.collect::<Vec<_>>();
18
-
19
21
if results.is_empty() {
20
22
println!("No results found");
21
23
return Ok(());
22
24
}
23
25
24
26
for result in results {
25
-
if Some("audio".to_string()) == result.r#type {
26
-
println!(
27
+
match result.playing {
28
+
Some(playing) => println!(
27
29
"{} | {} | id: {}",
28
-
result.text.magenta(),
29
-
result.subtext.unwrap_or_default(),
30
-
result.guide_id.unwrap()
31
-
);
30
+
result.name.magenta(),
31
+
playing,
32
+
result.id
33
+
),
34
+
None => println!("{} | id: {}", result.name.magenta(), result.id),
32
35
}
33
36
}
34
37
Ok(())
+128
src/types.rs
+128
src/types.rs
···
1
+
use std::thread;
2
+
3
+
use radiobrowser::ApiStation;
4
+
use tunein::types::{SearchResult, StationLinkDetails};
5
+
6
+
use crate::extract::extract_stream_url;
7
+
8
+
#[derive(Debug, Clone)]
9
+
pub struct Station {
10
+
pub id: String,
11
+
pub name: String,
12
+
pub codec: String,
13
+
pub bitrate: u32,
14
+
pub stream_url: String,
15
+
pub playing: Option<String>,
16
+
}
17
+
18
+
impl From<ApiStation> for Station {
19
+
fn from(station: ApiStation) -> Station {
20
+
Station {
21
+
id: station.stationuuid,
22
+
name: station.name,
23
+
codec: station.codec,
24
+
bitrate: station.bitrate,
25
+
stream_url: station.url_resolved,
26
+
playing: None,
27
+
}
28
+
}
29
+
}
30
+
31
+
impl From<SearchResult> for Station {
32
+
fn from(result: SearchResult) -> Station {
33
+
Station {
34
+
id: result.guide_id.unwrap_or_default(),
35
+
name: result.text,
36
+
bitrate: result
37
+
.bitrate
38
+
.unwrap_or("0".to_string())
39
+
.parse()
40
+
.unwrap_or_default(),
41
+
codec: Default::default(),
42
+
stream_url: Default::default(),
43
+
playing: result.subtext,
44
+
}
45
+
}
46
+
}
47
+
48
+
impl From<Box<SearchResult>> for Station {
49
+
fn from(result: Box<SearchResult>) -> Station {
50
+
Station {
51
+
id: result.guide_id.unwrap_or_default(),
52
+
name: result.text,
53
+
bitrate: result
54
+
.bitrate
55
+
.unwrap_or("0".to_string())
56
+
.parse()
57
+
.unwrap_or_default(),
58
+
codec: Default::default(),
59
+
stream_url: Default::default(),
60
+
playing: None,
61
+
}
62
+
}
63
+
}
64
+
65
+
impl From<StationLinkDetails> for Station {
66
+
fn from(details: StationLinkDetails) -> Station {
67
+
let handle = thread::spawn(move || {
68
+
let rt = tokio::runtime::Runtime::new().unwrap();
69
+
rt.block_on(extract_stream_url(&details.url, details.playlist_type))
70
+
});
71
+
let stream_url = handle.join().unwrap().unwrap();
72
+
Station {
73
+
id: Default::default(),
74
+
name: Default::default(),
75
+
bitrate: details.bitrate,
76
+
stream_url,
77
+
codec: details.media_type.to_uppercase(),
78
+
playing: None,
79
+
}
80
+
}
81
+
}
82
+
83
+
impl From<tunein::types::Station> for Station {
84
+
fn from(st: tunein::types::Station) -> Station {
85
+
Station {
86
+
id: st.guide_id.unwrap_or_default(),
87
+
name: st.text,
88
+
bitrate: st
89
+
.bitrate
90
+
.unwrap_or("0".to_string())
91
+
.parse()
92
+
.unwrap_or_default(),
93
+
stream_url: Default::default(),
94
+
codec: st.formats.unwrap_or_default().to_uppercase(),
95
+
playing: st.playing,
96
+
}
97
+
}
98
+
}
99
+
100
+
impl From<Box<tunein::types::Station>> for Station {
101
+
fn from(st: Box<tunein::types::Station>) -> Station {
102
+
Station {
103
+
id: st.guide_id.unwrap_or_default(),
104
+
name: st.text,
105
+
bitrate: st
106
+
.bitrate
107
+
.unwrap_or("0".to_string())
108
+
.parse()
109
+
.unwrap_or_default(),
110
+
stream_url: Default::default(),
111
+
codec: st.formats.unwrap_or_default().to_uppercase(),
112
+
playing: st.playing,
113
+
}
114
+
}
115
+
}
116
+
117
+
impl From<tunein::types::CategoryDetails> for Station {
118
+
fn from(ct: tunein::types::CategoryDetails) -> Station {
119
+
Station {
120
+
id: ct.guide_id.unwrap_or_default(),
121
+
name: ct.text,
122
+
bitrate: 0,
123
+
stream_url: Default::default(),
124
+
codec: Default::default(),
125
+
playing: None,
126
+
}
127
+
}
128
+
}