@gallop.software/studio 2.3.43 → 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.
@@ -1979,74 +1979,187 @@ async function handleMoveStream(request) {
1979
1979
  continue;
1980
1980
  } catch {
1981
1981
  }
1982
- await fs6.rename(absolutePath, newAbsolutePath);
1983
- const stats = await fs6.stat(newAbsolutePath);
1984
- if (stats.isFile() && isImage && entry) {
1985
- const oldThumbPaths = getAllThumbnailPaths(oldKey);
1986
- const newThumbPaths = getAllThumbnailPaths(newKey);
1987
- for (let j = 0; j < oldThumbPaths.length; j++) {
1988
- const oldThumbPath = getPublicPath(oldThumbPaths[j]);
1989
- const newThumbPath = getPublicPath(newThumbPaths[j]);
1990
- try {
1991
- await fs6.access(oldThumbPath);
1992
- sourceFolders.add(path6.dirname(oldThumbPath));
1993
- await fs6.mkdir(path6.dirname(newThumbPath), { recursive: true });
1994
- await fs6.rename(oldThumbPath, newThumbPath);
1995
- } 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
+ }
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
+ }
1996
2010
  }
2011
+ delete meta[oldKey];
2012
+ meta[newKey] = entry;
1997
2013
  }
1998
- delete meta[oldKey];
1999
- 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);
2000
2024
  } else if (stats.isDirectory()) {
2001
2025
  const oldPrefix = oldKey + "/";
2002
2026
  const newPrefix = newKey + "/";
2003
- for (const key of Object.keys(meta)) {
2004
- if (key.startsWith(oldPrefix)) {
2005
- const newMetaKey = newPrefix + key.slice(oldPrefix.length);
2006
- meta[newMetaKey] = meta[key];
2007
- delete meta[key];
2008
- }
2009
- }
2010
- const oldThumbRelPath = oldKey.slice(1);
2011
- const newThumbRelPath = newKey.slice(1);
2012
- const imagesDir = getPublicPath("images");
2013
- const oldThumbFolder = path6.join(imagesDir, oldThumbRelPath);
2014
- const newThumbFolder = path6.join(imagesDir, newThumbRelPath);
2015
- try {
2016
- await fs6.access(oldThumbFolder);
2017
- sourceFolders.add(oldThumbFolder);
2018
- await fs6.mkdir(path6.dirname(newThumbFolder), { recursive: true });
2019
- await fs6.rename(oldThumbFolder, newThumbFolder);
2020
- } catch {
2021
- }
2022
- }
2023
- moved.push(itemPath);
2024
- if (stats.isDirectory()) {
2025
- const countFilesInDir = async (dir) => {
2026
- let count = 0;
2027
+ const localFiles = [];
2028
+ const collectLocalFiles = async (dir, relativeDir) => {
2027
2029
  const entries = await fs6.readdir(dir, { withFileTypes: true });
2028
- for (const entry2 of entries) {
2029
- if (entry2.isDirectory()) {
2030
- 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);
2031
2034
  } else {
2032
- count++;
2035
+ localFiles.push({ relativePath: entryRelPath, isImage: isImageFile(dirEntry.name) });
2033
2036
  }
2034
2037
  }
2035
- return count;
2036
2038
  };
2037
- const filesInDir = await countFilesInDir(newAbsolutePath);
2038
- processedFiles += filesInDir;
2039
- } else {
2040
- 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);
2041
2162
  }
2042
- sendEvent({
2043
- type: "progress",
2044
- current: processedFiles,
2045
- total: totalFiles,
2046
- moved: moved.length,
2047
- percent: Math.round(processedFiles / totalFiles * 100),
2048
- currentFile: itemName
2049
- });
2050
2163
  }
2051
2164
  } catch (err) {
2052
2165
  console.error(`Failed to move ${itemName}:`, err);