--- In simpy-user@yahoogroups.com, "davitofr" <davito9l@...> wrote:
> I am trying to upload my bookmarks from Firefox 3.0. FF3
> now uses tags for bookmarks.
Years ago, I uploaded my Powermarks bookmarks into Simpy. PowerMarks heavily used tags and I did not want to lose them. So I wrote a Windows Script that uses Simpy's REST API to upload bookmarks including tags. You just need to get the bookmarks in a delimited file format. Or you can modify the script to do what you want. There's lots of comments in the script. Oh, and it only works in Windows, of course.
Since I can't attach or post a file here, I'll just append the contents of file here. Hopefully it won't be garbled or cut. Save it to a file with the ".wsf" extension.
<?xml version="1.0" ?>
<job>
<script language="JavaScript">
<![CDATA[
/**************************************************************************
This Windows script will import one or more delimited files of bookmarks to the
Simpy online social bookmark manager using Simpy's REST API.
INSTRUCTIONS
Create one or more delimited text files with your bookmarks.
Each bookmark on a separate line. No first line with field names.
Each line contains four fields:
title the name/title of the bookmark.
href the URL of the bookmark.
tags delimited list of tags/keywords. optional, may be empty.
note notes on the bookmark. optional, may be empty.
Choose a field delimiter that is not found in your bookmark title, href,
tags, or note. The delimiter may be a string of multiple characters.
This script does not support a text qualifier, like a double quote
surrounding each field; though it wouldn't take much with the right
regular expression; modify the section of this script labeled "parse
bookmark line".
See comments further on for notes on exporting Kaylon PowerMarks
bookmarks.
Add values to the settings variables (see next section "SETTINGS FOR IMPORT").
Save the modified script.
Drag and drop your bookmark files from Windows Explorer onto this Windows
script file (or a shortcut to this file).
Monitor the log file(s) to monitor the progress of this script.
The log file(s) have ".log" appended to the name of the import file.
This script throttles itself to import no more than one link per second.
A message will popup when the script finishes.
If an error occurs, check the end of the log file for the bookmark that
failed, or at least the last bookmark that was saved.
If href is over 256 characters, the bookmark is skipped; an error message is
appended to the log; import will continue. Title is truncated to 256 characters
if too long. Nickname is truncated to 128 characters if too long.
If URL being imported already exists in Simpy, all parameters except title and
URL are replaced. If a parameter is not specified, it's existing value in Simpy
is deleted. Existing add, indexed, and visited dates are not changed. modified
date is updated.
SETTINGS FOR IMPORT
Set values for the following variables, found just below this comment.
fieldDelimiter
Delimiter used between fields of each bookmark/line.
May be multiple characters to ensure uniqueness.
tagDelimiter
Delimiter used between tags.
May be multiple characters to ensure uniqueness.
tagCommaReplacement
Simpy uses commas to delimit tags.
If there's a comma in a tag, other than as a delimiter, it will be
replaced by the value of this variable.
tagSpaceSurrogate
Simpy allows spaces in tabs, but many other bookmark systems do not.
If you used another character, like "_" or ".", in place of space,
and want to use spaces in Simpy, specify that other character in
this vaariable.
Set to an empty string "" if you have no surrogate spaces.
privateTag
Tag that indicates link should be private in Simpy.
Set to an empty string "" if you have no private tag.
publicTag
Tag that indicates link should be public in Simpy.
Set to an empty string "" if you have no public tag.
defaultAccessType
If publicTag or privateTag is not specified, or link has neither tag,
this variable specifies default access type of the link.
"1" to create public links in Simpy by default.
"0" to create private links in Simpy by default.
copyTitleToNickname
false to add link with no nickname.
true to copy the title to the nickname.
The first person who adds a link to Simpy gets to set the link title.
You will see their title - unless you set a nickname.
If you tended to edit the bookmark name to be more readable or searchable,
you probably want to copy that name to the nickname, as well as the title.
tagForAll
Specify tag to include on all links.
Comma-delimit multiple tags.
username
Your Simpy username.
password
Your Simpy password.
**************************************************************************/
var fieldDelimiter = "";
var tagDelimiter = "";
var tagCommaReplacement = "";
var tagSpaceSurrogate = "";
var privateTag = "";
var publicTag = "";
var defaultAccessType = "1";
var copyTitleToNickname = false;
var tagForAll = "";
var username = "";
var password = "";
/**************************************************************************
Kaylon PowerMarks Notes
Export your Kaylon PowerMarks bookmarks to a delimited format file.
Use File | Export from them PowerMarks menu.
Format
choose "Delimited ASCII".
Title
not used.
Filename
enter or browse a filename to which to export.
Export
choose "All", unless you're testing the export/import on a
few "Selected" bookmarks.
Sort by
choose "Add Date", and your imported Simpy links will be
chronologically ordered the same as your PowerMarks bookmarks.
Sort Order
choose "A-Z" (see Sort by).
Fields to Export
Tick "Name", "URL", and "Keywords".
If desired, tick a fourth field for the Simpy Note.
Generally the fourth field will be "Notes" or "User". Description
is another possibility. Depends on where you put your notes.
Leave the other fields unticked; only four may be ticked.
Delimit String
choose a character or multi-character string that you know
does not appear in your data, like "|||".
To find a good Delimit String, first set to a space. Export.
Open the exported file in a text editor. Use the editor's
Find command to find your delimit string, like "|||". If
the string is not found, it is a good Delimit String.
Note that PowerMarks keywords are space delimited. Set space as the tagDelimiter
in this script.
If you want to import both notes and user fields, or even other PowerMarks fields,
concatenate them into a single Simpy note field. Modify the section of this script
labeled "parse bookmark line".
all possible fields that can be exported from PowerMarks.
1. name
2. url
3. keywords, space delimited.
4. decription
5. notes
6. status checking: Changed, No Change, Checking Off.
7. schedule: Daily, Weekly. empty means None.
8. add date: date/time
9. last visited: date/time
10. last modified: date/time
11. last checked: date/time
12. visited: # times visited
13. user: a pair double quotes indicates no value.
14. rating: integer.
15. username: a pair double quotes indicates no value.
date/time format: mm-dd-yy hh:mm:ss AM
where "AM" may be "AM" or "PM".
example: 02-04-05 09:35:27 PM
Even though "status" and "password" are included in the field to export
from PowerMarks, they do not get into exported file. Status does seem to be
in the status checking field.
Simpy HTTPLogin API Command
Logs into Simpy with a username and password. Use this command before
executing any other. Use HTTP Basic Authentication with
WinHTTPRequest.SetCredentials().
URL:
http://www.simpy.com/simpy/api/rest/HTTPLogin.do
Parameters:
none.
Returned HTTP Status Codes:
200: Success
401: Unauthenticated
Simpy SaveLink API Command
Saves the given link and returns a status response indicating either success
or failure.
URL:
http://www.simpy.com/simpy/api/rest/SaveLink.do?parameters
Required Parameters:
title The title of the page to save. Max length 256.
href The URL of the page to save. Max length 256.
accessType Use 1 to make the link public and 0 to make it private.
Optional Parameters:
tags Comma-separated list of tags.
urlNickname An alternative, custom title. Max length 128.
note A free-text note to go with the link.
Parameter values must be URI encoded and separated with apersand "&".
If URL already exists, all parameters except title and URL are replaced.
If a parameter is not specified, it's existing value in Simpy is deleted.
Existing add, indexed, and visited dates are not changed. modified date is updated.
Examples:
http://www.simpy.com/simpy/api/rest/SaveLink.do?title=Example&href=http://example.com&accessType=1
http://www.simpy.com/simpy/api/rest/SaveLink.do?title=Example&href=http://foo.com&accessType=1&tags=foo,site
Returned HTTP Status Codes:
200: Success
301: Entity storage error
500: Storage quota reached
Example HTTP Response:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE links SYSTEM "Status.dtd">
<status>
<code>0</code>
<message>Link saved successfully.</message>
</status>
Note: I got the XML response only when the command was successful. When an
error occured, the response was a Simpy's generic error HTML page.
**************************************************************************/
/**************************************************************************
REVISION HISTORY
2006.04.02 Don Arsenault
original version.
**************************************************************************/
var cntHrefTooLong = 0;
var msg;
var args = WScript.Arguments;
// if no arguments, display help.
if (args.length == 0) {
msg = "Import Delimited File to Simpy. \r\n"
+ "Please read the INSTRUCTIONS contained in the comment "
+ "at the beginning of this Windows Script file.";
WScript.Echo( msg );
WScript.Quit();
}
// check settings.
msg = ""
if (fieldDelimiter == "") { msg += ((msg!="")?", ":"") + "fieldDelimiter" }
if (tagDelimiter == "") { msg += ((msg!="")?", ":"") + "tagDelimiter" }
if (defaultAccessType != "0" && defaultAccessType != "1") { msg += ((msg!="")?", ":"") + "defaultAccessType" }
if (copyTitleToNickname != true && copyTitleToNickname != false) { msg += ((msg!="")?", ":"") + "copyTitleToNickname" }
if (username == "") { msg += ((msg!="")?", ":"") + "username" }
if (password == "") { msg += ((msg!="")?", ":"") + "password" }
if (msg!="") {
msg = "Import Delimited File to Simpy. \r\n"
+ "Please assign values to the settings (" + msg + "). "
+ "See instructions at the beginning of this script file.";
WScript.Echo( msg );
WScript.Quit();
}
// ok to continue?
var button = shell.Popup(
"This will import your dropped bookmark files into Simpy.",
0, "Import Delimited File to Simpy", 1 + 64);
if (button == 2 ) { //Cancel button.
WScript.Quit();
}
// prototypes.
loadPrototypes();
// loop for each file.
for (var i=0; i<args.length; i++) {
main(args(i));
}
// final message.
if (cntHrefTooLong == 0) {
WScript.Echo( "Import Delimited File to Simpy.\r\n\r\nSuccess!");
}
else {
msg = "Import Delimited File to Simpy.\r\n\r\n"
+ cntHrefTooLong + " href's/URLs are too long and were not imported.\r\n"
+ "Search the log file(s) for \"HREF TOO LONG\" errors.";
WScript.Echo(msg);
}
function main(inPath) {
//var inPath = "C:\\Documents and Settings\\darsenault\\My Documents\\Docs\\ProductResearch\\Bookmark Manager\\pmexport.txt";
var accessType;
var inLine;
var inLineNum = 0;
var msg;
var startTime;
var endTime;
var sleepTime;
var httpCmd;
var httpData;
var logCnt = 0;
var logPath = inPath + ".log";
var logStream;
var HTTPREQUEST_SETCREDENTIALS_FOR_SERVER = 0;
// error if input file does not exist.
if (!fso.FileExists(inPath)) {
msg = "Import Delimited File to Simpy. \r\n"
+ "Input file does not exists: \r\n" + inPath;
WScript.Echo( msg );
WScript.Quit();
}
// append heading to log.
logStream = fso.OpenTextFile(logPath, ForAppending, true, TristateUseDefault);
logStream.WriteLine("\r\n==================================================");
logStream.WriteLine((new Date()).toLocaleString());
logStream.WriteLine(inPath);
logStream.WriteLine("==================================================\r\n");
logStream.Close();
// open input file for reading.
var inStream = fso.OpenTextFile(inPath, ForReading, false, TristateUseDefault);
// HTTP object.
var http = new ActiveXObject("WinHttp.WinHttpRequest.5.1");
// Authenticate.
httpCmd = "http://www.simpy.com/simpy/api/rest/HTTPLogin.do"
http.open("GET", httpCmd, false);
http.SetCredentials( username, password, HTTPREQUEST_SETCREDENTIALS_FOR_SERVER);
http.send();
// quit if error.
if (http.Status != 200) {
msg = "Import Delimited File to Simpy. \r\n"
+ "Authentication failed:"
+ http.Status + " " + decodeURIComponent(http.StatusText)
+ "\r\n"
+ "Check username and password, and that www.simpy.com is active.";
// append msg to log.
logStream = fso.OpenTextFile(logPath, ForAppending, true, TristateUseDefault);
logStream.WriteLine(msg);
logStream.Close();
WScript.Echo( msg );
WScript.Quit();
}
// loop through lines of input file.
while (!inStream.AtEndOfStream) {
startTime = new Date();
// read next line.
inLine = inStream.ReadLine();
inLineNum += 1;
inLine = inLine.trim();
// skip empty lines.
if (inLine != "") {
// parse bookmark line.
fld = inLine.split(fieldDelimiter);
var title = fld[0].trim();
var href = fld[1].trim();
var tags = (fld[2])?(fld[2].trim()):"";
var note = (fld[3])?(fld[3].trim()):"";
// change tags to comma-delimited, if needed.
if (tagDelimiter!="," && tags!="") {
// can't have any commas in the tags.
tags = tags.split(tagDelimiter).join("\x01");
tags = tags.replace(/,/g, tagCommaReplacement);
tags = tags.replace(/\x01/g, ",");
}
// replace space surrogate with real space, if surrogate was specified.
if (tagSpaceSurrogate.length > 0) {
tags = tags.split(tagSpaceSurrogate).join(" ");
}
// set access type based on tags.
privateTagNdx = tags.indexOf(privateTag);
publicTagNdx = tags.indexOf(publicTag);
if (
(privateTagNdx >= 0)
&& (
(privateTagNdx == 0)
|| (tags.charAt(privateTagNdx - 1) == ",")
)
&& (
(privateTagNdx + privateTag.length >= tags.length)
|| (tags.charAt(privateTagNdx + privateTag.length) == ",")
)
) {
accessType = "0";
}
else if (
(publicTagNdx >= 0)
&& (
(publicTagNdx == 0)
|| (tags.charAt(publicTagNdx - 1) == ",")
)
&& (
(publicTagNdx + publicTag.length >= tags.length)
|| (tags.charAt(publicTagNdx + publicTag.length) == ",")
)
) {
accessType = "1";
}
else {
accessType = defaultAccessType;
}
// append optional tagForAll.
if (tagForAll!="") {
tags = tags + "," + tagForAll;
}
// SaveLink only if href not too long.
if (href.length <= 256) {
// SaveLink.
httpCmd =
"http://www.simpy.com/simpy/api/rest/SaveLink.do"
+ "?title=" + encodeURIComponent(title.substr(0, 256))
+ "&href=" + encodeURIComponent(href)
+ "&accessType=" + encodeURIComponent(accessType)
+ ((copyTitleToNickname)?("&urlNickname=" + encodeURIComponent(title.substr(0, 128))):"")
+ ((tags!="")?("&tags=" + encodeURIComponent(tags)):"")
+ ((note!="")?("¬e=" + encodeURIComponent(note)):"");
http.open("GET", httpCmd, false);
http.send();
// quit if error.
if (http.Status != 200) {
// append msg to log.
msg =
(inLineNum+"").rjust(4, "0") + " FAILED " + (new Date()).toODBCTimeString()
+ "\r\n"
+ " title: " + title
+ "\r\n"
+ " href: " + href
+ "\r\n"
+ " command: " + httpCmd
+ "\r\n"
+ "ERROR: " + http.Status + " " + decodeURIComponent(http.StatusText)
+ "\r\n"
+ http.GetAllResponseHeaders( )
+ "\r\n"
+ "\r\n"
+ http.ResponseText;
logStream = fso.OpenTextFile(logPath, ForAppending, true, TristateUseDefault);
logStream.WriteLine(msg);
logStream.Close();
// popup error msg.
msg = "Import Delimited File to Simpy. \r\n"
+ "SaveLink failed:"
+ http.Status + " " + decodeURIComponent(http.StatusText)
+ "\r\n"
+ "Line #" + inLineNum + ": "
+ "\r\n"
+ title
+ "\r\n"
+ href;
WScript.Echo(msg);
WScript.Quit();
}
// log.
msg =
(inLineNum+"").rjust(4, "0") + " SAVED " + (new Date()).toODBCTimeString()
+ "\r\n"
+ " title: "+ title
+ "\r\n"
+ " href: " + href
+ "\r\n"
+ " command: " + httpCmd;
logStream = fso.OpenTextFile(logPath, ForAppending, true, TristateUseDefault);
logStream.WriteLine(msg);
logStream.Close();
// sleep up to a sec.
endTime = new Date();
sleepTime = 1000 - (endTime.getTime() - startTime.getTime());
if (sleepTime > 0) {
WScript.Sleep(sleepTime);
}
}
// FAIL if href too long.
else {
// count.
cntHrefTooLong += 1;
// append msg to log.
msg =
(inLineNum+"").rjust(4, "0") + " FAILED " + (new Date()).toODBCTimeString()
+ "\r\n"
+ " title: " + title
+ "\r\n"
+ " href: " + href
+ "\r\n"
+ "ERROR: HREF TOO LONG (max 256 characters)"
+ "\r\n";
logStream = fso.OpenTextFile(logPath, ForAppending, true, TristateUseDefault);
logStream.WriteLine(msg);
logStream.Close();
}
}
}
// close file.
inStream.Close();
}
function loadPrototypes() {
// ltrim.
String.prototype.ltrim = function() {
var i=-1;
while (this.charCodeAt(++i)<33);
return this.substring(i);
};
// rtrim.
String.prototype.rtrim = function() {
var i = this.length;
while (this.charCodeAt(--i)<33);
return this.substring(0, ++i);
};
// trim.
String.prototype.trim = function() {
return this.rtrim().ltrim();
};
// ljust.
String.prototype.ljust = function(the_length, filler) {
return(
this
+ ((filler==null)?" ":filler).repeat(
(the_length<=this.length)?0:(the_length - this.length)
)
);
}
// rjust.
String.prototype.rjust = function(the_length, filler) {
return(
((filler==null)?" ":filler).repeat(
(the_length<=this.length)?0:(the_length - this.length)
)
+ this
);
}
// repeat.
// repeats string specified number of times.
String.prototype.repeat = function(count) {
return new Array(++count).join(this);
}
// toODBCTimeString: hh:mi:ss.mmm.
Date.prototype.toODBCTimeString = function() {
if (isNaN(this.valueOf())) {
return(Math.NaN);
}
else {
return(this.getHours().toString().rjust(2, "0") + ":"
+ this.getMinutes().toString().rjust(2, "0") + ":"
+ this.getSeconds().toString().rjust(2, "0") + "."
+ this.getMilliseconds().toString().rjust(3, "0") + "."
);
}
}
}
]]>
</script>
<reference object="Scripting.FileSystemObject"/>
<object id="fso" progid="Scripting.FileSystemObject"/>
<reference object="WScript.Shell"/>
<object id="shell" progid="WScript.Shell"/>
</job>