[WIP] music platform user data scraper
teal-fm atproto

Moved the parsing of the time stamp for lastFM to the struct

Changed files
+41 -18
service
lastfm
spotify
+4 -15
service/lastfm/lastfm.go
··· 316 316 return nil 317 317 } 318 318 319 - uts, err := strconv.ParseInt(lastNonNowPlaying.Date.UTS, 10, 64) 320 - if err != nil { 321 - log.Printf("error parsing timestamp '%s' for track %s - %s: %v", 322 - lastNonNowPlaying.Date.UTS, lastNonNowPlaying.Artist.Text, lastNonNowPlaying.Name, err) 323 - } 324 - latestTrackTime := time.Unix(uts, 0) 319 + latestTrackTime := lastNonNowPlaying.Date 325 320 326 321 // print both 327 322 fmt.Printf("latestTrackTime: %s\n", latestTrackTime) 328 323 fmt.Printf("lastKnownTimestamp: %s\n", lastKnownTimestamp) 329 324 330 - if lastKnownTimestamp != nil && lastKnownTimestamp.Equal(latestTrackTime) { 325 + if lastKnownTimestamp != nil && lastKnownTimestamp.Equal(latestTrackTime.Time) { 331 326 log.Printf("no new tracks to process for user %s.", username) 332 327 return nil 333 328 } 334 329 335 330 for _, track := range tracks { 336 - if track.Date == nil || track.Date.UTS == "" { 331 + if track.Date == nil { 337 332 log.Printf("skipping track without timestamp for %s: %s - %s", username, track.Artist.Text, track.Name) 338 333 continue 339 334 } 340 335 341 - uts, err := strconv.ParseInt(track.Date.UTS, 10, 64) 342 - if err != nil { 343 - log.Printf("error parsing timestamp '%s' for track %s - %s: %v", track.Date.UTS, track.Artist.Text, track.Name, err) 344 - continue 345 - } 346 - trackTime := time.Unix(uts, 0) 347 - 336 + trackTime := track.Date.Time 348 337 // before or at last known 349 338 if lastKnownTimestamp != nil && (trackTime.Before(*lastKnownTimestamp) || trackTime.Equal(*lastKnownTimestamp)) { 350 339 if processedCount == 0 {
+36 -2
service/lastfm/model.go
··· 1 1 package lastfm 2 2 3 + import ( 4 + "encoding/json" 5 + "strconv" 6 + "time" 7 + ) 8 + 3 9 // Structs to represent the Last.fm API response for user.getrecenttracks 4 10 type RecentTracksResponse struct { 5 11 RecentTracks RecentTracks `json:"recenttracks"` ··· 19 25 Name string `json:"name"` 20 26 URL string `json:"url"` 21 27 Date *TrackDate `json:"date,omitempty"` // Use pointer for optional fields 22 - Attr *struct { // Custom handling for @attr.nowplaying 28 + Attr *struct { // Custom handling for @attr.nowplaying 23 29 NowPlaying string `json:"nowplaying"` // Field name corrected to match struct tag 24 30 } `json:"@attr,omitempty"` // This captures the @attr object within the track 25 31 } ··· 39 45 Text string `json:"#text"` // Album name 40 46 } 41 47 42 - type TrackDate struct { 48 + // ApiTrackDate This is the real structure returned from lastFM. 49 + // Represents a date associated with a track, including both a Unix timestamp and a human-readable string. 50 + // UTS is a Unix timestamp stored as a string. 51 + // Text contains the human-readable date string. 52 + type ApiTrackDate struct { 43 53 UTS string `json:"uts"` // Unix timestamp string 44 54 Text string `json:"#text"` // Human-readable date string 55 + } 56 + 57 + // TrackDate This is the struct we use to represent a date associated with a track. 58 + // It is a wrapper around time.Time that implements json.Unmarshaler. 59 + type TrackDate struct { 60 + time.Time 61 + } 62 + 63 + // UnmarshalJSON Implements json.Unmarshaler. 64 + // Parses the UTS field from the API response and converts it to a time.Time. 65 + // The time.Time is stored in the Time field. 66 + // The Text field is ignored since it can be parsed from the Time field if needed. 67 + func (t *TrackDate) UnmarshalJSON(b []byte) (err error) { 68 + var apiTrackDate ApiTrackDate 69 + if err := json.Unmarshal(b, &apiTrackDate); err != nil { 70 + return err 71 + } 72 + uts, err := strconv.ParseInt(apiTrackDate.UTS, 10, 64) 73 + if err != nil { 74 + return err 75 + } 76 + date := time.Unix(uts, 0).UTC() 77 + t.Time = date 78 + return 45 79 } 46 80 47 81 type TrackXMLAttr struct {
+1 -1
service/spotify/spotify.go
··· 526 526 ServiceBaseUrl: "open.spotify.com", 527 527 ISRC: response.Item.ExternalIDs.ISRC, 528 528 HasStamped: false, 529 - Timestamp: time.Now(), 529 + Timestamp: time.Now().UTC(), 530 530 } 531 531 532 532 return track, nil