1#!/usr/bin/env python3
2#coding:utf8
3
4
5# *** TROUBLESHOOTING ***
6# 1) If you get the error "ImportError: No module named zope.interface" then add an empty __init__.py file to the PYTHONDIR/Lib/site-packages/zope directory
7# 2) It is expected that you will have NSIS 3 NSIS from http://nsis.sourceforge.net installed.
8
9import codecs
10import sys
11# try:
12#     if (sys.version_info.major != 2) or (sys.version_info.minor < 7):
13#         raise Exception("You must build Syncplay with Python 2.7!")
14# except AttributeError:
15#     import warnings
16#     warnings.warn("You must build Syncplay with Python 2.7!")
17
18from glob import glob
19import os
20import subprocess
21from string import Template
22
23from distutils.core import setup
24try:
25    from py2exe.build_exe import py2exe
26except ImportError:
27    from py2exe.distutils_buildexe import py2exe
28
29import syncplay
30from syncplay.messages import getMissingStrings
31
32missingStrings = getMissingStrings()
33if missingStrings is not None and missingStrings is not "":
34    import warnings
35    warnings.warn("MISSING/UNUSED STRINGS DETECTED:\n{}".format(missingStrings))
36
37def get_nsis_path():
38    bin_name = "makensis.exe"
39    from winreg import HKEY_LOCAL_MACHINE as HKLM
40    from winreg import KEY_READ, KEY_WOW64_32KEY, OpenKey, QueryValueEx
41
42    try:
43        nsisreg = OpenKey(HKLM, "Software\\NSIS", 0, KEY_READ | KEY_WOW64_32KEY)
44        if QueryValueEx(nsisreg, "VersionMajor")[0] >= 3:
45            return "{}\\{}".format(QueryValueEx(nsisreg, "")[0], bin_name)
46        else:
47            raise Exception("You must install NSIS 3 or later.")
48    except WindowsError:
49        return bin_name
50
51NSIS_COMPILE = get_nsis_path()
52
53OUT_DIR = "syncplay_v{}".format(syncplay.version)
54SETUP_SCRIPT_PATH = "syncplay_setup.nsi"
55NSIS_SCRIPT_TEMPLATE = r"""
56  !include LogicLib.nsh
57  !include nsDialogs.nsh
58  !include FileFunc.nsh
59
60  LoadLanguageFile "$${NSISDIR}\Contrib\Language files\English.nlf"
61  LoadLanguageFile "$${NSISDIR}\Contrib\Language files\Polish.nlf"
62  LoadLanguageFile "$${NSISDIR}\Contrib\Language files\Russian.nlf"
63  LoadLanguageFile "$${NSISDIR}\Contrib\Language files\German.nlf"
64  LoadLanguageFile "$${NSISDIR}\Contrib\Language files\Italian.nlf"
65  LoadLanguageFile "$${NSISDIR}\Contrib\Language files\Spanish.nlf"
66
67  Unicode true
68
69  Name "Syncplay $version"
70  OutFile "Syncplay-$version-Setup.exe"
71  InstallDir $$PROGRAMFILES\Syncplay
72  RequestExecutionLevel admin
73  ManifestDPIAware false
74  XPStyle on
75  Icon syncplay\resources\icon.ico ;Change DIR
76  SetCompressor /SOLID lzma
77
78  VIProductVersion "$version.0"
79  VIAddVersionKey /LANG=$${LANG_ENGLISH} "ProductName" "Syncplay"
80  VIAddVersionKey /LANG=$${LANG_ENGLISH} "FileVersion" "$version.0"
81  VIAddVersionKey /LANG=$${LANG_ENGLISH} "LegalCopyright" "Syncplay"
82  VIAddVersionKey /LANG=$${LANG_ENGLISH} "FileDescription" "Syncplay"
83
84  VIAddVersionKey /LANG=$${LANG_POLISH} "ProductName" "Syncplay"
85  VIAddVersionKey /LANG=$${LANG_POLISH} "FileVersion" "$version.0"
86  VIAddVersionKey /LANG=$${LANG_POLISH} "LegalCopyright" "Syncplay"
87  VIAddVersionKey /LANG=$${LANG_POLISH} "FileDescription" "Syncplay"
88
89  VIAddVersionKey /LANG=$${LANG_RUSSIAN} "ProductName" "Syncplay"
90  VIAddVersionKey /LANG=$${LANG_RUSSIAN} "FileVersion" "$version.0"
91  VIAddVersionKey /LANG=$${LANG_RUSSIAN} "LegalCopyright" "Syncplay"
92  VIAddVersionKey /LANG=$${LANG_RUSSIAN} "FileDescription" "Syncplay"
93
94  VIAddVersionKey /LANG=$${LANG_ITALIAN} "ProductName" "Syncplay"
95  VIAddVersionKey /LANG=$${LANG_ITALIAN} "FileVersion" "$version.0"
96  VIAddVersionKey /LANG=$${LANG_ITALIAN} "LegalCopyright" "Syncplay"
97  VIAddVersionKey /LANG=$${LANG_ITALIAN} "FileDescription" "Syncplay"
98
99  VIAddVersionKey /LANG=$${LANG_SPANISH} "ProductName" "Syncplay"
100  VIAddVersionKey /LANG=$${LANG_SPANISH} "FileVersion" "$version.0"
101  VIAddVersionKey /LANG=$${LANG_SPANISH} "LegalCopyright" "Syncplay"
102  VIAddVersionKey /LANG=$${LANG_SPANISH} "FileDescription" "Syncplay"
103
104  LangString ^SyncplayLanguage $${LANG_ENGLISH} "en"
105  LangString ^Associate $${LANG_ENGLISH} "Associate Syncplay with multimedia files."
106  LangString ^Shortcut $${LANG_ENGLISH} "Create Shortcuts in following locations:"
107  LangString ^StartMenu $${LANG_ENGLISH} "Start Menu"
108  LangString ^Desktop $${LANG_ENGLISH} "Desktop"
109  LangString ^QuickLaunchBar $${LANG_ENGLISH} "Quick Launch Bar"
110  LangString ^AutomaticUpdates $${LANG_ENGLISH} "Check for updates automatically"
111  LangString ^UninstConfig $${LANG_ENGLISH} "Delete configuration file."
112
113  LangString ^SyncplayLanguage $${LANG_POLISH} "pl"
114  LangString ^Associate $${LANG_POLISH} "Skojarz Syncplaya z multimediami"
115  LangString ^Shortcut $${LANG_POLISH} "Utworz skroty w nastepujacych miejscach:"
116  LangString ^StartMenu $${LANG_POLISH} "Menu Start"
117  LangString ^Desktop $${LANG_POLISH} "Pulpit"
118  LangString ^QuickLaunchBar $${LANG_POLISH} "Pasek szybkiego uruchamiania"
119  LangString ^UninstConfig $${LANG_POLISH} "Usun plik konfiguracyjny."
120
121  LangString ^SyncplayLanguage $${LANG_RUSSIAN} "ru"
122  LangString ^Associate $${LANG_RUSSIAN} "Ассоциировать Syncplay с видеофайлами"
123  LangString ^Shortcut $${LANG_RUSSIAN} "Создать ярлыки:"
124  LangString ^StartMenu $${LANG_RUSSIAN} "в меню Пуск"
125  LangString ^Desktop $${LANG_RUSSIAN} "на рабочем столе"
126  LangString ^QuickLaunchBar $${LANG_RUSSIAN} "в меню быстрого запуска"
127  LangString ^AutomaticUpdates $${LANG_RUSSIAN} "Проверять обновления автоматически"; TODO: Confirm Russian translation ("Check for updates automatically")
128  LangString ^UninstConfig $${LANG_RUSSIAN} "Удалить файл настроек."
129
130  LangString ^SyncplayLanguage $${LANG_GERMAN} "de"
131  LangString ^Associate $${LANG_GERMAN} "Syncplay als Standardprogramm für Multimedia-Dateien verwenden."
132  LangString ^Shortcut $${LANG_GERMAN} "Erstelle Verknüpfungen an folgenden Orten:"
133  LangString ^StartMenu $${LANG_GERMAN} "Startmenü"
134  LangString ^Desktop $${LANG_GERMAN} "Desktop"
135  LangString ^QuickLaunchBar $${LANG_GERMAN} "Schnellstartleiste"
136  LangString ^AutomaticUpdates $${LANG_GERMAN} "Automatisch nach Updates suchen";
137  LangString ^UninstConfig $${LANG_GERMAN} "Konfigurationsdatei löschen."
138
139  LangString ^SyncplayLanguage $${LANG_ITALIAN} "it"
140  LangString ^Associate $${LANG_ITALIAN} "Associa Syncplay con i file multimediali."
141  LangString ^Shortcut $${LANG_ITALIAN} "Crea i collegamenti nei percorsi seguenti:"
142  LangString ^StartMenu $${LANG_ITALIAN} "Menu Start"
143  LangString ^Desktop $${LANG_ITALIAN} "Desktop"
144  LangString ^QuickLaunchBar $${LANG_ITALIAN} "Barra di avvio rapido"
145  LangString ^AutomaticUpdates $${LANG_ITALIAN} "Controllo automatico degli aggiornamenti"
146  LangString ^UninstConfig $${LANG_ITALIAN} "Cancella i file di configurazione."
147
148  LangString ^SyncplayLanguage $${LANG_SPANISH} "es"
149  LangString ^Associate $${LANG_SPANISH} "Asociar Syncplay con archivos multimedia."
150  LangString ^Shortcut $${LANG_SPANISH} "Crear accesos directos en las siguientes ubicaciones:"
151  LangString ^StartMenu $${LANG_SPANISH} "Menú de inicio"
152  LangString ^Desktop $${LANG_SPANISH} "Escritorio"
153  LangString ^QuickLaunchBar $${LANG_SPANISH} "Barra de acceso rápido"
154  LangString ^AutomaticUpdates $${LANG_SPANISH} "Buscar actualizaciones automáticamente"
155  LangString ^UninstConfig $${LANG_SPANISH} "Borrar archivo de configuración."
156
157  ; Remove text to save space
158  LangString ^ClickInstall $${LANG_GERMAN} " "
159
160  PageEx license
161    LicenseData syncplay\resources\license.rtf
162  PageExEnd
163  Page custom DirectoryCustom DirectoryCustomLeave
164  Page instFiles
165
166  UninstPage custom un.installConfirm un.installConfirmLeave
167  UninstPage instFiles
168
169  Var Dialog
170  Var Icon_Syncplay
171  Var Icon_Syncplay_Handle
172  ;Var CheckBox_Associate
173  Var CheckBox_AutomaticUpdates
174  Var CheckBox_StartMenuShortcut
175  Var CheckBox_DesktopShortcut
176  Var CheckBox_QuickLaunchShortcut
177  ;Var CheckBox_Associate_State
178  Var CheckBox_AutomaticUpdates_State
179  Var CheckBox_StartMenuShortcut_State
180  Var CheckBox_DesktopShortcut_State
181  Var CheckBox_QuickLaunchShortcut_State
182  Var Button_Browse
183  Var Directory
184  Var GroupBox_DirSub
185  Var Label_Text
186  Var Label_Shortcut
187  Var Label_Size
188  Var Label_Space
189  Var Text_Directory
190
191  Var Uninst_Dialog
192  Var Uninst_Icon
193  Var Uninst_Icon_Handle
194  Var Uninst_Label_Directory
195  Var Uninst_Label_Text
196  Var Uninst_Text_Directory
197  Var Uninst_CheckBox_Config
198  Var Uninst_CheckBox_Config_State
199
200  Var Size
201  Var SizeHex
202  Var AvailibleSpace
203  Var AvailibleSpaceGiB
204  Var Drive
205  Var VLC_Directory
206
207  ;!macro APP_ASSOCIATE EXT FileCLASS DESCRIPTION COMMANDTEXT COMMAND
208  ;  WriteRegStr HKCR ".$${EXT}" "" "$${FileCLASS}"
209  ;  WriteRegStr HKCR "$${FileCLASS}" "" `$${DESCRIPTION}`
210  ;  WriteRegStr HKCR "$${FileCLASS}\shell" "" "open"
211  ;  WriteRegStr HKCR "$${FileCLASS}\shell\open" "" `$${COMMANDTEXT}`
212  ;  WriteRegStr HKCR "$${FileCLASS}\shell\open\command" "" `$${COMMAND}`
213  ;!macroend
214
215  !macro APP_UNASSOCIATE EXT FileCLASS
216    ; Backup the previously associated File class
217    ReadRegStr $$R0 HKCR ".$${EXT}" `$${FileCLASS}_backup`
218    WriteRegStr HKCR ".$${EXT}" "" "$$R0"
219    DeleteRegKey HKCR `$${FileCLASS}`
220  !macroend
221
222  ;!macro ASSOCIATE EXT
223  ;  !insertmacro APP_ASSOCIATE "$${EXT}" "Syncplay.$${EXT}" "$$INSTDIR\Syncplay.exe,%1%" \
224  ;  "Open with Syncplay" "$$INSTDIR\Syncplay.exe $$\"%1$$\""
225  ;!macroend
226
227  !macro UNASSOCIATE EXT
228    !insertmacro APP_UNASSOCIATE "$${EXT}" "Syncplay.$${EXT}"
229  !macroend
230
231  ;Prevents from running more than one instance of installer and sets default state of checkboxes
232  Function .onInit
233    System::Call 'kernel32::CreateMutexA(i 0, i 0, t "SyncplayMutex") i .r1 ?e'
234    Pop $$R0
235    StrCmp $$R0 0 +3
236    MessageBox MB_OK|MB_ICONEXCLAMATION "The installer is already running."
237      Abort
238
239    ;StrCpy $$CheckBox_Associate_State $${BST_CHECKED}
240    StrCpy $$CheckBox_StartMenuShortcut_State $${BST_CHECKED}
241
242    Call GetSize
243    Call DriveSpace
244    Call Language
245  FunctionEnd
246
247  ;Language selection dialog
248  Function Language
249    Push ""
250    Push $${LANG_ENGLISH}
251    Push English
252    Push $${LANG_POLISH}
253    Push Polski
254    Push $${LANG_RUSSIAN}
255    Push Русский
256    Push $${LANG_GERMAN}
257    Push Deutsch
258    Push $${LANG_ITALIAN}
259    Push Italiano
260    Push $${LANG_SPANISH}
261    Push Español
262    Push A ; A means auto count languages
263    LangDLL::LangDialog "Language Selection" "Please select the language of Syncplay and the installer"
264    Pop $$LANGUAGE
265    StrCmp $$LANGUAGE "cancel" 0 +2
266      Abort
267  FunctionEnd
268
269  Function DirectoryCustom
270
271    nsDialogs::Create 1018
272    Pop $$Dialog
273
274    GetFunctionAddress $$R8 DirectoryCustomLeave
275    nsDialogs::OnBack $$R8
276
277    $${NSD_CreateIcon} 0u 0u 22u 20u ""
278    Pop $$Icon_Syncplay
279    $${NSD_SetIconFromInstaller} $$Icon_Syncplay $$Icon_Syncplay_Handle
280
281    $${NSD_CreateLabel} 25u 0u 241u 34u "$$(^DirText)"
282    Pop $$Label_Text
283
284    $${NSD_CreateText} 8u 38u 187u 12u "$$INSTDIR"
285    Pop $$Text_Directory
286    $${NSD_SetFocus} $$Text_Directory
287
288    $${NSD_CreateBrowseButton} 202u 37u 55u 14u "$$(^BrowseBtn)"
289    Pop $$Button_Browse
290    $${NSD_OnClick} $$Button_Browse DirectoryBrowseDialog
291
292    $${NSD_CreateGroupBox} 1u 27u 264u 30u "$$(^DirSubText)"
293    Pop $$GroupBox_DirSub
294
295    $${NSD_CreateLabel} 0u 122u 132 8u "$$(^SpaceRequired)$$SizeMB"
296    Pop $$Label_Size
297
298    $${NSD_CreateLabel} 321u 122u 132 8u "$$(^SpaceAvailable)$$AvailibleSpaceGiB.$$AvailibleSpaceGB"
299    Pop $$Label_Space
300
301    ;$${NSD_CreateCheckBox} 8u 59u 187u 10u "$$(^Associate)"
302    ;Pop $$CheckBox_Associate
303
304    $${NSD_CreateCheckBox} 8u 72u 250u 10u "$$(^AutomaticUpdates)"
305    Pop $$CheckBox_AutomaticUpdates
306    $${NSD_Check} $$CheckBox_AutomaticUpdates
307
308    $${NSD_CreateLabel} 8u 95u 187u 10u "$$(^Shortcut)"
309    Pop $$Label_Shortcut
310
311    $${NSD_CreateCheckbox} 8u 105u 60u 10u "$$(^StartMenu)"
312    Pop $$CheckBox_StartMenuShortcut
313
314    $${NSD_CreateCheckbox} 78u 105u 70u 10u "$$(^Desktop)"
315    Pop $$CheckBox_DesktopShortcut
316
317    $${NSD_CreateCheckbox} 158u 105u 130u 10u "$$(^QuickLaunchBar)"
318    Pop $$CheckBox_QuickLaunchShortcut
319
320    ;$${If} $$CheckBox_Associate_State == $${BST_CHECKED}
321    ;  $${NSD_Check} $$CheckBox_Associate
322    ;$${EndIf}
323
324
325    $${If} $$CheckBox_StartMenuShortcut_State == $${BST_CHECKED}
326      $${NSD_Check} $$CheckBox_StartMenuShortcut
327    $${EndIf}
328
329    $${If} $$CheckBox_DesktopShortcut_State == $${BST_CHECKED}
330      $${NSD_Check} $$CheckBox_DesktopShortcut
331    $${EndIf}
332
333    $${If} $$CheckBox_QuickLaunchShortcut_State == $${BST_CHECKED}
334      $${NSD_Check} $$CheckBox_QuickLaunchShortcut
335    $${EndIf}
336
337    $${If} $$CheckBox_AutomaticUpdates_State == $${BST_CHECKED}
338      $${NSD_Check} $$CheckBox_AutomaticUpdates
339    $${EndIf}
340
341    nsDialogs::Show
342
343    $${NSD_FreeIcon} $$Icon_Syncplay_Handle
344
345  FunctionEnd
346
347  Function DirectoryCustomLeave
348    $${NSD_GetText} $$Text_Directory $$INSTDIR
349    ;$${NSD_GetState} $$CheckBox_Associate $$CheckBox_Associate_State
350    $${NSD_GetState} $$CheckBox_AutomaticUpdates $$CheckBox_AutomaticUpdates_State
351    $${NSD_GetState} $$CheckBox_StartMenuShortcut $$CheckBox_StartMenuShortcut_State
352    $${NSD_GetState} $$CheckBox_DesktopShortcut $$CheckBox_DesktopShortcut_State
353    $${NSD_GetState} $$CheckBox_QuickLaunchShortcut $$CheckBox_QuickLaunchShortcut_State
354  FunctionEnd
355
356  Function DirectoryBrowseDialog
357    nsDialogs::SelectFolderDialog $$(^DirBrowseText)
358    Pop $$Directory
359    $${If} $$Directory != error
360    StrCpy $$INSTDIR $$Directory
361    $${NSD_SetText} $$Text_Directory $$INSTDIR
362    Call DriveSpace
363    $${NSD_SetText} $$Label_Space "$$(^SpaceAvailable)$$AvailibleSpaceGiB.$$AvailibleSpaceGB"
364    $${EndIf}
365    Abort
366  FunctionEnd
367
368  Function GetSize
369    StrCpy $$Size "$totalSize"
370    IntOp $$Size $$Size / 1024
371    IntFmt $$SizeHex "0x%08X" $$Size
372    IntOp $$Size $$Size / 1024
373  FunctionEnd
374
375  ;Calculates Free Space on HDD
376  Function DriveSpace
377    StrCpy $$Drive $$INSTDIR 1
378    $${DriveSpace} "$$Drive:\" "/D=F /S=M" $$AvailibleSpace
379    IntOp $$AvailibleSpaceGiB $$AvailibleSpace / 1024
380    IntOp $$AvailibleSpace $$AvailibleSpace % 1024
381    IntOp $$AvailibleSpace $$AvailibleSpace / 102
382  FunctionEnd
383
384  Function InstallOptions
385    ;$${If} $$CheckBox_Associate_State == $${BST_CHECKED}
386    ;  Call Associate
387    ;  DetailPrint "Associated Syncplay with multimedia files"
388    ;$${EndIf}
389
390    $${If} $$CheckBox_StartMenuShortcut_State == $${BST_CHECKED}
391      CreateDirectory $$SMPROGRAMS\Syncplay
392      SetOutPath "$$INSTDIR"
393      CreateShortCut "$$SMPROGRAMS\Syncplay\Syncplay.lnk" "$$INSTDIR\Syncplay.exe" ""
394      CreateShortCut "$$SMPROGRAMS\Syncplay\Syncplay Server.lnk" "$$INSTDIR\syncplayServer.exe" ""
395      CreateShortCut "$$SMPROGRAMS\Syncplay\Uninstall.lnk" "$$INSTDIR\Uninstall.exe" ""
396      WriteINIStr "$$SMPROGRAMS\Syncplay\SyncplayWebsite.url" "InternetShortcut" "URL" "https://syncplay.pl"
397    $${EndIf}
398
399    $${If} $$CheckBox_DesktopShortcut_State == $${BST_CHECKED}
400      SetOutPath "$$INSTDIR"
401      CreateShortCut "$$DESKTOP\Syncplay.lnk" "$$INSTDIR\Syncplay.exe" ""
402    $${EndIf}
403
404    $${If} $$CheckBox_QuickLaunchShortcut_State == $${BST_CHECKED}
405      SetOutPath "$$INSTDIR"
406      CreateShortCut "$$QUICKLAUNCH\Syncplay.lnk" "$$INSTDIR\Syncplay.exe" ""
407    $${EndIf}
408  FunctionEnd
409
410  ;Associates extensions with Syncplay
411  ;Function Associate
412  ;  !insertmacro ASSOCIATE avi
413  ;  !insertmacro ASSOCIATE mpg
414  ;  !insertmacro ASSOCIATE mpeg
415  ;  !insertmacro ASSOCIATE mpe
416  ;  !insertmacro ASSOCIATE m1v
417  ;  !insertmacro ASSOCIATE m2v
418  ;  !insertmacro ASSOCIATE mpv2
419  ;  !insertmacro ASSOCIATE mp2v
420  ;  !insertmacro ASSOCIATE mkv
421  ;  !insertmacro ASSOCIATE mp4
422  ;  !insertmacro ASSOCIATE m4v
423  ;  !insertmacro ASSOCIATE mp4v
424  ;  !insertmacro ASSOCIATE 3gp
425  ;  !insertmacro ASSOCIATE 3gpp
426  ;  !insertmacro ASSOCIATE 3g2
427  ;  !insertmacro ASSOCIATE 3pg2
428  ;  !insertmacro ASSOCIATE flv
429  ;  !insertmacro ASSOCIATE f4v
430  ;  !insertmacro ASSOCIATE rm
431  ;  !insertmacro ASSOCIATE wmv
432  ;  !insertmacro ASSOCIATE swf
433  ;  !insertmacro ASSOCIATE rmvb
434  ;  !insertmacro ASSOCIATE divx
435  ;  !insertmacro ASSOCIATE amv
436  ;FunctionEnd
437
438  Function WriteRegistry
439    Call GetSize
440    WriteRegStr HKLM SOFTWARE\Syncplay "Install_Dir" "$$INSTDIR"
441    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "DisplayName" "Syncplay"
442    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "InstallLocation" "$$INSTDIR"
443    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "UninstallString" '"$$INSTDIR\uninstall.exe"'
444    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "DisplayIcon" "$$INSTDIR\resources\icon.ico"
445    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "Publisher" "Syncplay"
446    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "DisplayVersion" "$version"
447    WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "URLInfoAbout" "https://syncplay.pl/"
448    WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "NoModify" 1
449    WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "NoRepair" 1
450    WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "EstimatedSize" "$$SizeHex"
451    WriteINIStr $$APPDATA\syncplay.ini general language $$(^SyncplayLanguage)
452    $${If} $$CheckBox_AutomaticUpdates_State == $${BST_CHECKED}
453        WriteINIStr $$APPDATA\syncplay.ini general CheckForUpdatesAutomatically "True"
454    $${Else}
455        WriteINIStr $$APPDATA\syncplay.ini general CheckForUpdatesAutomatically "False"
456    $${EndIf}
457  FunctionEnd
458
459  Function un.installConfirm
460    nsDialogs::Create 1018
461    Pop $$Uninst_Dialog
462
463    $${NSD_CreateIcon} 0u 1u 22u 20u ""
464    Pop $$Uninst_Icon
465    $${NSD_SetIconFromInstaller} $$Uninst_Icon $$Uninst_Icon_Handle
466
467    $${NSD_CreateLabel} 0u 45u 55u 8u "$$(^UninstallingSubText)"
468    Pop $$Uninst_Label_Directory
469
470    $${NSD_CreateLabel} 25u 0u 241u 34u "$$(^UninstallingText)"
471    Pop $$Uninst_Label_Text
472
473    ReadRegStr $$INSTDIR HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "InstallLocation"
474    $${NSD_CreateText} 56u 43u 209u 12u "$$INSTDIR"
475    Pop $$Uninst_Text_Directory
476    EnableWindow $$Uninst_Text_Directory 0
477
478    $${NSD_CreateCheckBox} 0u 60u 250u 10u "$$(^UninstConfig)"
479    Pop $$Uninst_CheckBox_Config
480
481
482    nsDialogs::Show
483    $${NSD_FreeIcon} $$Uninst_Icon_Handle
484  FunctionEnd
485
486  Function un.installConfirmLeave
487    $${NSD_GetState} $$Uninst_CheckBox_Config $$Uninst_CheckBox_Config_State
488  FunctionEnd
489
490  Function un.AssociateDel
491    !insertmacro UNASSOCIATE avi
492    !insertmacro UNASSOCIATE mpg
493    !insertmacro UNASSOCIATE mpeg
494    !insertmacro UNASSOCIATE mpe
495    !insertmacro UNASSOCIATE m1v
496    !insertmacro UNASSOCIATE m2v
497    !insertmacro UNASSOCIATE mpv2
498    !insertmacro UNASSOCIATE mp2v
499    !insertmacro UNASSOCIATE mkv
500    !insertmacro UNASSOCIATE mp4
501    !insertmacro UNASSOCIATE m4v
502    !insertmacro UNASSOCIATE mp4v
503    !insertmacro UNASSOCIATE 3gp
504    !insertmacro UNASSOCIATE 3gpp
505    !insertmacro UNASSOCIATE 3g2
506    !insertmacro UNASSOCIATE 3pg2
507    !insertmacro UNASSOCIATE flv
508    !insertmacro UNASSOCIATE f4v
509    !insertmacro UNASSOCIATE rm
510    !insertmacro UNASSOCIATE wmv
511    !insertmacro UNASSOCIATE swf
512    !insertmacro UNASSOCIATE rmvb
513    !insertmacro UNASSOCIATE divx
514    !insertmacro UNASSOCIATE amv
515  FunctionEnd
516
517  Function un.InstallOptions
518    Delete $$SMPROGRAMS\Syncplay\Syncplay.lnk
519    Delete "$$SMPROGRAMS\Syncplay\Syncplay Server.lnk"
520    Delete $$SMPROGRAMS\Syncplay\Uninstall.lnk
521    Delete $$SMPROGRAMS\Syncplay\SyncplayWebsite.url
522    RMDir $$SMPROGRAMS\Syncplay
523    Delete $$DESKTOP\Syncplay.lnk
524    Delete $$QUICKLAUNCH\Syncplay.lnk
525    ReadRegStr $$VLC_Directory HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay" "VLCInstallLocation"
526    IfFileExists "$$VLC_Directory\lua\intf\syncplay.lua" 0 +2
527    Delete $$VLC_Directory\lua\intf\syncplay.lua
528  FunctionEnd
529
530  Section "Install"
531    SetOverwrite on
532    SetOutPath $$INSTDIR
533    WriteUninstaller uninstall.exe
534
535    $installFiles
536
537    Call InstallOptions
538    Call WriteRegistry
539  SectionEnd
540
541  Section "Uninstall"
542    Call un.AssociateDel
543    Call un.InstallOptions
544    $uninstallFiles
545    DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Syncplay"
546    DeleteRegKey HKLM SOFTWARE\Syncplay
547    Delete $$INSTDIR\uninstall.exe
548    RMDir $$INSTDIR\Syncplay\\resources\lua\intf
549    RMDir $$INSTDIR\Syncplay\\resources\lua
550    RMDir $$INSTDIR\Syncplay\\resources
551    RMDir $$INSTDIR\resources
552    RMDir $$INSTDIR\lib
553    RMDir $$INSTDIR
554
555    $${If} $$Uninst_CheckBox_Config_State == $${BST_CHECKED}
556      IfFileExists "$$APPDATA\.syncplay" 0 +2
557      Delete $$APPDATA\.syncplay
558      IfFileExists "$$APPDATA\syncplay.ini" 0 +2
559      Delete $$APPDATA\syncplay.ini
560    $${EndIf}
561  SectionEnd
562"""
563
564class NSISScript(object):
565    def create(self):
566        fileList, totalSize = self.getBuildDirContents(OUT_DIR)
567        print("Total size eq: {}".format(totalSize))
568        installFiles = self.prepareInstallListTemplate(fileList)
569        uninstallFiles = self.prepareDeleteListTemplate(fileList)
570
571        if os.path.isfile(SETUP_SCRIPT_PATH):
572            raise RuntimeError("Cannot create setup script, file exists at {}".format(SETUP_SCRIPT_PATH))
573        contents = Template(NSIS_SCRIPT_TEMPLATE).substitute(
574            version=syncplay.version,
575            uninstallFiles=uninstallFiles,
576            installFiles=installFiles,
577            totalSize=totalSize,
578        )
579        with codecs.open(SETUP_SCRIPT_PATH, "w", "utf-8-sig") as outfile:
580            outfile.write(contents)
581
582    def compile(self):
583        if not os.path.isfile(NSIS_COMPILE):
584            return "makensis.exe not found, won't create the installer"
585        subproc = subprocess.Popen([NSIS_COMPILE, SETUP_SCRIPT_PATH], env=os.environ)
586        subproc.communicate()
587        retcode = subproc.returncode
588        os.remove(SETUP_SCRIPT_PATH)
589        if retcode:
590            raise RuntimeError("NSIS compilation return code: %d" % retcode)
591
592    def getBuildDirContents(self, path):
593        fileList = {}
594        totalSize = 0
595        for root, _, files in os.walk(path):
596            totalSize += sum(os.path.getsize(os.path.join(root, file_)) for file_ in files)
597            for file_ in files:
598                new_root = root.replace(OUT_DIR, "").strip("\\")
599                if new_root not in fileList:
600                    fileList[new_root] = []
601                fileList[new_root].append(file_)
602        return fileList, totalSize
603
604    def prepareInstallListTemplate(self, fileList):
605        create = []
606        for dir_ in fileList.keys():
607            create.append('SetOutPath "$INSTDIR\\{}"'.format(dir_))
608            for file_ in fileList[dir_]:
609                create.append('FILE "{}\\{}\\{}"'.format(OUT_DIR, dir_, file_))
610        return "\n".join(create)
611
612    def prepareDeleteListTemplate(self, fileList):
613        delete = []
614        for dir_ in fileList.keys():
615            for file_ in fileList[dir_]:
616                delete.append('DELETE "$INSTDIR\\{}\\{}"'.format(dir_, file_))
617            delete.append('RMdir "$INSTDIR\\{}"'.format(file_))
618        return "\n".join(delete)
619
620def pruneUnneededLibraries():
621    from pathlib import Path
622    cwd = os.getcwd()
623    libDir = cwd + '\\' + OUT_DIR + '\\lib\\'
624    unneededModules = ['PySide2.Qt3D*', 'PySide2.QtAxContainer.pyd', 'PySide2.QtCharts.pyd', 'PySide2.QtConcurrent.pyd',
625                       'PySide2.QtDataVisualization.pyd', 'PySide2.QtHelp.pyd', 'PySide2.QtLocation.pyd',
626                       'PySide2.QtMultimedia.pyd', 'PySide2.QtMultimediaWidgets.pyd', 'PySide2.QtOpenGL.pyd',
627                       'PySide2.QtPositioning.pyd', 'PySide2.QtPrintSupport.pyd', 'PySide2.QtQml.pyd',
628                       'PySide2.QtQuick.pyd', 'PySide2.QtQuickWidgets.pyd', 'PySide2.QtScxml.pyd', 'PySide2.QtSensors.pyd',
629                       'PySide2.QtSql.pyd', 'PySide2.QtSvg.pyd', 'PySide2.QtTest.pyd', 'PySide2.QtTextToSpeech.pyd',
630                       'PySide2.QtUiTools.pyd', 'PySide2.QtWebChannel.pyd', 'PySide2.QtWebEngine.pyd',
631                       'PySide2.QtWebEngineCore.pyd', 'PySide2.QtWebEngineWidgets.pyd', 'PySide2.QtWebSockets.pyd',
632                       'PySide2.QtWinExtras.pyd', 'PySide2.QtXml.pyd', 'PySide2.QtXmlPatterns.pyd']
633    unneededLibs = ['Qt53D*', 'Qt5Charts.dll', 'Qt5Concurrent.dll', 'Qt5DataVisualization.dll', 'Qt5Gamepad.dll', 'Qt5Help.dll',
634                    'Qt5Location.dll', 'Qt5Multimedia.dll', 'Qt5MultimediaWidgets.dll', 'Qt5OpenGL.dll', 'Qt5Positioning.dll',
635                    'Qt5PrintSupport.dll', 'Qt5Quick.dll', 'Qt5QuickWidgets.dll', 'Qt5Scxml.dll', 'Qt5Sensors.dll', 'Qt5Sql.dll',
636                    'Qt5Svg.dll', 'Qt5Test.dll', 'Qt5TextToSpeech.dll', 'Qt5WebChannel.dll', 'Qt5WebEngine.dll',
637                    'Qt5WebEngineCore.dll', 'Qt5WebEngineWidgets.dll', 'Qt5WebSockets.dll', 'Qt5WinExtras.dll', 'Qt5Xml.dll',
638                    'Qt5XmlPatterns.dll']
639    windowsDLL = ['MSVCP140.dll', 'VCRUNTIME140.dll']
640    deleteList = unneededModules + unneededLibs + windowsDLL
641    deleteList.append('api-*')
642    for filename in deleteList:
643        for p in Path(libDir).glob(filename):
644            p.unlink()
645
646def copyQtPlugins(paths):
647    import shutil
648    from PySide2 import QtCore
649    basePath = QtCore.QLibraryInfo.location(QtCore.QLibraryInfo.PluginsPath)
650    basePath = basePath.replace('/', '\\')
651    destBase = os.getcwd() + '\\' + OUT_DIR
652    for elem in paths:
653        elemDir, elemName = os.path.split(elem)
654        source = basePath + '\\' + elem
655        dest = destBase + '\\' + elem
656        destDir = destBase + '\\' + elemDir
657        os.makedirs(destDir, exist_ok=True)
658        shutil.copy(source, dest)
659
660class build_installer(py2exe):
661    def run(self):
662        py2exe.run(self)
663        print('*** deleting unnecessary libraries and modules ***')
664        pruneUnneededLibraries()
665        print('*** copying qt plugins ***')
666        copyQtPlugins(qt_plugins)
667        script = NSISScript()
668        script.create()
669        print("*** compiling the NSIS setup script ***")
670        script.compile()
671        print("*** DONE ***")
672
673guiIcons = glob('syncplay/resources/*.png') +  ['syncplay/resources/spinner.mng']
674
675resources = [
676    "syncplay/resources/icon.ico",
677    "syncplay/resources/syncplayintf.lua",
678    "syncplay/resources/license.rtf",
679    "syncplay/resources/third-party-notices.rtf"
680]
681resources.extend(guiIcons)
682intf_resources = ["syncplay/resources/lua/intf/syncplay.lua"]
683
684qt_plugins = ['platforms\\qwindows.dll', 'styles\\qwindowsvistastyle.dll']
685
686common_info = dict(
687    name='Syncplay',
688    version=syncplay.version,
689    author='Uriziel',
690    author_email='dev@syncplay.pl',
691    description='Syncplay',
692)
693
694info = dict(
695    common_info,
696    windows=[{
697      "script": "syncplayClient.py",
698      "icon_resources": [(1, "syncplay\\resources\\icon.ico")],
699      'dest_base': "Syncplay"},
700    ],
701    console=['syncplayServer.py'],
702    # *** If you wish to make the Syncplay client use console mode (for --no-gui to work) then comment out the above two lines and uncomment the following line:
703    # console=['syncplayServer.py', {"script":"syncplayClient.py", "icon_resources":[(1, "resources\\icon.ico")], 'dest_base': "Syncplay"}],
704
705    options={
706        'py2exe': {
707            'dist_dir': OUT_DIR,
708            'packages': 'PySide2, cffi, OpenSSL, certifi',
709            'includes': 'twisted, sys, encodings, datetime, os, time, math, urllib, ast, unicodedata, _ssl, win32pipe, win32file',
710            'excludes': 'venv, doctest, pdb, unittest, win32clipboard, win32pdh, win32security, win32trace, win32ui, winxpgui, win32process, Tkinter',
711            'dll_excludes': 'msvcr71.dll, MSVCP90.dll, POWRPROF.dll',
712            'optimize': 2,
713            'compressed': 1
714        }
715    },
716    data_files=[("resources", resources), ("resources/lua/intf", intf_resources)],
717    zipfile="lib/libsync",
718    cmdclass={"py2exe": build_installer},
719)
720
721sys.argv.extend(['py2exe'])
722setup(**info)