Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 'use strict';
- window.DefineScript('Fluent Control Panel 0.9', {author:'eurekagliese', options:{grab_focus:false}});
- include(fb.ComponentPath + 'samples\\complete\\js\\lodash.min.js');
- include(fb.ComponentPath + 'samples\\complete\\js\\helpers.js');
- include(fb.ComponentPath + 'samples\\complete\\js\\panel.js');
- include(fb.ComponentPath + 'samples\\complete\\js\\seekbar.js');
- include(fb.ComponentPath + 'samples\\complete\\js\\rating.js');
- include(fb.ComponentPath + 'samples\\complete\\js\\volume.js');
- const ColourTypeCUI = {
- text: 0,
- selection_text: 1,
- inactive_selection_text: 2,
- background: 3,
- selection_background: 4,
- inactive_selection_background: 5,
- active_item_frame: 6
- };
- const ColourTypeDUI = {
- text: 0,
- background: 1,
- highlight: 2,
- selection: 3
- };
- let g_is_default_ui = window.InstanceType;
- let g_textcolour = 0;
- let g_textcolour_hl = 0;
- let g_backcolour = 0;
- let g_hot = false;
- let g_metadb = null;
- let g_img = null;
- let blur_img = null;
- let blur_radius = 24;
- let overlay = 128;
- let ww = 0;
- let wh = 0;
- let bx = 0;
- let by = 0;
- let cx = 0;
- let cy = 0;
- var nextTrackInfo = "No next track."; // Stores the text to display
- var isPlaying = false; // To track playback state
- let colours = {
- red : _RGB(255, 0, 0),
- love : _RGB(255, 0, 0),
- seekbar_background : _RGBA(128, 128, 128, 128),
- rating_bg : _RGBA(128, 128, 128, 224)
- };
- let properties = {
- art : new _p('FLUENT.ALBUMART.SHOW', true),
- vol : new _p('FLUENT.VOLUME.SHOW.', true),
- blur : new _p('FLUENT.BLUR.SHOW', false),
- sbar : new _p('FLUENT.SEEKBAR.SHOW', true),
- nxt : new _p('FLUENT.NEXT.SHOW', true),
- rate : new _p('FLUENT.BUTTON.RATING', _RGB(255, 200, 0))
- };
- let tfo = {
- artist : fb.TitleFormat('%artist%'),
- title : fb.TitleFormat('%title%'),
- playback_time : fb.TitleFormat('%playback_time% '),
- length : fb.TitleFormat(' %length%'),
- lov: fb.TitleFormat('$if2(%loved%,0)')
- };
- // font sizes
- let fluent_font = gdi.Font('Segoe Fluent Icons', 48);
- let fluent_font_hover = gdi.Font('Segoe Fluent Icons', 54);
- let chara = {
- heart_on : '\ueb52',
- heart_off : '\ueb51',
- heart_break : '\ue00C',
- stop : '\uE71A',
- prev : '\uE892',
- play : '\uE768',
- pause : '\uE769',
- next : '\uE893',
- add_queue : '\ue109',
- search : '\uE721',
- consol : '\ue8e4',
- settings : '\uE713',
- volume : '\ue767',
- vol0 : '\uE992',
- vol1 : '\uE993',
- vol2 : '\uE994',
- vol3 : '\uE995',
- shuffle : '\ue8b1',
- rating_on : '\ue735',
- rating_off : '\ue734',
- };
- //////////////////////////////////////////////////////////////
- let panel = new _panel();
- let seekbar = new _seekbar(0, 0, 0, 0);
- let buttons = new _buttons();
- let rating = new _rating(0, 0, 14, 0); // x, y, size, colour
- let volume = new _volume(0, 0, 100, 40);
- let isLoved = 0;
- let isLovedh = 0;
- const bs = _scale(32);
- get_colours();
- panel.item_focus_change();
- update_album_art(fb.GetNowPlaying());
- updateNextTrackInfo(); // Initial update
- buttons.update = () => {
- const x = ((panel.w - (bs * 7)) / 2);
- const y = _scale(4);
- let lv = tfo.lov.Eval();
- buttons.buttons.love = new _button(x, y, bs, bs, {
- normal : lv == 1 ? _chrToImg(chara.heart_on, colours.love, fluent_font) : _chrToImg(chara.heart_off, g_textcolour, fluent_font),
- hover : lv == 1 ? _chrToImg(chara.heart_break, colours.red, fluent_font_hover) : _chrToImg(chara.heart_on, colours.love, fluent_font_hover)}, () => {
- let selected_items = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
- if (selected_items && selected_items.Count !== 0) {
- const tmp = isLovedh == isLoved ? "1" : isLovedh;
- let tags = {};
- tags['LOVED'] = tmp;
- selected_items.UpdateFileInfoFromJSON(JSON.stringify(tags));
- isLoved = !isLoved;
- }
- }, '');
- buttons.buttons.stop = new _button(x + bs, y, bs, bs, {normal : fb.StopAfterCurrent ? _chrToImg(chara.stop, colours.red, fluent_font) : _chrToImg(chara.stop, g_textcolour, fluent_font), hover : _chrToImg(chara.stop, g_textcolour_hl, fluent_font_hover)}, () => { fb.Stop(); }, '');
- buttons.buttons.previous = new _button(x + (bs * 2), y, bs, bs, {normal : _chrToImg(chara.prev, g_textcolour, fluent_font), hover : _chrToImg(chara.prev, g_textcolour_hl, fluent_font_hover)}, () => { fb.Prev(); }, '');
- buttons.buttons.play = new _button( x + (bs * 3), y, bs, bs, {normal : !fb.IsPlaying || fb.IsPaused ? _chrToImg(chara.play, g_textcolour, fluent_font) : _chrToImg(chara.pause, g_textcolour, fluent_font), hover : !fb.IsPlaying || fb.IsPaused ? _chrToImg(chara.play, g_textcolour_hl, fluent_font_hover) : _chrToImg(chara.pause, g_textcolour_hl, fluent_font_hover)}, () => { fb.PlayOrPause(); }, !fb.IsPlaying || fb.IsPaused ? '' : '');
- buttons.buttons.next = new _button(x + (bs * 4), y, bs, bs, {normal : _chrToImg(chara.next, g_textcolour, fluent_font), hover : _chrToImg(chara.next, g_textcolour_hl, fluent_font_hover)}, () => { fb.Next(); }, '');
- buttons.buttons.shuffle = new _button(x + (bs * 5), y, bs, bs, {normal : _chrToImg(chara.shuffle, plman.PlaybackOrder == 0 ? g_textcolour : g_textcolour_hl, fluent_font), hover : _chrToImg(chara.shuffle, colours.red, fluent_font_hover)}, () => { plman.PlaybackOrder = (plman.PlaybackOrder !== 4) ? 4 : 0; }, '');
- buttons.buttons.add_queue = new _button(bx + (bs * 6), y, bs, bs, {normal : _chrToImg(chara.add_queue, g_textcolour, fluent_font), hover : _chrToImg(chara.add_queue, g_textcolour_hl, fluent_font_hover)}, () => {
- let selected_items = plman.GetPlaylistSelectedItems(plman.ActivePlaylist);
- if (selected_items && selected_items.Count !== 0) {
- fb.RunContextCommandWithMetadb("Add to playback queue", selected_items);
- }
- }, '');
- const xx = (panel.w - (bs * 2));
- const yy = Math.round((panel.h - bs) / 2);
- buttons.buttons.volume = new _button(xx - (bs * 3), yy, bs, bs, {normal : fb.Volume === -100 ? _chrToImg(chara.vol0, g_textcolour, fluent_font) : fb.Volume > -4 ? _chrToImg(chara.vol3, g_textcolour, fluent_font) : fb.Volume > -15 ? _chrToImg(chara.vol2, g_textcolour, fluent_font) : fb.Volume > -30 ? _chrToImg(chara.vol1, g_textcolour, fluent_font) : _chrToImg(chara.vol0, g_textcolour, fluent_font), hover : _chrToImg(chara.volume, g_textcolour_hl, fluent_font_hover)}, () => { fb.VolumeMute(); }, '');
- buttons.buttons.search = new _button(xx - (bs * 2), yy, bs, bs, {normal : _chrToImg(chara.search, g_textcolour, fluent_font), hover : _chrToImg(chara.search, g_textcolour_hl, fluent_font_hover)}, () => { fb.RunMainMenuCommand('Library/Search'); }, '');
- buttons.buttons.consol = new _button(xx - bs, yy, bs, bs, {normal : _chrToImg(chara.consol, g_textcolour, fluent_font), hover : _chrToImg(chara.consol, g_textcolour_hl, fluent_font_hover)}, () => { fb.ShowConsole(); }, '');
- buttons.buttons.settings = new _button(xx, yy, bs, bs, {normal : _chrToImg(chara.settings, g_textcolour, fluent_font), hover : _chrToImg(chara.settings, g_textcolour_hl, fluent_font_hover)}, () => { fb.ShowPreferences(); }, '');
- }
- function on_size() {
- panel.size();
- ww = window.Width;
- wh = window.Height;
- bx = ((panel.w - (bs * 7)) / 2);
- by = seekbar.y - _scale(36);
- cx = (panel.w - (bs * 2));
- cy = Math.round((panel.h - bs) / 2);
- seekbar.x = Math.round(panel.w * 0.22);
- seekbar.w = panel.w - seekbar.x - _scale(280);
- seekbar.h = _scale(14);
- seekbar.y = panel.h * 0.6;
- rating.x = properties.art.enabled ? panel.h + 10 : _scale(12);
- rating.y = panel.h - _scale(25);
- volume.x = panel.w - (bs * 5);
- volume.y = seekbar.y + _scale(12);
- volume.h = _scale(4);
- buttons.update();
- }
- function on_paint(gr) {
- gr.FillSolidRect(0, 0, panel.w, panel.h, g_backcolour);
- if (properties.blur.enabled && g_img) {
- _drawImage(gr, blur_img, 0, 0, panel.w, panel.h, image.crop);
- const overlayColor = window.IsDark ? _RGBA(0, 0, 0, overlay) : _RGBA(255, 255, 255, overlay);
- gr.FillSolidRect(0, 0, panel.w, panel.h, overlayColor);
- }
- buttons.paint(gr);
- if (properties.sbar.enabled) {
- gr.FillSolidRect(seekbar.x, seekbar.y + _scale(4), seekbar.w + _scale(6), _scale(4), colours.seekbar_background); //seekbar_bg
- }
- // test for playback time repaint
- // gr.FillSolidRect(bx - (bs * 4), _scale(12), _scale(72), _scale(18), colours.red);
- if (fb.IsPlaying) {
- rating.paint(gr);
- if (properties.art.enabled) {
- if (g_img) {
- _drawImage(gr, g_img, 0, 0, panel.h, panel.h, image.crop_top);
- }
- }
- // Track information
- gr.GdiDrawText(tfo.title.Eval(), panel.fonts.title, g_textcolour, properties.art.enabled ? panel.h + 10 : _scale(12), _scale(11) , properties.art.enabled ? panel.w / 4.7 : panel.w /4, _scale(18), LEFT);
- gr.GdiDrawText(tfo.artist.Eval(), panel.fonts.normal, g_textcolour, properties.art.enabled ? panel.h + 10 : _scale(12), Math.round((panel.h - _scale(18)) / 2), properties.art.enabled ? panel.w * 0.13 : panel.w * 0.23, _scale(18), LEFT);
- // Draw the next track information
- if (plman.PlaybackOrder == 0 && properties.nxt.enabled) {
- gr.GdiDrawText(nextTrackInfo, panel.fonts.normal, g_textcolour, (panel.w / 5) * 3.2, _scale(10), panel.w / 3.5, _scale(18), LEFT);
- }
- gr.SetSmoothingMode(2);
- // seekbar
- if (fb.PlaybackLength > 0) {
- const pos = seekbar.pos();
- if (properties.sbar.enabled) {
- gr.FillSolidRect(seekbar.x, seekbar.y + _scale(4), pos, _scale(4), g_textcolour); //progress_bar
- gr.FillEllipse(seekbar.x + pos - 4, seekbar.y, _scale(12), _scale(12),g_textcolour_hl); //knob
- }
- // playback time and length
- gr.GdiDrawText(tfo.playback_time.Eval(), panel.fonts.title, g_textcolour, bx - (bs * 4), _scale(20), _scale(72), 0, RIGHT);
- gr.GdiDrawText("/" + tfo.length.Eval(), panel.fonts.normal, g_textcolour, bx - (bs * 1.7), _scale(20), _scale(72), 0, LEFT);
- }
- // volume
- if (properties.vol.enabled) {
- gr.FillSolidRect(volume.x, volume.y, volume.w, volume.h, colours.seekbar_background);
- gr.FillSolidRect(volume.x, volume.y, volume.pos(), volume.h, g_textcolour);
- gr.GdiDrawText(fb.Volume.toFixed(2) + ' dB', panel.fonts.normal, g_textcolour, _scale(8), volume.y + _scale(2), volume.x + _scale(128), 0, RIGHT);
- }
- }
- }
- rating.paint = (gr) => {
- if (panel.metadb) {
- gr.SetTextRenderingHint(4);
- for (let i = 0; i < rating.get_max(); i++) {
- if (i + 1 > (rating.hover ? rating.hrating : rating.rating)) {
- gr.DrawString(chars.rating_off, rating.font, colours.rating_bg, rating.x + (i * rating.h), rating.y, rating.h, rating.h, SF_CENTRE);
- } else {
- gr.DrawString(chars.rating_on, rating.font, rating.colour, rating.x + (i * rating.h), rating.y, rating.h, rating.h, SF_CENTRE);
- }
- }
- }
- }
- function on_metadb_changed() {
- rating.metadb_changed();
- }
- function on_playback_new_track() {
- // When a new track starts, the "next" track might change.
- updateNextTrackInfo();
- update_album_art(g_metadb);
- panel.item_focus_change();
- buttons.update();
- }
- function update_album_art(metadb) {
- g_metadb = fb.IsPlaying ? fb.GetNowPlaying() : fb.GetFocusItem();
- g_img = utils.GetAlbumArtV2(g_metadb, 0);
- if (g_img && g_img.Width > 200) {
- var r = 200 / g_img.Width;
- g_img = g_img.Resize(200, g_img.Height * r, 2);
- if (g_img != null) {
- blur_img = g_img.Clone(0, 0, g_img.Width, g_img.Height);
- blur_img.StackBlur(blur_radius);
- }
- }
- window.Repaint();
- }
- // update the playback time
- function on_playback_time() {
- window.RepaintRect(bx - (bs * 4), _scale(12), _scale(72), _scale(18));
- }
- function on_playback_edited() {
- buttons.update();
- window.Repaint();
- }
- function on_playback_seek() {
- seekbar.playback_seek();
- }
- function on_playback_stop() {
- buttons.update();
- window.Repaint();
- }
- function on_playback_stop(reason) {
- if (reason != 2) {
- panel.item_focus_change();
- }
- }
- function on_playback_pause() {
- buttons.update();
- window.Repaint();
- }
- function on_playback_starting() {
- buttons.update();
- window.Repaint();
- }
- function on_playback_dynamic_info_track() {
- panel.item_focus_change();
- }
- function on_playback_order_changed() {
- updateNextTrackInfo(); // Playback order affects what the "next" track is.
- buttons.update();
- window.Repaint();
- }
- function on_playlist_switch() {
- updateNextTrackInfo(); // Switching playlists means the next track might be different.
- panel.item_focus_change();
- }
- function on_item_focus_change() {
- panel.item_focus_change();
- }
- function on_colours_changed() {
- get_colours();
- buttons.update();
- panel.colours_changed();
- window.Repaint();
- }
- function on_volume_change() {
- buttons.update();
- volume.volume_change();
- window.Repaint();
- }
- // mouse events
- function on_mouse_wheel(s) {
- volume.wheel(s);
- let easy_vol = vol2pos(fb.Volume);
- easy_vol += s / 20;
- fb.Volume = pos2vol(easy_vol);
- }
- function on_mouse_move(x, y) {
- if (!g_hot) {
- g_hot = true;
- window.SetCursor(IDC_HAND);
- window.Repaint();
- }
- if (buttons.move(x, y) || rating.move(x, y) || seekbar.move(x, y) || volume.move(x, y)) return;
- }
- function on_mouse_leave() {
- if (g_hot) {
- g_hot = false;
- window.Repaint();
- }
- buttons.leave();
- rating.leave();
- }
- function on_mouse_lbtn_down(x, y) {
- seekbar.lbtn_down(x, y);
- volume.lbtn_down(x, y);
- }
- function on_mouse_lbtn_up(x, y) {
- if ([buttons, seekbar, rating, volume].some(el => el.lbtn_up(x, y))) {
- return;
- }
- fb.RunMainMenuCommand('View/Show now playing in playlist');
- // search artist in library
- if (x < _scale(200) && x > _scale(12) && y < _scale(72) && y > _scale(12)) {
- fb.ShowLibrarySearchUI(tfo.artist.Eval())
- } return;
- }
- function on_mouse_mbtn_up(x, y) {
- // flush playback queue with middle click
- if (buttons.buttons.add_queue.trace(x, y)) {
- fb.RunMainMenuCommand("Flush playback queue");
- return true
- }
- }
- function on_mouse_rbtn_up(x, y) {
- if (buttons.buttons.stop.trace(x, y)) {
- fb.StopAfterCurrent = !fb.StopAfterCurrent;
- buttons.update();
- return true
- }
- if (buttons.buttons.add_queue.trace(x, y)) {
- queueSelectedTracksRandomizedAppend(); // Add selected tracks to the queue in a random order (append to queue, do not flush)
- return true
- }
- if (buttons.buttons.search.trace(x, y)) {
- plman.SetActivePlaylistContext(); //activated the current playlist
- fb.RunMainMenuCommand('Edit/Search'); // search in current playlist
- return true
- }
- if (rating.trace(x, y)) {
- return panel.rbtn_up(x, y, rating);
- }
- // menu
- let m = window.CreatePopupMenu();
- let s = window.CreatePopupMenu();
- let c = fb.CreateContextMenuManager();
- let col = window.CreatePopupMenu();
- if (fb.IsPlaying) {
- c.InitNowPlaying();
- c.BuildMenu(s, 1);
- s.AppendTo(m, MF_STRING, 'Now playing');
- m.AppendMenuSeparator();
- }
- m.AppendMenuItem(MF_STRING, 10000, 'Show album art');
- m.CheckMenuItem(10000, properties.art.enabled);
- m.AppendMenuItem(MF_STRING, 10001, 'Show volume slider');
- m.CheckMenuItem(10001, properties.vol.enabled);
- m.AppendMenuItem(MF_STRING, 10002, 'Show blur effect');
- m.CheckMenuItem(10002, properties.blur.enabled);
- m.AppendMenuItem(MF_STRING, 10003, 'Show seekbar');
- m.CheckMenuItem(10003, properties.sbar.enabled);
- m.AppendMenuItem(MF_STRING, 10004, 'Show next track');
- m.CheckMenuItem(10004, properties.nxt.enabled);
- m.AppendMenuSeparator();
- col.AppendMenuItem(MF_STRING, 10005, 'Rating');
- col.AppendTo(m, MF_STRING, 'Colours');
- m.AppendMenuSeparator();
- m.AppendMenuItem(MF_STRING, 10010, 'Configure');
- const idx = m.TrackPopupMenu(x, y);
- switch (idx) {
- case 0:
- break;
- case 10000:
- properties.art.toggle();
- on_size();
- window.Repaint();
- break;
- case 10001:
- properties.vol.toggle();
- window.Repaint();
- break;
- case 10002:
- properties.blur.toggle();
- window.Repaint();
- break;
- case 10003:
- properties.sbar.toggle();
- window.Repaint();
- break;
- case 10004:
- properties.nxt.toggle();
- window.Repaint();
- break;
- case 10005:
- properties.rate.value = utils.ColourPicker(window.ID, properties.rate.value);
- get_colours();
- buttons.update();
- window.Repaint();
- break;
- case 10010:
- window.ShowConfigureV2();
- break;
- default:
- c.ExecuteByID(idx - 1);
- break;
- }
- return true;
- }
- function get_colours() {
- rating.colour = properties.rate.value;
- if (g_is_default_ui) { // DUI
- g_textcolour = window.GetColourDUI(ColourTypeDUI.text);
- g_textcolour_hl = window.GetColourDUI(ColourTypeDUI.highlight);
- g_backcolour = window.GetColourDUI(ColourTypeDUI.background);
- } else { // CUI
- g_textcolour = window.GetColourCUI(ColourTypeCUI.text);
- g_textcolour_hl = window.GetColourCUI(ColourTypeCUI.text);
- g_backcolour = window.GetColourCUI(ColourTypeCUI.background);
- }
- }
- function vol2pos(v) {
- return (Math.pow(10, v / 50) - 0.01) / 0.99;
- }
- function pos2vol(pos) {
- return 50 * Math.log(0.99 * pos + 0.01) / Math.LN10;
- }
- /**
- * Updates the information about the next upcoming track.
- * Prioritizes tracks in the playback queue.
- */
- function updateNextTrackInfo() {
- var nextTrack = null;
- // Use GetPlaybackQueueHandles to get a FbMetadbHandleList directly
- var queueHandles = plman.GetPlaybackQueueHandles();
- // 1. Check for tracks in the playback queue first
- if (queueHandles.Count > 0) {
- // The first item in the queueHandles list is the highest priority next track
- nextTrack = queueHandles[0];
- // console.log("Next track from queue (from updateNextTrackInfo):", nextTrack ? fb.TitleFormat("%title%").EvalWithMetadb(nextTrack) : "N/A"); // For debugging
- } else {
- // 2. If no queue, check the next track in the current playlist
- var currentPlaylistIndex = plman.PlayingPlaylist;
- // Ensure a valid playlist is currently playing and it has items
- if (currentPlaylistIndex !== -1 && plman.PlaylistItemCount(currentPlaylistIndex) > 0) {
- var playingItemLocation = plman.GetPlayingItemLocation();
- if (playingItemLocation.IsValid) {
- var currentIndex = playingItemLocation.PlaylistItemIndex;
- var playlistLength = plman.PlaylistItemCount(currentPlaylistIndex);
- // Check if there's a next track in the playlist
- if (currentIndex < playlistLength - 1) {
- // Get all items in the current playlist and then access the next one by index
- var playlistItems = plman.GetPlaylistItems(currentPlaylistIndex);
- if (playlistItems && playlistItems.Count > currentIndex + 1) {
- nextTrack = playlistItems[currentIndex + 1];
- // console.log("Next track from playlist (from updateNextTrackInfo):", nextTrack ? fb.TitleFormat("%title%").EvalWithMetadb(nextTrack) : "N/A"); // For debugging
- }
- }
- }
- }
- }
- // Format the track information for display
- if (nextTrack) {
- // Use TitleFormat to get artist and title reliably
- var tf = fb.TitleFormat("%artist% - %title%");
- nextTrackInfo = "Next: " + tf.EvalWithMetadb(nextTrack);
- } else {
- nextTrackInfo = "No next track.";
- }
- window.Repaint(); // Request a repaint to update the display
- }
- function on_playback_queue_changed() {
- // Add a small delay to ensure foobar2000 has fully processed the queue change
- window.SetTimeout(function() {
- updateNextTrackInfo();
- }, 50); // 50ms delay
- }
- // Add selected tracks to the queue in a random order (append to queue, do not flush)
- function queueSelectedTracksRandomizedAppend() {
- const activePlaylistIndex = plman.ActivePlaylist;
- const selectedHandles = plman.GetPlaylistSelectedItems(activePlaylistIndex);
- if (!selectedHandles || selectedHandles.Count === 0) {
- fb.ShowPopupMessage("No tracks selected. Please select one or more tracks in your playlist.");
- return;
- }
- // Fisher-Yates shuffle
- for (let i = selectedHandles.Count - 1; i > 0; i--) {
- const j = Math.floor(Math.random() * (i + 1));
- const temp = selectedHandles[i];
- selectedHandles[i] = selectedHandles[j];
- selectedHandles[j] = temp;
- }
- // Get all items in the playlist
- const playlistItems = plman.GetPlaylistItems(activePlaylistIndex);
- // Add shuffled tracks to the queue (append)
- for (let i = 0; i < selectedHandles.Count; i++) {
- const idx = playlistItems.Find(selectedHandles[i]);
- if (idx !== -1) {
- plman.AddPlaylistItemToPlaybackQueue(activePlaylistIndex, idx);
- }
- }
- // fb.ShowPopupMessage("Selected tracks appended to the queue in random order.");
- }
Advertisement
Add Comment
Please, Sign In to add comment