mirror of
https://github.com/gryf/pentadactyl-pm.git
synced 2026-02-21 23:55:45 +01:00
Merge.
This commit is contained in:
143
xulmus/content/bookmarks.js
Executable file → Normal file
143
xulmus/content/bookmarks.js
Executable file → Normal 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
172
xulmus/content/config.js
Executable file → Normal 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
0
xulmus/content/liberator.dtd
Executable file → Normal file
851
xulmus/content/player.js
Executable file → Normal file
851
xulmus/content/player.js
Executable file → Normal 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
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
8
xulmus/content/xulmus.svg
Executable file → Normal 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
0
xulmus/content/xulmus.xul
Executable file → Normal file
Reference in New Issue
Block a user