This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
mikesaa309's profile picture

how to add movies to computercraft?

Started by mikesaa309, 24 December 2012 - 12:37 PM
mikesaa309 #1
Posted 24 December 2012 - 01:37 PM
hi all,

i found out about the secret starwars movie in cc and like many people have decided to build a cinema which is looking good still need to add a few things to it before completion but i has working lights and a projector (which is just a redstone lamp to give a lighting effect of a projector). So anyway I was wondering is there any way you can add more movies to the game. I found a site that does ACSII animations and also a short clip from the matrix in ascii which looks amazing its the actual footage but turned into ACSII. Now after looking on the wiki and forums i found the HTTP api which i tried using http.get("url") which worked for a while then returned an error "bios:148: to long with out yeilding" and also the movie is too big for the screen. so how will i adapt the following code to 1. make the movie smaller and 2. not get that error?


local monitor = peripheral.wrap("back") – replace with the side of the monitor
term.redirect(monitor) – redirects the output to the monitor

local sExample = http.get("http://ftp.pcworld.com/pub/screencams/ascii-matrix.html") –Get contents of page
write(sExample.readAll()) –Read and print contents of page
term.restore() – restores the output to the computer screen
ChunLing #2
Posted 24 December 2012 - 06:37 PM
You need a sleep(0.05) or something else that yields. You also need it because this loop spams downloads without any regard to the frame-rate you actually need, which can cause a bit of lag.

Or…hmm…you are looping this, right?

If not, then you need to adapt your playback function to use a loop and only read one frame at a time. While doing that, you can also compress the screen by skipping every other line and every other character of the lines you display. Kinda a sloppy fix.
Edited on 24 December 2012 - 05:42 PM
mikesaa309 #3
Posted 25 December 2012 - 06:31 AM
how would i do that, i'm useless at coding :/
ChunLing #4
Posted 26 December 2012 - 05:52 PM
Okay…well as interesting as it is that write was able to use the javascript in this page to display all the ascii art, we really only want the ascii art because running the code ends in not yielding. So first you have to find some way to skip to the part where the ascii art begins. Then we need to create a new string using elements from the old string.

For this, we'll use string.sub(). Because we'll be doing a bunch of operations on the string, we'll need assign the string to a variable. And we'll be rebuilding the string on the other end, in another string or set of strings. So (for now):
local source,frames = sExample.readAll(),""
Now we can use string.find to get the beginning of the ascii art. Fortunately for us, the beginnings of all the frames look the same, (a bunch of "R"s). So maybe initially we'll do something like:
local sindex = source:find("RRRRRRRRRR")
I think that ten "R"s should be enough. Then we can use string.sub with that value, and that value + the number of characters per frame (looks like 15,390, but don't hold me to that), and concatenate the result onto our frames.
frames = frames..source:sub(sindex,sindex+15390)
and now we have a single frame of the movie, stored in frames.

Now, we want all the frames, not just one. And we want them smaller. So let's revise our process a bit. First, we change frames to be a table of strings rather than a single string. Second, we skip over the header and footer of "R"s using some simple math. And third, we use a loop. So now we have something more like:
local source,frames = sExample.readAll(),{}
local sindex = source:find("RRRRRRRRRR")
for i=1, math.floor((#source-sindex)/15507) do
    frames[i] = ""..source:sub((sindex*i)+2020,(sindex*i)+13171)
end
Be aware that the numbers in here are all just estimated from looking at the page source for what I presume to be the first frame. They may not be exactly right. I don't even know that all the frames are exactly the same size (they should be, right?). Oops, turns out that the ascii art cleverly dispenses with whitespace at the end of each line. Umm…

Anyway, now we want to also cut off some of the sides of the frame. Hah, that's a bit trickier. But of course still possible, and it will help us deal with our other problem of lines not all being the same length. We just need to make a table of lines in the source ascii art, and replace the simple assignment of frames to another for loop that builds frames one line at a time, using the middle of each line. Let's start with breaking down the source into a table of lines, since we haven't covered that yet.
local lines,ln = {},1
for v in string.gmatch(source:sub(sindex),"([^\n]+)") do
    lines[ln] = v
    ln = ln+1
end
The point here is to use gmatch in an iteration to pull out each line in source from sindex on, and assign that to a successive entry in a table, lines.

Now, once we've done that, we need to go through and cut off the excess portion of those lines. We'll start with the left portion, then do the right. It's a simple string.sub on the line…if the line is long enough. We'll try with trimming off about…20 characters, first on the. So:
for i=1,#lines do
    if #lines[i] > 20 then lines[i] = ""..string.sub(lines[i],20) end
    if #lines[i] > 160 then lines[i] = ""..string.sub(lines[i],1,160)
    else lines[] = "" end
end
Now, if we get "too long without yielding" (cause this is a lot of string manipulation), we can just add some sleep(0) inside our loops.
local source = sExample.readAll() sExample.close()
local sindex = source:find("RRRRRRRRRR")
local lines,ln = {},1
for v in string.gmatch(source:sub(sindex),"([^\n]+)") do
    lines[ln] = v
    ln = ln+1
    sleep(0)
end
for i=1,#lines do
    if #lines[i] > 20 then lines[i] = ""..string.sub(lines[i],20) end
    if #lines[i] > 160 then lines[i] = ""..string.sub(lines[i],1,160)
    else lines[i] = "" end
    sleep(0)
end
Writing a function to shorten each line further by skipping every other character is something I'll leave to you for now.

Then, we need a playback loop. We can use a nested for loop to write out a given number of lines, sleep(0.1) (or whatever our framerate is), and then write the next set of lines. You can skip lines (like the headers and every other line if we need more compression) and whatever.
willhcraft #5
Posted 25 May 2013 - 12:33 AM
nvm. forget this was here
willhcraft #6
Posted 25 May 2013 - 12:37 AM
Okay…well as interesting as it is that write was able to use the javascript in this page to display all the ascii art, we really only want the ascii art because running the code ends in not yielding. So first you have to find some way to skip to the part where the ascii art begins. Then we need to create a new string using elements from the old string.

For this, we'll use string.sub(). Because we'll be doing a bunch of operations on the string, we'll need assign the string to a variable. And we'll be rebuilding the string on the other end, in another string or set of strings. So (for now):
local source,frames = sExample.readAll(),""
Now we can use string.find to get the beginning of the ascii art. Fortunately for us, the beginnings of all the frames look the same, (a bunch of "R"s). So maybe initially we'll do something like:
local sindex = source:find("RRRRRRRRRR")
I think that ten "R"s should be enough. Then we can use string.sub with that value, and that value + the number of characters per frame (looks like 15,390, but don't hold me to that), and concatenate the result onto our frames.
frames = frames..source:sub(sindex,sindex+15390)
and now we have a single frame of the movie, stored in frames.

Now, we want all the frames, not just one. And we want them smaller. So let's revise our process a bit. First, we change frames to be a table of strings rather than a single string. Second, we skip over the header and footer of "R"s using some simple math. And third, we use a loop. So now we have something more like:
local source,frames = sExample.readAll(),{}
local sindex = source:find("RRRRRRRRRR")
for i=1, math.floor((#source-sindex)/15507) do
	frames[i] = ""..source:sub((sindex*i)+2020,(sindex*i)+13171)
end
Be aware that the numbers in here are all just estimated from looking at the page source for what I presume to be the first frame. They may not be exactly right. I don't even know that all the frames are exactly the same size (they should be, right?). Oops, turns out that the ascii art cleverly dispenses with whitespace at the end of each line. Umm…

Anyway, now we want to also cut off some of the sides of the frame. Hah, that's a bit trickier. But of course still possible, and it will help us deal with our other problem of lines not all being the same length. We just need to make a table of lines in the source ascii art, and replace the simple assignment of frames to another for loop that builds frames one line at a time, using the middle of each line. Let's start with breaking down the source into a table of lines, since we haven't covered that yet.
local lines,ln = {},1
for v in string.gmatch(source:sub(sindex),"([^\n]+)") do
	lines[ln] = v
	ln = ln+1
end
The point here is to use gmatch in an iteration to pull out each line in source from sindex on, and assign that to a successive entry in a table, lines.

Now, once we've done that, we need to go through and cut off the excess portion of those lines. We'll start with the left portion, then do the right. It's a simple string.sub on the line…if the line is long enough. We'll try with trimming off about…20 characters, first on the. So:
for i=1,#lines do
	if #lines[i] > 20 then lines[i] = ""..string.sub(lines[i],20) end
	if #lines[i] > 160 then lines[i] = ""..string.sub(lines[i],1,160)
	else lines[] = "" end
end
Now, if we get "too long without yielding" (cause this is a lot of string manipulation), we can just add some sleep(0) inside our loops.
local source = sExample.readAll() sExample.close()
local sindex = source:find("RRRRRRRRRR")
local lines,ln = {},1
for v in string.gmatch(source:sub(sindex),"([^\n]+)") do
	lines[ln] = v
	ln = ln+1
	sleep(0)
end
for i=1,#lines do
	if #lines[i] > 20 then lines[i] = ""..string.sub(lines[i],20) end
	if #lines[i] > 160 then lines[i] = ""..string.sub(lines[i],1,160)
	else lines[i] = "" end
	sleep(0)
end
Writing a function to shorten each line further by skipping every other character is something I'll leave to you for now.

Then, we need a playback loop. We can use a nested for loop to write out a given number of lines, sleep(0.1) (or whatever our framerate is), and then write the next set of lines. You can skip lines (like the headers and every other line if we need more compression) and whatever.

So when you put all the code together what do you get? I've read through the entire thing multiple times but I have no experience coding so I am quite confused.