1
0
mirror of https://github.com/gryf/pentadactyl-pm.git synced 2026-02-21 23:55:45 +01:00
This commit is contained in:
Kris Maglione
2009-03-30 01:14:46 -04:00
113 changed files with 1839 additions and 712 deletions

143
xulmus/content/bookmarks.js Executable file → Normal file
View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -57,7 +57,7 @@ function Bookmarks() //{{{
/////////////////////////////////////////////////////////////////////////////{{{
const historyService = PlacesUtils.history; //Cc["@mozilla.org/browser/global-history;1"].getService(Ci.nsIGlobalHistory);
const bookmarksService = PlacesUtils.bookmarks //Cc["@songbirdnest.com/servicepane/bookmarks;1"].getService(Ci.sbIBookmarks);
const bookmarksService = PlacesUtils.bookmarks //Cc["@songbirdnest.com/servicepane/bookmarks;1"].getService(Ci.sbIBookmarks);
const taggingService = PlacesUtils.tagging //Cc["@mozilla.org/browser/tagging-service;1"].getService(Ci.nsITaggingService);
const faviconService = Cc["@mozilla.org/browser/favicon-service;1"].getService(Ci.nsIFaviconService);
@@ -571,14 +571,14 @@ function Bookmarks() //{{{
getSuggestions: function getSuggestions(engineName, query, callback)
{
const responseType = "application/x-suggestions+json";
let engine = services.get("browserSearch").getEngineByAlias(engineName);
if (engine && engine.supportsResponseType(responseType))
var queryURI = engine.getSubmission(query, responseType).uri.spec;
if (!queryURI)
return [];
function process(resp)
{
let results = [];
@@ -594,7 +594,7 @@ function Bookmarks() //{{{
}
let resp = util.httpGet(queryURI, callback && process);
if (!callback)
return process(resp);
},
@@ -620,76 +620,77 @@ function Bookmarks() //{{{
// we need to make sure our custom alias have been set, even if the user
// did not :open <tab> once before
this.getSearchEngines();
function getShortcutOrURI(aURL, aPostDataRef)
{
var shortcutURL = null;
var keyword = aURL;
var param = "";
var searchService = Cc['@mozilla.org/browser/search-service;1'].getService(Ci.nsIBrowserSearchService);
var offset = aURL.indexOf(" ");
if (offset > 0)
{
keyword = aURL.substr(0, offset);
param = aURL.substr(offset + 1);
}
if (!aPostDataRef)
{
aPostDataRef = {};
function getShortcutOrURI(aURL, aPostDataRef)
{
var shortcutURL = null;
var keyword = aURL;
var param = "";
var searchService = Cc['@mozilla.org/browser/search-service;1'].getService(Ci.nsIBrowserSearchService);
var offset = aURL.indexOf(" ");
if (offset > 0)
{
keyword = aURL.substr(0, offset);
param = aURL.substr(offset + 1);
}
var engine = searchService.getEngineByAlias(keyword);
if (engine)
{
var submission = engine.getSubmission(param, null);
aPostDataRef.value = submission.postData;
return submission.uri.spec;
}
[shortcutURL, aPostDataRef.value] = PlacesUtils.getURLAndPostDataForKeyword(keyword);
if (!shortcutURL)
{
return aURL;
}
var postData = "";
if (aPostDataRef.value)
{
postData = unescape(aPostDataRef.value);
}
if (/%s/i.test(shortcutURL) || /%s/i.test(postData))
{
var charset = "";
const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
var matches = shortcutURL.match(re);
if (matches)
{
[, shortcutURL, charset] = matches;
}
else
{
try
{
charset = PlacesUtils.history.getCharsetForURI(makeURI(shortcutURL));
} catch (e) { }
}
var encodedParam = "";
if (charset)
{
encodedParam = escape(convertFromUnicode(charset, param));
} else {
encodedParam = encodeURIComponent(param);
}
shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
if (/%s/i.test(postData))
{
aPostDataRef.value = getPostDataStream(postData, param, encodedParam, "application/x-www-form-urlencoded");
}
} else if (param) {
aPostDataRef.value = null;
return aURL;
if (!aPostDataRef)
{
aPostDataRef = {};
}
return shortcutURL;
var engine = searchService.getEngineByAlias(keyword);
if (engine)
{
var submission = engine.getSubmission(param, null);
aPostDataRef.value = submission.postData;
return submission.uri.spec;
}
[shortcutURL, aPostDataRef.value] = PlacesUtils.getURLAndPostDataForKeyword(keyword);
if (!shortcutURL)
{
return aURL;
}
var postData = "";
if (aPostDataRef.value)
{
postData = unescape(aPostDataRef.value);
}
if (/%s/i.test(shortcutURL) || /%s/i.test(postData))
{
var charset = "";
const re = /^(.*)\&mozcharset=([a-zA-Z][_\-a-zA-Z0-9]+)\s*$/;
var matches = shortcutURL.match(re);
if (matches)
{
[, shortcutURL, charset] = matches;
}
else
{
try
{
charset = PlacesUtils.history.getCharsetForURI(makeURI(shortcutURL));
} catch (e) { }
}
var encodedParam = "";
if (charset)
{
encodedParam = escape(convertFromUnicode(charset, param));
} else {
encodedParam = encodeURIComponent(param);
}
shortcutURL = shortcutURL.replace(/%s/g, encodedParam).replace(/%S/g, param);
if (/%s/i.test(postData))
{
aPostDataRef.value = getPostDataStream(postData, param, encodedParam, "application/x-www-form-urlencoded");
}
} else if (param) {
aPostDataRef.value = null;
return aURL;
}
return shortcutURL;
}
url = getShortcutOrURI(searchString, aPostDataRef);
if (url == searchString)
url = null;

172
xulmus/content/config.js Executable file → Normal file
View File

@@ -11,7 +11,7 @@ WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
for the specific language governing rights and limitations under the
License.
Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@gmx.net>
Copyright (c) 2006-2009 by Martin Stubenschrott <stubenschrott@vimperator.org>
Alternatively, the contents of this file may be used under the terms of
either the GNU General Public License Version 2 or later (the "GPL"), or
@@ -33,12 +33,12 @@ const config = { //{{{
//mainWindowID: "mainplayer",
/*** optional options, there are checked for existence and a fallback provided ***/
features: ["bookmarks", "hints", "marks", "history", "quickmarks", "session", "tabs", "windows", "player"],
defaults: { guioptions: "rb" },
defaults: { guioptions: "mprb" },
guioptions: {
m: ["Menubar", ["main-menubar"]],
T: ["Toolbar", ["nav-bar"]],
B: ["Bookmark bar", ["PersonalToolbar"]]
m: ["Menubar", ["main-menubar"]],
T: ["Toolbar", ["nav-bar"]],
p: ["Player controls", ["player_wrapper"]]
},
//get visualbellWindow() getBrowser().mPanelContainer,
@@ -54,53 +54,74 @@ const config = { //{{{
["DOMLoad", "Triggered when a page's DOM content has fully loaded"],
["DownloadPost", "Triggered when a download has completed"],
["Fullscreen", "Triggered when the browser's fullscreen state changes"],
["LocationChange", "Triggered when changing tabs or when naviagtion to a new location"],
["LocationChange", "Triggered when changing tabs or when navigation to a new location"],
["PageLoadPre", "Triggered after a page load is initiated"],
["PageLoad", "Triggered when a page gets (re)loaded/opened"],
["ShellCmdPost", "Triggered after executing a shell command with :!cmd"],
["XulmusEnter", "Triggered after Xulmus starts"],
["XulmusLeavePre", "Triggered before exiting Xulmus, just before destroying each module"],
["XulmusLeave", "Triggered before exiting Xulmus"]],
["TrackChangePre", "Triggered before a playing track is changed"],
["TrackChange", "Triggered after a playing track has changed"],
["ViewChangePre", "Triggered before a sequencer view is changed"],
["ViewChange", "Triggered after a sequencer view is changed"],
["StreamStart", "Triggered after a stream has started"],
["StreamPause", "Triggered after a stream has paused"],
["StreamEnd", "Triggered after a stream has ended"],
["StreamStop", "Triggered after a stream has stopped"],
["XulmusEnter", "Triggered after Songbird starts"],
["XulmusLeavePre", "Triggered before exiting Songbird, just before destroying each module"],
["XulmusLeave", "Triggered before exiting Songbird"]],
// TODO: remove those which don't make sense, can't be provided.
dialogs: [
["about", "About Songbird",
function () { window.openDialog("chrome://browser/content/aboutDialog.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
function () { window.openDialog("chrome://songbird/content/xul/about.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
/*
["addbookmark", "Add bookmark for the current page",
function () { PlacesCommandHook.bookmarkCurrentPage(true, PlacesUtils.bookmarksRootId); }],
*/
["addons", "Manage Add-ons",
function () { window.BrowserOpenAddonsMgr(); }],
function () { SBOpenPreferences("paneAddons"); }],
/*
["bookmarks", "List your bookmarks",
function () { window.openDialog("chrome://browser/content/bookmarks/bookmarksPanel.xul", "Bookmarks", "dialog,centerscreen,width=600,height=600"); }],
*/
["checkupdates", "Check for updates",
function () { window.checkForUpdates(); }],
["cleardata", "Clear private data",
function () { Cc[GLUE_CID].getService(Ci.nsIBrowserGlue).sanitize(window || null); }],
function () { Sanitizer.showUI(); }],
["cookies", "List your cookies",
function () { window.toOpenWindowByType("Browser:Cookies", "chrome://browser/content/preferences/cookies.xul", "chrome,dialog=no,resizable"); }],
["console", "JavaScript console",
function () { window.toJavaScriptConsole(); }],
/*
["customizetoolbar", "Customize the Toolbar",
function () { window.BrowserCustomizeToolbar(); }],
*/
["dominspector", "DOM Inspector",
function () { try { window.inspectDOMDocument(content.document); } catch (e) { liberator.echoerr("DOM Inspector extension not installed"); } }],
["downloads", "Manage Downloads",
function () { window.toOpenWindowByType("Download:Manager", "chrome://mozapps/content/downloads/downloads.xul", "chrome,dialog=no,resizable"); }],
/*
["history", "List your history",
function () { window.openDialog("chrome://browser/content/history/history-panel.xul", "History", "dialog,centerscreen,width=600,height=600"); }],
["import", "Import Preferences, Bookmarks, History, etc. from other browsers",
function () { window.BrowserImport(); }],
*/
["openfile", "Open the file selector dialog",
function () { window.BrowserOpenFileWindow(); }],
function () { SBFileOpen(); }],
/*
["pageinfo", "Show information about the current page",
function () { window.BrowserPageInfo(); }],
*/
["pagesource", "View page source",
function () { window.BrowserViewSourceOfDocument(content.document); }],
["places", "Places Organizer: Manage your bookmarks and history",
function () { PlacesCommandHook.showPlacesOrganizer(ORGANIZER_ROOT_BOOKMARKS); }],
["preferences", "Show Firefox preferences dialog",
["preferences", "Show Songbird preferences dialog",
function () { window.openPreferences(); }],
/*
["printpreview", "Preview the page before printing",
function () { PrintUtils.printPreview(onEnterPrintPreview, onExitPrintPreview); }],
*/
["printsetup", "Setup the page size and orientation before printing",
function () { PrintUtils.showPageSetup(); }],
["print", "Show print dialog",
@@ -112,7 +133,9 @@ const config = { //{{{
["searchengines", "Manage installed search engines",
function () { window.openDialog("chrome://browser/content/search/engineManager.xul", "_blank", "chrome,dialog,modal,centerscreen"); }],
["selectionsource", "View selection source",
function () { buffer.viewSelectionSource(); }]
function () { buffer.viewSelectionSource(); }],
["subscribe", "Add a new subscription",
function () { SBSubscribe(); }]
],
focusChange: function() {
@@ -127,14 +150,14 @@ const config = { //{{{
//TODO : Write intro.html and tutorial.html
// they are sorted by relevance, not alphabetically
//helpFiles: [ "intro.html" ],
/* "intro.html", "tutorial.html", "starting.html", "browsing.html",
"buffer.html", "cmdline.html", "insert.html", "options.html",
"pattern.html", "tabs.html", "hints.html", "map.html", "eval.html",
"marks.html", "repeat.html", "autocommands.html", "print.html",
"gui.html", "styling.html", "message.html", "developer.html",
"various.html", "index.html", "version.html"
], */
helpFiles: [
"intro.html", /*"tutorial.html",*/ "starting.html", "player.html",
"browsing.html", "buffer.html", "cmdline.html", "insert.html",
"options.html", "pattern.html", "tabs.html", "hints.html", "map.html",
"eval.html", "marks.html", "repeat.html", "autocommands.html",
"print.html", "gui.html", "styling.html", "message.html",
"developer.html", "various.html", "index.html", "version.html"
],
optionDefaults: {
stal: 0,
@@ -179,6 +202,31 @@ const config = { //{{{
liberator.open(pre + newNumberStr + post);
}
function openDisplayPane(id)
{
let pane = document.getElementById(id);
let manager = Components.classes['@songbirdnest.com/Songbird/DisplayPane/Manager;1']
.getService(Components.interfaces.sbIDisplayPaneManager);
let paneinfo = manager.getPaneInfo(pane._lastURL.stringValue);
if (!paneinfo)
paneinfo = manager.defaultPaneInfo;
pane.loadContent(paneinfo);
}
// FIXME: best way to format these args? Hyphenated? One word like :dialog?
let displayPanes = {
"content pane bottom": "displaypane_contentpane_bottom",
"service pane bottom": "displaypane_servicepane_bottom",
"right sidebar": "displaypane_right_sidebar"
};
completion.displayPane = function (context) {
context.title = ["Display Pane"];
context.completions = displayPanes; // FIXME: useful description etc
};
// load Xulmus specific modules
// FIXME: Why aren't these listed in config.scripts?
// FIXME: Why isn't this automatic? -> how would one know which classes to load where? --mst
@@ -198,6 +246,7 @@ const config = { //{{{
liberator.loadModule("hints", Hints);
// Load the Player module
liberator.loadModule("player", Player);
////////////////////////////////////////////////////////////////////////////////
////////////////////// STYLES //////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
@@ -369,7 +418,7 @@ const config = { //{{{
"Show " + config.hostApplication + " preferences",
function (args)
{
if (args.bang) // open Firefox settings GUI dialog
if (args.bang) // open Songbird settings GUI dialog
{
liberator.open("about:config",
(options["newtab"] && options.get("newtab").has("all", "prefs"))
@@ -396,66 +445,40 @@ const config = { //{{{
},
{ argCount: "0" });
// TODO: move sidebar commands to ui.js?
commands.add(["sbcl[ose]"],
"Close the sidebar window",
function ()
{
if (!document.getElementById("sidebar-box").hidden)
toggleSidebar();
},
{ argCount: "0" });
commands.add(["sideb[ar]", "sb[ar]", "sbope[n]"],
"Open the sidebar window",
commands.add(["dpcl[ose]"],
"Close a display pane",
function (args)
{
let arg = args.literalArg;
// focus if the requested sidebar is already open
if (document.getElementById("sidebar-title").value == arg)
{
document.getElementById("sidebar-box").focus();
return;
}
if (arg in displayPanes)
document.getElementById(displayPanes[arg]).hide();
else
liberator.echoerr("E475: Invalid argument: " + arg);
let menu = document.getElementById("viewSidebarMenu");
for (let [,panel] in Iterator(menu.childNodes))
{
if (panel.label == arg)
{
panel.doCommand();
return;
}
}
liberator.echoerr("No sidebar " + arg + " found");
},
{
argCount: "1",
completer: function (context) completion.sidebar(context),
completer: function (context) completion.displayPane(context),
literal: 0
});
commands.add(["winc[lose]", "wc[lose]"],
"Close window",
function () { window.close(); },
{ argCount: "0" });
commands.add(["wino[pen]", "wo[pen]", "wine[dit]"],
"Open one or more URLs in a new window",
// TODO: this should accept a second arg to specify content
commands.add(["displayp[ane]", "dp[ane]", "dpope[n]"],
"Open a display pane",
function (args)
{
args = args.string;
let arg = args.literalArg;
if (args)
liberator.open(args, liberator.NEW_WINDOW);
if (arg in displayPanes)
openDisplayPane(displayPanes[arg])
// TODO: focus when we have better key handling of these extended modes
else
liberator.open("about:blank", liberator.NEW_WINDOW);
liberator.echoerr("E475: Invalid argument: " + arg);
},
{
completer: function (context) completion.url(context),
argCount: "1",
completer: function (context) completion.displayPane(context),
literal: 0
});
@@ -463,6 +486,9 @@ const config = { //{{{
////////////////////// OPTIONS /////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
let stal = options.get("showtabline");
stal.value = stal.defaultValue = 2;
options.add(["online"],
"Set the 'work offline' option",
"boolean", true,
@@ -505,8 +531,18 @@ const config = { //{{{
options.add(["urlseparator"],
"Set the separator regexp used to separate multiple URL args",
"string", ",\\s");
//}}}
// TODO: mention this to SB devs, they seem keen to provide these
// functions to make porting from FF as simple as possible.
window.toJavaScriptConsole = function () {
toOpenWindowByType("global:console", "chrome://global/content/console.xul");
}
window.BrowserStop = function () {
getBrowser().mCurrentBrowser.stop();
}
}
//}}}
}; //}}}
// vim: set fdm=marker sw=4 ts=4 et:

0
xulmus/content/liberator.dtd Executable file → Normal file
View File

851
xulmus/content/player.js Executable file → Normal file
View File

@@ -1,75 +1,490 @@
//Import Artist List as this can be huge
var artists = getArtistsArray();
function Player() // {{{
{
////////////////////////////////////////////////////////////////////////////////
////////////////////// PRIVATE SECTION /////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
let lastSearchString = "";
let lastSearchIndex = 0;
let lastSearchView = _SBGetCurrentView();
// Get the focus to the visible playlist first
//window._SBShowMainLibrary();
function getArtistsArray()
{
var list = LibraryUtils.mainLibrary;
// Create an enumeration listener to count each item
var listener = {
count: 0,
onEnumerationBegin: function (aMediaList) {
this.count = 0;
},
onEnumeratedItem: function (aMediaList, aMediaItem) {
this.count++;
},
onEnumerationEnd: function (aMediaList, aStatusCode) {}
};
var artistCounts = {};
var artists = list.getDistinctValuesForProperty(SBProperties.artistName);
var artist;
var artistArray = [];
var i = 0;
// Count the number of media items for each distinct artist
while (artists.hasMore())
{
artist = artists.getNext();
artistArray[i] = [artist, artist];
list.enumerateItemsByProperty(SBProperties.artistName,
artist,
listener,
Ci.sbIMediaList.ENUMERATIONTYPE_LOCKING);
artistCounts[artist] = listener.count;
i++;
}
//liberator.dump("Count : "+artistCounts.toSource());
return artistArray;
}
// Get the artist names before hand.
let artists = getArtistsArray();
const pageService = Components.classes["@songbirdnest.com/Songbird/MediaPageManager;1"]
.getService(Components.interfaces.sbIMediaPageManager);
// Register Callbacks for searching.
liberator.registerCallback("change", modes.SEARCH_VIEW_FORWARD, function (str) { player.onSearchKeyPress(str); });
liberator.registerCallback("submit", modes.SEARCH_VIEW_FORWARD, function (str) { player.onSearchSubmit(str); });
//liberator.registerCallback("cancel", modes.SEARCH_VIEW_FORWARD, function (command) { player.searchView(command);});
// interval (milliseconds)
function seek(interval, direction)
{
let position = gMM.playbackControl ? gMM.playbackControl.position : 0;
player.seekTo(position + (direction ? interval : -interval));
}
function focusTrack(mediaItem)
{
SBGetBrowser().mediaTab.mediaPage.highlightItem(_SBGetCurrentView().getIndexForItem(mediaItem));
}
var mediaCoreListener = {
onMediacoreEvent: function (event)
{
switch (event.type)
{
case Ci.sbIMediacoreEvent.BEFORE_TRACK_CHANGE:
liberator.log("Before track changed: " + event.data);
autocommands.trigger("TrackChangePre", { track: event.data });
break;
case Ci.sbIMediacoreEvent.TRACK_CHANGE:
autocommands.trigger("TrackChange", { track: event.data });
break;
case Ci.sbIMediacoreEvent.BEFORE_VIEW_CHANGE:
liberator.log("Before view changed: " + event.data);
autocommands.trigger("ViewChangePre", { view: event.data });
break;
case Ci.sbIMediacoreEvent.VIEW_CHANGE:
liberator.log("View changed: " + event.data);
autocommands.trigger("ViewChange", { view: event.data });
break;
case Ci.sbIMediacoreEvent.STREAM_START:
liberator.log("Track started: " + gMM.sequencer.currentItem);
autocommands.trigger("StreamStart", { track: gMM.sequencer.currentItem });
break;
case Ci.sbIMediacoreEvent.STREAM_PAUSE:
liberator.log("Track paused: " + gMM.sequencer.currentItem);
autocommands.trigger("StreamPause", { track: gMM.sequencer.currentItem });
break;
case Ci.sbIMediacoreEvent.STREAM_END:
liberator.log("Track ended: " + gMM.sequencer.currentItem);
autocommands.trigger("StreamEnd", { track: gMM.sequencer.currentItem });
break;
case Ci.sbIMediacoreEvent.STREAM_STOP:
liberator.log("Track stopped: " + gMM.sequencer.currentItem);
autocommands.trigger("StreamStop", { track: gMM.sequencer.currentItem });
break;
}
}
};
gMM.addListener(mediaCoreListener);
liberator.registerObserver("shutdown", function () {
gMM.removeListener(mediaCoreListener);
});
/////////////////////////////////////////////////////////////////////////////}}}
////////////////////// MAPPINGS ////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
mappings.add([modes.PLAYER],
["x"], "Play Track",
function ()
{
gMM.sequencer.play();
});
["x"], "Play track",
function () { player.play(); });
mappings.add([modes.PLAYER],
["z"], "Previous Track",
function ()
{
gSongbirdWindowController.doCommand("cmd_control_previous");
});
["z"], "Previous track",
function () { player.previous(); });
mappings.add([modes.PLAYER],
["c"], "Pause/Unpause Track",
function ()
{
gSongbirdWindowController.doCommand("cmd_control_playpause");
});
["c"], "Pause/unpause track",
function () { player.togglePlayPause(); });
mappings.add([modes.PLAYER],
["b"], "Next Track",
function ()
{
gSongbirdWindowController.doCommand("cmd_control_next");
});
["b"], "Next track",
function () { player.next(); });
mappings.add([modes.PLAYER],
["v"], "Stop Track",
function ()
["v"], "Stop track",
function () { player.stop(); });
mappings.add([modes.PLAYER],
["f"], "Filter library",
function () { commandline.open(":", "filter ", modes.EX); });
mappings.add([modes.PLAYER],
["F"], "Loads current view filtered by the keywords",
function () { commandline.open(":", "Filter ", modes.EX); });
mappings.add([modes.PLAYER],
["i"], "Select current track",
function () { gSongbirdWindowController.doCommand("cmd_find_current_track"); });
mappings.add([modes.PLAYER],
["s"], "Toggle shuffle",
function () { player.toggleShuffle(); });
mappings.add([modes.PLAYER],
["r"], "Toggle repeat",
function () { player.toggleRepeat(); });
mappings.add([modes.PLAYER],
["h", "<Left>"], "Seek -10s",
function (count) { player.seekBackward(Math.max(1, count) * 10000); },
{ flags: Mappings.flags.COUNT });
mappings.add([modes.PLAYER],
["l", "<Right>"], "Seek +10s",
function (count) { player.seekForward(Math.max(1, count) * 10000); },
{ flags: Mappings.flags.COUNT });
mappings.add([modes.PLAYER],
["H", "<S-Left>"], "Seek -1m",
function (count) { player.seekBackward(Math.max(1, count) * 60000); },
{ flags: Mappings.flags.COUNT });
mappings.add([modes.PLAYER],
["L", "<S-Right>"], "Seek +1m",
function (count) { player.seekForward(Math.max(1, count) * 60000); },
{ flags: Mappings.flags.COUNT });
mappings.add([modes.PLAYER],
["=", "+"], "Increase volume by 10%",
function () { player.increaseVolume(); });
mappings.add([modes.PLAYER],
["-"], "Decrease volume by 10%",
function () { player.decreaseVolume(); });
mappings.add([modes.PLAYER],
["/"], "Search forward for a track",
function (args) { commandline.open("/", "", modes.SEARCH_VIEW_FORWARD); });
mappings.add([modes.PLAYER],
["n"], "Find the next track",
function () { player.searchViewAgain(false);});
mappings.add([modes.PLAYER],
["N"], "Find the previous track",
function () { player.searchViewAgain(true);});
for (let i in util.range(0, 6))
{
let (rating = i) {
mappings.add([modes.PLAYER],
["<C-" + rating + ">"], "Rate the current media item " + rating,
function () { player.rateMediaItem(rating); });
}
}
////////////////// ///////////////////////////////////////////////////////////}}}
////////////////////// COMMANDS ////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
// TODO: rename :Filter to :filter and move this functionality into :tqueue etc? --djk
commands.add(["f[ilter]"],
"Filter and play tracks",
function (args)
{
// Store the old view
// let prev_view = gMM.status.view;
let library = LibraryUtils.mainLibrary;
let mainView = library.createView();
let sqncr = gMM.sequencer;
let customProps = Cc["@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
.createInstance(Ci.sbIMutablePropertyArray);
// args
switch (args.length)
{
case 3:
customProps.appendProperty(SBProperties.trackName, args[2].toString());
case 2:
customProps.appendProperty(SBProperties.albumName, args[1].toString());
case 1:
customProps.appendProperty(SBProperties.artistName, args[0].toString());
break;
default:
break;
}
sqncr.playView(mainView, mainView.getIndexForItem(library.getItemsByProperties(customProps).queryElementAt(0, Ci.sbIMediaItem)));
player.focusPlayingTrack();
},
{
argCount: "+",
completer: function (context, args) completion.song(context, args)
});
commands.add(["F[ilter]"],
"Filter tracks based on keywords {genre/artist/album/track}",
function (args)
{
let library = LibraryUtils.mainLibrary;
let view = LibraryUtils.createStandardMediaListView(LibraryUtils.mainLibrary, args.literalArg);
if (view.length == 0)
liberator.echoerr("No Tracks matching the keywords");
else
{
SBGetBrowser().loadMediaList(LibraryUtils.mainLibrary, null, null, view,
"chrome://songbird/content/mediapages/filtersPage.xul");
// TODO: make this focusTrack work ?
focusTrack(view.getItemByIndex(0));
}
},
{
argCount: "1",
literal: 0
//completer: function (context, args) completion.tracks(context, args);
});
commands.add(["load"],
"Load a playlist",
function (args)
{
let arg = args.literalArg;
if (arg)
{
// load the selected playlist/smart playlist
let playlists = player.getPlaylists();
for ([i, list] in Iterator(playlists))
{
if (util.compareIgnoreCase(arg, list.name) == 0)
{
SBGetBrowser().loadMediaList(playlists[i]);
focusTrack(_SBGetCurrentView().getItemByIndex(0));
return;
}
}
liberator.echoerr("E475: Invalid argument: " + arg);
}
else
{
// load main library if there are no args
_SBShowMainLibrary();
}
},
{
argCount: "?",
completer: function (context, args) completion.playlist(context, args),
literal: 0
});
// TODO: better off as a single command (:player play) or cmus compatible (:player-play)? --djk
commands.add(["playerp[lay]"],
"Play track",
function () { player.play(); });
commands.add(["playerpa[use]"],
"Pause/unpause track",
function () { player.togglePlayPause(); });
commands.add(["playern[ext]"],
"Play next track",
function () { player.next(); });
commands.add(["playerpr[ev]"],
"Play previous track",
function () { player.previous(); });
commands.add(["players[top]"],
"Stop track",
function () { player.stop(); });
commands.add(["see[k]"],
"Seek to a track position",
function (args)
{
let arg = args[0];
// intentionally supports 999:99:99
if (!/^[+-]?(\d+[smh]?|(\d+:\d\d:|\d+:)?\d{2})$/.test(arg))
{
liberator.echoerr("E475: Invalid argument: " + arg);
return;
}
function ms(t, m) Math.abs(parseInt(t, 10) * { s: 1000, m: 60000, h: 3600000 }[m])
if (/:/.test(arg))
{
let [seconds, minutes, hours] = arg.split(":").reverse();
hours = hours || 0;
var value = ms(seconds, "s") + ms(minutes, "m") + ms(hours, "h");
}
else
{
if (!/[smh]/.test(arg.substr(-1)))
arg += "s"; // default to seconds
value = ms(arg.substring(arg, arg.length - 1), arg.substr(-1));
}
if (/^[-+]/.test(arg))
arg[0] == "-" ? player.seekBackward(value) : player.seekForward(value)
else
player.seekTo(value)
},
{ argCount: "1" });
commands.add(["mediav[iew]"],
"Change the current media view",
function (args)
{
// FIXME: is this a SB restriction? --djk
if (!gBrowser.currentMediaPage)
{
liberator.echoerr("Exxx: Can only set the media view from the media tab"); // XXX
return;
}
let arg = args[0];
if (arg)
{
let pages = player.getMediaPages();
for ([,page] in Iterator(pages))
{
if (util.compareIgnoreCase(arg, page.contentTitle) == 0)
{
player.loadMediaPage(page, gBrowser.currentMediaListView.mediaList, gBrowser.currentMediaListView);
return;
}
}
liberator.echoerr("E475: Invalid argument: " + arg);
}
},
{
argCount: "1",
completer: function (context) completion.mediaView(context),
literal: 0
});
// TODO: maybe :vol! could toggle mute on/off? --djk
commands.add(["vol[ume]"],
"Set the volume",
function (args)
{
let arg = args[0];
if (!/^[+-]?\d+$/.test(arg))
{
liberator.echoerr("E488: Trailing characters");
return;
}
let level = parseInt(arg, 10) / 100;
if (/^[+-]/.test(arg))
level = player.volume + level;
player.volume = Math.min(Math.max(level, 0), 1);
},
{ argCount: "1" });
/////////////////////////////////////////////////////////////////////////////}}}
////////////////////// PUBLIC SECTION //////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
return {
// TODO: check bounds and round, 0 - 1 or 0 - 100?
get volume() gMM.volumeControl.volume,
set volume(value)
{
gMM.volumeControl.volume = value;
},
// FIXME: can't be called from non-media tabs since 840e78
play: function play()
{
// Check if there is any selection in place, else play first item of the visible view.
if (_SBGetCurrentView().selection.count != 0)
{
// Play the selection.
gMM.sequencer.playView(_SBGetCurrentView(), _SBGetCurrentView().getIndexForItem(_SBGetCurrentView().selection.currentMediaItem));
focusTrack(gMM.sequencer.currentItem);
}
else
{
gMM.sequencer.playView(SBGetBrowser().currentMediaListView, 0);
focusTrack(gMM.sequencer.currentItem);
}
},
stop: function stop()
{
gMM.sequencer.stop();
});
},
mappings.add([modes.PLAYER],
["l"], "Play Media",
function ()
next: function next()
{
commandline.open(":", "playmedia ", modes.EX);
});
gSongbirdWindowController.doCommand("cmd_control_next");
gSongbirdWindowController.doCommand("cmd_find_current_track");
},
mappings.add([modes.PLAYER],
["s"], "Toggle Shuffle",
function ()
previous: function previous()
{
gSongbirdWindowController.doCommand("cmd_control_previous");
gSongbirdWindowController.doCommand("cmd_find_current_track");
},
togglePlayPause: function togglePlayPause()
{
gSongbirdWindowController.doCommand("cmd_control_playpause");
focusTrack(gMM.sequencer.currentItem);
},
toggleShuffle: function toggleShuffle()
{
if (gMM.sequencer.mode != gMM.sequencer.MODE_SHUFFLE)
gMM.sequencer.mode = gMM.sequencer.MODE_SHUFFLE;
else
gMM.sequencer.mode = gMM.sequencer.MODE_FORWARD;
});
},
mappings.add([modes.PLAYER],
["r"], "Toggle Repeat",
function ()
// FIXME: not really toggling - good enough for now.
toggleRepeat: function toggleRepeat()
{
switch (gMM.sequencer.repeatMode)
{
@@ -86,131 +501,249 @@ function Player() // {{{
gMM.sequencer.repeatMode = gMM.sequencer.MODE_REPEAT_NONE;
break;
}
});
/////////////////////////////////////////////////////////////////////////////}}}
////////////////////// COMMANDS ////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
commands.add(["playmedia"],
"Play Media",
function (args)
{
//Store the old view
//var prev_view = gMM.status.view;
var library = LibraryUtils.mainLibrary;
var mainView = library.createView();
var sqncr = gMM.sequencer;
var customProps = Cc["@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
.createInstance(Ci.sbIMutablePropertyArray);
//args
if (args.length == 1)
{
customProps.appendProperty(SBProperties.artistName,args[0].toString());
}
else if (args.length == 2)
{
customProps.appendProperty(SBProperties.artistName,args[0].toString());
customProps.appendProperty(SBProperties.albumName,args[1].toString());
}
else if (args.length == 3)
{
customProps.appendProperty(SBProperties.artistName,args[0].toString());
customProps.appendProperty(SBProperties.albumName,args[1].toString());
customProps.appendProperty(SBProperties.trackName,args[2].toString());
}
sqncr.playView(mainView, mainView.getIndexForItem(library.getItemsByProperties(customProps).queryElementAt(0,Ci.sbIMediaItem)));
},
seekForward: function seekForward(interval)
{
completer: function (context, args) completion.song(context, args)
});
seek(interval, true);
},
/////////////////////////////////////////////////////////////////////////////}}}
////////////////////// PUBLIC SECTION //////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////{{{
seekBackward: function seekBackward(interval)
{
seek(interval, false);
},
seekTo: function seekTo(position)
{
// FIXME: if not playing
if (!gMM.playbackControl)
this.play();
let min = 0;
let max = gMM.playbackControl.duration - 5000; // TODO: 5s buffer like cmus desirable?
gMM.playbackControl.position = Math.min(Math.max(position, min), max);
},
// FIXME: 10% ?
// I think just general increments of say 0.05 might be better --djk
increaseVolume: function increaseVolume()
{
gMM.volumeControl.volume = gMM.volumeControl.volume * 1.1;
},
decreaseVolume: function decreaseVolume()
{
if (gMM.volumeControl.volume == 0)
gMM.volumeControl.volume = 0.1;
else
gMM.volumeControl.volume = gMM.volumeControl.volume * 0.9;
},
focusPlayingTrack :function focusPlayingTrack()
{
focusTrack(gMM.sequencer.currentItem);
},
listTracks: function listTracks(view)
{
//let myView = LibraryUtils.createStandardMediaListView(LibraryUtils.mainLibrary, args);
let length = view.length;
let tracksList = [];
for (let i = 0; i < length; i++)
{
let mediaItem = view.getItemByIndex(i);
let trackName = mediaItem.getProperty(SBProperties.trackName);
let albumName = mediaItem.getProperty(SBProperties.albumName);
let artistName = mediaItem.getProperty(SBProperties.artistName);
tracksList[i] = [trackName, "Album : " + albumName + " Artist : " + artistName];
}
return tracksList;
},
searchView: function searchView (args)
{
let currentView = _SBGetCurrentView();
let mediaItemList = currentView.mediaList;
let search = _getSearchString(currentView);
let searchString = "";
if (search != "")
searchString = args + " " + search;
else
searchString = args;
lastSearchString = searchString;
let mySearchView = LibraryUtils.createStandardMediaListView(mediaItemList, searchString);
if (mySearchView.length)
{
lastSearchView = mySearchView;
lastSearchIndex = 0;
focusTrack(mySearchView.getItemByIndex(lastSearchIndex));
}
else
{
liberator.echoerr("E486 Pattern not found: " + searchString, commandline.FORCE_SINGLELINE);
}
},
searchViewAgain: function searchViewAgain(reverse)
{
function echo(str)
{
setTimeout(function () {
commandline.echo(str, commandline.HL_WARNINGMSG, commandline.APPEND_TO_MESSAGES | commandline.FORCE_SINGLELINE);
}, 0);
}
if (reverse)
{
if (lastSearchIndex == 0)
{
lastSearchIndex = lastSearchView.length - 1;
echo("Search hit TOP, continuing at BOTTOM");
}
else
lastSearchIndex = lastSearchIndex - 1;
}
else
{
if (lastSearchIndex == (lastSearchView.length - 1))
{
lastSearchIndex = 0;
echo("Search hit BOTTOM, continuing at TOP");
}
else
lastSearchIndex = lastSearchIndex + 1;
}
//FIXME: Implement for "?" --ken
commandline.echo("/" + lastSearchString, null, commandline.FORCE_SINGLELINE);
focusTrack(lastSearchView.getItemByIndex(lastSearchIndex));
},
onSearchKeyPress: function (str)
{
if (options["incsearch"])
this.searchView(str);
},
onSearchSubmit: function (str)
{
this.searchView(str);
},
getPlaylists: function getPlaylists()
{
let mainLibrary = LibraryUtils.mainLibrary;
let playlists = [mainLibrary];
let listener = {
onEnumerationBegin: function () { },
onEnumerationEnd: function () { },
onEnumeratedItem: function (list, item)
{
// FIXME: why are there null items and duplicates?
if (!playlists.some(function (list) list.name == item.name) && item.name != null)
{
playlists.push(item);
}
return Components.interfaces.sbIMediaListEnumerationListener.CONTINUE;
}
};
mainLibrary.enumerateItemsByProperty("http://songbirdnest.com/data/1.0#isList", "1", listener);
return playlists;
},
// Play track at 'row' in 'playlist'
playPlaylist: function playPlaylist(playlist, row)
{
gMM.sequencer.playView(playlist.createView(), row);
},
getMediaPages: function getMediaPages()
{
let list = gBrowser.currentMediaPage.mediaListView.mediaList;
let pages = pageService.getAvailablePages(list);
return ArrayConverter.JSArray(pages).map(function (page) page.QueryInterface(Components.interfaces.sbIMediaPageInfo));
},
loadMediaPage: function loadMediaList(page, list, view)
{
pageService.setPage(list, page);
gBrowser.loadMediaList(list, null, null, view, null);
},
rateMediaItem: function rateMediaItem(rating)
{
if (gMM.sequencer.currentItem)
gMM.sequencer.currentItem.setProperty(SBProperties.rating, rating);
},
getArtists: function getArtists()
{
return artists;
},
getAlbums: function getAlbums(artist)
{
var list = LibraryUtils.mainLibrary;
var albumArray = [], returnArray = [];
var items = list.getItemsByProperty(SBProperties.artistName, artist).enumerate();
var i = 0, j = 0;
while (items.hasMoreElements())
{
album = items.getNext().getProperty(SBProperties.albumName);
albumArray[i] = [album, album];
if (i == 0)
{
returnArray[j] = albumArray[i];
j++;
}
else if (albumArray[i-1].toString() != albumArray[i].toString())
{
returnArray[i] = albumArray[i];
j++;
}
i++;
}
return returnArray;
},
getTracks: function getTracks(artist, album)
{
var list = LibraryUtils.mainLibrary;
var tracksArray = [];
var pa = Cc["@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
.createInstance(Ci.sbIMutablePropertyArray);
var i = 0;
pa.appendProperty(SBProperties.artistName, artist.toString());
pa.appendProperty(SBProperties.albumName, album.toString());
var items = list.getItemsByProperties(pa).enumerate();
while (items.hasMoreElements())
{
track = items.getNext().getProperty(SBProperties.trackName);
tracksArray[i] = [track, track];
i++;
}
return tracksArray;
}
};
//}}}
} // }}}
function getArtists()
{
return this.artists;
}
function getArtistsArray()
{
var list = LibraryUtils.mainLibrary;
// Create an enumeration listener to count each item
var listener = {
count: 0,
onEnumerationBegin: function (aMediaList) {
this.count = 0;
},
onEnumeratedItem: function (aMediaList, aMediaItem) {
this.count++;
},
onEnumerationEnd: function (aMediaList, aStatusCode) {}
};
var artistCounts = {};
var artists = list.getDistinctValuesForProperty(SBProperties.artistName);
var artist;
var artistArray = [];
var i = 0;
// Count the number of media items for each distinct artist
while (artists.hasMore()) {
artist = artists.getNext();
artistArray[i] = [artist,artist];
list.enumerateItemsByProperty(SBProperties.artistName,
artist,
listener,
Ci.sbIMediaList.ENUMERATIONTYPE_LOCKING);
artistCounts[artist] = listener.count;
i++;
}
//liberator.dump("Count : "+artistCounts.toSource());
return artistArray;
}
function getAlbums(artist)
{
var list = LibraryUtils.mainLibrary;
var albumArray = [];
var items = list.getItemsByProperty(SBProperties.artistName, artist).enumerate();
var i = 0;
while (items.hasMoreElements()) {
album = items.getNext().getProperty(SBProperties.albumName);
albumArray[i] = [album, album];
i++;
}
return util.Array.uniq(albumArray);
}
function getTracks(artist,album)
{
var list = LibraryUtils.mainLibrary;
var tracksArray = [];
var pa = Cc["@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1"]
.createInstance(Ci.sbIMutablePropertyArray);
var i = 0;
pa.appendProperty(SBProperties.artistName,artist.toString());
pa.appendProperty(SBProperties.albumName,album.toString());
var items = list.getItemsByProperties(pa).enumerate();
while (items.hasMoreElements()) {
track = items.getNext().getProperty(SBProperties.trackName);
tracksArray[i] = [track, track];
i++;
}
return tracksArray;
}
// vim: set fdm=marker sw=4 ts=4 et:

BIN
xulmus/content/xulmus.png Executable file → Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

8
xulmus/content/xulmus.svg Executable file → Normal file
View File

@@ -15,9 +15,9 @@
inkscape:version="0.46"
version="1.0"
sodipodi:docbase="/home/maxauthority/code/vimperator"
sodipodi:docname="vimperator.svg"
sodipodi:docname="xulmus.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/maxauthority/code/vimperator/vimperator.png"
inkscape:export-filename="/home/maxauthority/code/vimperator/xulmus.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
@@ -73,10 +73,10 @@
sodipodi:role="line"
id="tspan2231"
x="6.2673268"
y="29.896835">vimperator_</tspan></text>
y="29.896835">xulmus_</tspan></text>
<text
xml:space="preserve"
style="font-size:24px;font-style:normal;font-weight:normal;fill:#0000ff;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono"
style="font-size:24px;font-style:normal;font-weight:normal;fill:#00ff00;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:DejaVu Sans Mono"
x="6.4079518"
y="53.183945"
id="text2233"><tspan

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

0
xulmus/content/xulmus.xul Executable file → Normal file
View File