@gallop.software/studio 2.3.42 → 2.3.44

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.
@@ -1841,6 +1841,10 @@ async function handleMoveStream(request) {
1841
1841
  currentFile: path6.basename(vItem.newKey)
1842
1842
  });
1843
1843
  }
1844
+ const newFolderPath = getPublicPath(newKey);
1845
+ await deleteEmptyFolders(newFolderPath);
1846
+ const newThumbFolder = path6.join(getPublicPath("images"), newKey.slice(1));
1847
+ await deleteEmptyFolders(newThumbFolder);
1844
1848
  moved.push(itemPath);
1845
1849
  continue;
1846
1850
  }
@@ -1912,6 +1916,11 @@ async function handleMoveStream(request) {
1912
1916
  if (hasProcessedThumbnails) {
1913
1917
  await deleteLocalThumbnails(newKey);
1914
1918
  }
1919
+ await deleteEmptyFolders(path6.dirname(newAbsolutePath));
1920
+ if (hasProcessedThumbnails) {
1921
+ const newThumbRelPath = newKey.slice(1);
1922
+ await deleteEmptyFolders(path6.join(getPublicPath("images"), newThumbRelPath));
1923
+ }
1915
1924
  newEntry.c = entry?.c;
1916
1925
  delete meta[oldKey];
1917
1926
  meta[newKey] = newEntry;
@@ -1970,74 +1979,187 @@ async function handleMoveStream(request) {
1970
1979
  continue;
1971
1980
  } catch {
1972
1981
  }
1973
- await fs6.rename(absolutePath, newAbsolutePath);
1974
- const stats = await fs6.stat(newAbsolutePath);
1975
- if (stats.isFile() && isImage && entry) {
1976
- const oldThumbPaths = getAllThumbnailPaths(oldKey);
1977
- const newThumbPaths = getAllThumbnailPaths(newKey);
1978
- for (let j = 0; j < oldThumbPaths.length; j++) {
1979
- const oldThumbPath = getPublicPath(oldThumbPaths[j]);
1980
- const newThumbPath = getPublicPath(newThumbPaths[j]);
1981
- try {
1982
- await fs6.access(oldThumbPath);
1983
- sourceFolders.add(path6.dirname(oldThumbPath));
1984
- await fs6.mkdir(path6.dirname(newThumbPath), { recursive: true });
1985
- await fs6.rename(oldThumbPath, newThumbPath);
1986
- } catch {
1982
+ const stats = await fs6.stat(absolutePath);
1983
+ if (stats.isFile()) {
1984
+ await fs6.mkdir(path6.dirname(newAbsolutePath), { recursive: true });
1985
+ await fs6.rename(absolutePath, newAbsolutePath);
1986
+ if (isImage && entry) {
1987
+ const oldThumbPaths = getAllThumbnailPaths(oldKey);
1988
+ const newThumbPaths = getAllThumbnailPaths(newKey);
1989
+ for (let j = 0; j < oldThumbPaths.length; j++) {
1990
+ const oldThumbPath = getPublicPath(oldThumbPaths[j]);
1991
+ const newThumbPath = getPublicPath(newThumbPaths[j]);
1992
+ try {
1993
+ await fs6.access(oldThumbPath);
1994
+ sourceFolders.add(path6.dirname(oldThumbPath));
1995
+ await fs6.mkdir(path6.dirname(newThumbPath), { recursive: true });
1996
+ await fs6.rename(oldThumbPath, newThumbPath);
1997
+ } catch {
1998
+ }
1987
1999
  }
2000
+ const fileIsInCloud = entry.c !== void 0;
2001
+ const fileCdnUrl2 = fileIsInCloud ? cdnUrls[entry.c] : void 0;
2002
+ const fileIsInR2 = fileIsInCloud && fileCdnUrl2 === r2PublicUrl;
2003
+ const fileHasThumbs = isProcessed(entry);
2004
+ if (fileIsInR2) {
2005
+ await deleteFromCdn(oldKey, fileHasThumbs);
2006
+ await uploadOriginalToCdn(newKey);
2007
+ if (fileHasThumbs) {
2008
+ await uploadToCdn(newKey);
2009
+ }
2010
+ }
2011
+ delete meta[oldKey];
2012
+ meta[newKey] = entry;
1988
2013
  }
1989
- delete meta[oldKey];
1990
- meta[newKey] = entry;
2014
+ processedFiles++;
2015
+ sendEvent({
2016
+ type: "progress",
2017
+ current: processedFiles,
2018
+ total: totalFiles,
2019
+ moved: moved.length,
2020
+ percent: Math.round(processedFiles / totalFiles * 100),
2021
+ currentFile: itemName
2022
+ });
2023
+ moved.push(itemPath);
1991
2024
  } else if (stats.isDirectory()) {
1992
2025
  const oldPrefix = oldKey + "/";
1993
2026
  const newPrefix = newKey + "/";
1994
- for (const key of Object.keys(meta)) {
1995
- if (key.startsWith(oldPrefix)) {
1996
- const newMetaKey = newPrefix + key.slice(oldPrefix.length);
1997
- meta[newMetaKey] = meta[key];
1998
- delete meta[key];
1999
- }
2000
- }
2001
- const oldThumbRelPath = oldKey.slice(1);
2002
- const newThumbRelPath = newKey.slice(1);
2003
- const imagesDir = getPublicPath("images");
2004
- const oldThumbFolder = path6.join(imagesDir, oldThumbRelPath);
2005
- const newThumbFolder = path6.join(imagesDir, newThumbRelPath);
2006
- try {
2007
- await fs6.access(oldThumbFolder);
2008
- sourceFolders.add(oldThumbFolder);
2009
- await fs6.mkdir(path6.dirname(newThumbFolder), { recursive: true });
2010
- await fs6.rename(oldThumbFolder, newThumbFolder);
2011
- } catch {
2012
- }
2013
- }
2014
- moved.push(itemPath);
2015
- if (stats.isDirectory()) {
2016
- const countFilesInDir = async (dir) => {
2017
- let count = 0;
2027
+ const localFiles = [];
2028
+ const collectLocalFiles = async (dir, relativeDir) => {
2018
2029
  const entries = await fs6.readdir(dir, { withFileTypes: true });
2019
- for (const entry2 of entries) {
2020
- if (entry2.isDirectory()) {
2021
- count += await countFilesInDir(path6.join(dir, entry2.name));
2030
+ for (const dirEntry of entries) {
2031
+ const entryRelPath = relativeDir ? `${relativeDir}/${dirEntry.name}` : dirEntry.name;
2032
+ if (dirEntry.isDirectory()) {
2033
+ await collectLocalFiles(path6.join(dir, dirEntry.name), entryRelPath);
2022
2034
  } else {
2023
- count++;
2035
+ localFiles.push({ relativePath: entryRelPath, isImage: isImageFile(dirEntry.name) });
2024
2036
  }
2025
2037
  }
2026
- return count;
2027
2038
  };
2028
- const filesInDir = await countFilesInDir(newAbsolutePath);
2029
- processedFiles += filesInDir;
2030
- } else {
2031
- processedFiles++;
2039
+ await collectLocalFiles(absolutePath, "");
2040
+ const cloudOnlyFiles = [];
2041
+ for (const [metaKey, metaEntry] of Object.entries(meta)) {
2042
+ if (metaKey.startsWith(oldPrefix) && metaEntry && typeof metaEntry === "object") {
2043
+ const relPath = metaKey.slice(oldPrefix.length);
2044
+ const localPath = path6.join(absolutePath, relPath);
2045
+ try {
2046
+ await fs6.access(localPath);
2047
+ } catch {
2048
+ cloudOnlyFiles.push({
2049
+ oldKey: metaKey,
2050
+ newKey: newPrefix + relPath,
2051
+ entry: metaEntry
2052
+ });
2053
+ }
2054
+ }
2055
+ }
2056
+ for (const localFile of localFiles) {
2057
+ const fileOldPath = path6.join(absolutePath, localFile.relativePath);
2058
+ const fileNewPath = path6.join(newAbsolutePath, localFile.relativePath);
2059
+ const fileOldKey = oldPrefix + localFile.relativePath;
2060
+ const fileNewKey = newPrefix + localFile.relativePath;
2061
+ const fileEntry = meta[fileOldKey];
2062
+ sourceFolders.add(path6.dirname(fileOldPath));
2063
+ await fs6.mkdir(path6.dirname(fileNewPath), { recursive: true });
2064
+ await fs6.rename(fileOldPath, fileNewPath);
2065
+ if (localFile.isImage && fileEntry) {
2066
+ const oldThumbPaths = getAllThumbnailPaths(fileOldKey);
2067
+ const newThumbPaths = getAllThumbnailPaths(fileNewKey);
2068
+ for (let t = 0; t < oldThumbPaths.length; t++) {
2069
+ const oldThumbPath = getPublicPath(oldThumbPaths[t]);
2070
+ const newThumbPath = getPublicPath(newThumbPaths[t]);
2071
+ try {
2072
+ await fs6.access(oldThumbPath);
2073
+ sourceFolders.add(path6.dirname(oldThumbPath));
2074
+ await fs6.mkdir(path6.dirname(newThumbPath), { recursive: true });
2075
+ await fs6.rename(oldThumbPath, newThumbPath);
2076
+ } catch {
2077
+ }
2078
+ }
2079
+ const fileIsInCloud = fileEntry.c !== void 0;
2080
+ const fileCdnUrl2 = fileIsInCloud ? cdnUrls[fileEntry.c] : void 0;
2081
+ const fileIsInR2 = fileIsInCloud && fileCdnUrl2 === r2PublicUrl;
2082
+ const fileHasThumbs = isProcessed(fileEntry);
2083
+ if (fileIsInR2) {
2084
+ await deleteFromCdn(fileOldKey, fileHasThumbs);
2085
+ await uploadOriginalToCdn(fileNewKey);
2086
+ if (fileHasThumbs) {
2087
+ await uploadToCdn(fileNewKey);
2088
+ }
2089
+ }
2090
+ delete meta[fileOldKey];
2091
+ meta[fileNewKey] = fileEntry;
2092
+ }
2093
+ processedFiles++;
2094
+ sendEvent({
2095
+ type: "progress",
2096
+ current: processedFiles,
2097
+ total: totalFiles,
2098
+ moved: moved.length,
2099
+ percent: Math.round(processedFiles / totalFiles * 100),
2100
+ currentFile: path6.basename(localFile.relativePath)
2101
+ });
2102
+ }
2103
+ for (const cloudFile of cloudOnlyFiles) {
2104
+ const cloudEntry = cloudFile.entry;
2105
+ const cloudIsInCloud = cloudEntry.c !== void 0;
2106
+ const cloudCdnUrl = cloudIsInCloud ? cdnUrls[cloudEntry.c] : void 0;
2107
+ const cloudIsInR2 = cloudIsInCloud && cloudCdnUrl === r2PublicUrl;
2108
+ const cloudHasThumbs = isProcessed(cloudEntry);
2109
+ if (cloudIsInR2) {
2110
+ try {
2111
+ const cloudLocalPath = getPublicPath(cloudFile.newKey);
2112
+ const buffer = await downloadFromCdn(cloudFile.oldKey);
2113
+ await fs6.mkdir(path6.dirname(cloudLocalPath), { recursive: true });
2114
+ await fs6.writeFile(cloudLocalPath, buffer);
2115
+ if (cloudHasThumbs) {
2116
+ const oldThumbPaths = getAllThumbnailPaths(cloudFile.oldKey);
2117
+ const newThumbPaths = getAllThumbnailPaths(cloudFile.newKey);
2118
+ for (let t = 0; t < oldThumbPaths.length; t++) {
2119
+ try {
2120
+ const thumbBuffer = await downloadFromCdn(oldThumbPaths[t]);
2121
+ const newThumbLocalPath = getPublicPath(newThumbPaths[t]);
2122
+ await fs6.mkdir(path6.dirname(newThumbLocalPath), { recursive: true });
2123
+ await fs6.writeFile(newThumbLocalPath, thumbBuffer);
2124
+ } catch {
2125
+ }
2126
+ }
2127
+ }
2128
+ await deleteFromCdn(cloudFile.oldKey, cloudHasThumbs);
2129
+ await uploadOriginalToCdn(cloudFile.newKey);
2130
+ if (cloudHasThumbs) {
2131
+ await uploadToCdn(cloudFile.newKey);
2132
+ }
2133
+ try {
2134
+ await fs6.unlink(cloudLocalPath);
2135
+ } catch {
2136
+ }
2137
+ if (cloudHasThumbs) {
2138
+ await deleteLocalThumbnails(cloudFile.newKey);
2139
+ }
2140
+ await deleteEmptyFolders(path6.dirname(cloudLocalPath));
2141
+ } catch (err) {
2142
+ console.error(`Failed to move cloud file ${cloudFile.oldKey}:`, err);
2143
+ }
2144
+ }
2145
+ delete meta[cloudFile.oldKey];
2146
+ meta[cloudFile.newKey] = cloudEntry;
2147
+ processedFiles++;
2148
+ sendEvent({
2149
+ type: "progress",
2150
+ current: processedFiles,
2151
+ total: totalFiles,
2152
+ moved: moved.length,
2153
+ percent: Math.round(processedFiles / totalFiles * 100),
2154
+ currentFile: path6.basename(cloudFile.newKey)
2155
+ });
2156
+ }
2157
+ sourceFolders.add(absolutePath);
2158
+ const oldThumbRelPath = oldKey.slice(1);
2159
+ const oldThumbFolder = path6.join(getPublicPath("images"), oldThumbRelPath);
2160
+ sourceFolders.add(oldThumbFolder);
2161
+ moved.push(itemPath);
2032
2162
  }
2033
- sendEvent({
2034
- type: "progress",
2035
- current: processedFiles,
2036
- total: totalFiles,
2037
- moved: moved.length,
2038
- percent: Math.round(processedFiles / totalFiles * 100),
2039
- currentFile: itemName
2040
- });
2041
2163
  }
2042
2164
  } catch (err) {
2043
2165
  console.error(`Failed to move ${itemName}:`, err);