+77
-4
Cargo.lock
+77
-4
Cargo.lock
···
3064
3064
3065
3065
[[package]]
3066
3066
name = "log"
3067
-
version = "0.4.27"
3067
+
version = "0.4.28"
3068
3068
source = "registry+https://github.com/rust-lang/crates.io-index"
3069
-
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
3069
+
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
3070
3070
3071
3071
[[package]]
3072
3072
name = "lru-slab"
···
3227
3227
"winapi",
3228
3228
]
3229
3229
3230
+
[[package]]
3231
+
name = "nu-ansi-term"
3232
+
version = "0.50.1"
3233
+
source = "registry+https://github.com/rust-lang/crates.io-index"
3234
+
checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
3235
+
dependencies = [
3236
+
"windows-sys 0.52.0",
3237
+
]
3238
+
3230
3239
[[package]]
3231
3240
name = "nuid"
3232
3241
version = "0.5.0"
···
3402
3411
3403
3412
[[package]]
3404
3413
name = "owo-colors"
3405
-
version = "4.2.1"
3414
+
version = "4.2.2"
3406
3415
source = "registry+https://github.com/rust-lang/crates.io-index"
3407
-
checksum = "26995317201fa17f3656c36716aed4a7c81743a9634ac4c99c0eeda495db0cec"
3416
+
checksum = "48dd4f4a2c8405440fd0462561f0e5806bd0f77e86f51c761481bdd4018b545e"
3408
3417
dependencies = [
3409
3418
"supports-color 2.1.0",
3410
3419
"supports-color 3.0.2",
···
4837
4846
"sqlx",
4838
4847
"tokio",
4839
4848
"tokio-stream",
4849
+
"tracing",
4840
4850
]
4841
4851
4842
4852
[[package]]
···
4888
4898
"tempfile",
4889
4899
"tokio",
4890
4900
"tokio-stream",
4901
+
"tracing",
4891
4902
]
4892
4903
4893
4904
[[package]]
···
4919
4930
"tempfile",
4920
4931
"tokio",
4921
4932
"tokio-stream",
4933
+
"tracing",
4922
4934
]
4923
4935
4924
4936
[[package]]
···
4941
4953
"tokio",
4942
4954
"tokio-stream",
4943
4955
"tokio-tungstenite",
4956
+
"tracing",
4944
4957
"tungstenite",
4945
4958
"url",
4946
4959
]
···
4968
4981
"sqlx",
4969
4982
"tokio",
4970
4983
"tokio-stream",
4984
+
"tracing",
4971
4985
]
4972
4986
4973
4987
[[package]]
···
4995
5009
"sqlx",
4996
5010
"tokio",
4997
5011
"tokio-stream",
5012
+
"tracing",
4998
5013
"uuid",
4999
5014
]
5000
5015
···
5018
5033
"sqlx",
5019
5034
"tokio",
5020
5035
"tokio-stream",
5036
+
"tracing",
5021
5037
]
5022
5038
5023
5039
[[package]]
···
5034
5050
"sqlx",
5035
5051
"tokio",
5036
5052
"tokio-stream",
5053
+
"tracing",
5037
5054
]
5038
5055
5039
5056
[[package]]
···
5053
5070
"serde_json",
5054
5071
"tokio",
5055
5072
"tokio-stream",
5073
+
"tracing",
5056
5074
"uuid",
5057
5075
]
5058
5076
···
5080
5098
"sqlx",
5081
5099
"tokio",
5082
5100
"tokio-stream",
5101
+
"tracing",
5083
5102
]
5084
5103
5085
5104
[[package]]
···
5089
5108
"anyhow",
5090
5109
"clap",
5091
5110
"dotenv",
5111
+
"owo-colors",
5092
5112
"rocksky-analytics",
5093
5113
"rocksky-dropbox",
5094
5114
"rocksky-googledrive",
···
5099
5119
"rocksky-tracklist",
5100
5120
"rocksky-webscrobbler",
5101
5121
"tokio",
5122
+
"tracing",
5123
+
"tracing-log",
5124
+
"tracing-subscriber",
5102
5125
]
5103
5126
5104
5127
[[package]]
···
5630
5653
"tokio",
5631
5654
]
5632
5655
5656
+
[[package]]
5657
+
name = "sharded-slab"
5658
+
version = "0.1.7"
5659
+
source = "registry+https://github.com/rust-lang/crates.io-index"
5660
+
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
5661
+
dependencies = [
5662
+
"lazy_static",
5663
+
]
5664
+
5633
5665
[[package]]
5634
5666
name = "shlex"
5635
5667
version = "1.3.0"
···
6440
6472
"syn 2.0.101",
6441
6473
]
6442
6474
6475
+
[[package]]
6476
+
name = "thread_local"
6477
+
version = "1.1.9"
6478
+
source = "registry+https://github.com/rust-lang/crates.io-index"
6479
+
checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185"
6480
+
dependencies = [
6481
+
"cfg-if",
6482
+
]
6483
+
6443
6484
[[package]]
6444
6485
name = "time"
6445
6486
version = "0.3.44"
···
6780
6821
checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c"
6781
6822
dependencies = [
6782
6823
"once_cell",
6824
+
"valuable",
6825
+
]
6826
+
6827
+
[[package]]
6828
+
name = "tracing-log"
6829
+
version = "0.2.0"
6830
+
source = "registry+https://github.com/rust-lang/crates.io-index"
6831
+
checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3"
6832
+
dependencies = [
6833
+
"log",
6834
+
"once_cell",
6835
+
"tracing-core",
6836
+
]
6837
+
6838
+
[[package]]
6839
+
name = "tracing-subscriber"
6840
+
version = "0.3.20"
6841
+
source = "registry+https://github.com/rust-lang/crates.io-index"
6842
+
checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5"
6843
+
dependencies = [
6844
+
"nu-ansi-term",
6845
+
"sharded-slab",
6846
+
"smallvec",
6847
+
"thread_local",
6848
+
"tracing-core",
6849
+
"tracing-log",
6783
6850
]
6784
6851
6785
6852
[[package]]
···
6958
7025
"wasm-bindgen",
6959
7026
]
6960
7027
7028
+
[[package]]
7029
+
name = "valuable"
7030
+
version = "0.1.1"
7031
+
source = "registry+https://github.com/rust-lang/crates.io-index"
7032
+
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
7033
+
6961
7034
[[package]]
6962
7035
name = "vcpkg"
6963
7036
version = "0.2.15"
+1
crates/analytics/Cargo.toml
+1
crates/analytics/Cargo.toml
+2
-2
crates/analytics/src/cmd/serve.rs
+2
-2
crates/analytics/src/cmd/serve.rs
···
29
29
req: HttpRequest,
30
30
) -> Result<impl Responder, actix_web::Error> {
31
31
let method = req.match_info().get("method").unwrap_or("unknown");
32
-
println!("Method: {}", method.bright_green());
32
+
tracing::info!(method = %method.bright_green(), "API call");
33
33
34
34
let conn = data.get_ref().clone();
35
35
handle(method, &mut payload, &req, conn)
···
45
45
let addr = format!("{}:{}", host, port);
46
46
47
47
let url = format!("http://{}", addr);
48
-
println!("Listening on {}", url.bright_green());
48
+
tracing::info!(url = %url.bright_green(), "Listening on");
49
49
50
50
let conn = conn.clone();
51
51
HttpServer::new(move || {
+37
-84
crates/analytics/src/core.rs
+37
-84
crates/analytics/src/core.rs
···
194
194
.await?;
195
195
196
196
for (i, track) in tracks.clone().into_iter().enumerate() {
197
-
println!(
198
-
"track {} - {} - {}",
199
-
i,
200
-
track.title.bright_green(),
201
-
track.artist
202
-
);
197
+
tracing::info!(track = i, title = %track.title.bright_green(), artist = %track.artist);
203
198
match conn.execute(
204
199
"INSERT INTO tracks (
205
200
id,
···
255
250
],
256
251
) {
257
252
Ok(_) => (),
258
-
Err(e) => println!("error: {}", e),
253
+
Err(e) => tracing::error!(error = %e, "Error inserting track"),
259
254
}
260
255
}
261
256
262
-
println!("tracks: {:?}", tracks.len());
257
+
tracing::info!(tracks = tracks.len(), "Loaded tracks");
263
258
Ok(())
264
259
}
265
260
···
277
272
.await?;
278
273
279
274
for (i, artist) in artists.clone().into_iter().enumerate() {
280
-
println!("artist {} - {}", i, artist.name.bright_green());
275
+
tracing::info!(artist = i, name = %artist.name.bright_green());
281
276
match conn.execute(
282
277
"INSERT INTO artists (
283
278
id,
···
323
318
],
324
319
) {
325
320
Ok(_) => (),
326
-
Err(e) => println!("error: {}", e),
321
+
Err(e) => tracing::error!(error = %e, "Error inserting artist"),
327
322
}
328
323
}
329
324
330
-
println!("artists: {:?}", artists.len());
325
+
tracing::info!(artists = artists.len(), "Loaded artists");
331
326
Ok(())
332
327
}
333
328
···
342
337
.await?;
343
338
344
339
for (i, album) in albums.clone().into_iter().enumerate() {
345
-
println!("album {} - {}", i, album.title.bright_green());
340
+
tracing::info!(album = i, title = %album.title.bright_green(), artist = %album.artist);
346
341
match conn.execute(
347
342
"INSERT INTO albums (
348
343
id,
···
388
383
],
389
384
) {
390
385
Ok(_) => (),
391
-
Err(e) => println!("error: {}", e),
386
+
Err(e) => tracing::error!(error = %e, "Error inserting album"),
392
387
}
393
388
}
394
389
395
-
println!("albums: {:?}", albums.len());
390
+
tracing::info!(albums = albums.len(), "Loaded albums");
396
391
Ok(())
397
392
}
398
393
···
407
402
.await?;
408
403
409
404
for (i, user) in users.clone().into_iter().enumerate() {
410
-
println!("user {} - {}", i, user.display_name.bright_green());
405
+
tracing::info!(user = i, name = %user.display_name.bright_green());
411
406
match conn.execute(
412
407
"INSERT INTO users (
413
408
id,
···
429
424
],
430
425
) {
431
426
Ok(_) => (),
432
-
Err(e) => println!("error: {}", e),
427
+
Err(e) => tracing::error!(error = %e, "Error inserting user"),
433
428
}
434
429
}
435
430
436
-
println!("users: {:?}", users.len());
431
+
tracing::info!(users = users.len(), "Loaded users");
437
432
Ok(())
438
433
}
439
434
···
451
446
.await?;
452
447
453
448
for (i, scrobble) in scrobbles.clone().into_iter().enumerate() {
454
-
println!(
455
-
"scrobble {} - {}",
456
-
i,
457
-
match scrobble.uri.clone() {
458
-
Some(uri) => uri.to_string(),
459
-
None => "None".to_string(),
460
-
}
461
-
.bright_green()
462
-
);
449
+
tracing::info!(scrobble = i, uri = %scrobble.uri.clone().unwrap_or_else(|| "None".to_string()).bright_green());
463
450
match conn.execute(
464
451
"INSERT INTO scrobbles (
465
452
id,
···
489
476
],
490
477
) {
491
478
Ok(_) => (),
492
-
Err(e) => println!("error: {}", e),
479
+
Err(e) => tracing::error!(error = %e, "Error inserting scrobble"),
493
480
}
494
481
}
495
482
496
-
println!("scrobbles: {:?}", scrobbles.len());
483
+
tracing::info!(scrobbles = scrobbles.len(), "Loaded scrobbles");
497
484
Ok(())
498
485
}
499
486
···
511
498
.await?;
512
499
513
500
for (i, album_track) in album_tracks.clone().into_iter().enumerate() {
514
-
println!(
515
-
"album_track {} - {} - {}",
516
-
i,
517
-
album_track.album_id.bright_green(),
518
-
album_track.track_id
519
-
);
501
+
tracing::info!(album_track = i, album_id = %album_track.album_id.bright_green(), track_id = %album_track.track_id);
520
502
match conn.execute(
521
503
"INSERT INTO album_tracks (
522
504
id,
···
532
514
],
533
515
) {
534
516
Ok(_) => (),
535
-
Err(e) => println!("error: {}", e),
517
+
Err(e) => tracing::error!(error = %e, "Error inserting album_track"),
536
518
}
537
519
}
538
-
println!("album_tracks: {:?}", album_tracks.len());
520
+
521
+
tracing::info!(album_tracks = album_tracks.len(), "Loaded album_tracks");
539
522
Ok(())
540
523
}
541
524
···
553
536
.await?;
554
537
555
538
for (i, loved_track) in loved_tracks.clone().into_iter().enumerate() {
556
-
println!(
557
-
"loved_track {} - {} - {}",
558
-
i,
559
-
loved_track.user_id.bright_green(),
560
-
loved_track.track_id
561
-
);
539
+
tracing::info!(loved_track = i, user_id = %loved_track.user_id.bright_green(), track_id = %loved_track.track_id);
562
540
match conn.execute(
563
541
"INSERT INTO loved_tracks (
564
542
id,
···
577
555
],
578
556
) {
579
557
Ok(_) => (),
580
-
Err(e) => println!("error: {}", e),
558
+
Err(e) => tracing::error!(error = %e, "Error inserting loved_track"),
581
559
}
582
560
}
583
561
584
-
println!("loved_tracks: {:?}", loved_tracks.len());
562
+
tracing::info!(loved_tracks = loved_tracks.len(), "Loaded loved_tracks");
585
563
Ok(())
586
564
}
587
565
···
599
577
.await?;
600
578
601
579
for (i, artist_track) in artist_tracks.clone().into_iter().enumerate() {
602
-
println!(
603
-
"artist_track {} - {} - {}",
604
-
i,
605
-
artist_track.artist_id.bright_green(),
606
-
artist_track.track_id
607
-
);
580
+
tracing::info!(artist_track = i, artist_id = %artist_track.artist_id.bright_green(), track_id = %artist_track.track_id);
608
581
match conn.execute(
609
582
"INSERT INTO artist_tracks (id, artist_id, track_id, created_at) VALUES (?, ?, ?, ?)",
610
583
params![
···
615
588
],
616
589
) {
617
590
Ok(_) => (),
618
-
Err(e) => println!("error: {}", e),
591
+
Err(e) => tracing::error!(error = %e, "Error inserting artist_track"),
619
592
}
620
593
}
621
594
622
-
println!("artist_tracks: {:?}", artist_tracks.len());
595
+
tracing::info!(artist_tracks = artist_tracks.len(), "Loaded artist_tracks");
623
596
Ok(())
624
597
}
625
598
···
637
610
.await?;
638
611
639
612
for (i, artist_album) in artist_albums.clone().into_iter().enumerate() {
640
-
println!(
641
-
"artist_albums {} - {} - {}",
642
-
i,
643
-
artist_album.artist_id.bright_green(),
644
-
artist_album.album_id
645
-
);
613
+
tracing::info!(artist_album = i, artist_id = %artist_album.artist_id.bright_green(), album_id = %artist_album.album_id);
646
614
match conn.execute(
647
615
"INSERT INTO artist_albums (id, artist_id, album_id, created_at) VALUES (?, ?, ?, ?)",
648
616
params![
···
653
621
],
654
622
) {
655
623
Ok(_) => (),
656
-
Err(e) => println!("error: {}", e),
624
+
Err(e) => tracing::error!(error = %e, "Error inserting artist_album"),
657
625
}
658
626
}
659
627
660
-
println!("artist_albums: {:?}", artist_albums.len());
628
+
tracing::info!(artist_albums = artist_albums.len(), "Loaded artist_albums");
661
629
Ok(())
662
630
}
663
631
···
675
643
.await?;
676
644
677
645
for (i, user_album) in user_albums.clone().into_iter().enumerate() {
678
-
println!(
679
-
"user_album {} - {} - {}",
680
-
i,
681
-
user_album.user_id.bright_green(),
682
-
user_album.album_id
683
-
);
646
+
tracing::info!(user_album = i, user_id = %user_album.user_id.bright_green(), album_id = %user_album.album_id);
684
647
match conn.execute(
685
648
"INSERT INTO user_albums (id, user_id, album_id, created_at) VALUES (?, ?, ?, ?)",
686
649
params![
···
691
654
],
692
655
) {
693
656
Ok(_) => (),
694
-
Err(e) => println!("error: {}", e),
657
+
Err(e) => tracing::error!(error = %e, "Error inserting user_album"),
695
658
}
696
659
}
697
660
698
-
println!("user_albums: {:?}", user_albums.len());
661
+
tracing::info!(user_albums = user_albums.len(), "Loaded user_albums");
699
662
Ok(())
700
663
}
701
664
···
713
676
.await?;
714
677
715
678
for (i, user_artist) in user_artists.clone().into_iter().enumerate() {
716
-
println!(
717
-
"user_artist {} - {} - {}",
718
-
i,
719
-
user_artist.user_id.bright_green(),
720
-
user_artist.artist_id
721
-
);
679
+
tracing::info!(user_artist = i, user_id = %user_artist.user_id.bright_green(), artist_id = %user_artist.artist_id);
722
680
match conn.execute(
723
681
"INSERT INTO user_artists (id, user_id, artist_id, created_at) VALUES (?, ?, ?, ?)",
724
682
params![
···
729
687
],
730
688
) {
731
689
Ok(_) => (),
732
-
Err(e) => println!("error: {}", e),
690
+
Err(e) => tracing::error!(error = %e, "Error inserting user_artist"),
733
691
}
734
692
}
735
693
736
-
println!("user_artists: {:?}", user_artists.len());
694
+
tracing::info!(user_artists = user_artists.len(), "Loaded user_artists");
737
695
Ok(())
738
696
}
739
697
···
751
709
.await?;
752
710
753
711
for (i, user_track) in user_tracks.clone().into_iter().enumerate() {
754
-
println!(
755
-
"user_track {} - {} - {}",
756
-
i,
757
-
user_track.user_id.bright_green(),
758
-
user_track.track_id
759
-
);
712
+
tracing::info!(user_track = i, user_id = %user_track.user_id.bright_green(), track_id = %user_track.track_id);
760
713
match conn.execute(
761
714
"INSERT INTO user_tracks (id, user_id, track_id, created_at) VALUES (?, ?, ?, ?)",
762
715
params![
···
767
720
],
768
721
) {
769
722
Ok(_) => (),
770
-
Err(e) => println!("error: {}", e),
723
+
Err(e) => tracing::error!(error = %e, "Error inserting user_track"),
771
724
}
772
725
}
773
726
774
-
println!("user_tracks: {:?}", user_tracks.len());
727
+
tracing::info!(user_tracks = user_tracks.len(), "Loaded user_tracks");
775
728
Ok(())
776
729
}
+4
crates/analytics/src/handlers/albums.rs
+4
crates/analytics/src/handlers/albums.rs
···
22
22
let offset = pagination.skip.unwrap_or(0);
23
23
let limit = pagination.take.unwrap_or(20);
24
24
let did = params.user_did;
25
+
tracing::info!(limit, offset, user_did = ?did, "Get albums");
25
26
26
27
let conn = conn.lock().unwrap();
27
28
let mut stmt = match did {
···
118
119
let offset = pagination.skip.unwrap_or(0);
119
120
let limit = pagination.take.unwrap_or(20);
120
121
let did = params.user_did;
122
+
tracing::info!(limit, offset, user_did = ?did, "Get top albums");
121
123
122
124
let conn = conn.lock().unwrap();
123
125
let mut stmt = match did {
···
237
239
let body = read_payload!(payload);
238
240
let params = serde_json::from_slice::<GetAlbumTracksParams>(&body)?;
239
241
let conn = conn.lock().unwrap();
242
+
tracing::info!(album_id = %params.album_id, "Get album tracks");
243
+
240
244
let mut stmt = conn.prepare(r#"
241
245
SELECT
242
246
t.id,
+2
crates/analytics/src/handlers/artists.rs
+2
crates/analytics/src/handlers/artists.rs
···
318
318
let body = read_payload!(payload);
319
319
let params = serde_json::from_slice::<GetArtistAlbumsParams>(&body)?;
320
320
let conn = conn.lock().unwrap();
321
+
tracing::info!(artist_id = %params.artist_id, "Get artist albums");
321
322
322
323
let mut stmt = conn.prepare(r#"
323
324
SELECT
···
376
377
let pagination = params.pagination.unwrap_or_default();
377
378
let offset = pagination.skip.unwrap_or(0);
378
379
let limit = pagination.take.unwrap_or(10);
380
+
tracing::info!(artist_id = %params.artist_id, limit, offset, "Get artist listeners");
379
381
380
382
let conn = conn.lock().unwrap();
381
383
let mut stmt =
+2
crates/analytics/src/handlers/scrobbles.rs
+2
crates/analytics/src/handlers/scrobbles.rs
···
19
19
let offset = pagination.skip.unwrap_or(0);
20
20
let limit = pagination.take.unwrap_or(20);
21
21
let did = params.user_did;
22
+
tracing::info!(limit, offset, user_did = ?did, "Get scrobbles");
22
23
23
24
let conn = conn.lock().unwrap();
24
25
let mut stmt = match did {
···
139
140
let pagination = params.pagination.unwrap_or_default();
140
141
let offset = pagination.skip.unwrap_or(0);
141
142
let limit = pagination.take.unwrap_or(10);
143
+
tracing::info!(limit, offset, user_did = ?params.user_did, "Get distinct scrobbles");
142
144
143
145
let conn = conn.lock().unwrap();
144
146
let mut stmt = conn.prepare(
+8
crates/analytics/src/handlers/stats.rs
+8
crates/analytics/src/handlers/stats.rs
···
23
23
let body = read_payload!(payload);
24
24
25
25
let params = serde_json::from_slice::<GetStatsParams>(&body)?;
26
+
tracing::info!(user_did = ?params.user_did, "Get stats");
26
27
27
28
let conn = conn.lock().unwrap();
28
29
let mut stmt = conn.prepare("SELECT COUNT(*) FROM scrobbles s LEFT JOIN users u ON s.user_id = u.id WHERE u.did = ? OR u.handle = ?")?;
···
118
119
.end
119
120
.unwrap_or(GetScrobblesPerDayParams::default().end.unwrap());
120
121
let did = params.user_did;
122
+
tracing::info!(start = %start, end = %end, user_did = ?did, "Get scrobbles per day");
121
123
122
124
let conn = conn.lock().unwrap();
123
125
match did {
···
190
192
.end
191
193
.unwrap_or(GetScrobblesPerDayParams::default().end.unwrap());
192
194
let did = params.user_did;
195
+
tracing::info!(start = %start, end = %end, user_did = ?did, "Get scrobbles per month");
193
196
194
197
let conn = conn.lock().unwrap();
195
198
match did {
···
266
269
.end
267
270
.unwrap_or(GetScrobblesPerDayParams::default().end.unwrap());
268
271
let did = params.user_did;
272
+
tracing::info!(start = %start, end = %end, user_did = ?did, "Get scrobbles per year");
269
273
270
274
let conn = conn.lock().unwrap();
271
275
match did {
···
338
342
.end
339
343
.unwrap_or(GetAlbumScrobblesParams::default().end.unwrap());
340
344
let conn = conn.lock().unwrap();
345
+
tracing::info!(album_id = %params.album_id, start = %start, end = %end, "Get album scrobbles");
346
+
341
347
let mut stmt = conn.prepare(
342
348
r#"
343
349
SELECT
···
379
385
.end
380
386
.unwrap_or(GetArtistScrobblesParams::default().end.unwrap());
381
387
let conn = conn.lock().unwrap();
388
+
tracing::info!(artist_id = %params.artist_id, start = %start, end = %end, "Get artist scrobbles");
382
389
383
390
let mut stmt = conn.prepare(
384
391
r#"
···
426
433
.end
427
434
.unwrap_or(GetTrackScrobblesParams::default().end.unwrap());
428
435
let conn = conn.lock().unwrap();
436
+
tracing::info!(track_id = %params.track_id, start = %start, end = %end, "Get track scrobbles");
429
437
430
438
let mut stmt = conn.prepare(
431
439
r#"
+3
crates/analytics/src/handlers/tracks.rs
+3
crates/analytics/src/handlers/tracks.rs
···
19
19
let offset = pagination.skip.unwrap_or(0);
20
20
let limit = pagination.take.unwrap_or(20);
21
21
let did = params.user_did;
22
+
tracing::info!(limit, offset, user_did = ?did, "Get tracks");
22
23
23
24
let conn = conn.lock().unwrap();
24
25
match did {
···
178
179
let offset = pagination.skip.unwrap_or(0);
179
180
let limit = pagination.take.unwrap_or(20);
180
181
let did = params.user_did;
182
+
tracing::info!(limit, offset, user_did = ?did, "Get loved tracks");
181
183
182
184
let conn = conn.lock().unwrap();
183
185
let mut stmt = conn.prepare(
···
261
263
let offset = pagination.skip.unwrap_or(0);
262
264
let limit = pagination.take.unwrap_or(20);
263
265
let did = params.user_did;
266
+
tracing::info!(limit, offset, user_did = ?did, "Get top tracks");
264
267
265
268
let conn = conn.lock().unwrap();
266
269
match did {
+174
-172
crates/analytics/src/subscriber/mod.rs
+174
-172
crates/analytics/src/subscriber/mod.rs
···
16
16
let addr = env::var("NATS_URL").unwrap_or_else(|_| "nats://localhost:4222".to_string());
17
17
let conn = conn.clone();
18
18
let nc = connect(&addr).await?;
19
-
println!("Connected to NATS server at {}", addr.bright_green());
19
+
tracing::info!(server = %addr.bright_green(), "Connected to NATS");
20
20
21
21
let nc = Arc::new(Mutex::new(nc));
22
22
on_scrobble(nc.clone(), conn.clone());
···
39
39
40
40
41
41
42
+
let data = String::from_utf8(msg.payload.to_vec()).unwrap();
43
+
match serde_json::from_str::<ScrobblePayload>(&data) {
44
+
Ok(payload) => match save_scrobble(conn.clone(), payload.clone()).await {
45
+
Ok(_) => tracing::info!(
46
+
uri = %payload.scrobble.uri.cyan(),
47
+
"Scrobble saved successfully",
48
+
),
49
+
Err(e) => tracing::error!("Error saving scrobble: {}", e),
50
+
},
51
+
Err(e) => {
52
+
tracing::error!("Error parsing payload: {}", e);
53
+
tracing::debug!("{}", data);
54
+
}
55
+
}
56
+
}
42
57
43
58
44
59
···
59
74
60
75
61
76
77
+
match serde_json::from_str::<NewTrackPayload>(&data) {
78
+
Ok(payload) => match save_track(conn.clone(), payload.clone()).await {
79
+
Ok(_) => {
80
+
tracing::info!(
81
+
title = %payload.track.title.cyan(),
82
+
"Track saved successfully",
83
+
)
84
+
}
85
+
Err(e) => tracing::error!("Error saving track: {}", e),
86
+
},
87
+
Err(e) => {
88
+
tracing::error!("Error parsing payload: {}", e);
89
+
tracing::debug!("{}", data);
90
+
}
91
+
}
92
+
}
62
93
63
94
64
95
···
78
109
79
110
80
111
112
+
let data = String::from_utf8(msg.payload.to_vec()).unwrap();
113
+
match serde_json::from_str::<LikePayload>(&data) {
114
+
Ok(payload) => match like(conn.clone(), payload.clone()).await {
115
+
Ok(_) => tracing::info!(
116
+
track_id = %payload.track_id.xata_id.cyan(),
117
+
"Like saved successfully",
118
+
),
119
+
Err(e) => tracing::error!("Error saving like: {}", e),
120
+
},
121
+
Err(e) => {
122
+
tracing::error!("Error parsing payload: {}", e);
123
+
tracing::debug!("{}", data);
124
+
}
125
+
}
126
+
}
81
127
82
128
83
129
···
97
143
98
144
99
145
146
+
let data = String::from_utf8(msg.payload.to_vec()).unwrap();
147
+
match serde_json::from_str::<UnlikePayload>(&data) {
148
+
Ok(payload) => match unlike(conn.clone(), payload.clone()).await {
149
+
Ok(_) => tracing::info!(
150
+
track_id = %payload.track_id.xata_id.cyan(),
151
+
"Unlike saved successfully",
152
+
),
153
+
Err(e) => tracing::error!("Error saving unlike: {}", e),
154
+
},
155
+
Err(e) => {
156
+
tracing::error!("Error parsing payload: {}", e);
157
+
tracing::debug!("{}", data);
158
+
}
159
+
}
160
+
}
100
161
101
162
102
163
···
116
177
117
178
118
179
180
+
let data = String::from_utf8(msg.payload.to_vec()).unwrap();
181
+
match serde_json::from_str::<UserPayload>(&data) {
182
+
Ok(payload) => match save_user(conn.clone(), payload.clone()).await {
183
+
Ok(_) => tracing::info!(
184
+
handle = %payload.handle.cyan(),
185
+
"User saved successfully",
186
+
),
187
+
Err(e) => tracing::error!("Error saving user: {}", e),
188
+
},
189
+
Err(e) => {
190
+
tracing::error!("Error parsing payload: {}", e);
191
+
tracing::debug!("{}", data);
192
+
}
193
+
}
194
+
}
119
195
120
196
121
197
···
176
252
177
253
178
254
255
+
Ok(_) => (),
256
+
Err(e) => {
257
+
if !e.to_string().contains("violates primary key constraint") {
258
+
tracing::error!("[artists] error: {}", e);
259
+
return Err(e.into());
260
+
}
261
+
}
179
262
180
263
181
264
···
224
307
225
308
226
309
310
+
Ok(_) => (),
311
+
Err(e) => {
312
+
if !e.to_string().contains("violates primary key constraint") {
313
+
tracing::error!("[albums] error: {}", e);
314
+
return Err(e.into());
315
+
}
316
+
}
227
317
228
318
229
319
···
280
370
281
371
282
372
373
+
Ok(_) => (),
374
+
Err(e) => {
375
+
if !e.to_string().contains("violates primary key constraint") {
376
+
tracing::error!("[tracks] error: {}", e);
377
+
return Err(e.into());
378
+
}
379
+
}
283
380
284
381
285
382
···
296
393
297
394
298
395
396
+
Ok(_) => (),
397
+
Err(e) => {
398
+
if !e.to_string().contains("violates primary key constraint") {
399
+
tracing::error!("[album_tracks] error: {}", e);
400
+
return Err(e.into());
401
+
}
402
+
}
299
403
300
404
301
405
···
307
411
308
412
309
413
414
+
Ok(_) => (),
415
+
Err(e) => {
416
+
if !e.to_string().contains("violates primary key constraint") {
417
+
tracing::error!("[artist_tracks] error: {}", e);
418
+
return Err(e.into());
419
+
}
420
+
}
310
421
311
422
312
423
···
318
429
319
430
320
431
432
+
Ok(_) => (),
433
+
Err(e) => {
434
+
if !e.to_string().contains("violates primary key constraint") {
435
+
tracing::error!("[artist_albums] error: {}", e);
436
+
return Err(e.into());
437
+
}
438
+
}
321
439
322
440
323
441
···
329
447
330
448
331
449
450
+
Ok(_) => (),
451
+
Err(e) => {
452
+
if !e.to_string().contains("violates primary key constraint") {
453
+
tracing::error!("[user_albums] error: {}", e);
454
+
return Err(e.into());
455
+
}
456
+
}
332
457
333
458
334
459
···
340
465
341
466
342
467
468
+
Ok(_) => (),
469
+
Err(e) => {
470
+
if !e.to_string().contains("violates primary key constraint") {
471
+
tracing::error!("[user_artists] error: {}", e);
472
+
return Err(e.into());
473
+
}
474
+
}
343
475
344
476
345
477
···
351
483
352
484
353
485
486
+
Ok(_) => (),
487
+
Err(e) => {
488
+
if !e.to_string().contains("violates primary key constraint") {
489
+
tracing::error!("[user_tracks] error: {}", e);
490
+
return Err(e.into());
491
+
}
492
+
}
354
493
355
494
356
495
···
381
520
382
521
383
522
523
+
Ok(_) => (),
524
+
Err(e) => {
525
+
if !e.to_string().contains("violates primary key constraint") {
526
+
tracing::error!("[scrobbles] error: {}", e);
527
+
return Err(e.into());
528
+
}
529
+
}
384
530
385
531
386
532
···
446
592
447
593
448
594
595
+
Ok(_) => (),
596
+
Err(e) => {
597
+
if !e.to_string().contains("violates primary key constraint") {
598
+
tracing::error!("[tracks] error: {}", e);
599
+
return Err(e.into());
600
+
}
601
+
}
449
602
450
603
451
604
···
462
615
463
616
464
617
618
+
Ok(_) => (),
619
+
Err(e) => {
620
+
if !e.to_string().contains("violates primary key constraint") {
621
+
tracing::error!("[album_tracks] error: {}", e);
622
+
return Err(e.into());
623
+
}
624
+
}
465
625
466
626
467
627
···
473
633
474
634
475
635
636
+
Ok(_) => (),
637
+
Err(e) => {
638
+
if !e.to_string().contains("violates primary key constraint") {
639
+
tracing::error!("[artist_tracks] error: {}", e);
640
+
return Err(e.into());
641
+
}
642
+
}
476
643
477
644
478
645
···
484
651
485
652
486
653
487
-
488
-
489
-
490
-
491
-
492
-
493
-
494
-
495
-
496
-
497
-
498
-
499
-
500
-
501
-
502
-
503
-
504
-
505
-
506
-
507
-
508
-
509
-
510
-
511
-
512
-
513
-
514
-
515
-
516
-
517
-
518
-
519
-
520
-
521
-
522
-
523
-
524
-
525
-
526
-
527
-
528
-
529
-
530
-
531
-
532
-
533
-
534
-
535
-
536
-
537
-
538
-
539
-
540
-
541
-
542
-
543
-
544
-
545
-
546
-
547
-
548
-
549
-
550
-
551
-
552
-
553
-
554
-
555
-
556
-
557
-
558
-
559
-
560
-
561
-
562
-
563
-
564
-
565
-
566
-
567
-
568
-
569
-
570
-
571
-
572
-
573
-
574
-
575
-
576
-
577
-
578
-
579
-
580
-
581
-
582
-
583
-
584
-
585
-
586
-
587
-
588
-
589
-
590
-
591
-
592
-
593
-
594
-
595
-
596
-
597
-
598
-
599
-
600
-
601
-
602
-
603
-
604
-
605
-
606
-
607
-
608
-
609
-
610
-
611
-
612
-
613
-
614
-
615
-
616
-
617
-
618
-
619
-
620
-
621
-
622
-
623
-
624
-
625
-
626
-
627
-
628
-
629
-
630
-
631
-
632
-
633
-
634
-
635
-
636
-
637
-
638
-
639
-
640
-
641
-
642
-
643
-
644
-
645
-
646
-
647
-
648
-
649
-
650
-
651
-
652
654
Ok(_) => (),
653
655
Err(e) => {
654
656
if !e.to_string().contains("violates primary key constraint") {
655
-
println!("[artist_albums] error: {}", e);
657
+
tracing::error!("[artist_albums] error: {}", e);
656
658
return Err(e.into());
657
659
}
658
660
}
···
684
686
Ok(_) => (),
685
687
Err(e) => {
686
688
if !e.to_string().contains("violates primary key constraint") {
687
-
println!("[likes] error: {}", e);
689
+
tracing::error!("[likes] error: {}", e);
688
690
return Err(e.into());
689
691
}
690
692
}
···
700
702
) {
701
703
Ok(_) => (),
702
704
Err(e) => {
703
-
println!("[unlikes] error: {}", e);
705
+
tracing::error!("[unlikes] error: {}", e);
704
706
return Err(e.into());
705
707
}
706
708
}
···
740
742
Ok(_) => (),
741
743
Err(e) => {
742
744
if !e.to_string().contains("violates primary key constraint") {
743
-
println!("[users] error: {}", e);
745
+
tracing::error!("[users] error: {}", e);
744
746
return Err(e.into());
745
747
}
746
748
}
···
921
923
922
924
match serde_json::from_str::<types::ScrobblePayload>(data) {
923
925
Err(e) => {
924
-
eprintln!("Error parsing payload: {}", e);
925
-
println!("{}", data);
926
+
tracing::error!("Error parsing payload: {}", e);
927
+
tracing::error!("{}", data);
926
928
}
927
929
Ok(_) => {}
928
930
}
+1
crates/dropbox/Cargo.toml
+1
crates/dropbox/Cargo.toml
+1
crates/googledrive/Cargo.toml
+1
crates/googledrive/Cargo.toml
+1
crates/jetstream/Cargo.toml
+1
crates/jetstream/Cargo.toml
+1
crates/playlists/Cargo.toml
+1
crates/playlists/Cargo.toml
+4
crates/rockskyd/Cargo.toml
+4
crates/rockskyd/Cargo.toml
+12
crates/rockskyd/src/main.rs
+12
crates/rockskyd/src/main.rs
···
1
1
use clap::Command;
2
2
use dotenv::dotenv;
3
+
use tracing_subscriber::fmt::format::Format;
3
4
4
5
pub mod cmd;
5
6
···
35
36
36
37
#[tokio::main]
37
38
async fn main() -> Result<(), Box<dyn std::error::Error>> {
39
+
let format = Format::default()
40
+
.with_level(true)
41
+
.with_target(true)
42
+
.with_ansi(true)
43
+
.compact();
44
+
45
+
tracing_subscriber::fmt()
46
+
.event_format(format)
47
+
.with_max_level(tracing::Level::INFO)
48
+
.init();
49
+
38
50
dotenv().ok();
39
51
40
52
let args = cli().get_matches();
+6
-9
crates/scrobbler/Cargo.toml
+6
-9
crates/scrobbler/Cargo.toml
···
3
3
4
4
5
5
6
+
license.workspace = true
7
+
repository.workspace = true
6
8
9
+
[dependencies]
10
+
serde = { version = "1.0.217", features = ["derive"] }
11
+
serde_json = "1.0.139"
7
12
8
13
9
14
···
32
37
33
38
34
39
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
40
actix-limitation = "0.5.1"
45
41
actix-session = "0.10.1"
46
42
tokio-stream = { version = "0.1.17", features = ["full"] }
43
+
tracing = "0.1.41"
+1
crates/spotify/Cargo.toml
+1
crates/spotify/Cargo.toml
+1
crates/storage/Cargo.toml
+1
crates/storage/Cargo.toml
+1
crates/tracklist/Cargo.toml
+1
crates/tracklist/Cargo.toml
+6
-9
crates/webscrobbler/Cargo.toml
+6
-9
crates/webscrobbler/Cargo.toml
···
3
3
4
4
5
5
6
+
license.workspace = true
7
+
repository.workspace = true
6
8
9
+
[dependencies]
10
+
serde = { version = "1.0.217", features = ["derive"] }
11
+
serde_json = "1.0.139"
7
12
8
13
9
14
···
30
35
31
36
32
37
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
38
tokio-stream = { version = "0.1.17", features = ["full"] }
43
39
actix-session = "0.10.1"
44
40
actix-limitation = "0.5.1"
41
+
tracing = "0.1.41"
+2
-2
crates/dropbox/src/cmd/serve.rs
+2
-2
crates/dropbox/src/cmd/serve.rs
···
27
27
req: HttpRequest,
28
28
) -> Result<impl Responder, actix_web::Error> {
29
29
let method = req.match_info().get("method").unwrap_or("unknown");
30
-
println!("Method: {}", method.bright_green());
30
+
tracing::info!(method = %method.bright_green(), "API call");
31
31
32
32
let conn = data.get_ref().clone();
33
33
handle(method, &mut payload, &req, conn)
···
41
41
let addr = format!("{}:{}", host, port);
42
42
43
43
let url = format!("http://{}", addr);
44
-
println!("Listening on {}", url.bright_green());
44
+
tracing::info!(url = %url.bright_green(), "Listening on");
45
45
46
46
let pool = PgPoolOptions::new()
47
47
.max_connections(5)
+8
crates/dropbox/src/handlers/files.rs
+8
crates/dropbox/src/handlers/files.rs
···
2
2
3
3
use actix_web::{web, HttpRequest, HttpResponse};
4
4
use anyhow::Error;
5
+
use owo_colors::OwoColorize;
5
6
use sqlx::{Pool, Postgres};
6
7
use tokio_stream::StreamExt;
7
8
···
24
25
let body = read_payload!(payload);
25
26
let params = serde_json::from_slice::<GetFilesParams>(&body)?;
26
27
let refresh_token = find_dropbox_refresh_token(&pool.clone(), ¶ms.did).await?;
28
+
tracing::info!(did = %params.did.bright_green(), "dropbox.getFiles");
27
29
28
30
if refresh_token.is_none() {
29
31
return Ok(HttpResponse::Unauthorized().finish());
···
48
50
let body = read_payload!(payload);
49
51
let params = serde_json::from_slice::<GetFilesParams>(&body)?;
50
52
let refresh_token = find_dropbox_refresh_token(&pool.clone(), ¶ms.did).await?;
53
+
tracing::info!(did = %params.did.bright_green(), "dropbox.createMusicFolder");
51
54
52
55
if refresh_token.is_none() {
53
56
return Ok(HttpResponse::Unauthorized().finish());
···
72
75
let body = read_payload!(payload);
73
76
let params = serde_json::from_slice::<GetFilesAtParams>(&body)?;
74
77
let refresh_token = find_dropbox_refresh_token(&pool.clone(), ¶ms.did).await?;
78
+
tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.getFilesAt");
75
79
76
80
if refresh_token.is_none() {
77
81
return Ok(HttpResponse::Unauthorized().finish());
···
96
100
let body = read_payload!(payload);
97
101
let params = serde_json::from_slice::<DownloadFileParams>(&body)?;
98
102
let refresh_token = find_dropbox_refresh_token(&pool.clone(), ¶ms.did).await?;
103
+
tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.downloadFile");
99
104
100
105
if refresh_token.is_none() {
101
106
return Ok(HttpResponse::Unauthorized().finish());
···
118
123
let body = read_payload!(payload);
119
124
let params = serde_json::from_slice::<DownloadFileParams>(&body)?;
120
125
let refresh_token = find_dropbox_refresh_token(&pool.clone(), ¶ms.did).await?;
126
+
tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.getTemporaryLink");
121
127
122
128
if refresh_token.is_none() {
123
129
return Ok(HttpResponse::Unauthorized().finish());
···
142
148
let body = read_payload!(payload);
143
149
let params = serde_json::from_slice::<DownloadFileParams>(&body)?;
144
150
let refresh_token = find_dropbox_refresh_token(&pool.clone(), ¶ms.did).await?;
151
+
tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.getMetadata");
145
152
146
153
if refresh_token.is_none() {
147
154
return Ok(HttpResponse::Unauthorized().finish());
···
165
172
) -> Result<HttpResponse, Error> {
166
173
let body = read_payload!(payload);
167
174
let params = serde_json::from_slice::<ScanFolderParams>(&body)?;
175
+
tracing::info!(did = %params.did.bright_green(), path = %params.path.bright_green(), "dropbox.scanFolder");
168
176
169
177
let pool = pool.clone();
170
178
thread::spawn(move || {
+60
-74
crates/dropbox/src/scan.rs
+60
-74
crates/dropbox/src/scan.rs
···
91
91
.await?;
92
92
93
93
if res.status().as_u16() == 400 || res.status().as_u16() == 409 {
94
-
println!("Path not found: {}", path.bright_red());
94
+
tracing::error!(path = %path.bright_red(), "Path not found");
95
95
return Ok(());
96
96
}
97
97
98
98
let entry = res.json::<Entry>().await?;
99
99
100
100
if entry.tag.clone().unwrap().as_str() == "folder" {
101
-
println!("Scanning folder: {}", path.bright_green());
101
+
tracing::info!(path = %path.bright_green(), "Scanning folder");
102
102
103
103
let parent_path = Path::new(&path)
104
104
.parent()
···
160
160
161
161
let client = Client::new();
162
162
163
-
println!("Downloading file: {}", path.bright_green());
163
+
tracing::info!(path = %path.bright_green(), "Downloading file");
164
164
165
165
let res = client
166
166
.post(&format!("{}/files/download", CONTENT_URL))
···
176
176
let mut tmpfile = File::create(&tmppath)?;
177
177
tmpfile.write_all(&bytes)?;
178
178
179
-
println!(
180
-
"Reading file: {}",
181
-
&tmppath.clone().display().to_string().bright_green()
182
-
);
179
+
tracing::info!(path = %tmppath.clone().display().to_string().bright_green(), "Reading file");
183
180
184
181
let tagged_file = match Probe::open(&tmppath)?.read() {
185
182
Ok(tagged_file) => tagged_file,
186
183
Err(e) => {
187
-
println!("Error opening file: {}", e);
184
+
tracing::error!(path = %tmppath.clone().display().to_string().bright_red(), "Error reading file: {}", e);
188
185
return Ok(());
189
186
}
190
187
};
···
193
190
let tag = match primary_tag {
194
191
Some(tag) => tag,
195
192
None => {
196
-
println!("No tag found in file");
193
+
tracing::error!(path = %tmppath.clone().display().to_string().bright_red(), "No tag found in file");
197
194
return Ok(());
198
195
}
199
196
};
200
197
201
198
let pictures = tag.pictures();
202
199
203
-
println!(
204
-
"Title: {}",
205
-
tag.get_string(&lofty::tag::ItemKey::TrackTitle)
206
-
.unwrap_or_default()
207
-
.bright_green()
208
-
);
209
-
println!(
210
-
"Artist: {}",
211
-
tag.get_string(&lofty::tag::ItemKey::TrackArtist)
212
-
.unwrap_or_default()
213
-
.bright_green()
200
+
tracing::info!(
201
+
title = %tag
202
+
.get_string(&lofty::tag::ItemKey::TrackTitle)
203
+
.unwrap_or_default(),
214
204
);
215
-
println!(
216
-
"Album Artist: {}",
217
-
tag.get_string(&lofty::tag::ItemKey::AlbumArtist)
218
-
.unwrap_or_default()
219
-
.bright_green()
205
+
tracing::info!(
206
+
artist = %tag
207
+
.get_string(&lofty::tag::ItemKey::TrackArtist)
208
+
.unwrap_or_default(),
220
209
);
221
-
println!(
222
-
"Album: {}",
223
-
tag.get_string(&lofty::tag::ItemKey::AlbumTitle)
224
-
.unwrap_or_default()
225
-
.bright_green()
210
+
tracing::info!(
211
+
album = %tag
212
+
.get_string(&lofty::tag::ItemKey::AlbumTitle)
213
+
.unwrap_or_default(),
226
214
);
227
-
println!(
228
-
"Lyrics: {}",
229
-
tag.get_string(&lofty::tag::ItemKey::Lyrics)
230
-
.unwrap_or_default()
231
-
.bright_green()
215
+
tracing::info!(
216
+
album_artist = %tag
217
+
.get_string(&lofty::tag::ItemKey::AlbumArtist)
218
+
.unwrap_or_default(),
232
219
);
233
-
println!("Year: {}", tag.year().unwrap_or_default().bright_green());
234
-
println!(
235
-
"Track Number: {}",
236
-
tag.track().unwrap_or_default().bright_green()
220
+
tracing::info!(
221
+
lyrics = %tag
222
+
.get_string(&lofty::tag::ItemKey::Lyrics)
223
+
.unwrap_or_default(),
237
224
);
238
-
println!(
239
-
"Track Total: {}",
240
-
tag.track_total().unwrap_or_default().bright_green()
225
+
tracing::info!(year = %tag.year().unwrap_or_default());
226
+
tracing::info!(track_number = %tag.track().unwrap_or_default());
227
+
tracing::info!(track_total = %tag.track_total().unwrap_or_default());
228
+
tracing::info!(
229
+
release_date = %tag
230
+
.get_string(&lofty::tag::ItemKey::OriginalReleaseDate)
231
+
.unwrap_or_default(),
241
232
);
242
-
println!(
243
-
"Release Date: {:?}",
244
-
tag.get_string(&lofty::tag::ItemKey::OriginalReleaseDate)
245
-
.unwrap_or_default()
246
-
.bright_green()
233
+
tracing::info!(
234
+
recording_date = %tag
235
+
.get_string(&lofty::tag::ItemKey::RecordingDate)
236
+
.unwrap_or_default(),
247
237
);
248
-
println!(
249
-
"Recording Date: {:?}",
250
-
tag.get_string(&lofty::tag::ItemKey::RecordingDate)
251
-
.unwrap_or_default()
252
-
.bright_green()
238
+
tracing::info!(
239
+
copyright_message = %tag
240
+
.get_string(&lofty::tag::ItemKey::CopyrightMessage)
241
+
.unwrap_or_default(),
253
242
);
254
-
println!(
255
-
"Copyright Message: {}",
256
-
tag.get_string(&lofty::tag::ItemKey::CopyrightMessage)
257
-
.unwrap_or_default()
258
-
.bright_green()
259
-
);
260
-
println!("Pictures: {:?}", pictures);
243
+
tracing::info!(pictures = ?pictures);
261
244
262
245
let title = tag
263
246
.get_string(&lofty::tag::ItemKey::TrackTitle)
···
290
273
291
274
match track {
292
275
Some(track) => {
293
-
println!("Track exists: {}", title.bright_green());
276
+
tracing::info!(title = %title.bright_green(), "Track exists");
294
277
let parent_path = Path::new(&path)
295
278
.parent()
296
279
.map(|p| p.to_string_lossy().to_string());
297
280
let status =
298
281
create_dropbox_path(&pool, &entry, &track, &dropbox_id, parent_path).await;
299
-
println!("status: {:?}", status);
282
+
tracing::info!(status = ?status);
300
283
301
284
// TODO: publish file metadata to nats
302
285
}
303
286
None => {
304
-
println!("Creating track: {}", title.bright_green());
287
+
tracing::info!(title = %title.bright_green(), "Creating track");
305
288
let album_art =
306
289
upload_album_cover(albumart_id.into(), pictures, &access_token).await?;
307
290
let client = Client::new();
···
338
321
}))
339
322
.send()
340
323
.await?;
341
-
println!("Track Saved: {} {}", title, response.status());
324
+
tracing::info!(title = title, status = %response.status(), "Track saved");
342
325
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
343
326
344
327
let track = get_track_by_hash(&pool, &hash).await?;
···
353
336
return Ok(());
354
337
}
355
338
356
-
println!("Failed to create track: {}", title.bright_green());
339
+
tracing::error!(title = %title.bright_red(), "Failed to create track");
357
340
}
358
341
}
359
342
···
413
396
.send()
414
397
.await?;
415
398
416
-
println!("Cover uploaded: {}", response.status());
399
+
tracing::info!(status = %response.status(), "Cover uploaded");
417
400
418
401
Ok(Some(name))
419
402
}
···
433
416
let meta_opts = MetadataOptions::default();
434
417
let format_opts = FormatOptions::default();
435
418
436
-
let probed =
437
-
match symphonia::default::get_probe().format(&hint, media_source, &format_opts, &meta_opts)
438
-
{
439
-
Ok(probed) => probed,
440
-
Err(_) => {
441
-
println!("Error probing file");
442
-
return Ok(duration);
443
-
}
444
-
};
419
+
let probed = match symphonia::default::get_probe().format(
420
+
&hint,
421
+
media_source,
422
+
&format_opts,
423
+
&meta_opts,
424
+
) {
425
+
Ok(probed) => probed,
426
+
Err(e) => {
427
+
tracing::error!(path = %path.display().to_string().bright_red(), "Error probing file: {}", e);
428
+
return Ok(duration);
429
+
}
430
+
};
445
431
446
432
if let Some(track) = probed.format.tracks().first() {
447
433
if let Some(duration) = track.codec_params.n_frames {
+2
-2
crates/googledrive/src/cmd/serve.rs
+2
-2
crates/googledrive/src/cmd/serve.rs
···
27
27
req: HttpRequest,
28
28
) -> Result<impl Responder, actix_web::Error> {
29
29
let method = req.match_info().get("method").unwrap_or("unknown");
30
-
println!("Method: {}", method.bright_green());
30
+
tracing::info!(method = %method.bright_green(), "API call");
31
31
32
32
let conn = data.get_ref().clone();
33
33
handle(method, &mut payload, &req, conn)
···
41
41
let addr = format!("{}:{}", host, port);
42
42
43
43
let url = format!("http://{}", addr);
44
-
println!("Listening on {}", url.bright_green());
44
+
tracing::info!(url = %url.bright_green(), "Listening on");
45
45
46
46
let pool = PgPoolOptions::new()
47
47
.max_connections(5)
+6
-1
crates/googledrive/src/repo/google_drive_path.rs
+6
-1
crates/googledrive/src/repo/google_drive_path.rs
···
1
+
use owo_colors::OwoColorize;
1
2
use sqlx::{Pool, Postgres};
2
3
3
4
use crate::{
···
47
48
.execute(pool)
48
49
.await?;
49
50
50
-
println!("{:?}", result);
51
+
tracing::info!(
52
+
file_id = %file.id.bright_green(),
53
+
rows_affected = %result.rows_affected(),
54
+
"Google Drive path created"
55
+
);
51
56
52
57
sqlx::query(
53
58
r#"
+27
-79
crates/googledrive/src/scan.rs
+27
-79
crates/googledrive/src/scan.rs
···
104
104
let file = res.json::<File>().await?;
105
105
106
106
if file.mime_type == "application/vnd.google-apps.folder" {
107
-
println!("Scanning folder: {}", file.name.bright_green());
107
+
tracing::info!(folder = %file.name.bright_green(), "Scanning folder");
108
108
109
109
create_google_drive_directory(
110
110
&pool,
···
172
172
return Ok(());
173
173
}
174
174
175
-
println!("Downloading file: {}", file.name.bright_green());
175
+
tracing::info!(file = %file.name.bright_green(), "Downloading file");
176
176
177
177
let client = Client::new();
178
178
···
191
191
let mut tmpfile = std::fs::File::create(&tmppath)?;
192
192
tmpfile.write_all(&bytes)?;
193
193
194
-
println!(
195
-
"Reading file: {}",
196
-
&tmppath.clone().display().to_string().bright_green()
197
-
);
194
+
tracing::info!(path = %tmppath.display(), "Reading file");
198
195
199
196
let tagged_file = match Probe::open(&tmppath)?.read() {
200
197
Ok(tagged_file) => tagged_file,
201
198
Err(e) => {
202
-
println!("Error opening file: {}", e);
199
+
tracing::warn!(file = %file.name.bright_green(), error = %e, "Failed to open file with lofty");
203
200
return Ok(());
204
201
}
205
202
};
···
208
205
let tag = match primary_tag {
209
206
Some(tag) => tag,
210
207
None => {
211
-
println!("No tag found in file");
208
+
tracing::warn!(file = %file.name.bright_green(), "No tag found in file");
212
209
return Ok(());
213
210
}
214
211
};
215
212
216
213
let pictures = tag.pictures();
217
214
218
-
println!(
219
-
"Title: {}",
220
-
tag.get_string(&lofty::tag::ItemKey::TrackTitle)
221
-
.unwrap_or_default()
222
-
.bright_green()
223
-
);
224
-
println!(
225
-
"Artist: {}",
226
-
tag.get_string(&lofty::tag::ItemKey::TrackArtist)
227
-
.unwrap_or_default()
228
-
.bright_green()
229
-
);
230
-
println!(
231
-
"Album Artist: {}",
232
-
tag.get_string(&lofty::tag::ItemKey::AlbumArtist)
233
-
.unwrap_or_default()
234
-
.bright_green()
235
-
);
236
-
println!(
237
-
"Album: {}",
238
-
tag.get_string(&lofty::tag::ItemKey::AlbumTitle)
239
-
.unwrap_or_default()
240
-
.bright_green()
241
-
);
242
-
println!(
243
-
"Lyrics: {}",
244
-
tag.get_string(&lofty::tag::ItemKey::Lyrics)
245
-
.unwrap_or_default()
246
-
.bright_green()
247
-
);
248
-
println!("Year: {}", tag.year().unwrap_or_default().bright_green());
249
-
println!(
250
-
"Track Number: {}",
251
-
tag.track().unwrap_or_default().bright_green()
252
-
);
253
-
println!(
254
-
"Track Total: {}",
255
-
tag.track_total().unwrap_or_default().bright_green()
256
-
);
257
-
println!(
258
-
"Release Date: {:?}",
259
-
tag.get_string(&lofty::tag::ItemKey::OriginalReleaseDate)
260
-
.unwrap_or_default()
261
-
.bright_green()
262
-
);
263
-
println!(
264
-
"Recording Date: {:?}",
265
-
tag.get_string(&lofty::tag::ItemKey::RecordingDate)
266
-
.unwrap_or_default()
267
-
.bright_green()
268
-
);
269
-
println!(
270
-
"Copyright Message: {}",
271
-
tag.get_string(&lofty::tag::ItemKey::CopyrightMessage)
272
-
.unwrap_or_default()
273
-
.bright_green()
274
-
);
275
-
println!("Pictures: {:?}", pictures);
215
+
tracing::info!(title = %tag.get_string(&lofty::tag::ItemKey::TrackTitle).unwrap_or_default(), "Title");
216
+
tracing::info!(artist = %tag.get_string(&lofty::tag::ItemKey::TrackArtist).unwrap_or_default(), "Artist");
217
+
tracing::info!(album_artist = %tag.get_string(&lofty::tag::ItemKey::AlbumArtist).unwrap_or_default(), "Album artist");
218
+
tracing::info!(album = %tag.get_string(&lofty::tag::ItemKey::AlbumTitle).unwrap_or_default(), "Album");
219
+
tracing::info!(lyrics = %tag.get_string(&lofty::tag::ItemKey::Lyrics).unwrap_or_default(), "Lyrics");
220
+
tracing::info!(year = %tag.year().unwrap_or_default(), "Year");
221
+
tracing::info!(track_number = %tag.track().unwrap_or_default(), "Track number");
222
+
tracing::info!(track_total = %tag.track_total().unwrap_or_default(), "Track total");
223
+
tracing::info!(release_date = %tag.get_string(&lofty::tag::ItemKey::OriginalReleaseDate).unwrap_or_default(), "Release date");
224
+
tracing::info!(recording_date = %tag.get_string(&lofty::tag::ItemKey::RecordingDate).unwrap_or_default(), "Recording date");
225
+
tracing::info!(copyright = %tag.get_string(&lofty::tag::ItemKey::CopyrightMessage).unwrap_or_default(), "Copyright message");
226
+
tracing::info!(pictures = %pictures.len(), "Pictures found");
276
227
277
228
let title = tag
278
229
.get_string(&lofty::tag::ItemKey::TrackTitle)
···
304
255
305
256
match track {
306
257
Some(track) => {
307
-
println!("Track exists: {}", title.bright_green());
258
+
tracing::info!(title = %title.bright_green(), "Track exists");
308
259
let parent_drive_id = parent_drive_file_id.as_deref();
309
-
let status = create_google_drive_path(
260
+
create_google_drive_path(
310
261
&pool,
311
262
&file,
312
263
&track,
···
315
266
)
316
267
.await?;
317
268
318
-
println!("status: {:?}", status);
319
269
// TODO: publish file metadata to nats
320
270
}
321
271
None => {
322
-
println!("Creating track: {}", title.bright_green());
272
+
tracing::info!(title = %title.bright_green(), "Creating track");
323
273
324
274
let albumart =
325
275
upload_album_cover(albumart_id.into(), pictures, &access_token).await?;
···
358
308
}))
359
309
.send()
360
310
.await?;
361
-
println!("Track Saved: {} {}", title, response.status());
311
+
tracing::info!(status = %response.status(), "Track saved");
362
312
tokio::time::sleep(std::time::Duration::from_secs(3)).await;
363
313
364
314
let track = get_track_by_hash(&pool, &hash).await?;
365
315
if let Some(track) = track {
366
316
let parent_drive_id = parent_drive_file_id.as_deref();
367
-
let status = create_google_drive_path(
317
+
create_google_drive_path(
368
318
&pool,
369
319
&file,
370
320
&track,
371
321
&google_drive_id,
372
322
parent_drive_id.unwrap_or(""),
373
323
)
374
-
.await;
375
-
376
-
println!("status: {:?}", status);
324
+
.await?;
377
325
378
326
// TODO: publish file metadata to nats
379
327
···
382
330
return Ok(());
383
331
}
384
332
385
-
println!("Failed to create track: {}", title.bright_green());
333
+
tracing::warn!(title = %title.bright_green(), "Failed to create track");
386
334
}
387
335
}
388
336
···
442
390
.send()
443
391
.await?;
444
392
445
-
println!("Cover uploaded: {}", response.status());
393
+
tracing::info!(status = %response.status(), "Cover uploaded");
446
394
447
395
Ok(Some(name))
448
396
}
···
466
414
match symphonia::default::get_probe().format(&hint, media_source, &format_opts, &meta_opts)
467
415
{
468
416
Ok(probed) => probed,
469
-
Err(_) => {
470
-
println!("Error probing file");
417
+
Err(e) => {
418
+
tracing::warn!(path = %path.display(), error = %e, "Failed to probe media");
471
419
return Ok(duration);
472
420
}
473
421
};
+25
-68
crates/jetstream/src/repo.rs
+25
-68
crates/jetstream/src/repo.rs
···
56
56
57
57
let user_id = save_user(&mut tx, did).await?;
58
58
59
-
println!(
60
-
"Saving scrobble: {} ",
61
-
format!(
62
-
"{} - {} - {}",
63
-
scrobble_record.title, scrobble_record.artist, scrobble_record.album
64
-
)
65
-
.magenta()
66
-
);
59
+
tracing::info!(title = %scrobble_record.title.magenta(), artist = %scrobble_record.artist.magenta(), album = %scrobble_record.album.magenta(), "Saving scrobble");
67
60
68
61
sqlx::query(
69
62
r#"
···
144
137
{
145
138
Ok(_) => {}
146
139
Err(e) => {
147
-
eprintln!("Failed to push to webhook queue: {}", e);
140
+
tracing::error!(error = %e, "Failed to push to webhook queue");
148
141
}
149
142
}
150
143
}
···
188
181
}
189
182
}
190
183
_ => {
191
-
println!("Unsupported operation: {}", commit.operation);
184
+
tracing::warn!(operation = %commit.operation, "Unsupported operation");
192
185
}
193
186
}
194
187
Ok(())
···
341
334
.await?;
342
335
343
336
if !albums.is_empty() {
344
-
println!("Album already exists: {}", albums[0].title.magenta());
337
+
tracing::info!(name = %albums[0].title.magenta(), "Album already exists");
345
338
return Ok(albums[0].xata_id.clone());
346
339
}
347
340
348
-
println!("Saving album: {}", scrobble_record.album.magenta());
341
+
tracing::info!(name = %scrobble_record.album, "Saving new album");
349
342
350
343
let uri: Option<String> = None;
351
344
let artist_uri: Option<String> = None;
···
402
395
.await?;
403
396
404
397
if !artists.is_empty() {
405
-
println!("Artist already exists: {}", artists[0].name.magenta());
398
+
tracing::info!(name = %scrobble_record.album_artist, "Artist already exists");
406
399
return Ok(artists[0].xata_id.clone());
407
400
}
408
401
409
-
println!("Saving artist: {}", scrobble_record.album_artist.magenta());
402
+
tracing::info!(name = %scrobble_record.album_artist, "Saving new artist");
410
403
411
404
let uri: Option<String> = None;
412
405
let picture = "";
···
450
443
.await?;
451
444
452
445
if !album_tracks.is_empty() {
453
-
println!(
454
-
"Album track already exists: {}",
455
-
format!("{} - {}", album_id, track_id).magenta()
456
-
);
446
+
tracing::info!(album_id = %album_id, track_id = %track_id, "Album track already exists");
457
447
return Ok(());
458
448
}
459
449
460
-
println!(
461
-
"Saving album track: {}",
462
-
format!("{} - {}", album_id, track_id).magenta()
463
-
);
450
+
tracing::info!(album_id = %album_id, track_id = %track_id, "Saving album track");
464
451
465
452
sqlx::query(
466
453
r#"
···
492
479
.await?;
493
480
494
481
if !artist_tracks.is_empty() {
495
-
println!(
496
-
"Artist track already exists: {}",
497
-
format!("{} - {}", artist_id, track_id).magenta()
498
-
);
482
+
tracing::info!(artist_id = %artist_id, track_id = %track_id, "Artist track already exists");
499
483
return Ok(());
500
484
}
501
485
502
-
println!(
503
-
"Saving artist track: {}",
504
-
format!("{} - {}", artist_id, track_id).magenta()
505
-
);
486
+
tracing::info!(artist_id = %artist_id, track_id = %track_id, "Saving artist track");
506
487
507
488
sqlx::query(
508
489
r#"
···
534
515
.await?;
535
516
536
517
if !artist_albums.is_empty() {
537
-
println!(
538
-
"Artist album already exists: {}",
539
-
format!("{} - {}", artist_id, album_id).magenta()
540
-
);
518
+
tracing::info!(artist_id = %artist_id, album_id = %album_id, "Artist album already exists");
541
519
return Ok(());
542
520
}
543
521
544
-
println!(
545
-
"Saving artist album: {}",
546
-
format!("{} - {}", artist_id, album_id).magenta()
547
-
);
522
+
tracing::info!(artist_id = %artist_id, album_id = %album_id, "Saving artist album");
548
523
549
524
sqlx::query(
550
525
r#"
···
585
560
586
561
match artists.is_empty() {
587
562
true => {
588
-
println!("Saving artist: {}", record.name.magenta());
563
+
tracing::info!(name = %record.name, "Artist not found in database, inserting new artist");
589
564
let did = users[0].did.clone();
590
565
sqlx::query(
591
566
r#"
···
632
607
.await?;
633
608
634
609
if !user_artists.is_empty() {
635
-
println!(
636
-
"User artist already exists: {}",
637
-
format!("{} - {}", user_id, artist_id).magenta()
638
-
);
610
+
tracing::info!(user_id = %user_id, artist_id = %artist_id, "Updating user artist");
639
611
sqlx::query(
640
612
r#"
641
613
UPDATE user_artists
···
652
624
return Ok(());
653
625
}
654
626
655
-
println!(
656
-
"Saving user artist: {}",
657
-
format!("{} - {}", user_id, artist_id).magenta()
658
-
);
627
+
tracing::info!(user_id = %user_id, artist_id = %artist_id, "Inserting user artist");
659
628
660
629
sqlx::query(
661
630
r#"
···
699
668
700
669
match albums.is_empty() {
701
670
true => {
702
-
println!("Saving album: {}", record.title.magenta());
671
+
tracing::info!(title = %record.title, artist = %record.artist, "Album not found in database, inserting new album");
703
672
let did = users[0].did.clone();
704
673
sqlx::query(
705
674
r#"
···
752
721
.await?;
753
722
754
723
if !user_albums.is_empty() {
755
-
println!(
756
-
"User album already exists: {}",
757
-
format!("{} - {}", user_id, album_id).magenta()
758
-
);
724
+
tracing::info!(user_id = %user_id, album_id = %album_id, "Updating user album");
759
725
sqlx::query(
760
726
r#"
761
727
UPDATE user_albums
···
772
738
return Ok(());
773
739
}
774
740
775
-
println!(
776
-
"Saving user album: {}",
777
-
format!("{} - {}", user_id, album_id).magenta()
778
-
);
741
+
tracing::info!(user_id = %user_id, album_id = %album_id, "Inserting user album");
779
742
780
743
sqlx::query(
781
744
r#"
···
822
785
823
786
match tracks.is_empty() {
824
787
true => {
825
-
println!("Saving track: {}", record.title.magenta());
788
+
tracing::info!(title = %record.title, artist = %record.artist, album = %record.album, "Track not found in database, inserting new track");
826
789
let did = users[0].did.clone();
827
790
sqlx::query(
828
791
r#"
···
894
857
.await?;
895
858
896
859
if !user_tracks.is_empty() {
897
-
println!(
898
-
"User track already exists: {}",
899
-
format!("{} - {}", user_id, track_id).magenta()
900
-
);
860
+
tracing::info!(user_id = %user_id, track_id = %track_id, "Updating user track");
901
861
sqlx::query(
902
862
r#"
903
863
UPDATE user_tracks
···
914
874
return Ok(());
915
875
}
916
876
917
-
println!(
918
-
"Saving user track: {}",
919
-
format!("{} - {}", user_id, track_id).magenta()
920
-
);
877
+
tracing::info!(user_id = %user_id, track_id = %track_id, "Inserting user track");
921
878
922
879
sqlx::query(
923
880
r#"
···
954
911
.await?;
955
912
956
913
if artists.is_empty() {
957
-
println!("Artist not found: {}", record.name.magenta());
914
+
tracing::warn!(name = %record.name, "Artist not found in database");
958
915
return Ok(());
959
916
}
960
917
···
1023
980
.fetch_all(&mut **tx)
1024
981
.await?;
1025
982
if albums.is_empty() {
1026
-
println!("Album not found: {}", record.title.magenta());
983
+
tracing::warn!(title = %record.title, "Album not found in database");
1027
984
return Ok(());
1028
985
}
1029
986
let album_id = &albums[0].xata_id;
···
1082
1039
.await?;
1083
1040
1084
1041
if tracks.is_empty() {
1085
-
println!("Track not found: {}", record.title.magenta());
1042
+
tracing::warn!(title = %record.title, "Track not found in database");
1086
1043
return Ok(());
1087
1044
}
1088
1045
+6
-9
crates/jetstream/src/subscriber.rs
+6
-9
crates/jetstream/src/subscriber.rs
···
40
40
let pool = Arc::new(Mutex::new(pool));
41
41
42
42
let (mut ws_stream, _) = connect_async(&self.service_url).await?;
43
-
println!(
44
-
"Connected to jetstream at {}",
45
-
self.service_url.bright_green()
46
-
);
43
+
tracing::info!(url = %self.service_url.bright_green(), "Connected to jetstream at");
47
44
48
45
while let Some(msg) = ws_stream.next().await {
49
46
match msg {
50
47
Ok(msg) => {
51
48
if let Err(e) = handle_message(state.clone(), pool.clone(), msg).await {
52
-
eprintln!("Error handling message: {}", e);
49
+
tracing::error!(error = %e, "Error handling message");
53
50
}
54
51
}
55
52
Err(e) => {
56
-
eprintln!("WebSocket error: {}", e);
53
+
tracing::error!(error = %e, "WebSocket error");
57
54
break;
58
55
}
59
56
}
···
76
73
return Ok::<(), Error>(());
77
74
}
78
75
79
-
println!("Received message: {:#?}", message);
76
+
tracing::info!(message = %text.bright_green(), "Received message");
80
77
if let Some(commit) = message.commit {
81
78
match save_scrobble(state, pool, &message.did, commit).await {
82
79
Ok(_) => {
83
-
println!("Scrobble saved successfully");
80
+
tracing::info!(user_id = %message.did.bright_green(), "Scrobble saved successfully");
84
81
}
85
82
Err(e) => {
86
-
eprintln!("Error saving scrobble: {}", e);
83
+
tracing::error!(error = %e, "Error saving scrobble");
87
84
}
88
85
}
89
86
}
+2
-2
crates/jetstream/src/webhook/discord/mod.rs
+2
-2
crates/jetstream/src/webhook/discord/mod.rs
···
37
37
embeds: Vec<DiscordEmbed>,
38
38
) -> reqwest::Result<()> {
39
39
if discord_webhook_url.is_empty() {
40
-
println!("DISCORD_WEBHOOK_URL is not set, skipping webhook post");
40
+
tracing::warn!("DISCORD_WEBHOOK_URL is not set, skipping webhook post");
41
41
return Ok(());
42
42
}
43
43
···
48
48
let res = http.post(discord_webhook_url).json(&body).send().await?;
49
49
if !res.status().is_success() {
50
50
let text = res.text().await.unwrap_or_default();
51
-
eprintln!("Failed to post to Discord webhook: {}", text);
51
+
tracing::error!(error = %text, "Failed to post to Discord webhook");
52
52
}
53
53
Ok(())
54
54
}
+2
-2
crates/jetstream/src/webhook_worker.rs
+2
-2
crates/jetstream/src/webhook_worker.rs
···
79
79
}
80
80
Ok(None) => break,
81
81
Err(e) => {
82
-
eprintln!("Failed to pop from Redis: {}", e);
82
+
tracing::error!(error = %e, "Failed to pop from Redis");
83
83
break;
84
84
}
85
85
}
···
93
93
tokens -= 1;
94
94
95
95
if let Err(e) = discord::post_embeds(&http, &discord_webhook_url, embeds).await {
96
-
eprintln!("Failed to post to Discord webhook: {}", e);
96
+
tracing::error!(error = %e, "Failed to post to Discord webhook");
97
97
}
98
98
}
99
99
}
+1
-1
crates/scrobbler/src/auth.rs
+1
-1
crates/scrobbler/src/auth.rs
···
37
37
let expected_password = md5::compute(expected_password);
38
38
let expected_password = format!("{:x}", expected_password);
39
39
if expected_password != password_md5 {
40
-
println!("{} != {}", expected_password, password_md5);
40
+
tracing::error!(expected = %expected_password, provided = %password_md5, "Invalid password");
41
41
return Err(Error::msg("Invalid password"));
42
42
}
43
43
Ok(())
+1
-1
crates/scrobbler/src/handlers/v1/nowplaying.rs
+1
-1
crates/scrobbler/src/handlers/v1/nowplaying.rs
···
18
18
let a = form.get("a").unwrap().to_string();
19
19
let t = form.get("t").unwrap().to_string();
20
20
21
-
println!("Now playing: {} - {} {}", a, t, s.cyan());
21
+
tracing::info!(artist = %a, track = %t, user = %s.cyan(), "Now playing");
22
22
23
23
let user_id = verify_session_id(cache, &s);
24
24
if let Err(e) = user_id {
+5
-6
crates/scrobbler/src/handlers/v1/submission.rs
+5
-6
crates/scrobbler/src/handlers/v1/submission.rs
···
1
+
use actix_web::HttpResponse;
2
+
use anyhow::Error;
3
+
use serde_json::json;
4
+
use std::{collections::BTreeMap, sync::Arc};
1
5
2
6
3
7
···
21
25
22
26
23
27
24
-
25
-
26
-
27
-
28
-
29
28
}
30
29
31
30
let user_id = user_id.unwrap();
32
-
println!("Submission: {} - {} {} {} {}", a, t, i, user_id, s.cyan());
31
+
tracing::info!(artist = %a, track = %t, timestamp = %i, user_id = %user_id, "Submission");
33
32
34
33
match scrobble_v1(pool, cache, &form).await {
35
34
Ok(_) => Ok(HttpResponse::Ok().body("OK\n")),
+1
-4
crates/scrobbler/src/lib.rs
+1
-4
crates/scrobbler/src/lib.rs
···
56
56
.parse::<u16>()
57
57
.unwrap_or(7882);
58
58
59
-
println!(
60
-
"Starting Scrobble server @ {}",
61
-
format!("{}:{}", host, port).green()
62
-
);
59
+
tracing::info!(url = %format!("http://{}:{}", host, port).bright_green(), "Starting Scrobble server @");
63
60
64
61
let limiter = web::Data::new(
65
62
Limiter::builder("redis://127.0.0.1")
+2
-8
crates/scrobbler/src/listenbrainz/core/submit.rs
+2
-8
crates/scrobbler/src/listenbrainz/core/submit.rs
···
17
17
token: &str,
18
18
) -> Result<HttpResponse, Error> {
19
19
if payload.listen_type != "playing_now" {
20
-
println!("skipping listen type: {}", payload.listen_type.cyan());
20
+
tracing::info!(listen_type = %payload.listen_type.cyan(), "Skipping listen type");
21
21
return Ok(HttpResponse::Ok().json(json!({
22
22
"status": "ok",
23
23
"payload": {
···
62
62
63
63
cache.del(&format!("listenbrainz:cache:{}:{}:{}", artist, track, did))?;
64
64
65
-
println!(
66
-
"Retryable error on attempt {}/{}: {}",
67
-
attempt,
68
-
RETRIES,
69
-
e.to_string().yellow()
70
-
);
71
-
println!("{:#?}", payload);
65
+
tracing::error!(error = %e, attempt = attempt, "Retryable error submitting listens for {} - {} (attempt {}/{})", artist, track, attempt, RETRIES);
72
66
73
67
if attempt == RETRIES {
74
68
return Ok(HttpResponse::BadRequest().json(serde_json::json!({
+1
-1
crates/scrobbler/src/listenbrainz/core/validate_token.rs
+1
-1
crates/scrobbler/src/listenbrainz/core/validate_token.rs
+12
-13
crates/scrobbler/src/listenbrainz/handlers.rs
+12
-13
crates/scrobbler/src/listenbrainz/handlers.rs
···
58
58
let body = String::from_utf8_lossy(&payload);
59
59
let req = serde_json::from_str::<SubmitListensRequest>(&body)
60
60
.map_err(|e| {
61
-
println!("{}", body);
62
-
println!("Error parsing request body: {}", e);
61
+
tracing::error!(body = %body, error = %e, "Error parsing request body");
63
62
e
64
63
})
65
64
.map_err(actix_web::error::ErrorBadRequest)?;
···
116
115
}));
117
116
}
118
117
Err(e) => {
119
-
println!("Error validating token: {}", e);
118
+
tracing::error!(error = %e, "Error validating token");
120
119
return HttpResponse::InternalServerError().finish();
121
120
}
122
121
}
···
127
126
query: web::Query<String>,
128
127
data: web::Data<Arc<Pool<Postgres>>>,
129
128
) -> impl Responder {
130
-
let pool = data.get_ref();
129
+
let _pool = data.get_ref();
131
130
let query = query.into_inner();
132
131
133
132
match search_users(&query).await {
134
133
Ok(users) => HttpResponse::Ok().json(users),
135
134
Err(e) => {
136
-
println!("Error searching users: {}", e);
135
+
tracing::error!(error = %e, "Error searching users");
137
136
HttpResponse::InternalServerError().finish()
138
137
}
139
138
}
···
145
144
match get_listens(&user_name).await {
146
145
Ok(listens) => HttpResponse::Ok().json(listens),
147
146
Err(e) => {
148
-
println!("Error getting listens for user {}: {}", user_name, e);
147
+
tracing::error!(error = %e, "Error getting listens for user {}", user_name);
149
148
HttpResponse::InternalServerError().finish()
150
149
}
151
150
}
···
157
156
match get_listen_count(&user_name).await {
158
157
Ok(count) => HttpResponse::Ok().json(count),
159
158
Err(e) => {
160
-
println!("Error getting listen count for user {}: {}", user_name, e);
159
+
tracing::error!(error = %e, "Error getting listen count for user {}", user_name);
161
160
HttpResponse::InternalServerError().finish()
162
161
}
163
162
}
···
169
168
match get_playing_now(&user_name).await {
170
169
Ok(playing_now) => HttpResponse::Ok().json(playing_now),
171
170
Err(e) => {
172
-
println!("Error getting playing now for user {}: {}", user_name, e);
171
+
tracing::error!(error = %e, "Error getting playing now for user {}", user_name);
173
172
HttpResponse::InternalServerError().finish()
174
173
}
175
174
}
···
181
180
match get_top_artists(&user_name).await {
182
181
Ok(artists) => HttpResponse::Ok().json(artists),
183
182
Err(e) => {
184
-
println!("Error getting top artists: {}", e);
183
+
tracing::error!(error = %e, "Error getting top artists");
185
184
HttpResponse::InternalServerError().finish()
186
185
}
187
186
}
···
193
192
match get_top_releases(&user_name).await {
194
193
Ok(releases) => HttpResponse::Ok().json(releases),
195
194
Err(e) => {
196
-
println!("Error getting top releases: {}", e);
195
+
tracing::error!(error = %e, "Error getting top releases");
197
196
HttpResponse::InternalServerError().finish()
198
197
}
199
198
}
···
205
204
match get_top_recordings(&user_name).await {
206
205
Ok(recordings) => HttpResponse::Ok().json(recordings),
207
206
Err(e) => {
208
-
println!("Error getting sitewide recordings: {}", e);
207
+
tracing::error!(error = %e, "Error getting top recordings");
209
208
HttpResponse::InternalServerError().finish()
210
209
}
211
210
}
···
217
216
match get_top_release_groups(&user_name).await {
218
217
Ok(release_groups) => HttpResponse::Ok().json(release_groups),
219
218
Err(e) => {
220
-
println!("Error getting top release groups: {}", e);
219
+
tracing::error!(error = %e, "Error getting top release groups");
221
220
HttpResponse::InternalServerError().finish()
222
221
}
223
222
}
···
229
228
match get_top_recordings(&user_name).await {
230
229
Ok(recordings) => HttpResponse::Ok().json(recordings),
231
230
Err(e) => {
232
-
println!("Error getting top recordings: {}", e);
231
+
tracing::error!(error = %e, "Error getting top recordings");
233
232
HttpResponse::InternalServerError().finish()
234
233
}
235
234
}
-66
crates/scrobbler/src/main.rs
-66
crates/scrobbler/src/main.rs
···
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
.parse::<u16>()
59
-
.unwrap_or(7882);
60
-
61
-
println!(
62
-
"Starting Scrobble server @ {}",
63
-
format!("{}:{}", host, port).green()
64
-
);
65
-
66
-
let limiter = web::Data::new(
+3
-4
crates/scrobbler/src/rocksky.rs
+3
-4
crates/scrobbler/src/rocksky.rs
···
25
25
let token = generate_token(did)?;
26
26
let client = Client::new();
27
27
28
-
println!("Scrobbling track: \n {:#?}", track);
28
+
tracing::info!(did = %did, track = ?track, "Scrobbling track");
29
29
30
30
let response = client
31
31
.post(&format!("{}/now-playing", ROCKSKY_API))
···
35
35
.await?;
36
36
37
37
let status = response.status();
38
-
println!("Response status: {}", status);
38
+
tracing::info!(did = %did, artist = %track.artist, track = %track.title, status = %status, "Scrobble response");
39
39
if !status.is_success() {
40
40
let response_text = response.text().await?;
41
-
println!("did: {}", did);
42
-
println!("Failed to scrobble track: {}", response_text);
41
+
tracing::error!(did = %did, response = %response_text, "Failed to scrobble track");
43
42
return Err(Error::msg(format!(
44
43
"Failed to scrobble track: {}",
45
44
response_text
+25
-56
crates/scrobbler/src/scrobbler.rs
+25
-56
crates/scrobbler/src/scrobbler.rs
···
1
+
use std::{collections::BTreeMap, env};
1
2
3
+
use anyhow::Error;
4
+
use rand::Rng;
5
+
use sqlx::{Pool, Postgres};
2
6
3
7
4
8
···
125
129
126
130
127
131
128
-
129
-
130
-
131
-
132
-
133
132
);
134
133
let cached = cache.get(&key)?;
135
134
if cached.is_some() {
136
-
println!("{}", format!("Cached: {}", key).yellow());
135
+
tracing::info!(key = %key, "Cached:");
137
136
let track = serde_json::from_str::<Track>(&cached.unwrap())?;
138
137
scrobble.album = Some(track.album.clone());
139
138
rocksky::scrobble(cache, &did, track, scrobble.timestamp).await?;
···
144
143
if let Some(mbid) = &scrobble.mbid {
145
144
// let result = repo::track::get_track_by_mbid(pool, mbid).await?;
146
145
let result = mb_client.get_recording(mbid).await?;
147
-
println!("{}", "Musicbrainz (mbid)".yellow());
146
+
tracing::info!(%scrobble.artist, %scrobble.track, "Musicbrainz (mbid)");
148
147
scrobble.album = Some(Track::from(result.clone()).album);
149
148
rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?;
150
149
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
···
154
153
let result = repo::track::get_track(pool, &scrobble.track, &scrobble.artist).await?;
155
154
156
155
if let Some(track) = result {
157
-
println!("{}", "Xata (track)".yellow());
156
+
tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Xata (track)");
158
157
scrobble.album = Some(track.album.clone());
159
158
let album = repo::album::get_album_by_track_id(pool, &track.xata_id).await?;
160
159
let artist = repo::artist::get_artist_by_track_id(pool, &track.xata_id).await?;
···
204
203
.await?;
205
204
206
205
if let Some(track) = result.tracks.items.first() {
207
-
println!("{}", "Spotify (track)".yellow());
206
+
tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Spotify (track)");
208
207
scrobble.album = Some(track.album.name.clone());
209
208
let mut track = track.clone();
210
209
···
232
231
233
232
if let Some(recording) = result.recordings.first() {
234
233
let result = mb_client.get_recording(&recording.id).await?;
235
-
println!("{}", "Musicbrainz (recording)".yellow());
234
+
tracing::info!(%scrobble.artist, %scrobble.track, "Musicbrainz (recording)");
236
235
scrobble.album = Some(Track::from(result.clone()).album);
237
236
rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?;
238
237
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
239
238
continue;
240
239
}
241
240
242
-
println!(
243
-
"{} {} - {}, skipping",
244
-
"Track not found: ".yellow(),
245
-
scrobble.artist,
246
-
scrobble.track
247
-
);
241
+
tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Track not found, skipping");
248
242
scrobble.ignored = Some(true);
249
243
}
250
244
···
313
307
);
314
308
let cached = cache.get(&key)?;
315
309
if cached.is_some() {
316
-
println!("{}", format!("Cached: {}", key).yellow());
310
+
tracing::info!(key = %key, "Cached:");
317
311
let track = serde_json::from_str::<Track>(&cached.unwrap())?;
318
312
scrobble.album = Some(track.album.clone());
319
313
rocksky::scrobble(cache, &did, track, scrobble.timestamp).await?;
···
324
318
if let Some(mbid) = &scrobble.mbid {
325
319
// let result = repo::track::get_track_by_mbid(pool, mbid).await?;
326
320
let result = mb_client.get_recording(mbid).await?;
327
-
println!("{}", "Musicbrainz (mbid)".yellow());
321
+
tracing::info!(%scrobble.artist, %scrobble.track, "Musicbrainz (mbid)");
328
322
scrobble.album = Some(Track::from(result.clone()).album);
329
323
rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?;
330
324
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
···
334
328
let result = repo::track::get_track(pool, &scrobble.track, &scrobble.artist).await?;
335
329
336
330
if let Some(track) = result {
337
-
println!("{}", "Xata (track)".yellow());
331
+
tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Xata (track)");
338
332
scrobble.album = Some(track.album.clone());
339
333
let album = repo::album::get_album_by_track_id(pool, &track.xata_id).await?;
340
334
let artist = repo::artist::get_artist_by_track_id(pool, &track.xata_id).await?;
···
384
378
.await?;
385
379
386
380
if let Some(track) = result.tracks.items.first() {
387
-
println!("{}", "Spotify (track)".yellow());
381
+
tracing::info!(artist = %scrobble.artist, track = %scrobble.track, "Spotify (track)");
388
382
scrobble.album = Some(track.album.name.clone());
389
383
let mut track = track.clone();
390
384
···
412
406
413
407
if let Some(recording) = result.recordings.first() {
414
408
let result = mb_client.get_recording(&recording.id).await?;
415
-
println!("{}", "Musicbrainz (recording)".yellow());
409
+
tracing::info!(%scrobble.artist, %scrobble.track, "Musicbrainz (recording)");
416
410
scrobble.album = Some(Track::from(result.clone()).album);
417
411
rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?;
418
412
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
419
413
return Ok(());
420
414
}
421
415
422
-
println!(
423
-
"{} {} - {}, skipping",
424
-
"Track not found: ".yellow(),
425
-
artist,
426
-
track
427
-
);
416
+
tracing::info!(artist = %artist, track = %track, "Track not found, skipping");
428
417
429
418
Ok(())
430
419
}
···
435
424
req: &SubmitListensRequest,
436
425
token: &str,
437
426
) -> Result<(), Error> {
438
-
println!("Listenbrainz\n{:#?}", req);
427
+
tracing::info!(req = ?req, "Listenbrainz submission");
439
428
440
429
if req.payload.is_empty() {
441
430
return Err(Error::msg("No payload found"));
···
481
470
.get(&format!("listenbrainz:cache:{}:{}:{}", artist, track, did))?
482
471
.is_some()
483
472
{
484
-
println!(
485
-
"{} {} - {}, recently scrobbled",
486
-
"Already scrobbled: ".yellow(),
487
-
artist,
488
-
track
489
-
);
473
+
tracing::info!(artist= %artist, track = %track, "Recently scrobbled, skipping");
490
474
return Ok(());
491
475
}
492
476
···
496
480
.get(&format!("{}:current", spotify_user.email))?
497
481
.is_some()
498
482
{
499
-
println!(
500
-
"{} {} - {}, currently scrobbling, skipping",
501
-
"Currently scrobbling: ".yellow(),
502
-
artist,
503
-
track
504
-
);
483
+
tracing::info!(artist= %artist, track = %track, "Currently scrobbling, skipping");
505
484
return Ok(());
506
485
}
507
486
}
508
487
509
488
if cache.get(&format!("nowplaying:{}", did))?.is_some() {
510
-
println!(
511
-
"{} {} - {}, currently scrobbling, skipping",
512
-
"Currently scrobbling: ".yellow(),
513
-
artist,
514
-
track
515
-
);
489
+
tracing::info!(artist= %artist, track = %track, "Currently scrobbling, skipping");
516
490
return Ok(());
517
491
}
518
492
···
565
539
);
566
540
let cached = cache.get(&key)?;
567
541
if cached.is_some() {
568
-
println!("{}", format!("Cached: {}", key).yellow());
542
+
tracing::info!(key = %key, "Cached");
569
543
let track = serde_json::from_str::<Track>(&cached.unwrap())?;
570
544
scrobble.album = Some(track.album.clone());
571
545
rocksky::scrobble(cache, &did, track, scrobble.timestamp).await?;
···
576
550
if let Some(mbid) = &scrobble.mbid {
577
551
// let result = repo::track::get_track_by_mbid(pool, mbid).await?;
578
552
let result = mb_client.get_recording(mbid).await?;
579
-
println!("{}", "Musicbrainz (mbid)".yellow());
553
+
tracing::info!("Musicbrainz (mbid)");
580
554
scrobble.album = Some(Track::from(result.clone()).album);
581
555
rocksky::scrobble(cache, &did, result.into(), scrobble.timestamp).await?;
582
556
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
···
586
560
let result = repo::track::get_track(pool, &scrobble.track, &scrobble.artist).await?;
587
561
588
562
if let Some(track) = result {
589
-
println!("{}", "Xata (track)".yellow());
563
+
tracing::info!("Xata (track)");
590
564
scrobble.album = Some(track.album.clone());
591
565
let album = repo::album::get_album_by_track_id(pool, &track.xata_id).await?;
592
566
let artist = repo::artist::get_artist_by_track_id(pool, &track.xata_id).await?;
···
636
610
.await?;
637
611
638
612
if let Some(track) = result.tracks.items.first() {
639
-
println!("{}", "Spotify (track)".yellow());
613
+
tracing::info!("Spotify (track)");
640
614
scrobble.album = Some(track.album.name.clone());
641
615
let mut track = track.clone();
642
616
···
676
650
}
677
651
*/
678
652
679
-
println!(
680
-
"{} {} - {}, skipping",
681
-
"Track not found: ".yellow(),
682
-
artist,
683
-
track
684
-
);
653
+
tracing::warn!(artist = %artist, track = %track, "Track not found, skipping");
685
654
686
655
Ok(())
687
656
}
+2
-10
crates/scrobbler/src/spotify/client.rs
+2
-10
crates/scrobbler/src/spotify/client.rs
···
36
36
let data = response.text().await?;
37
37
38
38
if data == "Too many requests" {
39
-
println!(
40
-
"> retry-after {}",
41
-
headers.get("retry-after").unwrap().to_str().unwrap()
42
-
);
43
-
println!("> {} [get_album]", data);
39
+
tracing::info!(retry_after = %headers.get("retry-after").unwrap().to_str().unwrap(), data = %data, "Rate limited on get_album");
44
40
return Ok(None);
45
41
}
46
42
···
56
52
let data = response.text().await?;
57
53
58
54
if data == "Too many requests" {
59
-
println!(
60
-
"> retry-after {}",
61
-
headers.get("retry-after").unwrap().to_str().unwrap()
62
-
);
63
-
println!("> {} [get_artist]", data);
55
+
tracing::info!(retry_after = %headers.get("retry-after").unwrap().to_str().unwrap(), data = %data, "Rate limited on get_artist");
64
56
return Ok(None);
65
57
}
66
58
+7
-14
crates/webscrobbler/src/handlers.rs
+7
-14
crates/webscrobbler/src/handlers.rs
···
32
32
req: HttpRequest,
33
33
) -> Result<impl Responder, actix_web::Error> {
34
34
let id = req.match_info().get("id").unwrap();
35
-
println!("Received scrobble for ID: {}", id.cyan());
35
+
tracing::info!(id = %id.bright_green(), "Received scrobble");
36
36
37
37
let pool = data.get_ref().clone();
38
38
···
50
50
let body = read_payload!(payload);
51
51
let params = serde_json::from_slice::<ScrobbleRequest>(&body).map_err(|err| {
52
52
let body = String::from_utf8_lossy(&body);
53
-
println!("Failed to parse JSON: {}", body);
54
-
println!("Failed to parse JSON: {}", err);
53
+
tracing::error!(body = %body, error = %err, "Failed to parse JSON");
55
54
actix_web::error::ErrorBadRequest(format!("Failed to parse JSON: {}", err))
56
55
})?;
57
56
58
-
println!("Parsed scrobble request: {:#?}", params);
57
+
tracing::info!(params = ?params, "Parsed scrobble request");
59
58
60
59
if params.event_name != "scrobble" {
61
-
println!("Skipping non-scrobble event: {}", params.event_name.green());
60
+
tracing::info!(event_name = %params.event_name.cyan(), "Skipping non-scrobble event");
62
61
return Ok(HttpResponse::Ok().body("Skipping non-scrobble event"));
63
62
}
64
63
···
75
74
})?;
76
75
77
76
if spotify_token.is_some() {
78
-
println!("User has a Spotify token, skipping scrobble");
77
+
tracing::info!("User has a Spotify token, skipping scrobble");
79
78
return Ok(HttpResponse::Ok().body("User has a Spotify token, skipping scrobble"));
80
79
}
81
80
}
···
91
90
));
92
91
93
92
if cached.is_err() {
94
-
println!(
95
-
"Failed to check cache for Emby scrobble: {}",
96
-
cached.unwrap_err()
97
-
);
93
+
tracing::error!(artist = %artist, track = %track, error = %cached.unwrap_err(), "Failed to check cache for Emby scrobble");
98
94
return Ok(HttpResponse::Ok().body("Failed to check cache for Emby scrobble"));
99
95
}
100
96
101
97
if cached.unwrap().is_some() {
102
-
println!(
103
-
"Skipping duplicate scrobble for Emby: {} - {}",
104
-
artist, track
105
-
);
98
+
tracing::warn!(artist = %artist, track = %track, "Skipping duplicate scrobble for Emby");
106
99
return Ok(HttpResponse::Ok().body("Skipping duplicate scrobble for Emby"));
107
100
}
108
101
}
+1
-4
crates/webscrobbler/src/lib.rs
+1
-4
crates/webscrobbler/src/lib.rs
···
44
44
.parse::<u16>()
45
45
.unwrap_or(7883);
46
46
47
-
println!(
48
-
"Starting WebScrobbler Webhook @ {}",
49
-
format!("{}:{}", host, port).green()
50
-
);
47
+
tracing::info!(url = %format!("http://{}:{}", host, port).bright_green(), "Starting WebScrobbler server @");
51
48
52
49
let limiter = web::Data::new(
53
50
Limiter::builder("redis://127.0.0.1")
+4
-8
crates/webscrobbler/src/rocksky.rs
+4
-8
crates/webscrobbler/src/rocksky.rs
···
1
1
use anyhow::Error;
2
-
use owo_colors::OwoColorize;
3
2
use reqwest::Client;
4
3
5
4
use crate::{auth::generate_token, cache::Cache, types::Track};
···
26
25
let token = generate_token(did)?;
27
26
let client = Client::new();
28
27
29
-
println!("Scrobbling track: \n {:#?}", track);
28
+
tracing::info!(did = %did, track = ?track, "Scrobbling track");
30
29
31
30
let response = client
32
31
.post(&format!("{}/now-playing", ROCKSKY_API))
···
36
35
.await?;
37
36
38
37
if !response.status().is_success() {
39
-
println!(
40
-
"Failed to scrobble track: {}",
41
-
response.status().to_string()
42
-
);
38
+
tracing::error!(did = %did, artist = %track.artist, track = %track.title, status = %response.status(), "Failed to scrobble track");
43
39
let text = response.text().await?;
44
-
println!("Response: {}", text);
40
+
tracing::error!(did = %did, response = %text, "Response");
45
41
return Err(Error::msg(format!("Failed to scrobble track: {}", text)));
46
42
}
47
43
48
-
println!("Scrobbled track: {}", track.title.green());
44
+
tracing::info!(did = %did, artist = %track.artist, track = %track.title, "Scrobbled track");
49
45
50
46
Ok(())
51
47
}
+4
-9
crates/webscrobbler/src/scrobbler.rs
+4
-9
crates/webscrobbler/src/scrobbler.rs
···
34
34
35
35
let cached = cache.get(&key)?;
36
36
if cached.is_some() {
37
-
println!("{}", format!("Cached: {}", key).yellow());
37
+
tracing::info!(artist = %scrobble.data.song.parsed.artist, track = %scrobble.data.song.parsed.track, "Using cached track");
38
38
let track = serde_json::from_str::<Track>(&cached.unwrap())?;
39
39
rocksky::scrobble(cache, &did, track, scrobble.time).await?;
40
40
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
···
127
127
let result = spotify_client.search(&query).await?;
128
128
129
129
if let Some(track) = result.tracks.items.first() {
130
-
println!("{}", "Spotify (track)".yellow());
130
+
tracing::info!("Spotify (track)");
131
131
let mut track = track.clone();
132
132
133
133
if let Some(album) = spotify_client.get_album(&track.album.id).await? {
···
154
154
155
155
if let Some(recording) = result.recordings.first() {
156
156
let result = mb_client.get_recording(&recording.id).await?;
157
-
println!("{}", "Musicbrainz (recording)".yellow());
157
+
tracing::info!("Musicbrainz (recording)");
158
158
rocksky::scrobble(cache, &did, result.into(), scrobble.time).await?;
159
159
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
160
160
return Ok(());
161
161
}
162
162
163
-
println!(
164
-
"{} {} - {}, skipping",
165
-
"Track not found: ".yellow(),
166
-
scrobble.data.song.parsed.artist,
167
-
scrobble.data.song.parsed.track
168
-
);
163
+
tracing::warn!(artist = %scrobble.data.song.parsed.artist, track = %scrobble.data.song.parsed.track, "Track not found, skipping");
169
164
170
165
Ok(())
171
166
}
+2
-10
crates/webscrobbler/src/spotify/client.rs
+2
-10
crates/webscrobbler/src/spotify/client.rs
···
36
36
let data = response.text().await?;
37
37
38
38
if data == "Too many requests" {
39
-
println!(
40
-
"> retry-after {}",
41
-
headers.get("retry-after").unwrap().to_str().unwrap()
42
-
);
43
-
println!("> {} [get_album]", data);
39
+
tracing::info!(retry_after = %headers.get("retry-after").unwrap().to_str().unwrap(), data = %data, "Rate limited on get_album");
44
40
return Ok(None);
45
41
}
46
42
···
56
52
let data = response.text().await?;
57
53
58
54
if data == "Too many requests" {
59
-
println!(
60
-
"> retry-after {}",
61
-
headers.get("retry-after").unwrap().to_str().unwrap()
62
-
);
63
-
println!("> {} [get_artist]", data);
55
+
tracing::info!(retry_after = %headers.get("retry-after").unwrap().to_str().unwrap(), data = %data, "Rate limited on get_artist");
64
56
return Ok(None);
65
57
}
66
58
-50
crates/analytics/src/main.rs
-50
crates/analytics/src/main.rs
···
1
-
use core::create_tables;
2
-
use std::{
3
-
env,
4
-
sync::{Arc, Mutex},
5
-
};
6
-
7
-
use clap::Command;
8
-
use cmd::{serve::serve, sync::sync};
9
-
use dotenv::dotenv;
10
-
use duckdb::Connection;
11
-
use sqlx::postgres::PgPoolOptions;
12
-
13
-
pub mod cmd;
14
-
pub mod core;
15
-
pub mod handlers;
16
-
pub mod subscriber;
17
-
pub mod types;
18
-
pub mod xata;
19
-
20
-
fn cli() -> Command {
21
-
Command::new("analytics")
22
-
.version(env!("CARGO_PKG_VERSION"))
23
-
.about("Rocksky Analytics CLI built with Rust and DuckDB")
24
-
.subcommand(Command::new("sync").about("Sync data from Xata to DuckDB"))
25
-
.subcommand(Command::new("serve").about("Serve the Rocksky Analytics API"))
26
-
}
27
-
28
-
#[tokio::main]
29
-
async fn main() -> Result<(), Box<dyn std::error::Error>> {
30
-
dotenv().ok();
31
-
32
-
let pool = PgPoolOptions::new()
33
-
.max_connections(5)
34
-
.connect(&env::var("XATA_POSTGRES_URL")?)
35
-
.await?;
36
-
let conn = Connection::open("./rocksky-analytics.ddb")?;
37
-
38
-
create_tables(&conn).await?;
39
-
40
-
let args = cli().get_matches();
41
-
let conn = Arc::new(Mutex::new(conn));
42
-
43
-
match args.subcommand() {
44
-
Some(("sync", _)) => sync(conn, &pool).await?,
45
-
Some(("serve", _)) => serve(conn).await?,
46
-
_ => serve(conn).await?,
47
-
}
48
-
49
-
Ok(())
50
-
}
-37
crates/dropbox/src/main.rs
-37
crates/dropbox/src/main.rs
···
1
-
use clap::Command;
2
-
use cmd::{scan::scan, serve::serve};
3
-
use dotenv::dotenv;
4
-
5
-
pub mod client;
6
-
pub mod cmd;
7
-
pub mod consts;
8
-
pub mod crypto;
9
-
pub mod handlers;
10
-
pub mod repo;
11
-
pub mod scan;
12
-
pub mod token;
13
-
pub mod types;
14
-
pub mod xata;
15
-
16
-
fn cli() -> Command {
17
-
Command::new("dropbox")
18
-
.version(env!("CARGO_PKG_VERSION"))
19
-
.about("Rocksky Dropbox Service")
20
-
.subcommand(Command::new("scan").about("Scan Dropbox Music Folder"))
21
-
.subcommand(Command::new("serve").about("Serve Rocksky Dropbox API"))
22
-
}
23
-
24
-
#[tokio::main]
25
-
async fn main() -> Result<(), Box<dyn std::error::Error>> {
26
-
dotenv().ok();
27
-
28
-
let args = cli().get_matches();
29
-
30
-
match args.subcommand() {
31
-
Some(("scan", _)) => scan().await?,
32
-
Some(("serve", _)) => serve().await?,
33
-
_ => serve().await?,
34
-
}
35
-
36
-
Ok(())
37
-
}
-37
crates/googledrive/src/main.rs
-37
crates/googledrive/src/main.rs
···
1
-
use clap::Command;
2
-
use cmd::{scan::scan, serve::serve};
3
-
use dotenv::dotenv;
4
-
5
-
pub mod client;
6
-
pub mod cmd;
7
-
pub mod consts;
8
-
pub mod crypto;
9
-
pub mod handlers;
10
-
pub mod repo;
11
-
pub mod scan;
12
-
pub mod token;
13
-
pub mod types;
14
-
pub mod xata;
15
-
16
-
fn cli() -> Command {
17
-
Command::new("googledrive")
18
-
.version(env!("CARGO_PKG_VERSION"))
19
-
.about("Rocksky Google Drive Service")
20
-
.subcommand(Command::new("scan").about("Scan Google Drive Music Folder"))
21
-
.subcommand(Command::new("serve").about("Serve Rocksky Google Drive API"))
22
-
}
23
-
24
-
#[tokio::main]
25
-
async fn main() -> Result<(), Box<dyn std::error::Error>> {
26
-
dotenv().ok();
27
-
28
-
let args = cli().get_matches();
29
-
30
-
match args.subcommand() {
31
-
Some(("scan", _)) => scan().await?,
32
-
Some(("serve", _)) => serve().await?,
33
-
_ => serve().await?,
34
-
}
35
-
36
-
Ok(())
37
-
}
-37
crates/jetstream/src/main.rs
-37
crates/jetstream/src/main.rs
···
1
-
use std::{env, sync::Arc};
2
-
3
-
use dotenv::dotenv;
4
-
use subscriber::ScrobbleSubscriber;
5
-
use tokio::sync::Mutex;
6
-
7
-
use crate::webhook_worker::AppState;
8
-
9
-
pub mod profile;
10
-
pub mod repo;
11
-
pub mod subscriber;
12
-
pub mod types;
13
-
pub mod webhook;
14
-
pub mod webhook_worker;
15
-
pub mod xata;
16
-
17
-
#[tokio::main]
18
-
async fn main() -> Result<(), anyhow::Error> {
19
-
dotenv()?;
20
-
let jetstream_server = env::var("JETSTREAM_SERVER")
21
-
.unwrap_or_else(|_| "wss://jetstream2.us-west.bsky.network".to_string());
22
-
let url = format!(
23
-
"{}/subscribe?wantedCollections=app.rocksky.*",
24
-
jetstream_server
25
-
);
26
-
let subscriber = ScrobbleSubscriber::new(&url);
27
-
28
-
let redis_url = env::var("REDIS_URL").unwrap_or_else(|_| "redis://127.0.0.1:6379".to_string());
29
-
let redis = redis::Client::open(redis_url)?;
30
-
let queue_key =
31
-
env::var("WEBHOOK_QUEUE_KEY").unwrap_or_else(|_| "rocksky:webhook_queue".to_string());
32
-
33
-
let state = Arc::new(Mutex::new(AppState { redis, queue_key }));
34
-
35
-
subscriber.run(state).await?;
36
-
Ok(())
37
-
}
-65
crates/playlists/src/main.rs
-65
crates/playlists/src/main.rs
···
1
-
use core::{create_tables, find_spotify_users, load_users, save_playlists};
2
-
use std::{
3
-
env,
4
-
sync::{Arc, Mutex},
5
-
};
6
-
7
-
use anyhow::Error;
8
-
use async_nats::connect;
9
-
use dotenv::dotenv;
10
-
use duckdb::Connection;
11
-
use owo_colors::OwoColorize;
12
-
use rocksky_playlists::subscriber::subscribe;
13
-
use spotify::get_user_playlists;
14
-
use sqlx::postgres::PgPoolOptions;
15
-
16
-
pub mod core;
17
-
pub mod crypto;
18
-
pub mod spotify;
19
-
pub mod types;
20
-
pub mod xata;
21
-
22
-
#[tokio::main]
23
-
async fn main() -> Result<(), Error> {
24
-
dotenv().ok();
25
-
26
-
let conn = Connection::open("./rocksky-playlists.ddb")?;
27
-
let conn = Arc::new(Mutex::new(conn));
28
-
create_tables(conn.clone())?;
29
-
30
-
subscribe(conn.clone()).await?;
31
-
32
-
let pool = PgPoolOptions::new()
33
-
.max_connections(5)
34
-
.connect(&env::var("XATA_POSTGRES_URL")?)
35
-
.await?;
36
-
let users = find_spotify_users(&pool, 0, 100).await?;
37
-
38
-
load_users(conn.clone(), &pool).await?;
39
-
40
-
sqlx::query(r#"
41
-
CREATE UNIQUE INDEX IF NOT EXISTS user_playlists_unique_index ON user_playlists (user_id, playlist_id)
42
-
"#)
43
-
.execute(&pool)
44
-
.await?;
45
-
let conn = conn.clone();
46
-
47
-
let addr = env::var("NATS_URL").unwrap_or_else(|_| "nats://localhost:4222".to_string());
48
-
let nc = connect(&addr).await?;
49
-
let nc = Arc::new(Mutex::new(nc));
50
-
println!("Connected to NATS server at {}", addr.bright_green());
51
-
52
-
for user in users {
53
-
let token = user.1.clone();
54
-
let did = user.2.clone();
55
-
let user_id = user.3.clone();
56
-
let playlists = get_user_playlists(token).await?;
57
-
save_playlists(&pool, conn.clone(), nc.clone(), playlists, &user_id, &did).await?;
58
-
}
59
-
60
-
println!("Done!");
61
-
62
-
loop {
63
-
tokio::time::sleep(tokio::time::Duration::from_secs(1)).await;
64
-
}
65
-
}
History
1 round
0 comments
tsiry-sandratraina.com
submitted
#0
5 commits
expand
collapse
feat: update dependencies to include tracing and improve logging throughout the application
Refactor logging to use
tracing instead of println and eprintln
- Replaced all instances of `println!` and `eprintln!` with `tracing::info!`, `tracing::warn!`, and `tracing::error!` for better structured logging.
- Updated log messages to include relevant context and structured fields for improved traceability.
- Ensured consistent logging practices across the `jetstream`, `scrobbler`, and `webscrobbler` crates.
feat: remove unused crate main files for analytics, dropbox, googledrive, jetstream, playlists, scrobbler, and webscrobbler
feat: remove unused binary entries for scrobbler and webscrobbler
feat: remove unused owo_colors dependency from submission and scrobbler modules
expand 0 comments
pull request successfully merged