Revision history for App::DrivePlayer. 0.2.9 2026-04-30 - Fix: player IPC no longer drops mpv events when a recv() slices an event mid-line. _drain_events and _send_command_sync now share _pending_buf so partial events get reassembled across reads. Symptom: roughly every 15-20 tracks playback would stick on a finished track because end-file was lost and on_track_end never fired. - Settings: saving with changed Google credentials now tears down rest_api / drive / player and rebuilds them against the new config, so a refreshed token takes effect without restarting the app. - Errors: HTTP 4xx / OAuth-grant failures from Google now pop the Settings dialog automatically after the error is dismissed, routing the user straight to the credentials. Re-entry from errors fired inside the Settings dialog itself (e.g. Find-or-Create) is suppressed. - Tracklist: Artist, Album and Genre cells are now click targets that switch the sidebar to that group; the existing cursor-changed signal repopulates the tracklist. A hand cursor on hover indicates the cell is clickable. - Edit metadata: when an artist / album / genre value changes and other tracks share the previous value, a single confirmation dialog offers to apply the rename across all matching tracks -- so one mojibake fix can clean up the lingering sidebar entry instead of leaving it stuck behind unrenamed siblings. - Edit metadata: small grey help label under the Fetch button states that Fetch only fills blank fields, and that clearing a populated field lets Fetch replace it. - Config: write 'class: OAuth2Client' on the google_restapi blob (in addition to under auth) and require Google::RestApi >= 2.2.3. - Docs: README Files section converted from a GFM pipe table to a bulleted list so it renders correctly on MetaCPAN (Text::Markdown doesn't support tables). 0.2.8 2026-04-23 - Fix: Scanner now decodes UTF-8 at the Drive API boundary, preventing double-encoded mojibake (e.g. "Nazan Ãncel" instead of "Nazan Öncel") from landing in SQLite. New tools/fix_mojibake.pl repairs existing corrupted rows. - Edit dialog: context menu "Edit Metadata…" and "Fetch Metadata…" consolidated into a single "Edit…" with a Fetch button inside the dialog. Fetch fills only blank fields (whitespace-only counts as blank); to refresh a populated field, clear it first. - Edit dialog: entries force LTR layout with an invisible LRM prefix, so RTL content (Arabic, Hebrew) no longer flips the dialog to right-justified after a fill. Text strippers remove the marker on read so nothing leaks into the DB or queries. - Display: tracklist, sidebar, and now-playing label strip leading track-number prefixes from titles, leading YYYY- from albums, and underscores across title/artist/album. Stored values stay raw — DB lookups and sheet sync are unaffected. - Sheet sync: single-track metadata saves now update just the one row on the relevant worksheet (two Sheets API calls total — values.get on the drive_id column, then values.update on the matching row) instead of rewriting every tab. - Save: metadata edits refresh the single tracklist row in place, preserving sidebar selection and scroll position (was a full _load_library that bumped the user back to the "All Tracks" view). 0.2.7 2026-04-22 - Settings dialog: move the Google Sheet Sync section so it follows the Google API Credentials section (related Google settings grouped together). - Settings dialog: add mouseover tooltips on every label and input (OAuth Client ID / Secret / Token File, Spreadsheet ID, fpcalc row, AcoustID API Key) explaining what each value is and where it comes from. - Settings dialog: add clickable help links in the section notes pointing at Google Cloud Console (Credentials + Drive API library), google_restapi_oauth_token_creator, sheets.google.com, and the AcoustID application registration page. - Settings dialog: cap note width at 60 chars so long hints wrap cleanly instead of forcing the dialog wider. 0.2.6 2026-04-20 - Fix: track auto-advance now handles mpv 'end-file' with reason=error (transient network/stream failures), and no longer spuriously advances on reason=stop (which fires for user-initiated stop and for loadfile-replace pre-emption). - Fix: re-playing a track already visible in the list no longer re-centres the tracklist viewport. _highlight_path checks get_visible_range first and only scrolls when the target row is off-screen. - A-Z sidebar strip now follows the selected category: operates on Artists / Albums / Genres depending on the current sidebar selection, and is disabled (insensitive) while All Tracks or a Folders entry is selected. - New "YYYY-AlbumName" folder/filename convention: when an album (inferred from the folder path) or a filename starts with a 19xx/20xx year followed by '-', the prefix is stripped from the album/title and the year is written to the track's year metadata. Re-scan to populate existing tracks. - Tracklist gains a Year column between Genre and Duration. 0.2.5 2026-04-18 - Unified sheet sync: Library -> Sync now does a single bidirectional reconcile after the Drive scan. Rules: both sides have a value -> DB wins; one side blank -> filled from the other; drive_id only in DB -> added to sheet; drive_id only on sheet -> Drive is queried and the track is either added to the DB (exists) or removed from the sheet (gone). Drive API errors during the existence check preserve the row on both sides -- sync never destroys data on an API error. - Removed the separate File -> Sync from Sheet / Sync to Sheet menu items. Auto-push after metadata edits/fetches is kept as a targeted merge-push, since running a full two-way sync after every field edit would be wasteful. - Fix: clicking a track in the list no longer auto-scrolls the viewport between the two clicks of a double-click, which could cause a different track to end up under the cursor and be played instead of the one clicked. The tracklist now handles left-clicks manually so GTK's set_cursor auto-scroll never fires on click. 0.2.4 2026-04-17 - Sheet push is now a merge instead of a full replace: local non-blank values overwrite the sheet, local blanks preserve existing sheet values, and drive_ids only present on the sheet are kept intact. Prevents a device with partially-populated metadata from wiping data pushed from another device. - No longer auto-fetches metadata on startup. If another device has already populated metadata and synced it to the sheet, a new device doesn't need to refetch. Use Library → Fetch All Metadata to trigger a fetch manually. - Dropped the Composer field entirely (sheet, edit-metadata dialog, metadata-fetch pipeline, and DB schema). The only source was embedded FLAC tags, which in practice populated almost no tracks, so it was carrying no value. Existing databases have the column dropped on first run (SQLite >= 3.35). 0.2.3 2026-04-17 - Edit Metadata dialog now auto-syncs to the Google Sheet after save, so manual edits (e.g. fixing a genre) propagate to other devices without waiting for the next Library → Sync. 0.2.2 2026-04-16 - Fix duration_ms and genre not propagating to new devices on sheet pull: duration_ms was overwritten by Drive scans (moved to metadata fields) and was absent from skeleton-track creation. 0.2.1 2026-04-16 - Fix window height: replace alpha-strip button VBox with TreeView so the sidebar ScrolledWindow can properly constrain minimum height, allowing the main window to be resized smaller. - Alpha strip width increased to 32px to avoid scrollbar overlap. 0.2.0 2026-04-15 - GUI refactored into Moo roles (MetadataFetch, SheetSync, FolderBrowse). - Background metadata fetch via fork+pipe; UI remains responsive. - Live track-row updates in the list view as metadata arrives. - Retry Incomplete Metadata: re-fetches only tracks missing key fields. - FLAC embedded tag reading via Audio::FLAC::Header (optional). - MusicBrainz genre support (curated genres preferred over folksonomy tags). - Genre lookup now falls back through release → release-group levels. - Title cleaning now strips leading track numbers from underscore filenames. - Duration captured from mpv playback and persisted to DB and sheet. - Config supports google_restapi key introduced in Google::RestApi 2.2.1. - Track lookup fixed after column sort (was using stale position index). - Column widths set to sensible defaults on initial load. - Log4perl appenders set to UTF-8 to suppress wide-character warnings. - Library → Refresh menu item added. - Stop button hidden when playback is idle. - Folder-scoped metadata fetch via sidebar right-click. 0.1.0 2026-04-12 - Initial release. - GTK3 music player for Google Drive with SQLite local library. - Google Sheets sync for cross-device metadata portability. - AcoustID / iTunes / MusicBrainz metadata fetching. - Incremental folder sync with large-deletion confirmation.