lastfm_edit/commands/mod.rs
1pub mod delete;
2pub mod edit;
3pub mod show;
4pub mod utils;
5
6use crate::LastFmEditClientImpl;
7use clap::{arg, Subcommand};
8
9#[derive(Subcommand)]
10pub enum Commands {
11 /// Edit scrobble metadata
12 ///
13 /// This command allows you to edit scrobble metadata by specifying what to search for
14 /// and what to change it to. You can specify any combination of fields to search for,
15 /// and any combination of new values to change them to.
16 ///
17 /// Usage examples:
18 /// # Discover variations for an artist (dry run by default)
19 /// lastfm-edit edit --artist "Jimi Hendrix"
20 ///
21 /// # Discover variations with optional track name
22 /// lastfm-edit edit --artist "Radiohead" --track "Creep"
23 ///
24 /// # Actually apply edits (change artist name)
25 /// lastfm-edit edit --artist "The Beatles" --new-artist "Beatles, The" --apply
26 ///
27 /// # Change track name for specific track
28 /// lastfm-edit edit --artist "Jimi Hendrix" --track "Lover Man" --new-track "Lover Man (Live)" --apply
29 Edit {
30 /// Artist name (required)
31 #[arg(long)]
32 artist: String,
33
34 /// Track name (optional)
35 #[arg(long)]
36 track: Option<String>,
37
38 /// Album name (optional)
39 #[arg(long)]
40 album: Option<String>,
41
42 /// Album artist name (optional)
43 #[arg(long)]
44 album_artist: Option<String>,
45
46 /// New track name (optional)
47 #[arg(long)]
48 new_track: Option<String>,
49
50 /// New album name (optional)
51 #[arg(long)]
52 new_album: Option<String>,
53
54 /// New artist name (optional)
55 #[arg(long)]
56 new_artist: Option<String>,
57
58 /// New album artist name (optional)
59 #[arg(long)]
60 new_album_artist: Option<String>,
61
62 /// Timestamp for specific scrobble (optional)
63 #[arg(long)]
64 timestamp: Option<u64>,
65
66 /// Whether to edit all instances (optional, defaults to false)
67 #[arg(long)]
68 edit_all: bool,
69
70 /// Actually apply the edits (default is dry-run mode)
71 #[arg(long)]
72 apply: bool,
73
74 /// Perform a dry run without actually submitting edits (default behavior)
75 #[arg(long)]
76 dry_run: bool,
77 },
78 /// Delete scrobbles in a range
79 ///
80 /// This command allows you to delete scrobbles from your library. You can specify
81 /// timestamp ranges, delete recent scrobbles from specific pages, or use offsets
82 /// from the most recent scrobble.
83 ///
84 /// Usage examples:
85 /// # Show recent scrobbles that would be deleted (dry run)
86 /// lastfm-edit delete --recent-pages 1-3
87 ///
88 /// # Delete scrobbles from timestamp range
89 /// lastfm-edit delete --timestamp-range 1640995200-1641000000 --apply
90 ///
91 /// # Delete scrobbles by offset from most recent (0-indexed)
92 /// lastfm-edit delete --recent-offset 0-4 --apply
93 Delete {
94 /// Delete scrobbles from recent pages (format: start-end, 0-indexed)
95 #[arg(long, conflicts_with_all = ["timestamp_range", "recent_offset"])]
96 recent_pages: Option<String>,
97
98 /// Delete scrobbles from timestamp range (format: start_ts-end_ts)
99 #[arg(long, conflicts_with_all = ["recent_pages", "recent_offset"])]
100 timestamp_range: Option<String>,
101
102 /// Delete scrobbles by offset from most recent (format: start-end, 0-indexed)
103 #[arg(long, conflicts_with_all = ["recent_pages", "timestamp_range"])]
104 recent_offset: Option<String>,
105
106 /// Actually perform the deletions (default is dry-run mode)
107 #[arg(long)]
108 apply: bool,
109
110 /// Perform a dry run without actually deleting (default behavior)
111 #[arg(long)]
112 dry_run: bool,
113 },
114 /// Show scrobble details for specific offsets
115 ///
116 /// This command displays detailed information for scrobbles at the specified
117 /// offsets from your most recent scrobbles.
118 ///
119 /// Usage examples:
120 /// # Show details for the most recent scrobble (offset 0)
121 /// lastfm-edit show 0
122 ///
123 /// # Show details for multiple scrobbles (0-indexed)
124 /// lastfm-edit show 0 1 2 5 10
125 Show {
126 /// Offsets of scrobbles to show (0-indexed, 0 = most recent)
127 offsets: Vec<u64>,
128 },
129}
130
131/// Execute the appropriate command handler based on the parsed command
132pub async fn execute_command(
133 command: Commands,
134 client: &LastFmEditClientImpl,
135) -> Result<(), Box<dyn std::error::Error>> {
136 match command {
137 Commands::Edit {
138 artist,
139 track,
140 album,
141 album_artist,
142 new_track,
143 new_album,
144 new_artist,
145 new_album_artist,
146 timestamp,
147 edit_all,
148 apply,
149 dry_run,
150 } => {
151 // Determine whether this is a dry run or actual edit
152 let is_dry_run = dry_run || !apply;
153
154 let edit = edit::create_scrobble_edit_from_args(
155 &artist,
156 track.as_deref(),
157 album.as_deref(),
158 album_artist.as_deref(),
159 new_track.as_deref(),
160 new_album.as_deref(),
161 new_artist.as_deref(),
162 new_album_artist.as_deref(),
163 timestamp,
164 edit_all,
165 );
166
167 edit::handle_edit_command(client, &edit, is_dry_run).await
168 }
169
170 Commands::Delete {
171 recent_pages,
172 timestamp_range,
173 recent_offset,
174 apply,
175 dry_run,
176 } => {
177 // Determine whether this is a dry run or actual deletion
178 let is_dry_run = dry_run || !apply;
179
180 if let Some(pages_range) = recent_pages {
181 delete::handle_delete_recent_pages(client, &pages_range, is_dry_run).await
182 } else if let Some(ts_range) = timestamp_range {
183 delete::handle_delete_timestamp_range(client, &ts_range, is_dry_run).await
184 } else if let Some(offset_range) = recent_offset {
185 delete::handle_delete_recent_offset(client, &offset_range, is_dry_run).await
186 } else {
187 Err(
188 "Must specify one of: --recent-pages, --timestamp-range, or --recent-offset"
189 .into(),
190 )
191 }
192 }
193
194 Commands::Show { offsets } => {
195 if offsets.is_empty() {
196 return Err("Must specify at least one offset to show".into());
197 }
198
199 show::handle_show_scrobbles(client, &offsets).await
200 }
201 }
202}