-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathForm1.cs
371 lines (340 loc) · 16.1 KB
/
Form1.cs
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Security;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MoveSelectedFavorites
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
this.AllowDrop = true;
this.DragEnter += new DragEventHandler(MainForm_DragEnter);
this.DragDrop += new DragEventHandler(MainForm_DragDrop);
openFileDialog1 = new OpenFileDialog()
{
FileName = "Select the favorites text file",
Filter = "Text files (*.txt)|*.txt",
Title = "Open text file"
};
favoritesList = new List<string>();
log.Text += Environment.NewLine + DateTime.Now + ": Starting" + Environment.NewLine;
}
private List<string> favoritesList;
private void MainForm_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop))
{
favoritesList = new List<string>();
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
//foreach (string filePath in files) -- currently, cannot handle multiple files -- just pick one
if (files.Any())
{
//Console.WriteLine(filePath);
//Load file, save list of seeds
try
{
ProcessFavoritesFile(files[0], File.OpenRead(files[0]));
}
catch
{
log.Text += Environment.NewLine + DateTime.Now + ": Unable to load file " + files[0] + Environment.NewLine
+ "Only Drag-and-drop favorites text files containing seeds." + Environment.NewLine;
}
}
}
}
void MainForm_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Copy;
}
private void button1_Click(object sender, EventArgs e)
{
//var folderDialog = new FolderBrowserDialog();
DialogResult result = folderBrowserDestination.ShowDialog();
if (result == DialogResult.OK)
{
destinationFolder.Text = folderBrowserDestination.SelectedPath;
}
else
{
//Operation cancelled
}
}
private void selectSource_Click(object sender, EventArgs e)
{
//Reset any status fields
labelCopyCount.Text = String.Empty;
folderBrowserSource.SelectedPath = GetSourcePath();
DialogResult result = folderBrowserSource.ShowDialog();
if (result == DialogResult.OK)
{
sourceFolder.Text = folderBrowserSource.SelectedPath;
}
else
{
//Operation cancelled
}
}
private string GetSourcePath()
{
string result = folderBrowserSource.SelectedPath;
if (String.IsNullOrEmpty(folderBrowserSource.SelectedPath))
{
result = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Stable Diffusion UI");
}
return result;
}
private void copyButton_Click(object sender, EventArgs e)
{
UseWaitCursor = true;
labelCopyCount.Text = string.Empty;
List<String> copyList = new List<string>();
//Validate
if (favoritesList.Count == 0)
{
MessageBox.Show("First, load list of favorites.");
return;
}
try
{
//For each image file in the source folder,
// search contents for one of the listed seeds.
// If match found, perform action -- copy to destination folder
SearchFiles("*.png", "tEXtseed\0", copyList);
SearchFiles("*.webp", "\"seed\": ", copyList);
SearchFiles("*.jpeg", "\"seed\": ", copyList);
int imageCount = 0;
//for each file to process, copy
foreach (var fileName2 in copyList)
{
bool success = false;
success = CopyImageFile(fileName2);
if (success)
{
//list files to the window as they are copied, or at least report a count
imageCount++;
labelCopyCount.Text = imageCount + " files copied out of " + copyList.Count;
//If there is a corresponding JSON or TXT file, copy that too
string textFile = fileName2;
textFile = fileName2.Substring(0, fileName2.IndexOf('.', fileName2.Length - 5) + 1) + "json";
CopyImageFile(textFile);
textFile = fileName2.Substring(0, fileName2.IndexOf('.', fileName2.Length - 5) + 1) + "txt";
CopyImageFile(textFile);
}
}
//All files should be copied at this point. Can rename folder.
if (checkRenSource.Checked)
{
//If no files were copied, probably got the wrong directory -- don't rename.
if (imageCount > 0)
{
Directory.Move(sourceFolder.Text, sourceFolder.Text.TrimEnd('\\') + suffix.Text); //use TrimEnd() to remove unnecessary ending slashes
}
else
{
log.Text += Environment.NewLine + DateTime.Now + ": No files copied - source folder not renamed." + Environment.NewLine;
}
}
}
catch (Exception ex)
{
MessageBox.Show($"Error.\n\nError message: {ex.Message}\n\n" +
$"Details:\n\n{ex.StackTrace}");
}
//Done.
log.Text += Environment.NewLine + DateTime.Now + ": " + Environment.NewLine;
log.Text += "List " + favoritesLabel.Text + Environment.NewLine;
log.Text += $"Copied files from {sourceFolder.Text}" + Environment.NewLine;
//sourceFolder.Text = String.Empty; //Could clear the source folder, as reproducing the copy will produce no further results.
if (labelCopyCount.Text == string.Empty) //if empty, we must have failed to copy. Could happen if attempting to copy a 2nd time on the same folder.
{
labelCopyCount.Text = "Images to copy not found, or other error.";
}
log.Text += labelCopyCount.Text + Environment.NewLine;
UseWaitCursor = false;
}
/// <summary>
/// Copy file without overwrite
/// </summary>
/// <param name="fileName2">filename, with full path</param>
/// <returns>true if copy successful, false if destination exists (no copy)</returns>
private bool CopyImageFile(string fileName2)
{
//Build destination path
FileInfo file = new FileInfo(fileName2);
string originalFileName = file.FullName;
//if source name doesn't exist, don't bother trying to copy. This will happen with json/txt files.
if (!File.Exists(originalFileName))
{
return false;
}
string newFileName = Path.Combine(destinationFolder.Text, file.Name);
//if file exists, don't copy, and return status of false
if (File.Exists(newFileName))
{
return false;
}
File.Copy(originalFileName, newFileName); //could also use move
return true;
}
/// <summary>
/// Search Files for metadata
/// </summary>
/// <param name="filePattern"></param>
/// <param name="searchPattern"></param>
/// <param name="copyList"></param>
/// <remarks>Shouldn't need to search the entire file for .png or .jpeg, but you do for .webp.</remarks>
private void SearchFiles(string filePattern, string searchPattern, List<string> copyList)
{
string[] files = Directory.GetFiles(sourceFolder.Text, filePattern, SearchOption.TopDirectoryOnly);
foreach (string fileName in files)
{
//load first part of file in binary -- we don't need the entire file
try
{
StringBuilder sb = new StringBuilder();
using (Stream str = File.Open(fileName, FileMode.Open))
{
using (var reader = new StreamReader(str))
{
char[] buffer = new char[2000];
int bytesRead = 0;
int fileIndex = 0;
while ((bytesRead = reader.Read(buffer, 0, 2000)) > 0)
{
bool decodingUnicode = false;
int unicodeIndex = 0;
fileIndex += bytesRead;
//search for metadata string pattern, and copy until null character
string data = new String(buffer);
//if (fileName.Substring(fileName.Length-4)=="webp")
//{
// data = Encoding.Unicode.GetString(data.Select(c => (byte)c).ToArray()); //convert char array to byte array
//}
//else
if (fileName.Substring(fileName.Length - 4) == "jpeg" || fileName.Substring(fileName.Length - 4) == "webp")
{
//TODO: slight chance of buffer not big enough here
//Need to find the UNICODE block before decoding as UNICODE.
unicodeIndex = data.IndexOf("UNICODE");
if (decodingUnicode || unicodeIndex >= 0)
{
data = Encoding.Unicode.GetString(data.Substring(unicodeIndex + "UNICODE".Length).Select(c => (byte)c).ToArray()); //convert char array to byte array
decodingUnicode = true; //once we're decoding UNICODE, need to keep going
}
}
sb.Remove(0, Math.Max(0, sb.Length - searchPattern.Length));
//need to look just beyond the buffer, so as not to miss the pattern in the case it overlaps with the buffer size.
sb.Append(data);
data = sb.ToString();
int location = data.IndexOf(searchPattern, StringComparison.OrdinalIgnoreCase);
if (location == -1)
continue; //keep reading until we're done with the file
string seedData = data.Substring(location + searchPattern.Length, 15);
string seed = String.Empty;
foreach (char c in seedData)
{
//TODO: it is possible that extra numeric characters may appear at the end, and thus the occasional file won't copy. Need to revisit the file format.
if (c < '0' || c > '9')
break;
seed += c;
}
if (favoritesList.IndexOf(seed) != -1) //Found!
{
//if metadata string matches any seed in our list, then copy
//Need to save list of files to process after we're done reading them.
copyList.Add(fileName);
}
break; //get next file
}
}
}
}
catch (SecurityException ex)
{
MessageBox.Show($"Security error.\n\nError message: {ex.Message}\n\n" +
$"Details:\n\n{ex.StackTrace}");
}
catch (Exception ex)
{
MessageBox.Show($"Error.\n\nError message: {ex.Message}\n\n" +
$"Details:\n\n{ex.StackTrace}");
}
//if seed was never found in file, may need to fall back on the JSON or TXT sidecar file.
}
}
private OpenFileDialog openFileDialog1;
//see: https://learn.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-open-files-using-the-openfiledialog-component?view=netframeworkdesktop-4.8
private void favoritesButton_Click(object sender, EventArgs e)
{
labelCopyCount.Text = string.Empty;
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
ProcessFavoritesFile(openFileDialog1.FileName, openFileDialog1.OpenFile());
}
}
private void ProcessFavoritesFile(string filePath, Stream fileStream)
{
try
{
favoritesList = new List<string>();
using (Stream str = fileStream)
{
using (var reader = new StreamReader(str))
{
string line;
while ((line = reader.ReadLine()) != null)
{
favoritesList.Add(line);
}
favoritesLabel.Text = "Loaded: " + filePath;
//Process.Start("notepad.exe", filePath);
}
}
//attempt to match the closest directory that matches the loaded favorites file.
FileInfo file = new FileInfo(filePath);
Regex reg = new Regex("favoriteslist-([0-9]+)*");
var match = reg.Match(file.Name);
string time = match.Groups[1].Value;
//Regex reg = new Regex( Date, minus the last 3 characters + @"*");
if (time.Length < 3) //if no date found in the name, we can't process further - just exit
{
return;
}
reg = new Regex(time.Substring(0, time.Length - 3) + "*");
var dirs = Directory.GetDirectories(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Stable Diffusion UI"))
.Where(path => reg.IsMatch(path))
.ToList();
// -- generally should match just one, but could match more than one.
if (dirs.Count == 1)
{
sourceFolder.Text = dirs[0];
}
}
catch (SecurityException ex)
{
MessageBox.Show($"Security error.\n\nError message: {ex.Message}\n\n" +
$"Details:\n\n{ex.StackTrace}");
}
}
private void checkRenSource_CheckedChanged(object sender, EventArgs e)
{
suffix.Enabled = checkRenSource.Checked;
}
private void MainForm_Resize(object sender, EventArgs e)
{
log.Width = this.ClientSize.Width - 467;
}
}
}