I'm looking for a migration path from the outdated Video module to the current Filefield. I've got a starting point, Moshe wrote a migration script from Image to Imagefield, and I suspect that a lot of his process is applicable here. I am a fish out of water when it comes to coding mysql queries but I have the motivation and the scenario in hand. Anyone want to work with? Here is where I'm at.
I can transform a single Video node by hand in a few steps, takes 30 seconds per node by hand, so it must be a pretty easy thing to complete with the right query.
1. I already have a couple hundred Video nodes populated with files.
2. I create and config a new content type called Video2.
3. I create and config one file field for Video and Video2 content types.
4. Per Video node, I manually re-upload video file into the new file field.
5. Per Video node, I change each Video node into a Video2 (Nodetype module in my case).
6. Take a moment to curse myself and repeat 4, 5 and 6 until done.
It works beautifully. Changing the node type on each node sloughs off all the Video module features and leaves me with a neat node with a video-populated file field. Later I can uninstall the Video module and add a jQuery Media setup call it a day.
Moshe's script goes through a similar process. It requires users to create content types, fields, configure some options, then run the script.
I'll take a demented stab at editing the parts of Moshe's script that I understand, I'm hoping once I get this started that some other folks with pipe in and help out.
| Comment | File | Size | Author |
|---|---|---|---|
| #47 | video_migration.php_.txt | 5.47 KB | seaneffel |
| #44 | video_migration.php_.txt | 5.47 KB | bdragon |
| #41 | video_migration.php_.txt | 4.8 KB | bdragon |
| #37 | video_migration.php_.txt | 4.76 KB | seaneffel |
| #33 | video_migration.php_.txt | 4.69 KB | seaneffel |
Comments
Comment #1
seaneffel commentedI'm just showing my work as I move forward. I think the best plan for this migration script is to:
1. Advise users to back up their database.
2. Require users to add a cck filefield to their video content types.
3. Require users to create a new node type with the same filefield.
4. Script the insertion of video module values into corresponding filefield fields.
5. Script the changes of all video nodes into the user's new node type.
Working on the big part, number 4, I've picking apart the tables/fields touched by both video and filefield in order to learn how to map them. This is what I sorted out so far but I have a few holes that I don't know how to fill:
In the original video table there are only a few important fields to use as source information:
'nid' - node ID
'vidfile' - the full path to the location of the video file
'size' - which is the user-entered file size, not always the actual size
Using the above info, content_field_video should be mapped like this:
'nid' ---> 'nid' from video table
'vid' ---> 'nid' from video, assuming only one node version
'field_video_fid' ---> serialized file ID to match files table
'field_video_description' ---> 'vidfile' from video, file name only
'field_video_list' ---> value of 1, assuming no multiple files in field
The files table needs to be mapped like this:
'fid' ---> matching serialized value from video 'field_video_fid'
'nid' ---> matching video 'nid'
'filename' ---> 'vidfile' from video table, file name only
'filepath' ---> 'vidfile' from video, local path no file name
'filemime' ---> no matching field in video, detected during file upload
'filesize' ---> 'size' from video, but not always accurate
Comment #2
seaneffel commentedAdapted script so far, missing the important field mapping steps listed in comment #1.
Comment #3
seaneffel commentedHow am I doing so far? This is my stab at populating the new field_video table for each video node. I can tell for certain that there will be an issue, the video table's vidfile value is a path (http://something/something/file.mov) when instead I need to insert only the filename (file.mov). I haven't a clue on how to pull this off.
Comment #4
wmostrey commentedYou can use basename() for that. First strip off the "http://" part and then take the basename of that. For example:
If you path variable only contains a path relative to the Drupal root ("/files/somthing/file.mov") then you can just use basename on it.
Comment #5
seaneffel commentedThis is awesome, I'm trying to learn how to apply it in this case as we speak.
The video module holds the URL of each hosted video file in 'vidfile', so this would work. One of the hitches is that video handles data entry two ways. Users can either attach the file to the node and have it uploaded to the /files/videos directory, or manually enter the URL of a file hosted anywhere (sometimes even Youtube, etc). This second scenario puts a hiccup in my plan.
Maybe its a good idea to make this script so it only effects video nodes hosted in the site's /files/videos directory. We can write the instructions up to reflect this, and advise the user to manually change video nodes that are not hosted on their own server. Be nice to get a list of nodes that were not hosted in the files directory so that the users could find them, edit them, and potentially run the script again.
An alternative might be to advise the user to move all video files blindly into the /files/videos directory after running the script. We could hard code one path into the files table in the script.
Comment #6
seaneffel commentedHow about?
Just a shot in the dark. It doesn't yet determine if it is a locally hosted video file or a remote one.
Comment #7
wmostrey commentedWell how about this:
And then continue from there. After downloading the file you probably need to adjust something in the files table or so, I'm not sure how the video module stores that kind of information.
Comment #8
seaneffel commentedI don't like moving files around on the server. If the script botches a users migration then its not just restoring the database but also means moving big media files back where they came from and that's a lot of work.
It might be a better step just to notify users of video nodes that won't be migrated. That is, any node with a file URL on mysite.com is OK to migrate, any node with a file URL on notmysite.com (youtube, blip, vimeo, etc) should be skipped but noted in a log somewhere.
Please check my work, I don't even speak this language. I am not sure how to integrate this step into the larger script either.
Comment #9
seaneffel commentedJust wanted to try to put all this work together into one script to see how we're doing. Added a configuration line for base url, added a half baked condition in the first $sql step to only migrate video nodes whose file path contain the matching site's base url. Someone really should check my work.
What's left is the population of the files table, specifically detecting the mimetype based only on the file extension.
Comment #10
seaneffel commentedI realize we have to get the mimetype of each of the files. The video module doesn't capture this as data, but instead treats files based on their extension. I'm picking apart a function from the video module that detects mimetype based on the file extension, how am I doing?
Comment #11
wmostrey commentedWhat you're doing to get the extension of the file is dangerous: what would happen if you have a file named "this.is.my.filename.mov"?
Try this:
$video_ext = substr($video_name, -3);Or even better:
Here's more information about pathinfo().
And there's also the mimedetect module.
Comment #12
seaneffel commentedThis is my first experience writing up code so thanks for pointing this out. I've edited my comments above to reflect this.
The Mimetype module is required for Filefield already but I don't think we can harness it here, only when uploading fresh files?
If anyone had a moment to look over the three times this script runs an $sql, this is the place where I have the least confidence in my work.
Comment #13
dman commentedI'm in on this.
I'm not 'migrating' any old content, but attempting to get video embeds on a D6 site.
I was expecting that video.module would be helpful, but it's not on the way...
And this approach seems cleaner.
Um, So I'm using this filefield approach, and it's cool so far.
I've got an 'embedder' formatter/renderer extension working, I think this will work. I need to 'modularize' it a bit more.
Anyway, I think this is CURRENTLY easier than pushing the D5 video.module forward ... although I respect what is is/was ... it's harder than I can do in an evening.
Comment #14
seaneffel commentedd, did you look at jquery_media yet?
http://www.drupal.org/project/jquery_media
Comment #15
dman commentedWo.
Thanks for the link, it looks pretty damn ambitious, even for me :-)
I'll see if it fits.
I'm a fan of jScript embedding (due to browser inconsistancies) but ... this looks scary.
I'll try it and see if it does the job, I guess. Still, I'd rather have control of the theming ...
Sorry if I've dragged this 'migration' thread off-topic
Comment #16
seaneffel commentedI'm a lover of this jquery module, I made up a decent screencast on how to config:
http://www.drupaltherapy.com/node/50
In the meantime, if you have some skill with mysql, peek at my queries above and tell me if I'm totally whacked. Especially in the WHERE areas and relating to the video table.
Comment #17
wmostrey commentedYour queries appear to be correct but you should never include a variable directly into the query.
For example:
This should be:
This will check if the input is of the expected content type, so that you're no subject to sql injection. %s expects a string and %d expects a number.
Comment #18
dman commentedVery nice screencast. Thanks for that. A little light on the actual "how things work" side .. but it looks really approachable.
Nice pace.
It inspires me to some day choose a screencast proggie for myself and do something useful. What was it you used? (Yeah, I've got an OSX available also). Again ... sorry for getting off-topic,.
Comment #19
seaneffel commented@dman: Look at Snapz Pro for screen capture. Jing is free if you sign up for their free service and host with them.
@wmostrey: Thanks for your help with this so far, I'm going to edit the above comments with your changes and give it a maiden voyage. Will report back.
Comment #21
seaneffel commentedParse error: syntax error, unexpected T_ECHO in /Applications/MAMP/htdocs/video_migration.php on line 60
Still trying to get to the bottom of this
Comment #22
wmostrey commentedCould you attach the script in its current form, that would help debugging. I prefer that over editing previous comments since that makes reading this issue page a lot harder (also for future reference).
Comment #23
seaneffel commentedThe script I am currently working on is:
Comment #24
wmostrey commentedThere were a couple of php syntax issues, for instance
$route = str_replace( $base, "", $path ));instead of$route = str_replace( $base, "", $path );and you can't use the switch syntax to assign a variable like that so I create a small function for it. How does this run for you?Comment #25
seaneffel commentedWim, thanks for all your help here. I've got no results from running this script. I'm running it here on a Mac OS X and MAMP development site and I get nothing but the white screen displaying when the script runs. Even with error_reporting switched on, I can't learn anything more.
Comment #26
wmostrey commentedWell you don't have any php syntax errors anymore (you're still using variables in some queries instead of using placeholders though) so now it's debugging time to find out where there's a logical mistake in the flow of your script. My advice would be to go over your queries to see if they are correct:
I believe you're missing a "FROM" sequence here. It should look something like this:
INSERT INTO table1 (field1, field2, field3) SELECT n.field4, f.field5, "my value" FROM table2 n, table 3 f WHERE ...So you need so set a FROM for the "n." and "f." tables you're selecting or the query won't know where to get those.
This is a matter of trial and error and a lot of patience. Now that all the syntax errors are gone, this is the "fun" part :)
Comment #27
seaneffel commentedHere are some changes to the two sql runs, but running them still turns up a blank screen. My grasp of mysql is so poor that I'm basically making these things up. I understand the logic but I haven't got the language or vocabulary to write the queries. It will take a much bigger gun than me to straighten them out.
Comment #28
wmostrey commentedNice work with putting the placeholders. The queries themselves are not correct though.
OK so you're trying to link 3 tables together here: node, files and video, right? You link node and files by the nid field. How does the video table link in to any of those two? Also with a nid field?
Comment #29
seaneffel commentedYes, video table includes a nid that matches to node table. Look at comment #1 for the field mapping I intended to do.
I definitely don't understand the f. and n. thingies.
Comment #30
wmostrey commentedOK try this then:
Now if this wouldn't work, we'll have to split up the queries.
Comment #31
seaneffel commentedThe $base represents the site domain, which is only part of the value held in the vidfile in video table. Vidfile contains the full web address of the file. That's why I tried this LIKE command hoping to get something like an "if vidfile contains $base then". The way it looks now it wouldn't work?
Comment #32
wmostrey commentedAh well if you do "LIKE '%s'" then that's the same as "= '%s'". You need to put a "%" character where you expect extra text. For instance:
Now because the Drupal db_query placeholders also use %, for instance for %d or %s, this might get a little confusing.
So this becomes
v.vidfile LIKE '%%s%'. I hope this makes sense :)Comment #33
seaneffel commentedIt seems as if the script is running but not doing anything. I get a white screen when the script loads, but no errors. I made a few changes, yours from above and added curly brackets around table names at the start of INSERT INTO {files} and so on. Something is not right, could it be the environment that I am working in, on a local MAMP install?
Also, is there some check or test that can alert me on run when something doesn't do what's expected?
Comment #34
wmostrey commentedYou can't put quotes around a table name. So it's not
INSERT INTO {'%s'}butINSERT INTO {%s}. So none of your echo's are being outputted and nothing is being inserted? Do you happen to have a mysql error log file? For a default MAMP that's in /Applications/MAMP/logs/mysql_error_log. Your code should do what's expected, I think that it's now a matter of getting the correct SQL statement.Comment #35
seaneffel commentedThe only thing written on the mysql or the php error logs is what looks like startup stuff, no events recorded when this script runs.
080904 14:12:38 mysqld started
080904 14:12:38 [Warning] You have forced lower_case_table_names to 0 through a command-line option, even though your file system '/Applications/MAMP/db/mysql/' is case insensitive. This means that you can corrupt a MyISAM table by accessing it with different cases. You should consider changing lower_case_table_names to 1 or 2
080904 14:12:38 [Warning] One can only use the --user switch if running as root
080904 14:12:38 InnoDB: Started; log sequence number 0 43655
080904 14:12:38 [Note] /Applications/MAMP/Library/libexec/mysqld: ready for connections.
Version: '5.0.41' socket: '/Applications/MAMP/tmp/mysql/mysql.sock' port: 8889 Source distribution
Comment #36
wmostrey commentedDid removing the single quotes around the table names fix things or change anything? Could you attach the latest version again? I think it's better to attach the .php/.txt file instead of pasting it completely.
Comment #37
seaneffel commentedI changed the single quotes around the {%s} in the first sql, it did not help. Actually, none of the queries seem to be running properly. Could this be from my use of the $base value in each of the queries? All three have a WHERE $base LIKE v.vidfile, and if I handled that wrong then they wouldn't work.
My thought process was to exclude database changes to video nodes that did not hold the files on the same server. The user set the $base value as the domain name in the config section. Since the video table's vidfile is a web address it would either contain or not contain the $base value. If vidfile contained $base it was a local file and safe to change.
However, stripping out the whole
AND v.vidfile LIKE '%%s%'portion of the query gives the same white screen results.Comment #38
bdragon commentedA little bird told me that you guys could use some help.
Comment #39
bdragon commentedIt is actually
'%%%s%%'due to the placeholder rules.Comment #40
bdragon commentedDue to the way PHP handles
{}in strings internally, dynamic table names MUST be broken out from the string.Here's a safe way to do it...
$sql = 'SELECT bla FROM {'. db_escape_table($tablename) .'} WHERE ...';Comment #41
bdragon commentedFixed some syntax errors in the file, etc...
It might work better.
Comment #42
bdragon commentedCould I possibly get a db dump to help debug this?
Comment #43
seaneffel commentedI'll email you with a link to download. Thanks very much for helping out.
Comment #44
bdragon commentedI think this should do most of the work.
Comment #45
bdragon commentedHmm, I just realized that the code won't go and create the cck rows for the files it had to go make files table entries for... I think moving lines 69-84 down to line 165 or so would do the trick..
Comment #46
seaneffel commentedI get some activity when the script runs now. I get a "files table populated" and some errors for a few missing files, but no files are attached to the nodes and the node types aren't changed. It's a mystery.
Comment #47
seaneffel commentedAt one point the script asks for user configured URL information that is stored by the video module. At another point it pulls local URL information from the server itself. Then in the queries it compares the two in the WHERE portions.
For me, I'm running this script on a copy of my production database but hosted on a dev server, so those two values would never match up. Is this going to break the queries and tell me that the files table was populated but not do any other operations?
Here is the version I'm working with.
Comment #48
seaneffel commentedStatus update...
Throughout this process of tweaking this script, I have been spending about 30 minutes a day manually transforming the several hundred video nodes on our organizational site. Just this morning I managed to transform the last one, and my need for this script has evaporated for the most part.
I'm still interested in completing it, but I don't have the time to test and debug it and as I said before this is really not a strength of mine to begin with. Hopefully its close enough that the next person to need it can work out the kinks on their own.
I'll still be watching this thread so I can help now and then. Thanks to the folks above that pitched in to get this migration path this far.
Comment #49
quicksketch30 weeks since a post, I think this is safe to close. I would've made a documentation page on this to fit with the Image and Audio migration scripts (http://drupal.org/node/432852) but it doesn't seem that a fully working script was ever finished.