버전 3.9.2로 업데이트: 썸네일 번역 방식 변경 및 VIP 등급에서 이미지 프로세서 초기화 문제 수정. 초기 실행 시 모델 로딩으로 인한 반응 속도 저하에 대한 안내 추가. 업데이트 로그에 해당 내용 기록.

This commit is contained in:
9700X_PC 2025-07-10 16:19:46 +09:00
parent f803ba5d9b
commit 6be685f8bb
19 changed files with 753 additions and 15 deletions

View File

@ -0,0 +1,359 @@
; AutoPercenty3 Inno Setup Script
; 이 스크립트는 cx_Freeze로 빌드된 결과물이 있는 "build\exe.win-amd64-3.11" 폴더를 기반으로 인스톨러를 제작합니다.
; 20250710_160532에 생성됨
#define AppId "autopercenty"
#define MyAppName "Edit_PartTimer"
#define MyAppVersion "3.9.1"
#define MyAppPublisher "WhenRideMyCar"
#define MyAppProgramName "편집알바생"
#define MyAppDescription "편집알바생"
#define MyAppCopyright "Copyright 2024"
#define MyAppExeName "Edit_PartTimer3"
#define MySetupName "Edit_PartTimer Setup"
#define MySetupIcon "src/Edit_PartTimer3.ico"
#define MySetupOutputDir "dist/installer"
#define OldAppName "AutoPercenty3"
[Setup]
; 기본 설정
AppId={#AppId}
AppName={#MyAppProgramName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppPublisher}
OutputDir={#MySetupOutputDir}
OutputBaseFilename={#MySetupName}
SetupIconFile={#MySetupIcon}
Compression=lzma
SolidCompression=yes
; 업데이트 관련 설정 - 권한 최적화
PrivilegesRequired=admin
PrivilegesRequiredOverridesAllowed=dialog
UpdateUninstallLogAppName=yes
AppMutex={#MyAppName}
CloseApplications=yes
RestartApplications=no
; 보안 및 호환성 설정
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
AllowNoIcons=yes
; 버전 정보
VersionInfoVersion={#MyAppVersion}
VersionInfoCompany={#MyAppPublisher}
VersionInfoDescription={#MyAppDescription}
VersionInfoCopyright={#MyAppCopyright}
VersionInfoProductName={#MyAppProgramName}
VersionInfoProductVersion={#MyAppVersion}
[Languages]
Name: "korean"; MessagesFile: "compiler:Languages\Korean.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
[Dirs]
; 설치 시 {app}\logs 폴더를 생성하고,
; Users 그룹에 'modify' 권한(=쓰기 가능)을 부여
Name: "{app}\logs"; Permissions: users-modify
; 설치 시 {app}\user_data 폴더를 생성하고,
; Users 그룹에 'modify' 권한(=쓰기 가능)을 부여
Name: "{app}\user_data"; Permissions: users-modify
; Playwright 브라우저 폴더를 Program Files 내부에 생성
Name: "{app}\lib\src\browsers\chromium-1140"; Permissions: users-modify
; Playwright 브라우저 사용자폴더를 Program Files 내부에 생성
Name: "{app}\lib\src\browsers\user_data"; Permissions: users-modify
[Files]
; 프로그램 파일만 설치 (항상 덮어쓰기)
Source: "build\exe.win-amd64-3.11\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; VC++ 재배포 패키지 파일을 임시 폴더({tmp})에 복사
Source: "VC_redist.x64.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
[Registry]
; Playwright 브라우저 경로를 Program Files 내부로 설정
Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "PLAYWRIGHT_BROWSERS_PATH"; ValueData: "{app}\lib\src\browsers"; Flags: preservestringtype
[Icons]
; 시작 메뉴 바로가기
Name: "{group}\{#MyAppProgramName}"; Filename: "{app}\{#MyAppExeName}.exe"
; 바탕화면 바로가기
Name: "{autodesktop}\{#MyAppProgramName}"; Filename: "{app}\{#MyAppExeName}.exe"; Tasks: desktopicon
[Run]
; VC++ 재배포 패키지 설치 (필요할 경우)
Filename: "{tmp}\VC_redist.x64.exe"; Parameters: "/install /passive /norestart"; StatusMsg: "VC++ 재배포 패키지 설치 중..."; Check: NeedsVCredist
; 설치 후 프로그램 실행 (원할 경우)
Filename: "{app}\{#MyAppExeName}.exe"; Description: "{cm:LaunchProgram,{#MyAppProgramName}}"; Flags: nowait postinstall skipifsilent
[Code]
function CompareVersion(V1, V2: string): Integer;
var
P1, P2, N1, N2: Integer;
begin
P1 := 1;
P2 := 1;
Result := 0;
while (Result = 0) and ((P1 <= Length(V1)) or (P2 <= Length(V2))) do begin
while (P1 <= Length(V1)) and (V1[P1] = '.') do Inc(P1);
while (P2 <= Length(V2)) and (V2[P2] = '.') do Inc(P2);
if (P1 <= Length(V1)) and (P2 <= Length(V2)) then begin
N1 := 0; while (P1 <= Length(V1)) and (V1[P1] >= '0') and (V1[P1] <= '9') do begin N1 := N1 * 10 + Ord(V1[P1]) - Ord('0'); Inc(P1); end;
N2 := 0; while (P2 <= Length(V2)) and (V2[P2] >= '0') and (V2[P2] <= '9') do begin N2 := N2 * 10 + Ord(V2[P2]) - Ord('0'); Inc(P2); end;
if N1 < N2 then Result := -1 else if N1 > N2 then Result := 1;
end else begin
if P1 <= Length(V1) then Result := 1 else if P2 <= Length(V2) then Result := -1;
end;
while (P1 <= Length(V1)) and (V1[P1] <> '.') do Inc(P1);
while (P2 <= Length(V2)) and (V2[P2] <> '.') do Inc(P2);
end;
end;
// 파일 또는 폴더 복사 함수
procedure CopyDir(const SourcePath, DestPath: string);
var
FindRec: TFindRec;
SourceFilePath: string;
DestFilePath: string;
begin
ForceDirectories(DestPath);
if FindFirst(SourcePath + '\*', FindRec) then
begin
try
repeat
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
begin
SourceFilePath := SourcePath + '\' + FindRec.Name;
DestFilePath := DestPath + '\' + FindRec.Name;
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
begin
if FileCopy(SourceFilePath, DestFilePath, False) then
Log('파일 복사 성공: ' + SourceFilePath + ' -> ' + DestFilePath)
else
Log('파일 복사 실패: ' + SourceFilePath);
end
else
CopyDir(SourceFilePath, DestFilePath);
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
// 프로그램 실행 여부 확인
function IsAppRunning(const FileName: string): Boolean;
var
Handle: THandle;
begin
Handle := FindWindowByWindowName('{#MyAppProgramName}'); // 프로그램의 윈도우 타이틀로 찾기
Result := (Handle <> 0);
end;
// 프로그램 종료
procedure CloseApplication(const FileName: string);
var
Handle: THandle;
begin
Handle := FindWindowByWindowName('{#MyAppProgramName}');
if Handle <> 0 then
begin
PostMessage(Handle, 18, 0, 0); // WM_QUIT
Sleep(1000); // 종료 대기
end;
end;
// VC++ 재배포 패키지 필요 여부 확인
function NeedsVCredist: Boolean;
begin
if RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64') then
Result := False // 이미 설치됨
else
Result := True; // 미설치 -> 설치 필요
end;
// 설치 완료 후 실행 여부 확인
function InitializeFinish(): Boolean;
var
ResultCode: Integer;
begin
Result := True;
if MsgBox('설치가 완료되었습니다. 프로그램을 실행하시겠습니까?' + #13#10 +
'(실행 시 서버와 동기화하여 설정이 업데이트됩니다)',
mbConfirmation, MB_YESNO) = IDYES then
begin
Exec(ExpandConstant('{app}\{#MyAppExeName}.exe'), '', '', SW_SHOW, ewNoWait, ResultCode);
end;
end;
function InitializeSetup(): Boolean;
var
OldVersion: String;
NewVersion: String;
OldAppPath: String;
UserDataSourcePath, UserDataBackupPath: String;
OldUninstallString: String;
ResultCode: Integer;
begin
Result := True;
NewVersion := '{#MyAppVersion}';
UserDataBackupPath := ExpandConstant('{tmp}\user_data_backup');
// 이전 버전(AutoPercenty3) 확인
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#OldAppName}_is1',
'DisplayVersion', OldVersion) then
begin
// 이전 설치 경로 가져오기
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#OldAppName}_is1',
'InstallLocation', OldAppPath) then
begin
Log('이전 버전({#OldAppName})이 발견되었습니다. 경로: ' + OldAppPath);
// user_data 폴더 경로 설정 - 우선순위: Program Files → AppData\Local
UserDataSourcePath := OldAppPath + '\user_data';
// Program Files에 user_data가 없으면 AppData\Local에서 찾기
if not DirExists(UserDataSourcePath) then
begin
UserDataSourcePath := ExpandConstant('{localappdata}\' + '{#OldAppName}' + '\lib\user_data');
Log('Program Files에 user_data 없음. AppData\Local 경로 확인: ' + UserDataSourcePath);
end
else
begin
Log('Program Files에서 user_data 발견: ' + UserDataSourcePath);
end;
// 프로그램이 실행 중인지 확인하고 종료 요청
if IsAppRunning('{#OldAppName}.exe') then
begin
if MsgBox('프로그램을 업데이트하기 위해 실행 중인 프로그램을 종료해야 합니다.' + #13#10 +
'계속하시겠습니까?', mbConfirmation, MB_YESNO) = IDNO then
begin
Result := False;
exit;
end;
CloseApplication('{#OldAppName}.exe');
// 프로세스가 완전히 종료될 때까지 대기
Sleep(2000);
end;
// user_data 폴더 백업
if DirExists(UserDataSourcePath) then
begin
Log('user_data 폴더 백업 중: ' + UserDataSourcePath + ' -> ' + UserDataBackupPath);
ForceDirectories(UserDataBackupPath);
CopyDir(UserDataSourcePath, UserDataBackupPath);
end;
// 이전 버전 제거 (제거 프로그램 실행)
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#OldAppName}_is1',
'UninstallString', OldUninstallString) then
begin
// 사용자에게 확인
if MsgBox('이전 버전을 제거하고 새 버전을 설치하시겠습니까?' + #13#10 +
'사용자 데이터는 유지됩니다.', mbConfirmation, MB_YESNO) = IDYES then
begin
// 자동 제거를 위해 /SILENT 매개변수 추가
OldUninstallString := OldUninstallString + ' /SILENT';
Log('이전 버전 제거 실행: ' + OldUninstallString);
// 제거 프로그램 실행 및 완료 대기
if Exec(RemoveQuotes(OldUninstallString), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
Log('이전 버전 제거 완료: 결과 코드 ' + IntToStr(ResultCode));
end
else
begin
Log('이전 버전 제거 실패');
// 제거에 실패해도 계속 진행
end;
end;
end;
end;
end
// 현재 프로그램(Edit_PartTimer3) 버전 확인
else if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppName}_is1',
'DisplayVersion', OldVersion) then
begin
// 같은 버전이거나 더 높은 버전이 설치되어 있는 경우
if CompareVersion(OldVersion, NewVersion) >= 0 then
begin
MsgBox('현재 설치된 버전(' + OldVersion + ')이 이 설치 프로그램의 버전(' +
NewVersion + ')과 같거나 더 높습니다.' + #13#10 +
'설치를 계속할 수 없습니다.', mbInformation, MB_OK);
Result := False;
exit;
end;
// 이전 버전이 설치되어 있는 경우 업데이트 모드로 진행
if CompareVersion(OldVersion, NewVersion) < 0 then
begin
Log('업데이트 설치 진행: ' + OldVersion + ' -> ' + NewVersion);
// 프로그램이 실행 중인지 확인하고 종료 요청
if IsAppRunning('{#MyAppExeName}.exe') then
begin
if MsgBox('프로그램을 업데이트하기 위해 실행 중인 프로그램을 종료해야 합니다.' + #13#10 +
'계속하시겠습니까?', mbConfirmation, MB_YESNO) = IDNO then
begin
Result := False;
exit;
end;
CloseApplication('{#MyAppExeName}.exe');
end;
// Edit_PartTimer3의 user_data 폴더 백업 - 우선순위: Program Files → AppData\Local
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppName}_is1',
'InstallLocation', OldAppPath) then
begin
UserDataSourcePath := OldAppPath + '\user_data';
// Program Files에 user_data가 없으면 AppData\Local에서 찾기
if not DirExists(UserDataSourcePath) then
begin
UserDataSourcePath := ExpandConstant('{localappdata}\' + '{#MyAppName}' + '\lib\user_data');
Log('Program Files에 user_data 없음. AppData\Local 경로 확인: ' + UserDataSourcePath);
end
else
begin
Log('Program Files에서 user_data 발견: ' + UserDataSourcePath);
end;
if DirExists(UserDataSourcePath) then
begin
Log('user_data 폴더 백업 중: ' + UserDataSourcePath + ' -> ' + UserDataBackupPath);
ForceDirectories(UserDataBackupPath);
CopyDir(UserDataSourcePath, UserDataBackupPath);
end;
end;
end;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
UserDataBackupPath, UserDataDestPath: String;
begin
// 설치 완료 후
if CurStep = ssPostInstall then
begin
UserDataBackupPath := ExpandConstant('{tmp}\user_data_backup');
UserDataDestPath := ExpandConstant('{app}\user_data');
// 백업한 user_data 폴더가 있으면 복원
if DirExists(UserDataBackupPath) then
begin
Log('백업된 user_data 폴더 복원 중: ' + UserDataBackupPath + ' -> ' + UserDataDestPath);
ForceDirectories(UserDataDestPath);
CopyDir(UserDataBackupPath, UserDataDestPath);
Log('user_data 폴더 복원 완료');
end;
end;
end;

View File

@ -0,0 +1,359 @@
; AutoPercenty3 Inno Setup Script
; 이 스크립트는 cx_Freeze로 빌드된 결과물이 있는 "build\exe.win-amd64-3.11" 폴더를 기반으로 인스톨러를 제작합니다.
; 20250710_160643에 생성됨
#define AppId "autopercenty"
#define MyAppName "Edit_PartTimer"
#define MyAppVersion "3.9.2"
#define MyAppPublisher "WhenRideMyCar"
#define MyAppProgramName "편집알바생"
#define MyAppDescription "편집알바생"
#define MyAppCopyright "Copyright 2024"
#define MyAppExeName "Edit_PartTimer3"
#define MySetupName "Edit_PartTimer Setup"
#define MySetupIcon "src/Edit_PartTimer3.ico"
#define MySetupOutputDir "dist/installer"
#define OldAppName "AutoPercenty3"
[Setup]
; 기본 설정
AppId={#AppId}
AppName={#MyAppProgramName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppPublisher}
OutputDir={#MySetupOutputDir}
OutputBaseFilename={#MySetupName}
SetupIconFile={#MySetupIcon}
Compression=lzma
SolidCompression=yes
; 업데이트 관련 설정 - 권한 최적화
PrivilegesRequired=admin
PrivilegesRequiredOverridesAllowed=dialog
UpdateUninstallLogAppName=yes
AppMutex={#MyAppName}
CloseApplications=yes
RestartApplications=no
; 보안 및 호환성 설정
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
AllowNoIcons=yes
; 버전 정보
VersionInfoVersion={#MyAppVersion}
VersionInfoCompany={#MyAppPublisher}
VersionInfoDescription={#MyAppDescription}
VersionInfoCopyright={#MyAppCopyright}
VersionInfoProductName={#MyAppProgramName}
VersionInfoProductVersion={#MyAppVersion}
[Languages]
Name: "korean"; MessagesFile: "compiler:Languages\Korean.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"
[Dirs]
; 설치 시 {app}\logs 폴더를 생성하고,
; Users 그룹에 'modify' 권한(=쓰기 가능)을 부여
Name: "{app}\logs"; Permissions: users-modify
; 설치 시 {app}\user_data 폴더를 생성하고,
; Users 그룹에 'modify' 권한(=쓰기 가능)을 부여
Name: "{app}\user_data"; Permissions: users-modify
; Playwright 브라우저 폴더를 Program Files 내부에 생성
Name: "{app}\lib\src\browsers\chromium-1140"; Permissions: users-modify
; Playwright 브라우저 사용자폴더를 Program Files 내부에 생성
Name: "{app}\lib\src\browsers\user_data"; Permissions: users-modify
[Files]
; 프로그램 파일만 설치 (항상 덮어쓰기)
Source: "build\exe.win-amd64-3.11\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
; VC++ 재배포 패키지 파일을 임시 폴더({tmp})에 복사
Source: "VC_redist.x64.exe"; DestDir: "{tmp}"; Flags: deleteafterinstall
[Registry]
; Playwright 브라우저 경로를 Program Files 내부로 설정
Root: HKCU; Subkey: "Environment"; ValueType: expandsz; ValueName: "PLAYWRIGHT_BROWSERS_PATH"; ValueData: "{app}\lib\src\browsers"; Flags: preservestringtype
[Icons]
; 시작 메뉴 바로가기
Name: "{group}\{#MyAppProgramName}"; Filename: "{app}\{#MyAppExeName}.exe"
; 바탕화면 바로가기
Name: "{autodesktop}\{#MyAppProgramName}"; Filename: "{app}\{#MyAppExeName}.exe"; Tasks: desktopicon
[Run]
; VC++ 재배포 패키지 설치 (필요할 경우)
Filename: "{tmp}\VC_redist.x64.exe"; Parameters: "/install /passive /norestart"; StatusMsg: "VC++ 재배포 패키지 설치 중..."; Check: NeedsVCredist
; 설치 후 프로그램 실행 (원할 경우)
Filename: "{app}\{#MyAppExeName}.exe"; Description: "{cm:LaunchProgram,{#MyAppProgramName}}"; Flags: nowait postinstall skipifsilent
[Code]
function CompareVersion(V1, V2: string): Integer;
var
P1, P2, N1, N2: Integer;
begin
P1 := 1;
P2 := 1;
Result := 0;
while (Result = 0) and ((P1 <= Length(V1)) or (P2 <= Length(V2))) do begin
while (P1 <= Length(V1)) and (V1[P1] = '.') do Inc(P1);
while (P2 <= Length(V2)) and (V2[P2] = '.') do Inc(P2);
if (P1 <= Length(V1)) and (P2 <= Length(V2)) then begin
N1 := 0; while (P1 <= Length(V1)) and (V1[P1] >= '0') and (V1[P1] <= '9') do begin N1 := N1 * 10 + Ord(V1[P1]) - Ord('0'); Inc(P1); end;
N2 := 0; while (P2 <= Length(V2)) and (V2[P2] >= '0') and (V2[P2] <= '9') do begin N2 := N2 * 10 + Ord(V2[P2]) - Ord('0'); Inc(P2); end;
if N1 < N2 then Result := -1 else if N1 > N2 then Result := 1;
end else begin
if P1 <= Length(V1) then Result := 1 else if P2 <= Length(V2) then Result := -1;
end;
while (P1 <= Length(V1)) and (V1[P1] <> '.') do Inc(P1);
while (P2 <= Length(V2)) and (V2[P2] <> '.') do Inc(P2);
end;
end;
// 파일 또는 폴더 복사 함수
procedure CopyDir(const SourcePath, DestPath: string);
var
FindRec: TFindRec;
SourceFilePath: string;
DestFilePath: string;
begin
ForceDirectories(DestPath);
if FindFirst(SourcePath + '\*', FindRec) then
begin
try
repeat
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
begin
SourceFilePath := SourcePath + '\' + FindRec.Name;
DestFilePath := DestPath + '\' + FindRec.Name;
if FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
begin
if FileCopy(SourceFilePath, DestFilePath, False) then
Log('파일 복사 성공: ' + SourceFilePath + ' -> ' + DestFilePath)
else
Log('파일 복사 실패: ' + SourceFilePath);
end
else
CopyDir(SourceFilePath, DestFilePath);
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;
// 프로그램 실행 여부 확인
function IsAppRunning(const FileName: string): Boolean;
var
Handle: THandle;
begin
Handle := FindWindowByWindowName('{#MyAppProgramName}'); // 프로그램의 윈도우 타이틀로 찾기
Result := (Handle <> 0);
end;
// 프로그램 종료
procedure CloseApplication(const FileName: string);
var
Handle: THandle;
begin
Handle := FindWindowByWindowName('{#MyAppProgramName}');
if Handle <> 0 then
begin
PostMessage(Handle, 18, 0, 0); // WM_QUIT
Sleep(1000); // 종료 대기
end;
end;
// VC++ 재배포 패키지 필요 여부 확인
function NeedsVCredist: Boolean;
begin
if RegKeyExists(HKEY_LOCAL_MACHINE, 'SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x64') then
Result := False // 이미 설치됨
else
Result := True; // 미설치 -> 설치 필요
end;
// 설치 완료 후 실행 여부 확인
function InitializeFinish(): Boolean;
var
ResultCode: Integer;
begin
Result := True;
if MsgBox('설치가 완료되었습니다. 프로그램을 실행하시겠습니까?' + #13#10 +
'(실행 시 서버와 동기화하여 설정이 업데이트됩니다)',
mbConfirmation, MB_YESNO) = IDYES then
begin
Exec(ExpandConstant('{app}\{#MyAppExeName}.exe'), '', '', SW_SHOW, ewNoWait, ResultCode);
end;
end;
function InitializeSetup(): Boolean;
var
OldVersion: String;
NewVersion: String;
OldAppPath: String;
UserDataSourcePath, UserDataBackupPath: String;
OldUninstallString: String;
ResultCode: Integer;
begin
Result := True;
NewVersion := '{#MyAppVersion}';
UserDataBackupPath := ExpandConstant('{tmp}\user_data_backup');
// 이전 버전(AutoPercenty3) 확인
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#OldAppName}_is1',
'DisplayVersion', OldVersion) then
begin
// 이전 설치 경로 가져오기
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#OldAppName}_is1',
'InstallLocation', OldAppPath) then
begin
Log('이전 버전({#OldAppName})이 발견되었습니다. 경로: ' + OldAppPath);
// user_data 폴더 경로 설정 - 우선순위: Program Files → AppData\Local
UserDataSourcePath := OldAppPath + '\user_data';
// Program Files에 user_data가 없으면 AppData\Local에서 찾기
if not DirExists(UserDataSourcePath) then
begin
UserDataSourcePath := ExpandConstant('{localappdata}\' + '{#OldAppName}' + '\lib\user_data');
Log('Program Files에 user_data 없음. AppData\Local 경로 확인: ' + UserDataSourcePath);
end
else
begin
Log('Program Files에서 user_data 발견: ' + UserDataSourcePath);
end;
// 프로그램이 실행 중인지 확인하고 종료 요청
if IsAppRunning('{#OldAppName}.exe') then
begin
if MsgBox('프로그램을 업데이트하기 위해 실행 중인 프로그램을 종료해야 합니다.' + #13#10 +
'계속하시겠습니까?', mbConfirmation, MB_YESNO) = IDNO then
begin
Result := False;
exit;
end;
CloseApplication('{#OldAppName}.exe');
// 프로세스가 완전히 종료될 때까지 대기
Sleep(2000);
end;
// user_data 폴더 백업
if DirExists(UserDataSourcePath) then
begin
Log('user_data 폴더 백업 중: ' + UserDataSourcePath + ' -> ' + UserDataBackupPath);
ForceDirectories(UserDataBackupPath);
CopyDir(UserDataSourcePath, UserDataBackupPath);
end;
// 이전 버전 제거 (제거 프로그램 실행)
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#OldAppName}_is1',
'UninstallString', OldUninstallString) then
begin
// 사용자에게 확인
if MsgBox('이전 버전을 제거하고 새 버전을 설치하시겠습니까?' + #13#10 +
'사용자 데이터는 유지됩니다.', mbConfirmation, MB_YESNO) = IDYES then
begin
// 자동 제거를 위해 /SILENT 매개변수 추가
OldUninstallString := OldUninstallString + ' /SILENT';
Log('이전 버전 제거 실행: ' + OldUninstallString);
// 제거 프로그램 실행 및 완료 대기
if Exec(RemoveQuotes(OldUninstallString), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
Log('이전 버전 제거 완료: 결과 코드 ' + IntToStr(ResultCode));
end
else
begin
Log('이전 버전 제거 실패');
// 제거에 실패해도 계속 진행
end;
end;
end;
end;
end
// 현재 프로그램(Edit_PartTimer3) 버전 확인
else if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppName}_is1',
'DisplayVersion', OldVersion) then
begin
// 같은 버전이거나 더 높은 버전이 설치되어 있는 경우
if CompareVersion(OldVersion, NewVersion) >= 0 then
begin
MsgBox('현재 설치된 버전(' + OldVersion + ')이 이 설치 프로그램의 버전(' +
NewVersion + ')과 같거나 더 높습니다.' + #13#10 +
'설치를 계속할 수 없습니다.', mbInformation, MB_OK);
Result := False;
exit;
end;
// 이전 버전이 설치되어 있는 경우 업데이트 모드로 진행
if CompareVersion(OldVersion, NewVersion) < 0 then
begin
Log('업데이트 설치 진행: ' + OldVersion + ' -> ' + NewVersion);
// 프로그램이 실행 중인지 확인하고 종료 요청
if IsAppRunning('{#MyAppExeName}.exe') then
begin
if MsgBox('프로그램을 업데이트하기 위해 실행 중인 프로그램을 종료해야 합니다.' + #13#10 +
'계속하시겠습니까?', mbConfirmation, MB_YESNO) = IDNO then
begin
Result := False;
exit;
end;
CloseApplication('{#MyAppExeName}.exe');
end;
// Edit_PartTimer3의 user_data 폴더 백업 - 우선순위: Program Files → AppData\Local
if RegQueryStringValue(HKLM, 'Software\Microsoft\Windows\CurrentVersion\Uninstall\{#MyAppName}_is1',
'InstallLocation', OldAppPath) then
begin
UserDataSourcePath := OldAppPath + '\user_data';
// Program Files에 user_data가 없으면 AppData\Local에서 찾기
if not DirExists(UserDataSourcePath) then
begin
UserDataSourcePath := ExpandConstant('{localappdata}\' + '{#MyAppName}' + '\lib\user_data');
Log('Program Files에 user_data 없음. AppData\Local 경로 확인: ' + UserDataSourcePath);
end
else
begin
Log('Program Files에서 user_data 발견: ' + UserDataSourcePath);
end;
if DirExists(UserDataSourcePath) then
begin
Log('user_data 폴더 백업 중: ' + UserDataSourcePath + ' -> ' + UserDataBackupPath);
ForceDirectories(UserDataBackupPath);
CopyDir(UserDataSourcePath, UserDataBackupPath);
end;
end;
end;
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
UserDataBackupPath, UserDataDestPath: String;
begin
// 설치 완료 후
if CurStep = ssPostInstall then
begin
UserDataBackupPath := ExpandConstant('{tmp}\user_data_backup');
UserDataDestPath := ExpandConstant('{app}\user_data');
// 백업한 user_data 폴더가 있으면 복원
if DirExists(UserDataBackupPath) then
begin
Log('백업된 user_data 폴더 복원 중: ' + UserDataBackupPath + ' -> ' + UserDataDestPath);
ForceDirectories(UserDataDestPath);
CopyDir(UserDataBackupPath, UserDataDestPath);
Log('user_data 폴더 복원 완료');
end;
end;
end;

View File

@ -5107,25 +5107,30 @@ class MAIN_GUI(QMainWindow):
# 로그인 후 설정 버튼 비활성화
self.toggle_settings_button.setEnabled(False)
is_level_premium = self.user_membership_level == 'premium'
is_level_vip = self.user_membership_level == 'vip'
# is_valid_level = self.user_membership_level == 'premium' or self.user_membership_level == 'vip'
# is_level_vip = self.user_membership_level == 'vip'
is_trans_enabled = self.toggle_states.get('optionIMGTrans', False) or self.toggle_states.get('detail_IMGTrans', False) or self.toggle_states.get('thumb', False) or self.toggle_states.get('thumb_nukki', False)
self.logger.log(f"user_membership_level: {self.user_membership_level}", level=logging.DEBUG)
self.logger.log(f"is_level_premium: {is_level_premium}, is_trans_enabled: {is_trans_enabled}", level=logging.DEBUG)
try:
if is_level_premium and is_trans_enabled:
from src.modules.image_processor3 import ImageProcessor3
self.image_processor = ImageProcessor3(self.logger, self.browser_controller.page, self.toggle_states, self.toggle_states['unwanted_words'], self.base_dir)
self.browser_controller.image_processor = self.image_processor
# self.logger.log(f"user_membership_level: {self.user_membership_level}", level=logging.DEBUG)
# self.logger.log(f"is_valid_level: {is_valid_level}", level=logging.DEBUG)
self.logger.log(f"is_trans_enabled: {is_trans_enabled}", level=logging.DEBUG)
# try:
# if is_valid_level and is_trans_enabled:
# from src.modules.image_processor3 import ImageProcessor3
# self.image_processor = ImageProcessor3(self.logger, self.browser_controller.page, self.toggle_states, self.toggle_states['unwanted_words'], self.base_dir)
# self.browser_controller.image_processor = self.image_processor
# except Exception as e:
# self.logger.log(f"ImageProcessor3 초기화 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
if is_level_vip and is_trans_enabled:
try:
if is_trans_enabled:
from src.modules.image_processor3 import ImageProcessor3
self.image_processor = ImageProcessor3(self.logger, self.browser_controller.page, self.toggle_states, self.toggle_states['unwanted_words'], self.base_dir)
self.browser_controller.image_processor = self.image_processor
except Exception as e:
self.logger.log(f"ImageProcessor3 초기화 중 오류 발생: {e}", level=logging.ERROR, exc_info=True)
self.logger.log(f"ImageProcessor3 초기화 완료", level=logging.DEBUG)
self.browser_controller.update_toggle_states(self.toggle_states)

View File

@ -24,10 +24,20 @@ class BackgroundRemovalModule:
"u2net": "범용 모델 (사람/사물 모두, 빠르고 정확함, 대부분 상황에서 권장)",
"u2netp": "u2net 경량화 버전 (속도 빠름, 품질은 약간 낮음, 실시간/저사양용)",
"u2net_human_seg": "사람 인식 특화 (프로필, 인물 사진)",
"u2net_cloth_seg": "의류/패션 이미지 특화",
"u2net_cloth_seg": "의류/패션 이미지 특화 (상/하/전체 의류 분리)",
"silueta": "u2net과 유사하나 모델 크기가 43MB로 작음 (경량화)",
"isnet-general-use": "최신 고성능 범용 모델 (디테일 강조, 고성능PC 추천)",
"isnet-anime": "애니메이션 캐릭터 특화 고정밀 세그멘테이션",
"sam": "Segment Anything Model (최고 품질, 고사양/메모리 충분할 때)",
"sam-mobile": "SAM의 경량화 (모바일, 저사양PC, 빠른 속도)"
"sam-mobile": "SAM의 경량화 (모바일, 저사양PC, 빠른 속도)",
"birefnet-general": "범용 사전학습 모델 (빠르고 다양한 상황에 적합)",
"birefnet-general-lite": "경량화된 범용 사전학습 모델 (속도↑, 성능↓)",
"birefnet-portrait": "인물 사진 특화 사전학습 모델",
"birefnet-dis": "이분법적 이미지 세그멘테이션(Dichotomous Image Segmentation) 특화",
"birefnet-hrsod": "고해상도 주목 객체 검출(High-Resolution Salient Object Detection) 특화",
"birefnet-cod": "은닉 객체 검출(Concealed Object Detection) 특화",
"birefnet-massive": "대규모 데이터셋 기반 범용 모델",
"ben2-base": "Confidence Guided Matting(CGM) 기반의 새로운 전경 분리 방식 도입, 최신 연구 기반"
}
def __init__(self, logger=None, default_model="u2net"):

View File

@ -55,7 +55,7 @@ class ImageProcessor3:
self.mask_module = MaskModule(logger=self.logger, base_dir=self.base_dir)
self.text_rendering_module = TextRenderingModule(logger=self.logger, font_path=self.font_path)
self.postImageManager = PostImageManager(logger=self.logger, toggle_states=self.toggle_states)
self.background_removal_module = BackgroundRemovalModule(logger=self.logger)
self.background_removal_module = BackgroundRemovalModule(logger=self.logger, default_model="birefnet-general")
self.request_inpainting = RequestInpainting(logger=self.logger, server_url=self.toggle_states.get("request_inpainting_server_url", None))

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,7 +7,7 @@ import logging
""" 프로그램 기본 정보 """
__title__ = "Edit_PartTimer"
__description__ = "편집알바생"
__version__ = "3.9.1"
__version__ = "3.9.2"
__build__ = "1" # 빌드 번호
__author__ = "WhenRideMyCar"
__author_email__ = "abc@gmail.com"

View File

@ -1,7 +1,12 @@
# 3.9.2 업데이트 로그
## 초기 실행시 모델로딩으로 인해 반응이 느릴수 있습니다.
### 오류수정
- 썸네일 번역방식변경 추가
- 썸네일 번역방식 변경 추가
- vip일 경우 이미지프로세서가 초기화되지 않는 문제 수정
# 3.9.1 업데이트 로그