appydave-tools 0.18.2 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 754b54be8ce681f9743cadf14ecbd489aaaab2f569ebc78a7a9d70b673f9c8a7
4
- data.tar.gz: fd44964465106177b86c17e34e15d125c7256bd7575be16a83182d1f14fbc7d8
3
+ metadata.gz: 224b91f6d2a3b037091d744166f54b656f408695edd9a3b4d5f8f0599f84c841
4
+ data.tar.gz: aad4d21145e880dd65b31073e3c83e5165173638d4192a35d1da836d75159d60
5
5
  SHA512:
6
- metadata.gz: 05a625b643fcc72599156d2549459c5c9c800ab1ebd9da11aa82a6e4e4e2fee87e2784bdf610904a8a4b50790a5a7f53d41c2ddc813ea1e98b8f80fcc00da387
7
- data.tar.gz: b8d5ab9617a92f586e3a0d4938593b0f92443af7076d0f1d2c854535ba1d68bb932896944557bd5b94074d0bb6d69b49e72a5fd9ae7c05e64919bbc404d0daf1
6
+ metadata.gz: bf4d62d414afa97cd91115b7cea9e534d81641da2483528e551d4dcd043338055f8edd6be206ce0e8e0c3a1a8746568c1662110f275956c4b02fd2a201708f46
7
+ data.tar.gz: 198cf5f25d43543b9cc7861cfde567a3452ae35f5c18c9e525e9958fd3efe8fc2c9fb0af751123f3df2bfd5f40f47e4e943a89a188736e8056df27d7f9d8b71b
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [0.18.2](https://github.com/appydave/appydave-tools/compare/v0.18.1...v0.18.2) (2025-11-10)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * resolve Windows compatibility by removing hardcoded SSL certificate path ([fb4e6f7](https://github.com/appydave/appydave-tools/commit/fb4e6f74437e898229e1863f361d8ed4274a4ca6))
7
+
1
8
  ## [0.18.1](https://github.com/appydave/appydave-tools/compare/v0.18.0...v0.18.1) (2025-11-10)
2
9
 
3
10
 
@@ -1,6 +1,6 @@
1
1
  # CODEX Recommendations - Review & Status
2
2
 
3
- > Last updated: 2025-11-10
3
+ > Last updated: 2025-11-10 08:12:59 UTC
4
4
  > Original recommendations provided by Codex (GPT-5) on 2025-11-09
5
5
 
6
6
  This document captures Codex's architectural recommendations with implementation status and verdicts after engineering review.
@@ -146,6 +146,19 @@ end
146
146
 
147
147
  **Note:** These are legitimate technical debt items, not style preferences. Recommend creating GitHub issues for tracking.
148
148
 
149
+ ### 🔍 DAM Manifest & Sync Addendum (2025-11-10)
150
+
151
+ New DAM code mirrors the VAT manifest/sync flow but reintroduces several bugs plus new inconsistencies:
152
+
153
+ - **Archived projects still missing:** `collect_project_ids` explicitly skips the `archived` directory (`lib/appydave/tools/dam/manifest_generator.rb:70-99`), so the later logic that probes `brand_path/archived/<range>/<project>` never runs; manifests omit the majority of historical work. This also means `SyncFromSsd.should_sync_project?` (`lib/appydave/tools/dam/sync_from_ssd.rb:77-96`) will think everything is already local because manifests never flag archived presence.
154
+ - **Range math diverges between components:** Manifest uses `project_id =~ /^[a-z](\d+)/` to build ranges (`lib/appydave/tools/dam/manifest_generator.rb:214-224`), but the SSD sync hard-codes `/^b(\d+)/` (`lib/appydave/tools/dam/sync_from_ssd.rb:123-138`). Projects outside the `b` prefix (aitldr, voz, etc.) will all collapse into the fallback `000-099`, creating collisions.
155
+ - **SSD paths lose grouping info:** Manifests record `path: project_id` for SSD entries (`lib/appydave/tools/dam/manifest_generator.rb:119-126`), ignoring the range folders that exist on disk. The sync tool then assumes `ssd/<project_id>` (line 98) and will fail whenever the SSD organizes projects under range subdirectories.
156
+ - **Disk usage ignores archived location:** Even when a project only exists under `archived/<range>`, `calculate_disk_usage` points at `File.join(brand_path, project[:id])` (`lib/appydave/tools/dam/manifest_generator.rb:131-146`), so archived-only projects report 0 bytes. Need to reuse the resolved `local_path` (flat vs archived) instead of rebuilding the path blindly.
157
+ - **Heavy file detection still shallow:** `heavy_files?` only inspects direct children (`lib/appydave/tools/dam/manifest_generator.rb:233-239`), while `light_files?` walks `**/*`. Any team that keeps footage under nested folders (e.g., `/final/video.mp4`) gets `has_heavy_files: false`, which downstream sync logic relies on.
158
+ - **Sync exclusion filter misidentifies generated folders:** `EXCLUDE_PATTERNS` contain glob syntax (`**/node_modules/**`, `**/.DS_Store`), but `excluded_file?` strips `**/` and compares raw path segments (`lib/appydave/tools/dam/sync_from_ssd.rb:160-182`), so patterns like `.DS_Store` or `.turbo` may still slip through or block unrelated files. Consider using `File.fnmatch` with the original glob rather than manual string surgery.
159
+
160
+ Action: Fold these findings into the existing VAT manifest backlog or spin up DAM‑specific tickets so both manifest implementations converge on a single, tested service.
161
+
149
162
  ---
150
163
 
151
164
  ### ⚠️ CLI Standardization (Worth Auditing)
@@ -86,12 +86,23 @@ module Appydave
86
86
 
87
87
  # Scan SSD (if available)
88
88
  if ssd_available
89
- Dir.glob(File.join(ssd_backup, '*/')).each do |project_path|
90
- all_project_ids << File.basename(project_path)
89
+ Dir.glob(File.join(ssd_backup, '*/')).each do |ssd_path|
90
+ basename = File.basename(ssd_path)
91
+
92
+ if range_folder?(basename)
93
+ # Scan projects within SSD range folders
94
+ Dir.glob(File.join(ssd_path, '*/')).each do |project_path|
95
+ project_id = File.basename(project_path)
96
+ all_project_ids << project_id if valid_project_id?(project_id)
97
+ end
98
+ elsif valid_project_id?(basename)
99
+ # Direct project in SSD root (legacy structure)
100
+ all_project_ids << basename
101
+ end
91
102
  end
92
103
  end
93
104
 
94
- # Scan local (all projects in brand directory)
105
+ # Scan local flat structure (active projects only)
95
106
  Dir.glob(File.join(brand_path, '*/')).each do |path|
96
107
  basename = File.basename(path)
97
108
  # Skip hidden and special directories
@@ -101,36 +112,75 @@ module Appydave
101
112
  all_project_ids << basename if valid_project_id?(basename)
102
113
  end
103
114
 
115
+ # Scan archived structure (restored/archived projects)
116
+ archived_base = File.join(brand_path, 'archived')
117
+ if Dir.exist?(archived_base)
118
+ # Scan range folders (e.g., archived/a50-a99/, archived/b50-b99/)
119
+ Dir.glob(File.join(archived_base, '*/')).each do |range_folder|
120
+ # Scan projects within each range folder
121
+ Dir.glob(File.join(range_folder, '*/')).each do |project_path|
122
+ basename = File.basename(project_path)
123
+ all_project_ids << basename if valid_project_id?(basename)
124
+ end
125
+ end
126
+ end
127
+
104
128
  all_project_ids.uniq.sort
105
129
  end
106
130
 
107
131
  def build_project_entries(all_project_ids, ssd_backup, ssd_available)
108
- projects = []
109
-
110
- all_project_ids.each do |project_id|
111
- local_path = File.join(brand_path, project_id)
112
- ssd_path = ssd_available ? File.join(ssd_backup, project_id) : nil
113
-
114
- local_exists = Dir.exist?(local_path)
115
- ssd_exists = ssd_path && Dir.exist?(ssd_path)
116
-
117
- projects << {
118
- id: project_id,
119
- storage: {
120
- ssd: {
121
- exists: ssd_exists,
122
- path: ssd_exists ? project_id : nil
123
- },
124
- local: {
125
- exists: local_exists,
126
- has_heavy_files: local_exists ? heavy_files?(local_path) : false,
127
- has_light_files: local_exists ? light_files?(local_path) : false
128
- }
132
+ all_project_ids.map { |project_id| build_project_entry(project_id, ssd_backup, ssd_available) }
133
+ end
134
+
135
+ def build_project_entry(project_id, ssd_backup, ssd_available)
136
+ # Check flat structure (active projects)
137
+ flat_path = File.join(brand_path, project_id)
138
+ flat_exists = Dir.exist?(flat_path)
139
+
140
+ # Check archived structure (restored/archived projects)
141
+ range = determine_range(project_id)
142
+ archived_path = File.join(brand_path, 'archived', range, project_id)
143
+ archived_exists = Dir.exist?(archived_path)
144
+
145
+ # Determine which path to use for file detection
146
+ local_path = if flat_exists
147
+ flat_path
148
+ else
149
+ (archived_exists ? archived_path : flat_path)
150
+ end
151
+ local_exists = flat_exists || archived_exists
152
+
153
+ # Determine structure type
154
+ structure = if flat_exists
155
+ 'flat'
156
+ elsif archived_exists
157
+ 'archived'
158
+ end
159
+
160
+ # Check SSD (try both flat and range-based structures)
161
+ ssd_exists = if ssd_available
162
+ flat_ssd_path = File.join(ssd_backup, project_id)
163
+ range_ssd_path = File.join(ssd_backup, range, project_id)
164
+ Dir.exist?(flat_ssd_path) || Dir.exist?(range_ssd_path)
165
+ else
166
+ false
167
+ end
168
+
169
+ {
170
+ id: project_id,
171
+ storage: {
172
+ ssd: {
173
+ exists: ssd_exists,
174
+ path: ssd_exists ? project_id : nil
175
+ },
176
+ local: {
177
+ exists: local_exists,
178
+ structure: structure,
179
+ has_heavy_files: local_exists ? heavy_files?(local_path) : false,
180
+ has_light_files: local_exists ? light_files?(local_path) : false
129
181
  }
130
182
  }
131
- end
132
-
133
- projects
183
+ }
134
184
  end
135
185
 
136
186
  def calculate_disk_usage(projects, ssd_backup)
@@ -139,13 +189,27 @@ module Appydave
139
189
 
140
190
  projects.each do |project|
141
191
  if project[:storage][:local][:exists]
142
- local_path = File.join(brand_path, project[:id])
143
- local_bytes += calculate_directory_size(local_path)
192
+ # Try flat structure first, then archived structure
193
+ flat_path = File.join(brand_path, project[:id])
194
+ if Dir.exist?(flat_path)
195
+ local_bytes += calculate_directory_size(flat_path)
196
+ else
197
+ range = determine_range(project[:id])
198
+ archived_path = File.join(brand_path, 'archived', range, project[:id])
199
+ local_bytes += calculate_directory_size(archived_path) if Dir.exist?(archived_path)
200
+ end
144
201
  end
145
202
 
146
- if project[:storage][:ssd][:exists]
147
- ssd_path = File.join(ssd_backup, project[:id])
148
- ssd_bytes += calculate_directory_size(ssd_path)
203
+ next unless project[:storage][:ssd][:exists]
204
+
205
+ # Try flat structure first, then range-based structure
206
+ flat_ssd_path = File.join(ssd_backup, project[:id])
207
+ if Dir.exist?(flat_ssd_path)
208
+ ssd_bytes += calculate_directory_size(flat_ssd_path)
209
+ else
210
+ range = determine_range(project[:id])
211
+ range_ssd_path = File.join(ssd_backup, range, project[:id])
212
+ ssd_bytes += calculate_directory_size(range_ssd_path) if Dir.exist?(range_ssd_path)
149
213
  end
150
214
  end
151
215
 
@@ -190,6 +254,26 @@ module Appydave
190
254
  end
191
255
 
192
256
  # Helper methods
257
+
258
+ # Determine range folder for project
259
+ # Both SSD and local archived use 50-number ranges with letter prefixes:
260
+ # b00-b49, b50-b99, a01-a49, a50-a99
261
+ def determine_range(project_id)
262
+ # FliVideo/Modern pattern: b40, a82, etc.
263
+ if project_id =~ /^([a-z])(\d+)/
264
+ letter = Regexp.last_match(1)
265
+ number = Regexp.last_match(2).to_i
266
+ # 50-number ranges (0-49, 50-99)
267
+ range_start = (number / 50) * 50
268
+ range_end = range_start + 49
269
+ # Format with leading zeros and letter prefix
270
+ format("#{letter}%02d-#{letter}%02d", range_start, range_end)
271
+ else
272
+ # Legacy pattern or unknown
273
+ '000-099'
274
+ end
275
+ end
276
+
193
277
  def valid_project_id?(project_id)
194
278
  # Valid formats:
195
279
  # - Modern: letter + 2 digits + dash + name (e.g., b63-flivideo)
@@ -197,6 +281,23 @@ module Appydave
197
281
  !!(project_id =~ /^[a-z]\d{2}-/ || project_id =~ /^\d/)
198
282
  end
199
283
 
284
+ def range_folder?(folder_name)
285
+ # Range folder patterns with letter prefixes:
286
+ # - b00-b49, b50-b99, a00-a49, a50-a99 (letter + 2 digits + dash + same letter + 2 digits)
287
+ # - 000-099 (3 digits + dash + 3 digits)
288
+ # Must match: same letter on both sides (b00-b49, not b00-a49)
289
+ return true if folder_name =~ /^\d{3}-\d{3}$/
290
+
291
+ if folder_name =~ /^([a-z])(\d{2})-([a-z])(\d{2})$/
292
+ letter1 = Regexp.last_match(1)
293
+ letter2 = Regexp.last_match(3)
294
+ # Must be same letter on both sides
295
+ return letter1 == letter2
296
+ end
297
+
298
+ false
299
+ end
300
+
200
301
  def heavy_files?(dir)
201
302
  return false unless Dir.exist?(dir)
202
303
 
@@ -149,11 +149,11 @@ module Appydave
149
149
 
150
150
  # Determine if project should be synced
151
151
  def should_sync_project?(project)
152
- # Only sync if project exists on SSD but NOT in local flat structure
152
+ # Only sync if project exists on SSD but NOT locally (either flat or archived)
153
153
  return false unless project[:storage][:ssd][:exists]
154
154
 
155
- # Skip if exists locally in flat structure
156
- return false if project[:storage][:local][:exists] && project[:storage][:local][:structure] == 'flat'
155
+ # Skip if exists locally in any structure (flat or archived)
156
+ return false if project[:storage][:local][:exists]
157
157
 
158
158
  true
159
159
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Appydave
4
4
  module Tools
5
- VERSION = '0.18.2'
5
+ VERSION = '0.18.3'
6
6
  end
7
7
  end
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "appydave-tools",
3
- "version": "0.18.2",
3
+ "version": "0.18.3",
4
4
  "description": "AppyDave YouTube Automation Tools",
5
5
  "scripts": {
6
6
  "release": "semantic-release"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: appydave-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.2
4
+ version: 0.18.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Cruwys