operations.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. ########################################################################
  2. # Wiizard - A Wii games manager
  3. # Copyright (C) 2023 CYBERDEViL
  4. #
  5. # This file is part of Wiizard.
  6. #
  7. # Wiizard is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # Wiizard is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. ########################################################################
  21. import os
  22. from PyQt5.QtCore import pyqtSignal
  23. import pywwt
  24. from wiizard.thread import AbstractThread, THREAD_FLAG_IS_CANCELLABLE
  25. from wiizard.models.source import SOURCE_TYPE_LOCAL
  26. GAME_OP_DELETE = 1
  27. GAME_OP_ADD = 2
  28. GAME_OP_MOVE = GAME_OP_ADD | GAME_OP_DELETE
  29. class GameOperationsThread(AbstractThread):
  30. progress = pyqtSignal(int, str) # operation index, error message
  31. def __init__(self, operations):
  32. AbstractThread.__init__(self, flags=THREAD_FLAG_IS_CANCELLABLE)
  33. self.__operations = operations
  34. def execAdd(self, op):
  35. error = ""
  36. fromModel = op.game.sourceModel
  37. toModel = op.target
  38. if op.game.fileSize > toModel.getFree():
  39. error = "Not enough free space!"
  40. return error
  41. if fromModel.type == SOURCE_TYPE_LOCAL:
  42. # Local to local (regular file copy)
  43. if toModel.type == SOURCE_TYPE_LOCAL:
  44. frompath = os.path.join(op.game.sourcePath, op.game.filename)
  45. topath = os.path.join(toModel.location, op.game.filename)
  46. opStr = f"copy {frompath} to {topath}."
  47. print(f"Try to {opStr}")
  48. error = f"Failed to {opStr}"
  49. error += "\nFIXME copy local to local not implemented yet."
  50. # Local to WBFS partition
  51. else:
  52. filepath = os.path.join(op.game.sourcePath, op.game.filename)
  53. opStr = f"add '{filepath}' to '{toModel.location}'."
  54. result = None
  55. print(f"Try to {opStr}")
  56. try:
  57. result = pywwt.add_to_wbfs(toModel.location, filepath, testMode=False)
  58. except pywwt.error as err:
  59. error = f"Failed to {opStr}"
  60. error += f"\npywwt.error: '{err}'"
  61. else:
  62. if not result:
  63. error = f"Failed to {opStr}"
  64. else:
  65. # WBFS partition to local
  66. if toModel.type == SOURCE_TYPE_LOCAL:
  67. # TODO check file type
  68. # TODO check if file exists
  69. frompath = f"{fromModel.location}:{op.game.id6}"
  70. topath = os.path.join(toModel.location, f"{op.game.id6}.wbfs")
  71. opStr = f"export {frompath} to {topath}."
  72. result = None
  73. print(f"Try to {opStr}")
  74. try:
  75. result = pywwt.extract_from_wbfs(op.game.sourceModel.location,
  76. op.game.id6,
  77. topath,
  78. testMode=False)
  79. except pywwt.error as err:
  80. error = f"Failed to {opStr}"
  81. error += f"\npywwt.error: '{err}'"
  82. else:
  83. if not result:
  84. error = f"Failed to {opStr}"
  85. # WBFS partition to WBFS partition
  86. else:
  87. frompath = f"{fromModel.location}:{op.game.id6}"
  88. topath = f"{toModel.location}:{op.game.id6}"
  89. opStr = f"copy {frompath} to {topath}."
  90. result = None
  91. print(f"Try to {opStr}")
  92. try:
  93. result = pywwt.wbfs_to_wbfs(fromModel.location, toModel.location,
  94. op.game.id6)
  95. except pywwt.error as err:
  96. error = f"Failed to {opStr}"
  97. error += f"\npywwt.error: '{err}'"
  98. return error
  99. def execDelete(self, op):
  100. fromModel = op.game.sourceModel
  101. error = ""
  102. if fromModel.type == SOURCE_TYPE_LOCAL:
  103. # Delete local file
  104. filepath = os.path.join(op.game.sourcePath, op.game.filename)
  105. opStr = f"delete {filepath}."
  106. print(f"Try to {opStr}")
  107. error = f"Failed to {opStr}"
  108. error += "\nFIXME Delete local file not implemented yet."
  109. else:
  110. # Delete game from WBFS partition
  111. filepath = f"{fromModel.location}:{op.game.id6}"
  112. opStr = f"delete {filepath}."
  113. result = None
  114. print(f"Try to {opStr}")
  115. try:
  116. result = pywwt.remove_from_wbfs(fromModel.location, op.game.id6,
  117. testMode=False)
  118. except pywwt.error as err:
  119. error = f"Failed to {opStr}"
  120. error += f"\npywwt.error: '{err}'"
  121. else:
  122. if not result:
  123. error = f"Failed to {opStr}"
  124. return error
  125. def run(self):
  126. progress = 0
  127. for index in range(0, len(self.__operations)):
  128. error = ""
  129. op = self.__operations[index]
  130. # ADD game
  131. if op.operation == GAME_OP_ADD:
  132. error = self.execAdd(op)
  133. # DELETE game
  134. elif op.operation == GAME_OP_DELETE:
  135. error = self.execDelete(op)
  136. # MOVE game (First ADD and then DELETE)
  137. elif op.operation == GAME_OP_MOVE:
  138. error = self.execAdd(op)
  139. if not error:
  140. error = self.execDelete(op)
  141. progress += 1
  142. self.progress.emit(progress, error)
  143. if self.cancelled is True:
  144. break
  145. self.completed.emit()
  146. class GameOperation:
  147. def __init__(self, game, targetModel, operation):
  148. self.__game = game
  149. self.__targetModel = targetModel
  150. self.__operation = operation
  151. @property
  152. def operation(self):
  153. return self.__operation
  154. @property
  155. def game(self):
  156. return self.__game
  157. @property
  158. def target(self):
  159. return self.__targetModel