diff --git a/projects/common-api/src/main/java/dan200/computercraft/api/media/PrintoutContents.java b/projects/common-api/src/main/java/dan200/computercraft/api/media/PrintoutContents.java
new file mode 100644
index 0000000000..2825d796c7
--- /dev/null
+++ b/projects/common-api/src/main/java/dan200/computercraft/api/media/PrintoutContents.java
@@ -0,0 +1,46 @@
+// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
+//
+// SPDX-License-Identifier: MPL-2.0
+
+package dan200.computercraft.api.media;
+
+import dan200.computercraft.impl.ComputerCraftAPIService;
+import net.minecraft.world.item.ItemStack;
+
+import javax.annotation.Nullable;
+import java.util.stream.Stream;
+
+/**
+ * The contents of a page (or book) created by a ComputerCraft printer.
+ *
+ * @since 1.115
+ */
+@Nullable
+public interface PrintoutContents {
+ /**
+ * Get the (possibly empty) title for this printout.
+ *
+ * @return The title of this printout.
+ */
+ String getTitle();
+
+ /**
+ * Get the text contents of this printout, as a sequence of lines.
+ *
+ * The lines in the printout may include blank lines at the end of the document, as well as trailing spaces on each
+ * line.
+ *
+ * @return The text contents of this printout.
+ */
+ Stream getTextLines();
+
+ /**
+ * Get the printout contents for a particular stack.
+ *
+ * @param stack The stack to get the contents for.
+ * @return The printout contents, or {@code null} if this is not a printout item.
+ */
+ static @Nullable PrintoutContents get(ItemStack stack) {
+ return ComputerCraftAPIService.get().getPrintoutContents(stack);
+ }
+}
diff --git a/projects/common-api/src/main/java/dan200/computercraft/impl/ComputerCraftAPIService.java b/projects/common-api/src/main/java/dan200/computercraft/impl/ComputerCraftAPIService.java
index b45a8596a2..6dbf08f0c5 100644
--- a/projects/common-api/src/main/java/dan200/computercraft/impl/ComputerCraftAPIService.java
+++ b/projects/common-api/src/main/java/dan200/computercraft/impl/ComputerCraftAPIService.java
@@ -12,6 +12,7 @@
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.MediaProvider;
+import dan200.computercraft.api.media.PrintoutContents;
import dan200.computercraft.api.network.PacketNetwork;
import dan200.computercraft.api.network.wired.WiredElement;
import dan200.computercraft.api.network.wired.WiredNode;
@@ -75,6 +76,9 @@ static ComputerCraftAPIService get() {
DetailRegistry getBlockInWorldDetailRegistry();
+ @Nullable
+ PrintoutContents getPrintoutContents(ItemStack stack);
+
final class Instance {
static final @Nullable ComputerCraftAPIService INSTANCE;
static final @Nullable Throwable ERROR;
diff --git a/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java b/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java
index dc4ca4f7a8..a0ed7861d1 100644
--- a/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java
+++ b/projects/common/src/main/java/dan200/computercraft/impl/AbstractComputerCraftAPI.java
@@ -12,6 +12,7 @@
import dan200.computercraft.api.lua.GenericSource;
import dan200.computercraft.api.lua.ILuaAPIFactory;
import dan200.computercraft.api.media.MediaProvider;
+import dan200.computercraft.api.media.PrintoutContents;
import dan200.computercraft.api.network.PacketNetwork;
import dan200.computercraft.api.network.wired.WiredElement;
import dan200.computercraft.api.network.wired.WiredNode;
@@ -26,6 +27,7 @@
import dan200.computercraft.shared.computer.core.ServerContext;
import dan200.computercraft.shared.details.BlockDetails;
import dan200.computercraft.shared.details.ItemDetails;
+import dan200.computercraft.shared.media.items.PrintoutItem;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Registry;
@@ -39,6 +41,7 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.stream.Stream;
public abstract class AbstractComputerCraftAPI implements ComputerCraftAPIService {
private final DetailRegistry itemStackDetails = new DetailRegistryImpl<>(ItemDetails::fillBasic);
@@ -134,4 +137,21 @@ public final DetailRegistry getItemStackDetailRegistry() {
public final DetailRegistry getBlockInWorldDetailRegistry() {
return blockDetails;
}
+
+ @Override
+ public @Nullable PrintoutContents getPrintoutContents(ItemStack stack) {
+ return stack.getItem() instanceof PrintoutItem ? new PrintoutContentsImpl(stack) : null;
+ }
+
+ public record PrintoutContentsImpl(ItemStack stack) implements PrintoutContents {
+ @Override
+ public String getTitle() {
+ return PrintoutItem.getTitle(stack);
+ }
+
+ @Override
+ public Stream getTextLines() {
+ return Stream.of(PrintoutItem.getText(stack));
+ }
+ }
}
diff --git a/projects/core/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java b/projects/core/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java
index 11c4da7fe8..f5182868ae 100644
--- a/projects/core/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java
+++ b/projects/core/src/main/java/dan200/computercraft/core/apis/http/websocket/WebsocketHandle.java
@@ -69,7 +69,7 @@ public final MethodResult receive(Optional timeout) throws LuaException
* Send a websocket message to the connected server.
*
* @param message The message to send.
- * @param binary Whether this message should be treated as a
+ * @param binary Whether this message should be treated as a binary message.
* @throws LuaException If the message is too large.
* @throws LuaException If the websocket has been closed.
* @cc.changed 1.81.0 Added argument for binary mode.