File size: 8,823 Bytes
0dc6fb4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
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