Compare commits
No commits in common. "trunk" and "iss10" have entirely different histories.
27 changed files with 301 additions and 301 deletions
2
Makefile
2
Makefile
|
|
@ -1,2 +1,2 @@
|
||||||
install:
|
install:
|
||||||
cp dist/pyinstaller/manylinux_2_39_x86_64/doomcc /home/tynan/.local/bin/dcc
|
cp dist/pyinstaller/manylinux_2_39_x86_64/dcc /home/tynan/.local/bin/dcc
|
||||||
|
|
|
||||||
5
dcc/__main__.py
Normal file
5
dcc/__main__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
import sys
|
||||||
|
from dcc.main import main
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main(sys.argv[1:]))
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import av
|
import av
|
||||||
import copy
|
import copy
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import enum
|
import enum
|
||||||
import fractions
|
import fractions
|
||||||
import io
|
import io
|
||||||
|
|
@ -16,7 +16,7 @@ class State(enum.Enum):
|
||||||
DONE = 3
|
DONE = 3
|
||||||
|
|
||||||
|
|
||||||
class Concat(doomcc.doom_base.Wad):
|
class Concat(dcc.doom_base.Wad):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("start_map")
|
parser.add_argument("start_map")
|
||||||
|
|
@ -34,10 +34,12 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
+ f"to{parsed_args.end_map}"
|
+ f"to{parsed_args.end_map}"
|
||||||
)
|
)
|
||||||
output = av.open(
|
output = av.open(
|
||||||
self.fabricate.joinpath(parsed_args.wad).joinpath(f"{fn_base}.mp4"), "w"
|
self.fabricate.joinpath(parsed_args.wad).joinpath(
|
||||||
|
f"{fn_base}.mp4"), "w"
|
||||||
)
|
)
|
||||||
summary_file = open(
|
summary_file = open(
|
||||||
self.fabricate.joinpath(parsed_args.wad).joinpath(f"{fn_base}.txt"), "w"
|
self.fabricate.joinpath(parsed_args.wad).joinpath(
|
||||||
|
f"{fn_base}.txt"), "w"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._offset = 0
|
self._offset = 0
|
||||||
|
|
@ -64,13 +66,11 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
start_time = self._offset / 1000000
|
start_time = self._offset / 1000000
|
||||||
text = self._add_chunk(
|
text = self._add_chunk(
|
||||||
videodir.joinpath(f"{parsed_args.wad}_map{idx}.mp4"),
|
videodir.joinpath(f"{parsed_args.wad}_map{idx}.mp4"),
|
||||||
output,
|
output, not parsed_args.nooverlay
|
||||||
not parsed_args.nooverlay,
|
|
||||||
)
|
)
|
||||||
list.append(
|
list.append(
|
||||||
summary,
|
summary, f"{text} {math.floor(start_time / 60):02}:"
|
||||||
f"{text} {math.floor(start_time / 60):02}:"
|
+ f"{math.floor(start_time % 60):02}"
|
||||||
+ f"{math.floor(start_time % 60):02}",
|
|
||||||
)
|
)
|
||||||
if state == State.DONE:
|
if state == State.DONE:
|
||||||
break
|
break
|
||||||
|
|
@ -82,7 +82,8 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
|
|
||||||
def _add_chunk(self, v, output, overlay):
|
def _add_chunk(self, v, output, overlay):
|
||||||
chunk = av.open(v)
|
chunk = av.open(v)
|
||||||
if not (len(chunk.streams.video) == 1 and len(chunk.streams.audio) == 1):
|
if not (len(chunk.streams.video) == 1
|
||||||
|
and len(chunk.streams.audio) == 1):
|
||||||
raise Exception(
|
raise Exception(
|
||||||
f"irregular chunk {v}: streams {chunk.streams} "
|
f"irregular chunk {v}: streams {chunk.streams} "
|
||||||
+ f"(expected 1 video & 1 audio)"
|
+ f"(expected 1 video & 1 audio)"
|
||||||
|
|
@ -95,11 +96,16 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
text = ""
|
text = ""
|
||||||
if overlay:
|
if overlay:
|
||||||
img = wand.image.Image(
|
img = wand.image.Image(
|
||||||
height=chunk.streams[0].height, width=chunk.streams[0].width
|
height=chunk.streams[0].height,
|
||||||
|
width=chunk.streams[0].width
|
||||||
)
|
)
|
||||||
mapstring = v.name[-6:-4]
|
mapstring = v.name[-6:-4]
|
||||||
text = self._config["map_names"][f"map{mapstring}"]
|
text = self._config["map_names"][f"map{mapstring}"]
|
||||||
self.draw_text(img, f"MAP{mapstring}: {text}", font_size=120)
|
self.draw_text(
|
||||||
|
img,
|
||||||
|
f"MAP{mapstring}: {text}",
|
||||||
|
font_size=120
|
||||||
|
)
|
||||||
img.trim(reset_coords=True)
|
img.trim(reset_coords=True)
|
||||||
img.border("graya(25%, 25%)", 10, 10)
|
img.border("graya(25%, 25%)", 10, 10)
|
||||||
img.border(self.thumbnail_text_stroke, 16, 16)
|
img.border(self.thumbnail_text_stroke, 16, 16)
|
||||||
|
|
@ -107,14 +113,17 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
# multiple of 8. dude whyyyyyyy
|
# multiple of 8. dude whyyyyyyy
|
||||||
padfactor = 8
|
padfactor = 8
|
||||||
img.border("transparent", padfactor, 0)
|
img.border("transparent", padfactor, 0)
|
||||||
img.crop(width=img.width - img.width % padfactor, height=img.height)
|
img.crop(
|
||||||
|
width=img.width - img.width % padfactor,
|
||||||
|
height=img.height
|
||||||
|
)
|
||||||
|
|
||||||
if len(output.streams.get()) == 0:
|
if len(output.streams.get()) == 0:
|
||||||
# We can't use the input stream as a template here; it doesn't
|
# We can't use the input stream as a template here; it doesn't
|
||||||
# have everything needed to do encoding and will fail
|
# have everything needed to do encoding and will fail
|
||||||
# mysteriously later.
|
# mysteriously later.
|
||||||
vs = chunk.streams.video[0]
|
vs = chunk.streams.video[0]
|
||||||
vr = int(vs.time_base.denominator / vs.time_base.numerator)
|
vr = int(vs.time_base.denominator/vs.time_base.numerator)
|
||||||
ovs = output.add_stream("h264", rate=vr)
|
ovs = output.add_stream("h264", rate=vr)
|
||||||
ovs.extradata = copy.deepcopy(vs.extradata)
|
ovs.extradata = copy.deepcopy(vs.extradata)
|
||||||
ovs.height = vs.height
|
ovs.height = vs.height
|
||||||
|
|
@ -136,10 +145,12 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
oas.bit_rate = astr.bit_rate
|
oas.bit_rate = astr.bit_rate
|
||||||
|
|
||||||
src = ograph.add_buffer(
|
src = ograph.add_buffer(
|
||||||
template=chunk.streams.video[0], time_base=chunk.streams.video[0].time_base
|
template=chunk.streams.video[0],
|
||||||
|
time_base=chunk.streams.video[0].time_base
|
||||||
)
|
)
|
||||||
asrc = ograph.add_abuffer(
|
asrc = ograph.add_abuffer(
|
||||||
template=chunk.streams.audio[0], time_base=chunk.streams.audio[0].time_base
|
template=chunk.streams.audio[0],
|
||||||
|
time_base=chunk.streams.audio[0].time_base
|
||||||
)
|
)
|
||||||
# TODO: video fades are absolute relative to the input video; audio
|
# TODO: video fades are absolute relative to the input video; audio
|
||||||
# fades need to have their timestamps offset by the position in the
|
# fades need to have their timestamps offset by the position in the
|
||||||
|
|
@ -152,18 +163,19 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
iafade_start = self._offset * sample_rate / 1000000
|
iafade_start = self._offset * sample_rate / 1000000
|
||||||
iafade = ograph.add("afade", args=f"in:{iafade_start}:{sample_rate}")
|
iafade = ograph.add("afade", args=f"in:{iafade_start}:{sample_rate}")
|
||||||
oafade_start = (
|
oafade_start = (
|
||||||
self._offset + chunk.duration
|
(self._offset + chunk.duration) * sample_rate / 1000000
|
||||||
) * sample_rate / 1000000 - sample_rate
|
- sample_rate
|
||||||
|
)
|
||||||
oafade = ograph.add("afade", args=f"out:{oafade_start}:{sample_rate}")
|
oafade = ograph.add("afade", args=f"out:{oafade_start}:{sample_rate}")
|
||||||
|
|
||||||
if overlay:
|
if overlay:
|
||||||
overlay = ograph.add_buffer(
|
overlay = ograph.add_buffer(
|
||||||
width=img.width,
|
width=img.width, height=img.height,
|
||||||
height=img.height,
|
format="rgba", time_base=chunk.streams.video[0].time_base
|
||||||
format="rgba",
|
)
|
||||||
time_base=chunk.streams.video[0].time_base,
|
overlay_fo = ograph.add(
|
||||||
|
"fade", args=f"out:{4 * frame_rate}:{frame_rate}"
|
||||||
)
|
)
|
||||||
overlay_fo = ograph.add("fade", args=f"out:{4 * frame_rate}:{frame_rate}")
|
|
||||||
overlay.link_to(overlay_fo, 0, 0)
|
overlay.link_to(overlay_fo, 0, 0)
|
||||||
composite = ograph.add("overlay", args="x=4:y=4")
|
composite = ograph.add("overlay", args="x=4:y=4")
|
||||||
src.link_to(composite, 0, 0)
|
src.link_to(composite, 0, 0)
|
||||||
|
|
@ -182,8 +194,9 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
for packet in chunk.demux():
|
for packet in chunk.demux():
|
||||||
if packet.dts is None:
|
if packet.dts is None:
|
||||||
continue
|
continue
|
||||||
pof = (self._offset * packet.time_base.denominator) / (
|
pof = (
|
||||||
packet.time_base.numerator * 1000000
|
(self._offset * packet.time_base.denominator)
|
||||||
|
/ (packet.time_base.numerator * 1000000)
|
||||||
)
|
)
|
||||||
packet.dts += pof
|
packet.dts += pof
|
||||||
packet.pts += pof
|
packet.pts += pof
|
||||||
|
|
@ -208,7 +221,9 @@ class Concat(doomcc.doom_base.Wad):
|
||||||
|
|
||||||
def _make_text_frame(self, img, ifr):
|
def _make_text_frame(self, img, ifr):
|
||||||
# We need to give each frame its own memory it can own.
|
# We need to give each frame its own memory it can own.
|
||||||
text_frame = av.video.frame.VideoFrame(img.width, img.height, format="rgba")
|
text_frame = av.video.frame.VideoFrame(
|
||||||
|
img.width, img.height, format="rgba"
|
||||||
|
)
|
||||||
text_frame.planes[0].update(img.make_blob(format="rgba"))
|
text_frame.planes[0].update(img.make_blob(format="rgba"))
|
||||||
text_frame.pts = ifr.pts
|
text_frame.pts = ifr.pts
|
||||||
text_frame.dts = ifr.dts
|
text_frame.dts = ifr.dts
|
||||||
|
|
@ -12,15 +12,13 @@ class ConfigBase(object):
|
||||||
self._doom = pathlib.Path(parsed_args.doom)
|
self._doom = pathlib.Path(parsed_args.doom)
|
||||||
self._config_name = parsed_args.config_name
|
self._config_name = parsed_args.config_name
|
||||||
self._config = tomlkit.toml_file.TOMLFile(
|
self._config = tomlkit.toml_file.TOMLFile(
|
||||||
self.doom.joinpath(self.config_name)
|
self.doom.joinpath(self.config_name)).read()
|
||||||
).read()
|
|
||||||
|
|
||||||
self._dsda = self._config.get("dsda")
|
self._dsda = self._config.get("dsda")
|
||||||
if self._dsda is None:
|
if self._dsda is None:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"required key 'dsda' not set in config "
|
"required key 'dsda' not set in config "
|
||||||
+ f"{self.doom.joinpath(self.config_name)}."
|
+ f"{self.doom.joinpath(self.config_name)}.")
|
||||||
)
|
|
||||||
for d in ("iwads", "pwads", "demos", "fabricate"):
|
for d in ("iwads", "pwads", "demos", "fabricate"):
|
||||||
self._init_attr([d], d, fn=self.doom.joinpath)
|
self._init_attr([d], d, fn=self.doom.joinpath)
|
||||||
|
|
||||||
|
|
@ -31,7 +29,10 @@ class ConfigBase(object):
|
||||||
self._init_attr(["thumbnail", "text_fill"], "white")
|
self._init_attr(["thumbnail", "text_fill"], "white")
|
||||||
self._init_attr(["thumbnail", "text_stroke"], "red")
|
self._init_attr(["thumbnail", "text_stroke"], "red")
|
||||||
self._init_attr(["thumbnail", "overlay_name"], "M_DOOM_scaled.png")
|
self._init_attr(["thumbnail", "overlay_name"], "M_DOOM_scaled.png")
|
||||||
self._init_attr(["fetch", "mirror"], "https://youfailit.net/pub/idgames")
|
self._init_attr(
|
||||||
|
["fetch", "mirror"],
|
||||||
|
"https://youfailit.net/pub/idgames"
|
||||||
|
)
|
||||||
|
|
||||||
def _init_attr(self, what, default, fn=lambda x: x):
|
def _init_attr(self, what, default, fn=lambda x: x):
|
||||||
propname = "_".join(what)
|
propname = "_".join(what)
|
||||||
|
|
@ -44,7 +45,8 @@ class ConfigBase(object):
|
||||||
|
|
||||||
setattr(self, f"_{propname}", fn(val))
|
setattr(self, f"_{propname}", fn(val))
|
||||||
setattr(
|
setattr(
|
||||||
type(self), propname, property(lambda self: getattr(self, f"_{propname}"))
|
type(self), propname,
|
||||||
|
property(lambda self: getattr(self, f"_{propname}"))
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -63,10 +65,10 @@ class ConfigBase(object):
|
||||||
def get_parser_func(toc):
|
def get_parser_func(toc):
|
||||||
def add_common_args(self, prog_name):
|
def add_common_args(self, prog_name):
|
||||||
parser = super(toc, self).get_parser(prog_name)
|
parser = super(toc, self).get_parser(prog_name)
|
||||||
parser.add_argument("--doom", default=pathlib.Path.home().joinpath("doom"))
|
parser.add_argument(
|
||||||
|
"--doom", default=pathlib.Path.home().joinpath("doom"))
|
||||||
parser.add_argument("--config-name", default="config.toml")
|
parser.add_argument("--config-name", default="config.toml")
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
return add_common_args
|
return add_common_args
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import omg
|
import omg
|
||||||
import tomlkit.toml_file
|
import tomlkit.toml_file
|
||||||
|
|
||||||
|
|
||||||
class Configure(doomcc.doom_base.Wad):
|
class Configure(dcc.doom_base.Wad):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("--complevel", "--cl")
|
parser.add_argument("--complevel", "--cl")
|
||||||
|
|
@ -22,10 +22,12 @@ class Configure(doomcc.doom_base.Wad):
|
||||||
wad = omg.WadIO(w)
|
wad = omg.WadIO(w)
|
||||||
complevel = wad.read("COMPLVL").decode("ascii").strip()
|
complevel = wad.read("COMPLVL").decode("ascii").strip()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Wad {w} likely has no lump COMPLVL (exception {e})")
|
print(
|
||||||
|
f"Wad {w} likely has no lump COMPLVL (exception {e})")
|
||||||
if complevel is None:
|
if complevel is None:
|
||||||
complevel = input("Complevel? ")
|
complevel = input("Complevel? ")
|
||||||
|
|
||||||
|
|
||||||
doc = tomlkit.document()
|
doc = tomlkit.document()
|
||||||
doc.add("complevel", complevel)
|
doc.add("complevel", complevel)
|
||||||
if parsed_args.iwad is not None:
|
if parsed_args.iwad is not None:
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from cliff.command import Command
|
from cliff.command import Command
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import tomlkit
|
import tomlkit
|
||||||
|
|
||||||
|
|
||||||
class Wad(doomcc.config.Base):
|
class Wad(dcc.config.Base):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("wad")
|
parser.add_argument("wad")
|
||||||
|
|
@ -70,8 +70,9 @@ class Wad(doomcc.config.Base):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def thumb_overlay_path(self):
|
def thumb_overlay_path(self):
|
||||||
return self._ensure(self.fabricate.joinpath(self.wad)).joinpath(
|
return (
|
||||||
self.thumbnail_overlay_name
|
self._ensure(self.fabricate.joinpath(self.wad))
|
||||||
|
.joinpath(self.thumbnail_overlay_name)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -128,51 +129,55 @@ class WadMap(Wad):
|
||||||
|
|
||||||
def demo_in_path(self):
|
def demo_in_path(self):
|
||||||
candidates = [
|
candidates = [
|
||||||
x for x in self.demos.joinpath(self.wad).glob(self._file_base("*.lmp"))
|
x for x in self.demos.joinpath(self.wad)
|
||||||
|
.glob(self._file_base("*.lmp"))
|
||||||
]
|
]
|
||||||
if len(candidates) == 0:
|
if len(candidates) == 0:
|
||||||
raise Exception(
|
raise Exception(
|
||||||
"no suitable demo candidates for WAD {} MAP {}{}.".format(
|
"no suitable demo candidates for WAD {} MAP {} name {}."
|
||||||
self.wad,
|
.format(self.wad, self.map, self.name_string)
|
||||||
self.map,
|
|
||||||
f" name {self._name}" if self._name else "",
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
if len(candidates) == 1:
|
if len(candidates) == 1:
|
||||||
return candidates[0]
|
return candidates[0]
|
||||||
return sorted(filter(lambda s: re.search("-", str(s)), candidates))[-1]
|
return sorted(filter(lambda s: re.search("-", str(s)), candidates))[-1]
|
||||||
|
|
||||||
def dsda_text_path(self):
|
def dsda_text_path(self):
|
||||||
return self._ensure(self.demos.joinpath(self.wad)).joinpath(
|
return (
|
||||||
self._file_base(".txt")
|
self._ensure(self.demos.joinpath(self.wad))
|
||||||
|
.joinpath(self._file_base(".txt"))
|
||||||
)
|
)
|
||||||
|
|
||||||
def video_path(self):
|
def video_path(self):
|
||||||
return self._ensure(self.fabricate.joinpath(self.wad)).joinpath(
|
return (
|
||||||
self._file_base(".mp4")
|
self._ensure(self.fabricate.joinpath(self.wad))
|
||||||
|
.joinpath(self._file_base(".mp4"))
|
||||||
)
|
)
|
||||||
|
|
||||||
def demo_out_path(self):
|
def demo_out_path(self):
|
||||||
return self._ensure(self.demos.joinpath(self.wad)).joinpath(
|
return (
|
||||||
self._file_base(".lmp")
|
self._ensure(self.demos.joinpath(self.wad))
|
||||||
|
.joinpath(self._file_base(".lmp"))
|
||||||
)
|
)
|
||||||
|
|
||||||
def target_bucket(self):
|
def target_bucket(self):
|
||||||
return "doom/" + self._file_base(".lmp")
|
return "doom/" + self._file_base(".lmp")
|
||||||
|
|
||||||
def base_thumb_path(self):
|
def base_thumb_path(self):
|
||||||
return self._ensure(self.fabricate.joinpath(self.wad)).joinpath(
|
return (
|
||||||
self._file_base("_base.png")
|
self._ensure(self.fabricate.joinpath(self.wad))
|
||||||
|
.joinpath(self._file_base("_base.png"))
|
||||||
)
|
)
|
||||||
|
|
||||||
def text_thumb_path(self):
|
def text_thumb_path(self):
|
||||||
return self._ensure(self.fabricate.joinpath(self.wad)).joinpath(
|
return (
|
||||||
self._file_base("_text.png")
|
self._ensure(self.fabricate.joinpath(self.wad))
|
||||||
|
.joinpath(self._file_base("_text.png"))
|
||||||
)
|
)
|
||||||
|
|
||||||
def thumb_path(self):
|
def thumb_path(self):
|
||||||
return self._ensure(self.fabricate.joinpath(self.wad)).joinpath(
|
return (
|
||||||
self._file_base("_thumb.png")
|
self._ensure(self.fabricate.joinpath(self.wad))
|
||||||
|
.joinpath(self._file_base("_thumb.png"))
|
||||||
)
|
)
|
||||||
|
|
||||||
def _file_base(self, ext):
|
def _file_base(self, ext):
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
|
|
@ -7,7 +7,7 @@ import subprocess
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
|
|
||||||
class DSDA(doomcc.doom_base.WadMap):
|
class DSDA(dcc.doom_base.WadMap):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("-s", "--single", action="store_true")
|
parser.add_argument("-s", "--single", action="store_true")
|
||||||
|
|
@ -22,9 +22,10 @@ class DSDA(doomcc.doom_base.WadMap):
|
||||||
if shutil.which("xvfb-run") is not None:
|
if shutil.which("xvfb-run") is not None:
|
||||||
command = ["xvfb-run"] + command
|
command = ["xvfb-run"] + command
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
command
|
command + self.dsda_preamble(warp=False) + [
|
||||||
+ self.dsda_preamble(warp=False)
|
"-fastdemo", dip, "-nosound",
|
||||||
+ ["-fastdemo", dip, "-nosound", "-skiptic", "-1", "-export_text_file"]
|
"-skiptic", "-1", "-export_text_file"
|
||||||
|
]
|
||||||
)
|
)
|
||||||
editor = "nano"
|
editor = "nano"
|
||||||
if "EDITOR" in os.environ:
|
if "EDITOR" in os.environ:
|
||||||
|
|
@ -37,7 +38,7 @@ class DSDA(doomcc.doom_base.WadMap):
|
||||||
else:
|
else:
|
||||||
fh1 = self.wad[0:2] + self.map
|
fh1 = self.wad[0:2] + self.map
|
||||||
if parsed_args.single:
|
if parsed_args.single:
|
||||||
fh1 = self.wad[0 : min(len(self.wad), 4)]
|
fh1 = self.wad[0:min(len(self.wad), 4)]
|
||||||
fh2 = ""
|
fh2 = ""
|
||||||
with open(dtp, mode="r") as f:
|
with open(dtp, mode="r") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
|
|
@ -45,7 +46,7 @@ class DSDA(doomcc.doom_base.WadMap):
|
||||||
m = re.search("[^0-9]*([0-9]*):([0-9]*).[0-9]*", line)
|
m = re.search("[^0-9]*([0-9]*):([0-9]*).[0-9]*", line)
|
||||||
if m is None:
|
if m is None:
|
||||||
continue
|
continue
|
||||||
fh2 = m[1] + m[2]
|
fh2 = m[1]+m[2]
|
||||||
if len(fh2) % 2 == 1:
|
if len(fh2) % 2 == 1:
|
||||||
fh2 = "0" + fh2
|
fh2 = "0" + fh2
|
||||||
break
|
break
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class Eureka(doomcc.doom_base.WadMap):
|
class Eureka(dcc.doom_base.WadMap):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("--main")
|
parser.add_argument("--main")
|
||||||
|
|
@ -24,11 +24,7 @@ class Eureka(doomcc.doom_base.WadMap):
|
||||||
if complevel == "11" or complevel == "21":
|
if complevel == "11" or complevel == "21":
|
||||||
port = "mbf"
|
port = "mbf"
|
||||||
|
|
||||||
os.execvp(
|
os.execvp("eureka",
|
||||||
"eureka",
|
["eureka"] + ["-iwad", iwad] + ["-w", parsed_args.map]
|
||||||
["eureka"]
|
+ ["-p", port] + [mw]
|
||||||
+ ["-iwad", iwad]
|
|
||||||
+ ["-w", parsed_args.map]
|
|
||||||
+ ["-p", port]
|
|
||||||
+ [mw],
|
|
||||||
)
|
)
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import omg
|
import omg
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import wand.color
|
import wand.color
|
||||||
import wand.image
|
import wand.image
|
||||||
|
|
||||||
|
|
||||||
class Extract(doomcc.doom_base.Wad):
|
class Extract(dcc.doom_base.Wad):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("lump")
|
parser.add_argument('lump')
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
|
|
@ -24,9 +24,8 @@ class Extract(doomcc.doom_base.Wad):
|
||||||
) as img:
|
) as img:
|
||||||
img.transparent_color(wand.color.Color("#ff00ff"), 0.0)
|
img.transparent_color(wand.color.Color("#ff00ff"), 0.0)
|
||||||
img.save(
|
img.save(
|
||||||
filename=self.fabricate.joinpath(parsed_args.wad).joinpath(
|
filename=self.fabricate.joinpath(parsed_args.wad)
|
||||||
parsed_args.lump + ".png"
|
.joinpath(parsed_args.lump + ".png")
|
||||||
)
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -36,5 +35,6 @@ class Extract(doomcc.doom_base.Wad):
|
||||||
)
|
)
|
||||||
|
|
||||||
print(
|
print(
|
||||||
f"Lump {parsed_args.lump} not found in any wad in " + f"{parsed_args.wad}"
|
f"Lump {parsed_args.lump} not found in any wad in "
|
||||||
|
+ f"{parsed_args.wad}"
|
||||||
)
|
)
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
import contextlib
|
import contextlib
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
import tempfile
|
import tempfile
|
||||||
|
|
||||||
|
|
||||||
class Fabricate(doomcc.doom_base.WadMap):
|
class Fabricate(dcc.doom_base.WadMap):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("--fg", action="store_true")
|
parser.add_argument("--fg", action="store_true")
|
||||||
|
|
@ -18,12 +18,10 @@ class Fabricate(doomcc.doom_base.WadMap):
|
||||||
command = [self.dsda]
|
command = [self.dsda]
|
||||||
if not parsed_args.fg and shutil.which("xvfb-run") is not None:
|
if not parsed_args.fg and shutil.which("xvfb-run") is not None:
|
||||||
command = ["xvfb-run"] + command
|
command = ["xvfb-run"] + command
|
||||||
os.execvp(
|
os.execvp(command[0],
|
||||||
command[0],
|
command + self.dsda_preamble()
|
||||||
command
|
|
||||||
+ self.dsda_preamble()
|
|
||||||
+ ["-timedemo", self.demo_in_path()]
|
+ ["-timedemo", self.demo_in_path()]
|
||||||
+ ["-viddump", self.video_path()],
|
+ ["-viddump", self.video_path()]
|
||||||
)
|
)
|
||||||
|
|
||||||
def options_dict(self):
|
def options_dict(self):
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import io
|
import io
|
||||||
import json
|
import json
|
||||||
import pathlib
|
import pathlib
|
||||||
|
|
@ -9,7 +9,7 @@ import urllib.request
|
||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
|
|
||||||
class Fetch(doomcc.config.Base):
|
class Fetch(dcc.config.Base):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("id_or_name")
|
parser.add_argument("id_or_name")
|
||||||
|
|
@ -21,12 +21,14 @@ class Fetch(doomcc.config.Base):
|
||||||
idgames_id = self.search_idgames(parsed_args.id_or_name)
|
idgames_id = self.search_idgames(parsed_args.id_or_name)
|
||||||
|
|
||||||
reply = self.fetch_url(
|
reply = self.fetch_url(
|
||||||
"https://www.doomworld.com/idgames/api/"
|
"https://www.doomworld.com/idgames/api/" +
|
||||||
+ "api.php?action=get&id={}&out=json".format(idgames_id)
|
"api.php?action=get&id={}&out=json".format(idgames_id)
|
||||||
)
|
|
||||||
rpath = "/".join(
|
|
||||||
[self.fetch_mirror, reply["content"]["dir"], reply["content"]["filename"]]
|
|
||||||
)
|
)
|
||||||
|
rpath = "/".join([
|
||||||
|
self.fetch_mirror,
|
||||||
|
reply["content"]["dir"],
|
||||||
|
reply["content"]["filename"]
|
||||||
|
])
|
||||||
wad = reply["content"]["filename"][0:-4]
|
wad = reply["content"]["filename"][0:-4]
|
||||||
|
|
||||||
with urllib.request.urlopen(rpath) as response:
|
with urllib.request.urlopen(rpath) as response:
|
||||||
|
|
@ -36,8 +38,8 @@ class Fetch(doomcc.config.Base):
|
||||||
# TODO: explicit error handling. Let users choose when >1 result.
|
# TODO: explicit error handling. Let users choose when >1 result.
|
||||||
def search_idgames(self, wad):
|
def search_idgames(self, wad):
|
||||||
reply = self.fetch_url(
|
reply = self.fetch_url(
|
||||||
"https://www.doomworld.com/idgames/api/"
|
"https://www.doomworld.com/idgames/api/" +
|
||||||
+ "api.php?action=search&query={}&out=json".format(wad)
|
"api.php?action=search&query={}&out=json".format(wad)
|
||||||
)
|
)
|
||||||
if "content" not in reply:
|
if "content" not in reply:
|
||||||
sys.exit(f"No WAD named {wad} found on idgames.")
|
sys.exit(f"No WAD named {wad} found on idgames.")
|
||||||
|
|
@ -60,5 +62,8 @@ class Fetch(doomcc.config.Base):
|
||||||
if fetcher_path is None:
|
if fetcher_path is None:
|
||||||
raise Exception(f"Fetch util {fetcher} not found on PATH.")
|
raise Exception(f"Fetch util {fetcher} not found on PATH.")
|
||||||
|
|
||||||
proc = subprocess.run([fetcher_path, url], capture_output=True, check=True)
|
proc = subprocess.run(
|
||||||
|
[fetcher_path, url],
|
||||||
|
capture_output=True, check=True
|
||||||
|
)
|
||||||
return json.loads(proc.stdout)
|
return json.loads(proc.stdout)
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class List(doomcc.config.ListerBase):
|
class List(dcc.config.ListerBase):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("target")
|
parser.add_argument("target")
|
||||||
|
|
@ -12,19 +12,22 @@ class List(doomcc.config.ListerBase):
|
||||||
match parsed_args.target:
|
match parsed_args.target:
|
||||||
case "pwads":
|
case "pwads":
|
||||||
return (
|
return (
|
||||||
("pwads",),
|
("pwads",), sorted(
|
||||||
sorted((x.name,) for x in os.scandir(self.pwads) if x.is_dir()),
|
(x.name,) for x in os.scandir(self.pwads) if x.is_dir()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
case "iwads":
|
case "iwads":
|
||||||
return (
|
return (
|
||||||
("iwads",),
|
("iwads",), sorted(
|
||||||
sorted((x.name,) for x in os.scandir(self.iwads) if x.is_file()),
|
(x.name,) for x in
|
||||||
|
os.scandir(self.iwads) if x.is_file()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
case _:
|
case _:
|
||||||
raise Exception(f"unknown target {parsed_args.target}")
|
raise Exception(f"unknown target {parsed_args.target}")
|
||||||
|
|
||||||
|
|
||||||
class WadList(doomcc.config.ListerBase):
|
class WadList(dcc.config.ListerBase):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("wad")
|
parser.add_argument("wad")
|
||||||
|
|
@ -32,12 +35,11 @@ class WadList(doomcc.config.ListerBase):
|
||||||
|
|
||||||
def _get_results(self, name, base, wad, ext):
|
def _get_results(self, name, base, wad, ext):
|
||||||
return (
|
return (
|
||||||
(name,),
|
(name,), sorted(
|
||||||
sorted(
|
(x.name,) for x in
|
||||||
(x.name,)
|
os.scandir(base.joinpath(wad))
|
||||||
for x in os.scandir(base.joinpath(wad))
|
|
||||||
if x.name.endswith(ext)
|
if x.name.endswith(ext)
|
||||||
),
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -48,4 +50,6 @@ class ListDemos(WadList):
|
||||||
|
|
||||||
class ListVideos(WadList):
|
class ListVideos(WadList):
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
return self._get_results("videos", self.fabricate, parsed_args.wad, ".mp4")
|
return self._get_results(
|
||||||
|
"videos", self.fabricate, parsed_args.wad, ".mp4"
|
||||||
|
)
|
||||||
72
dcc/main.py
Normal file
72
dcc/main.py
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from cliff.app import App
|
||||||
|
from cliff.commandmanager import CommandManager
|
||||||
|
|
||||||
|
import dcc.concat
|
||||||
|
import dcc.configure
|
||||||
|
import dcc.dsda
|
||||||
|
import dcc.eureka
|
||||||
|
import dcc.extract
|
||||||
|
import dcc.fabricate
|
||||||
|
import dcc.fetch
|
||||||
|
import dcc.ls
|
||||||
|
import dcc.pb
|
||||||
|
import dcc.play
|
||||||
|
import dcc.put
|
||||||
|
import dcc.record
|
||||||
|
import dcc.rib
|
||||||
|
import dcc.ss
|
||||||
|
import dcc.text
|
||||||
|
import dcc.thumb
|
||||||
|
|
||||||
|
|
||||||
|
class DCC(App):
|
||||||
|
def __init__(self):
|
||||||
|
cm = CommandManager(None)
|
||||||
|
commands = {
|
||||||
|
"concat": dcc.concat.Concat,
|
||||||
|
"configure": dcc.configure.Configure,
|
||||||
|
"dsda": dcc.dsda.DSDA,
|
||||||
|
"eureka": dcc.eureka.Eureka,
|
||||||
|
"extract": dcc.extract.Extract,
|
||||||
|
"fabricate": dcc.fabricate.Fabricate,
|
||||||
|
"fetch": dcc.fetch.Fetch,
|
||||||
|
"ls": dcc.ls.List,
|
||||||
|
"ls demos": dcc.ls.ListDemos,
|
||||||
|
"ls videos": dcc.ls.ListVideos,
|
||||||
|
"pb": dcc.pb.PB,
|
||||||
|
"play": dcc.play.Play,
|
||||||
|
"put": dcc.put.Put,
|
||||||
|
"record": dcc.record.Record,
|
||||||
|
"rib": dcc.rib.RIB,
|
||||||
|
"ss": dcc.ss.SS,
|
||||||
|
"text": dcc.text.Text,
|
||||||
|
"thumb": dcc.thumb.Thumb,
|
||||||
|
}
|
||||||
|
for n, c in commands.items():
|
||||||
|
cm.add_command(n, c)
|
||||||
|
super().__init__(
|
||||||
|
description="Doom Command Center",
|
||||||
|
version="0.0.1",
|
||||||
|
command_manager=cm,
|
||||||
|
deferred_help=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
def initialize_app(self, argv):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def prepare_to_run_command(self, cmd):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def clean_up(self, cmd, result, err):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main(argv=sys.argv[1:]):
|
||||||
|
dcc = DCC()
|
||||||
|
return dcc.run(argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
sys.exit(main())
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class PB(doomcc.doom_base.WadMap):
|
class PB(dcc.doom_base.WadMap):
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
os.execvp("ffplay", ["ffplay", self.video_path()])
|
os.execvp("ffplay", ["ffplay", self.video_path()])
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class Play(doomcc.doom_base.WadMap):
|
class Play(dcc.doom_base.WadMap):
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
os.execv(self.dsda, [self.dsda] + self.dsda_preamble())
|
os.execv(self.dsda, [self.dsda] + self.dsda_preamble())
|
||||||
|
|
@ -1,22 +1,23 @@
|
||||||
import boto3
|
import boto3
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
|
|
||||||
|
|
||||||
class Put(doomcc.doom_base.WadMap):
|
class Put(dcc.doom_base.WadMap):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
# TODO: accept configuration for bucket name
|
# TODO: accept configuration for bucket name
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
s3_client = boto3.client("s3")
|
s3_client = boto3.client('s3')
|
||||||
demo = self.demo_in_path()
|
demo = self.demo_in_path()
|
||||||
bucket = self.target_bucket()
|
bucket = self.target_bucket()
|
||||||
print("Uploading {} to bucket {}.".format(demo, bucket))
|
print("Uploading {} to bucket {}.".format(demo, bucket))
|
||||||
s3_client.upload_file(
|
s3_client.upload_file(
|
||||||
demo,
|
demo, 'yrriban', bucket,
|
||||||
"yrriban",
|
ExtraArgs={
|
||||||
bucket,
|
'ContentType': 'binary/octet-stream',
|
||||||
ExtraArgs={"ContentType": "binary/octet-stream", "ACL": "public-read"},
|
'ACL': 'public-read'
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
||||||
class Record(doomcc.doom_base.WadMap):
|
class Record(dcc.doom_base.WadMap):
|
||||||
def take_action(self, parsed_args):
|
def take_action(self, parsed_args):
|
||||||
os.execv(
|
os.execv(self.dsda,
|
||||||
self.dsda,
|
[self.dsda] + self.dsda_preamble() +
|
||||||
[self.dsda] + self.dsda_preamble() + ["-record", self.demo_out_path()],
|
["-record", self.demo_out_path()]
|
||||||
)
|
)
|
||||||
|
|
||||||
def options_dict(self):
|
def options_dict(self):
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import pathlib
|
import pathlib
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
class RIB(doomcc.doom_base.WadMap):
|
class RIB(dcc.doom_base.WadMap):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("-s", "--secs_before", type=int, default=10)
|
parser.add_argument("-s", "--secs_before", type=int, default=10)
|
||||||
|
|
@ -16,10 +16,10 @@ class RIB(doomcc.doom_base.WadMap):
|
||||||
demo = ""
|
demo = ""
|
||||||
dt = 0
|
dt = 0
|
||||||
demodir = (
|
demodir = (
|
||||||
pathlib.Path.home()
|
pathlib.Path.home() /
|
||||||
/ ".dsda-doom"
|
".dsda-doom" /
|
||||||
/ "dsda_doom_data"
|
"dsda_doom_data" /
|
||||||
/ self.iwad_path.stem.lower()
|
self.iwad_path.stem.lower()
|
||||||
)
|
)
|
||||||
for w in self.load_order():
|
for w in self.load_order():
|
||||||
demodir = demodir.joinpath(w.stem.lower())
|
demodir = demodir.joinpath(w.stem.lower())
|
||||||
|
|
@ -41,10 +41,8 @@ class RIB(doomcc.doom_base.WadMap):
|
||||||
+ f"and map {parsed_args.map} (tried to look in {demodir})"
|
+ f"and map {parsed_args.map} (tried to look in {demodir})"
|
||||||
)
|
)
|
||||||
|
|
||||||
os.execv(
|
os.execv(self.dsda,
|
||||||
self.dsda,
|
[self.dsda] + self.dsda_preamble(warp=False)
|
||||||
[self.dsda]
|
|
||||||
+ self.dsda_preamble(warp=False)
|
|
||||||
+ ["-playdemo", demo]
|
+ ["-playdemo", demo]
|
||||||
+ ["-skiptic", str(-35 * parsed_args.secs_before)],
|
+ ["-skiptic", str(-35 * parsed_args.secs_before)]
|
||||||
)
|
)
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
from tkinter import messagebox
|
from tkinter import messagebox
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import sys
|
import sys
|
||||||
import wand.display
|
import wand.display
|
||||||
import wand.image
|
import wand.image
|
||||||
|
|
||||||
|
|
||||||
class SS(doomcc.doom_base.WadMap):
|
class SS(dcc.doom_base.WadMap):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("-g", "--gravity", default="center")
|
parser.add_argument("-g", "--gravity", default="center")
|
||||||
|
|
@ -22,11 +22,11 @@ class SS(doomcc.doom_base.WadMap):
|
||||||
height = self.thumbnail_height
|
height = self.thumbnail_height
|
||||||
with wand.image.Image(width=width, height=height, pseudo="x:") as img:
|
with wand.image.Image(width=width, height=height, pseudo="x:") as img:
|
||||||
img.reset_coords()
|
img.reset_coords()
|
||||||
if img.width < width or img.height < height:
|
if (img.width < width or img.height < height):
|
||||||
if not messagebox.askretrycancel(
|
if not messagebox.askretrycancel(
|
||||||
title="Doom Command Center",
|
title="DCC",
|
||||||
message=f"Image too small ({img.width}x{img.height})."
|
message=f"Image too small ({img.width}x{img.height})." +
|
||||||
+ "Try again?",
|
"Try again?"
|
||||||
):
|
):
|
||||||
sys.exit("Gave up trying to select an image.")
|
sys.exit("Gave up trying to select an image.")
|
||||||
return False
|
return False
|
||||||
|
|
@ -35,7 +35,7 @@ class SS(doomcc.doom_base.WadMap):
|
||||||
if not yolo:
|
if not yolo:
|
||||||
wand.display.display(img)
|
wand.display.display(img)
|
||||||
accepted = messagebox.askyesnocancel(
|
accepted = messagebox.askyesnocancel(
|
||||||
title="Doom Command Center", message="Is this image acceptable?"
|
title="DCC", message="Is this image acceptable?"
|
||||||
)
|
)
|
||||||
if accepted is None:
|
if accepted is None:
|
||||||
sys.exit("Gave up on image verification")
|
sys.exit("Gave up on image verification")
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import sys
|
import sys
|
||||||
import textwrap
|
import textwrap
|
||||||
import wand.drawing
|
import wand.drawing
|
||||||
|
|
@ -30,7 +30,9 @@ def draw_text(self, img, text, font_size=64, wrap_dist=0.75):
|
||||||
columns = len(wrapped_text)
|
columns = len(wrapped_text)
|
||||||
while columns > 0:
|
while columns > 0:
|
||||||
columns -= 1
|
columns -= 1
|
||||||
wrapped_text = "\n".join(textwrap.wrap(wrapped_text, columns))
|
wrapped_text = '\n'.join(
|
||||||
|
textwrap.wrap(wrapped_text, columns)
|
||||||
|
)
|
||||||
wrapped_width, _ = eval_metrics(wrapped_text)
|
wrapped_width, _ = eval_metrics(wrapped_text)
|
||||||
if wrapped_width <= target_width:
|
if wrapped_width <= target_width:
|
||||||
break
|
break
|
||||||
|
|
@ -41,20 +43,20 @@ def draw_text(self, img, text, font_size=64, wrap_dist=0.75):
|
||||||
)
|
)
|
||||||
textlines[idx] = wrapped_text
|
textlines[idx] = wrapped_text
|
||||||
|
|
||||||
wrapped_text = "\n".join(textlines)
|
wrapped_text = '\n'.join(textlines)
|
||||||
|
|
||||||
draw.text(5, int(draw.font_size) + 5, wrapped_text)
|
draw.text(5, int(draw.font_size) + 5, wrapped_text)
|
||||||
draw(img)
|
draw(img)
|
||||||
draw.stroke_color = wand.color.Color("none")
|
draw.stroke_color = wand.color.Color("none")
|
||||||
draw.stroke_width = 0
|
draw.stroke_width = 0
|
||||||
draw.text(5, int(draw.font_size) + 5, wrapped_text)
|
draw.text(5, int(draw.font_size)+5, wrapped_text)
|
||||||
draw(img)
|
draw(img)
|
||||||
|
|
||||||
|
|
||||||
doomcc.config.Base.draw_text = draw_text
|
dcc.config.Base.draw_text = draw_text
|
||||||
|
|
||||||
|
|
||||||
class Text(doomcc.doom_base.WadMap):
|
class Text(dcc.doom_base.WadMap):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("--nomap", action="store_true")
|
parser.add_argument("--nomap", action="store_true")
|
||||||
|
|
@ -72,9 +74,12 @@ class Text(doomcc.doom_base.WadMap):
|
||||||
text += "\n"
|
text += "\n"
|
||||||
text = "{}{}".format(text, parsed_args.demotype)
|
text = "{}{}".format(text, parsed_args.demotype)
|
||||||
with wand.image.Image(
|
with wand.image.Image(
|
||||||
height=self.thumbnail_height, width=self.thumbnail_width
|
height=self.thumbnail_height,
|
||||||
|
width=self.thumbnail_width
|
||||||
) as img:
|
) as img:
|
||||||
self.draw_text(img, text, wrap_dist=0.95)
|
self.draw_text(
|
||||||
|
img, text, wrap_dist=0.95
|
||||||
|
)
|
||||||
img.trim()
|
img.trim()
|
||||||
img.reset_coords()
|
img.reset_coords()
|
||||||
img.save(filename=self.text_thumb_path())
|
img.save(filename=self.text_thumb_path())
|
||||||
|
|
@ -86,7 +91,7 @@ class Text(doomcc.doom_base.WadMap):
|
||||||
map_names = self._config.get("map_names")
|
map_names = self._config.get("map_names")
|
||||||
if map_names is not None:
|
if map_names is not None:
|
||||||
text = map_names.get(f"map{mapnum}")
|
text = map_names.get(f"map{mapnum}")
|
||||||
if text is not None:
|
if text != "":
|
||||||
return text
|
return text
|
||||||
|
|
||||||
return input("Map Name? ")
|
return input("Map Name? ")
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import doomcc.config
|
import dcc.config
|
||||||
import doomcc.doom_base
|
import dcc.doom_base
|
||||||
import wand.color
|
import wand.color
|
||||||
import wand.image
|
import wand.image
|
||||||
|
|
||||||
|
|
||||||
class Thumb(doomcc.doom_base.WadMap):
|
class Thumb(dcc.doom_base.WadMap):
|
||||||
def get_parser(self, prog_name):
|
def get_parser(self, prog_name):
|
||||||
parser = super().get_parser(prog_name)
|
parser = super().get_parser(prog_name)
|
||||||
parser.add_argument("--index", action="store_true")
|
parser.add_argument("--index", action="store_true")
|
||||||
|
|
@ -17,7 +17,7 @@ class Thumb(doomcc.doom_base.WadMap):
|
||||||
overlay = self.thumb_overlay_path()
|
overlay = self.thumb_overlay_path()
|
||||||
with (
|
with (
|
||||||
wand.image.Image(filename=base) as bi,
|
wand.image.Image(filename=base) as bi,
|
||||||
wand.color.Color("transparent") as tc,
|
wand.color.Color("transparent") as tc
|
||||||
):
|
):
|
||||||
with wand.image.Image(filename=text) as ti:
|
with wand.image.Image(filename=text) as ti:
|
||||||
ti.border(tc, 5, 5)
|
ti.border(tc, 5, 5)
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
import sys
|
|
||||||
from doomcc.main import main
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main(sys.argv[1:]))
|
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
import sys
|
|
||||||
|
|
||||||
from cliff.app import App
|
|
||||||
from cliff.commandmanager import CommandManager
|
|
||||||
|
|
||||||
import doomcc.concat
|
|
||||||
import doomcc.configure
|
|
||||||
import doomcc.dsda
|
|
||||||
import doomcc.eureka
|
|
||||||
import doomcc.extract
|
|
||||||
import doomcc.fabricate
|
|
||||||
import doomcc.fetch
|
|
||||||
import doomcc.ls
|
|
||||||
import doomcc.pb
|
|
||||||
import doomcc.play
|
|
||||||
import doomcc.put
|
|
||||||
import doomcc.record
|
|
||||||
import doomcc.rib
|
|
||||||
import doomcc.ss
|
|
||||||
import doomcc.text
|
|
||||||
import doomcc.thumb
|
|
||||||
|
|
||||||
|
|
||||||
class DoomCC(App):
|
|
||||||
def __init__(self):
|
|
||||||
cm = CommandManager(None)
|
|
||||||
commands = {
|
|
||||||
"concat": doomcc.concat.Concat,
|
|
||||||
"configure": doomcc.configure.Configure,
|
|
||||||
"dsda": doomcc.dsda.DSDA,
|
|
||||||
"eureka": doomcc.eureka.Eureka,
|
|
||||||
"extract": doomcc.extract.Extract,
|
|
||||||
"fabricate": doomcc.fabricate.Fabricate,
|
|
||||||
"fetch": doomcc.fetch.Fetch,
|
|
||||||
"ls": doomcc.ls.List,
|
|
||||||
"ls demos": doomcc.ls.ListDemos,
|
|
||||||
"ls videos": doomcc.ls.ListVideos,
|
|
||||||
"pb": doomcc.pb.PB,
|
|
||||||
"play": doomcc.play.Play,
|
|
||||||
"put": doomcc.put.Put,
|
|
||||||
"record": doomcc.record.Record,
|
|
||||||
"rib": doomcc.rib.RIB,
|
|
||||||
"ss": doomcc.ss.SS,
|
|
||||||
"text": doomcc.text.Text,
|
|
||||||
"thumb": doomcc.thumb.Thumb,
|
|
||||||
}
|
|
||||||
for n, c in commands.items():
|
|
||||||
cm.add_command(n, c)
|
|
||||||
super().__init__(
|
|
||||||
description="Doom Command Center",
|
|
||||||
version="0.0.1",
|
|
||||||
command_manager=cm,
|
|
||||||
deferred_help=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
def initialize_app(self, argv):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def prepare_to_run_command(self, cmd):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def clean_up(self, cmd, result, err):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv=sys.argv[1:]):
|
|
||||||
doomcc = DoomCC()
|
|
||||||
return doomcc.run(argv)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
[project]
|
[project]
|
||||||
name = "doomcc"
|
name = "dcc"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "Doom Command Center"
|
description = "Doom Command Center"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "yrriban",email = "yrriban@gmail.com"}
|
{name = "yrriban",email = "yrriban@gmail.com"}
|
||||||
]
|
]
|
||||||
license = "MIT"
|
license = {text = "MIT"}
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.12"
|
requires-python = ">=3.12"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
|
@ -27,10 +27,10 @@ requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
doomcc = "doomcc.main:main"
|
dcc = "dcc.main:main"
|
||||||
|
|
||||||
[tool.poetry-pyinstaller-plugin.scripts]
|
[tool.poetry-pyinstaller-plugin.scripts]
|
||||||
doomcc = { source = "doomcc/main.py", type = "onefile" }
|
dcc = { source = "dcc/main.py", type = "onefile" }
|
||||||
|
|
||||||
[tool.poetry-pyinstaller-plugin.collect]
|
[tool.poetry-pyinstaller-plugin.collect]
|
||||||
all = ["cliff"]
|
all = ["cliff"]
|
||||||
|
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
import doomcc.doom_base
|
|
||||||
import os
|
|
||||||
import pathlib
|
|
||||||
import pytest
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
class Workbench:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def test_demo_in_path():
|
|
||||||
w = Workbench()
|
|
||||||
w.demo_in_path = lambda: doomcc.doom_base.WadMap.demo_in_path(w)
|
|
||||||
w._file_base = lambda path: doomcc.doom_base.WadMap._file_base(w, path)
|
|
||||||
w.wad = pathlib.Path("scythe")
|
|
||||||
w.map = "01"
|
|
||||||
w.name_string = "_index"
|
|
||||||
w._name = "index"
|
|
||||||
with tempfile.TemporaryDirectory() as td:
|
|
||||||
w.demos = pathlib.Path(td)
|
|
||||||
with pytest.raises(Exception):
|
|
||||||
w.demo_in_path()
|
|
||||||
|
|
||||||
dp = pathlib.Path(td).joinpath("scythe")
|
|
||||||
os.mkdir(dp)
|
|
||||||
dp.joinpath("scythe_map01_index.lmp").touch()
|
|
||||||
assert w.demo_in_path() == dp.joinpath("scythe_map01_index.lmp")
|
|
||||||
dp.joinpath("scythe_map01_index-00028.lmp").touch()
|
|
||||||
assert w.demo_in_path() == dp.joinpath("scythe_map01_index-00028.lmp")
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import cliff.app
|
import cliff.app
|
||||||
import doomcc.play
|
import dcc.play
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import mockito.matchers
|
import mockito.matchers
|
||||||
|
|
@ -26,15 +26,13 @@ def test_play(expect):
|
||||||
scp.mkdir()
|
scp.mkdir()
|
||||||
scp.joinpath("config.toml").touch()
|
scp.joinpath("config.toml").touch()
|
||||||
scp.joinpath("scythe.wad").touch()
|
scp.joinpath("scythe.wad").touch()
|
||||||
doomcc.play.Play.__init__ = lambda self: None
|
dcc.play.Play.__init__ = lambda self: None
|
||||||
doomcc.play.Play.get_epilog = lambda self: ""
|
dcc.play.Play.get_epilog = lambda self: ""
|
||||||
rig = doomcc.play.Play()
|
rig = dcc.play.Play()
|
||||||
rig._hooks = []
|
rig._hooks = []
|
||||||
parser = rig.get_parser("test_play")
|
parser = rig.get_parser("test_play")
|
||||||
parsed_args = parser.parse_args(args=["--doom", td, "scythe", "01"])
|
parsed_args = parser.parse_args(args=["--doom", td, "scythe", "01"])
|
||||||
with (
|
with expect(os, times=1).execv(
|
||||||
expect(os, times=1)
|
|
||||||
.execv(
|
|
||||||
tdp.joinpath("dsda-doom").joinpath("exe"),
|
tdp.joinpath("dsda-doom").joinpath("exe"),
|
||||||
[
|
[
|
||||||
tdp.joinpath("dsda-doom").joinpath("exe"),
|
tdp.joinpath("dsda-doom").joinpath("exe"),
|
||||||
|
|
@ -48,8 +46,6 @@ def test_play(expect):
|
||||||
"4",
|
"4",
|
||||||
"-warp",
|
"-warp",
|
||||||
"01",
|
"01",
|
||||||
],
|
]
|
||||||
)
|
).thenReturn(None):
|
||||||
.thenReturn(None)
|
|
||||||
):
|
|
||||||
assert rig.run(parsed_args) is None
|
assert rig.run(parsed_args) is None
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue