Skip to content

Commit d8c772d

Browse files
committed
misc: Update pygubu, reformat nbstool.py
1 parent ebb9ff4 commit d8c772d

File tree

3 files changed

+87
-62
lines changed

3 files changed

+87
-62
lines changed

nbstool.py

Lines changed: 77 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
# nuitka-project: --windows-file-description=NBSTool
3434

3535

36+
from __future__ import annotations
37+
3638
import asyncio
3739
import inspect
3840
import json
@@ -61,8 +63,8 @@
6163
from tkinter.filedialog import (askdirectory, askopenfilename,
6264
askopenfilenames, asksaveasfilename)
6365
from tkinter.messagebox import showerror, showinfo, showwarning
64-
from typing import (Any, Callable, Coroutine, Deque, Iterable, List, Literal,
65-
Optional, Union, Tuple)
66+
from typing import (Any, Callable, Coroutine, Deque, Iterable, Literal,
67+
Optional, Union)
6668

6769
import pygubu
6870
import pygubu.widgets.combobox
@@ -89,7 +91,7 @@
8991
# Ensure pydub.utils.which can splits the added ffmpeg path properly
9092
# Fix for the issue #10
9193
if not os.environ["PATH"].endswith(os.pathsep):
92-
os.environ["PATH"] += os.pathsep
94+
os.environ["PATH"] += os.pathsep
9395
# Add the path of the ffmpeg before the first pydub import statement
9496
os.environ["PATH"] += resource_path('ffmpeg', 'bin')
9597

@@ -355,25 +357,27 @@
355357
# Taken from Note Block World source code. This shouldn't violate AGPL, though.
356358
# https://github.com/OpenNBS/NoteBlockWorld/blob/main/shared/features/thumbnail/index.ts#L27
357359
NBS_INST_NOTE_COLORS_HEX = (
358-
'#1964ac',
359-
'#3c8e48',
360-
'#be6b6b',
361-
'#bebe19',
362-
'#9d5a98',
363-
'#572b21',
364-
'#bec65c',
365-
'#be19be',
366-
'#52908d',
367-
'#bebebe',
368-
'#1991be',
369-
'#be2328',
370-
'#be5728',
371-
'#19be19',
372-
'#be1957',
373-
'#575757',
360+
'#1964ac',
361+
'#3c8e48',
362+
'#be6b6b',
363+
'#bebe19',
364+
'#9d5a98',
365+
'#572b21',
366+
'#bec65c',
367+
'#be19be',
368+
'#52908d',
369+
'#bebebe',
370+
'#1991be',
371+
'#be2328',
372+
'#be5728',
373+
'#19be19',
374+
'#be1957',
375+
'#575757',
374376
)
375-
NBS_INST_NOTE_COLORS = tuple(Color(color) for color in NBS_INST_NOTE_COLORS_HEX)
376-
NBS_NOTE_COLORS_TO_INST = {color.to_string(hex=True): index for index, color in enumerate(NBS_INST_NOTE_COLORS)}
377+
NBS_INST_NOTE_COLORS = tuple(Color(color)
378+
for color in NBS_INST_NOTE_COLORS_HEX)
379+
NBS_NOTE_COLORS_TO_INST = {color.to_string(
380+
hex=True): index for index, color in enumerate(NBS_INST_NOTE_COLORS)}
377381

378382
NBSTOOL_FIRST_COMMIT_TIMESTAMP = 1565100420
379383
CONSONANTS = "bcdfghjklmnpqrstvwxyzBCDFGHJLKMNPQRSTVWXYZ"
@@ -496,7 +500,7 @@ def initVarsAndCallbacksFrom(self, builder: Builder):
496500

497501
def isInteger(self, value: str) -> bool:
498502
return value == '' or value.isdigit()
499-
503+
500504
def isRequiredInteger(self, value: str) -> bool:
501505
return value.isdigit()
502506

@@ -760,11 +764,14 @@ def initArrangeTab(self):
760764
def intImportImageTab(self):
761765
self.pixelArtImagePathVar.set('')
762766
self.imgInsertPosVar.set('lastLayer')
763-
pathChooser: PathChooserInput = self.builder.get_object('pixelArtImagePathChooser')
764-
filetypes = [('Image files', '*.png *.jpg *.jpeg *.gif *.bmp *.tiff *.webp'), ('All files', '*')]
767+
pathChooser: PathChooserInput = self.builder.get_object(
768+
'pixelArtImagePathChooser')
769+
filetypes = [
770+
('Image files', '*.png *.jpg *.jpeg *.gif *.bmp *.tiff *.webp'), ('All files', '*')]
765771
pathChooser.config(filetypes=filetypes, width=200)
766-
sizeCombo: PygubuCombobox = self.builder.get_object('imgInsertSizeCombo')
767-
options: List = []
772+
sizeCombo: PygubuCombobox = self.builder.get_object(
773+
'imgInsertSizeCombo')
774+
options: list = []
768775
for zoom in NBW_THUMBNAIL_ZOOM_PERCENT_VALUES:
769776
# zoom = 400% => width = 10, height = 6
770777
# zoom = 200% => width = 20, height = 12
@@ -920,9 +927,10 @@ def onClose(self, event=None):
920927
def onArrangeModeChanged(self):
921928
self.builder.get_object('arrangeGroupPrec')['state'] = 'normal' if (
922929
self.arrangeMode.get() == 'instruments') else 'disabled'
923-
930+
924931
def onImgInsertPosChanged(self):
925-
state = 'normal' if (self.imgInsertPosVar.get() == 'custom') else 'disabled'
932+
state = 'normal' if (self.imgInsertPosVar.get()
933+
== 'custom') else 'disabled'
926934
self.builder.get_object('imgInsertCustomLabel1')['state'] = state
927935
self.builder.get_object('imgInsertCustomLabel2')['state'] = state
928936
self.builder.get_object('imgInsertPosTickSpin')['state'] = state
@@ -945,6 +953,12 @@ async def work(dialog: ProgressDialog):
945953
try:
946954
notebook: ttk.Notebook = get_object('headerNotebook')
947955
headerModifiable = notebook.index(notebook.select()) == 1
956+
insertImageNotes: list[Note] = []
957+
if (imgPath := self.pixelArtImagePathVar.get()) and imgPath.strip() != '':
958+
zoomPercent = self.imgInsertSizePercentVar.get()
959+
insertWidth = NBW_WIDTH_DIVISOR // zoomPercent
960+
insertHeight = NBW_HEIGHT_DIVISOR // zoomPercent
961+
insertImageNotes = self.imageToNotes(imgPath, insertWidth, insertHeight)
948962
i = 0
949963
for i, index in enumerate(selectedIndexes):
950964
dialog.totalProgress.set(i)
@@ -1006,8 +1020,8 @@ async def work(dialog: ProgressDialog):
10061020
layer.volume = 100
10071021
if applyPan:
10081022
layer.pan = 0
1009-
1010-
if (imgPath := self.pixelArtImagePathVar.get()) and imgPath != '':
1023+
1024+
if insertImageNotes:
10111025
insertPos = self.imgInsertPosVar.get()
10121026
insertTick: int = -1
10131027
insertLayer: int = -1
@@ -1020,12 +1034,9 @@ async def work(dialog: ProgressDialog):
10201034
elif insertPos == 'custom':
10211035
insertTick = self.imgInsertPosTickVar.get()
10221036
insertLayer = self.imgInsertPosLayerVar.get()
1023-
1024-
zoomPercent = self.imgInsertSizePercentVar.get()
1025-
insertWidth = NBW_WIDTH_DIVISOR // zoomPercent
1026-
insertHeight = NBW_HEIGHT_DIVISOR // zoomPercent
10271037

1028-
self.insertImage(imgPath, songData, insertTick, insertLayer, insertWidth, insertHeight)
1038+
self.shiftNotes(insertImageNotes, insertTick, insertLayer)
1039+
songData.notes.extend(insertImageNotes)
10291040

10301041
dialog.setCurrentPercentage(randint(75, 85))
10311042
await sleep(0.001)
@@ -1037,7 +1048,8 @@ async def work(dialog: ProgressDialog):
10371048
self.songsData[k] = v
10381049
dialog.totalProgress.set(i+1)
10391050

1040-
showinfo("Applying tools", "All selected files have been processed.")
1051+
showinfo("Applying tools",
1052+
"All selected files have been processed.")
10411053
except CancelledError:
10421054
raise
10431055
except Exception as e:
@@ -1065,11 +1077,12 @@ def collapseNotes(self, notes) -> None:
10651077
note.layer = layer
10661078
prevNote = note
10671079

1068-
def insertImage(self, imgPath: str, song: NbsSong, x: int, y: int, width: int, height: int) -> None:
1080+
def imageToNotes(self, imgPath: str, width: int, height: int) -> list[Note]:
10691081
img = Image.open(imgPath)
10701082
img.thumbnail((width, height), Image.Resampling.NEAREST)
10711083
width, height = img.size
10721084
img = img.convert('RGBA')
1085+
notes = []
10731086

10741087
for i in range(width):
10751088
for j in range(height):
@@ -1078,9 +1091,18 @@ def insertImage(self, imgPath: str, song: NbsSong, x: int, y: int, width: int, h
10781091
r, g, b, a = color
10791092
if a <= 25:
10801093
continue
1081-
nearestColor = Color('srgb', (r / 255, g / 255, b / 255)).closest(NBS_INST_NOTE_COLORS)
1082-
inst = NBS_NOTE_COLORS_TO_INST[nearestColor.to_string(hex=True)]
1083-
song.notes.append(Note(x + i, y + j, inst, 0, 0))
1094+
nearestColor = Color(
1095+
'srgb', (r / 255, g / 255, b / 255)).closest(NBS_INST_NOTE_COLORS)
1096+
inst = NBS_NOTE_COLORS_TO_INST[nearestColor.to_string(
1097+
hex=True)]
1098+
notes.append(Note(i, j, inst, 0, 0))
1099+
1100+
return notes
1101+
1102+
def shiftNotes(self, notes: list[Note], x: int, y: int) -> None:
1103+
for note in notes:
1104+
note.tick += x
1105+
note.layer += y
10841106

10851107
def modifyHeaders(self, header):
10861108
def setAttrFromStrVar(key: str, value: str):
@@ -1463,7 +1485,7 @@ def __init__(self, master, parent):
14631485

14641486
def parseFilePaths(string: str) -> tuple:
14651487
strLen = len(string)
1466-
ret: List[str] = []
1488+
ret: list[str] = []
14671489
filePath = ''
14681490
isQuoted = False
14691491
for i, char in enumerate(string):
@@ -1666,19 +1688,20 @@ async def convert(self, filepath: str, dialog: ProgressDialog) -> NbsSong:
16661688
) if not self.autoExpand.get() else 0
16671689
fadeOut = self.trailingNoteVelMode.get() == 'fadeOut'
16681690
return await midi2nbs(filepath, expandMult, self.importDuration.get(),
1669-
self.durationSpacing.get(), self.trailingVelocity.get(), self.trailingVelAsPercent.get(), fadeOut, self.applyStereo.get(), self.importVelocity.get(),
1670-
self.importPanning.get(), self.importPitch.get(),
1671-
dialog)
1691+
self.durationSpacing.get(), self.trailingVelocity.get(), self.trailingVelAsPercent.get(
1692+
), fadeOut, self.applyStereo.get(), self.importVelocity.get(),
1693+
self.importPanning.get(), self.importPitch.get(),
1694+
dialog)
16721695

16731696
def autoExpandChanged(self):
16741697
self.builder.get_object('expandScale')[
16751698
'state'] = 'disabled' if self.autoExpand.get() else 'normal'
1676-
1699+
16771700
def trailingNoteVelModeChanged(self):
1678-
fixedVelocity = self.trailingNoteVelMode.get() == 'fixed'
1679-
self.builder.get_object('trailingVelocitySpin')[
1701+
fixedVelocity = self.trailingNoteVelMode.get() == 'fixed'
1702+
self.builder.get_object('trailingVelocitySpin')[
16801703
'state'] = 'normal' if fixedVelocity else 'disabled'
1681-
self.builder.get_object('trailingVelPercentCheck')[
1704+
self.builder.get_object('trailingVelPercentCheck')[
16821705
'state'] = 'normal' if fixedVelocity else 'disabled'
16831706

16841707
def importDurationChanged(self):
@@ -1697,8 +1720,10 @@ def importDurationChanged(self):
16971720
if self.importDuration.get():
16981721
self.trailingNoteVelModeChanged()
16991722
else:
1700-
self.builder.get_object('trailingVelocitySpin')['state'] = 'disabled'
1701-
self.builder.get_object('trailingVelPercentCheck')['state'] = 'disabled'
1723+
self.builder.get_object('trailingVelocitySpin')[
1724+
'state'] = 'disabled'
1725+
self.builder.get_object('trailingVelPercentCheck')[
1726+
'state'] = 'disabled'
17021727

17031728
def applyStereoChanged(self):
17041729
pass
@@ -2103,7 +2128,8 @@ def main() -> None:
21032128
logger.info("NBSTool v{}", __version__)
21042129
logger.info("Platform: {}", platform.platform())
21052130
logger.info("Python: {}", sys.version)
2106-
logger.info("Architecture: {}", "64-bit" if sys.maxsize > 2**32 else "32-bit")
2131+
logger.info("Architecture: {}", "64-bit" if sys.maxsize >
2132+
2**32 else "32-bit")
21072133
if '__compiled__' in globals():
21082134
logger.info("Running in Nuitka-compiled mode")
21092135
logger.info("Nuitka version: {}", version('nuitka'))

poetry.lock

Lines changed: 9 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ package-mode = false
88
[tool.poetry.dependencies]
99
python = ">=3.8, <3.9"
1010
Pillow = ">=9.0.0"
11-
# pygubu = ">=0.23"
12-
pygubu = "0.35.6"
11+
pygubu = ">=0.23"
1312
mido = ">=1.2.9"
1413
lxml = ">=4.9.1"
1514
lark = ">=1.0.0"

0 commit comments

Comments
 (0)