Attribute VB_Name = "AmazonUrlCleaner" Option Explicit ' ============================================================================= ' Amazon image URL auto-cleaner ' ' INSTALL into Template.xlsm: ' 1. Alt+F11 → File → Import File → select AmazonUrlCleaner.bas ONLY ' 2. Double-click ThisWorkbook — paste Sub from AmazonUrlCleaner_ThisWorkbook.txt ' 3. Debug → Compile VBAProject, then save as .xlsm ' ' SCOPE: ' - Only Manual and WriteBuffer worksheets ' - Only cells from B2 onward (never row 1, never column A) ' - After any change in that region (including transpose paste), cleans the ' full used B2+ block so every transposed Amazon URL is processed ' ============================================================================= Private Const FIRST_DATA_ROW As Long = 2 Private Const FIRST_IMAGE_COL As Long = 2 Private Const MANUAL_SHEET As String = "Manual" Private Const WRITEBUFFER_SHEET As String = "WriteBuffer" ' Called from ThisWorkbook.Workbook_SheetChange Public Sub HandleAmazonUrlSheetChange(ByVal Sh As Object, ByVal Target As Range) Dim allowedRegion As Range Dim touched As Range Dim dataRange As Range Dim ws As Worksheet On Error GoTo ErrorHandler If Target Is Nothing Then Exit Sub If TypeName(Sh) <> "Worksheet" Then Exit Sub Set ws = Sh If Not IsAmazonCleanerTargetSheet(ws) Then Exit Sub Set allowedRegion = ws.Range( _ ws.Cells(FIRST_DATA_ROW, FIRST_IMAGE_COL), _ ws.Cells(ws.Rows.Count, ws.Columns.Count)) ' Only react when the edit touches B2+ (ignore row 1 / column A) Set touched = Intersect(Target, allowedRegion) If touched Is Nothing Then Exit Sub ' After transpose/paste, Target may be only the first cell (e.g. B2). ' Always clean the full used URL block from B2 onward on this sheet. Set dataRange = GetCleanerDataRange(ws) If dataRange Is Nothing Then Exit Sub CleanAmazonUrlsInRange dataRange Exit Sub ErrorHandler: Application.EnableEvents = True End Sub ' Optional: call from a transpose macro after writing values. Public Sub CleanAmazonUrlsOnSheet(ByVal targetSheet As Worksheet) Dim dataRange As Range If Not IsAmazonCleanerTargetSheet(targetSheet) Then Exit Sub Set dataRange = GetCleanerDataRange(targetSheet) If dataRange Is Nothing Then Exit Sub CleanAmazonUrlsInRange dataRange End Sub Public Function IsAmazonCleanerTargetSheet(ByVal targetSheet As Worksheet) As Boolean If targetSheet Is Nothing Then Exit Function IsAmazonCleanerTargetSheet = _ (StrComp(targetSheet.Name, MANUAL_SHEET, vbTextCompare) = 0) Or _ (StrComp(targetSheet.Name, WRITEBUFFER_SHEET, vbTextCompare) = 0) End Function ' Remove ._MODIFIER_ immediately before a supported image extension. Public Function CleanAmazonImageUrl(ByVal rawValue As String) As String Dim trimmed As String Dim lowerUrl As String Dim regex As Object trimmed = Trim$(rawValue) CleanAmazonImageUrl = trimmed If Len(trimmed) = 0 Then Exit Function lowerUrl = LCase$(trimmed) If Left$(lowerUrl, 7) <> "http://" And Left$(lowerUrl, 8) <> "https://" Then Exit Function End If If InStr(1, lowerUrl, "amazon.", vbBinaryCompare) = 0 And _ InStr(1, lowerUrl, "media-amazon.com", vbBinaryCompare) = 0 And _ InStr(1, lowerUrl, "ssl-images-amazon.com", vbBinaryCompare) = 0 Then Exit Function End If On Error GoTo CleanFailed Set regex = CreateObject("VBScript.RegExp") With regex .Global = True .IgnoreCase = True .Pattern = "\._[A-Za-z0-9_]+_(\.(jpg|jpeg|png|webp|gif))" CleanAmazonImageUrl = .Replace(trimmed, "$1") End With Exit Function CleanFailed: CleanAmazonImageUrl = trimmed End Function Public Sub CleanAmazonUrlsInRange(ByVal targetRange As Range) Dim area As Range Dim originalValue As Variant Dim originalText As String Dim cleanedText As String Dim previousEnableEvents As Boolean Dim previousScreenUpdating As Boolean Dim dataValues As Variant Dim r As Long Dim c As Long Dim changed As Boolean Dim rowCount As Long Dim colCount As Long If targetRange Is Nothing Then Exit Sub previousEnableEvents = Application.EnableEvents previousScreenUpdating = Application.ScreenUpdating On Error GoTo RestoreSettings Application.EnableEvents = False Application.ScreenUpdating = False For Each area In targetRange.Areas rowCount = area.Rows.Count colCount = area.Columns.Count If rowCount = 1 And colCount = 1 Then originalValue = area.Value2 If Not IsBlankOrError(originalValue) Then originalText = CStr(originalValue) cleanedText = CleanAmazonImageUrl(originalText) If StrComp(originalText, cleanedText, vbBinaryCompare) <> 0 Then area.Value2 = cleanedText End If End If Else dataValues = area.Value2 changed = False If IsArray(dataValues) Then ' Excel usually returns 2D; a single row/col can still be 2D (1 x N / N x 1). If ArrayDimensionCount(dataValues) = 1 Then ' Rare 1D array — normalize to row loop For c = LBound(dataValues) To UBound(dataValues) originalValue = dataValues(c) If Not IsBlankOrError(originalValue) Then originalText = CStr(originalValue) cleanedText = CleanAmazonImageUrl(originalText) If StrComp(originalText, cleanedText, vbBinaryCompare) <> 0 Then dataValues(c) = cleanedText changed = True End If End If Next c Else For r = LBound(dataValues, 1) To UBound(dataValues, 1) For c = LBound(dataValues, 2) To UBound(dataValues, 2) originalValue = dataValues(r, c) If Not IsBlankOrError(originalValue) Then originalText = CStr(originalValue) cleanedText = CleanAmazonImageUrl(originalText) If StrComp(originalText, cleanedText, vbBinaryCompare) <> 0 Then dataValues(r, c) = cleanedText changed = True End If End If Next c Next r End If If changed Then area.Value2 = dataValues End If End If End If Next area RestoreSettings: Application.EnableEvents = previousEnableEvents Application.ScreenUpdating = previousScreenUpdating End Sub ' Used data block from B2 through last used row/column on the sheet. Private Function GetCleanerDataRange(ByVal ws As Worksheet) As Range Dim lastRow As Long Dim lastCol As Long Dim colIndex As Long Dim colLastRow As Long Dim used As Range On Error Resume Next Set used = ws.UsedRange On Error GoTo 0 lastRow = FIRST_DATA_ROW - 1 lastCol = FIRST_IMAGE_COL If Not used Is Nothing Then lastCol = used.Column + used.Columns.Count - 1 If lastCol < FIRST_IMAGE_COL Then lastCol = FIRST_IMAGE_COL For colIndex = FIRST_IMAGE_COL To lastCol colLastRow = ws.Cells(ws.Rows.Count, colIndex).End(xlUp).Row If colLastRow > lastRow Then lastRow = colLastRow Next colIndex End If If lastRow < FIRST_DATA_ROW Then Exit Function If lastCol < FIRST_IMAGE_COL Then lastCol = FIRST_IMAGE_COL Set GetCleanerDataRange = ws.Range( _ ws.Cells(FIRST_DATA_ROW, FIRST_IMAGE_COL), _ ws.Cells(lastRow, lastCol)) End Function Private Function ArrayDimensionCount(ByVal dataValues As Variant) As Long Dim probe As Long On Error GoTo OneDimension probe = UBound(dataValues, 2) ArrayDimensionCount = 2 Exit Function OneDimension: ArrayDimensionCount = 1 End Function Private Function IsBlankOrError(ByVal cellValue As Variant) As Boolean If IsError(cellValue) Or IsEmpty(cellValue) Or IsNull(cellValue) Then IsBlankOrError = True Exit Function End If If VarType(cellValue) = vbObject Or VarType(cellValue) = vbDataObject Then IsBlankOrError = True Exit Function End If If Len(Trim$(CStr(cellValue))) = 0 Then IsBlankOrError = True End If End Function