Skip to main content

Notice

Please note that most of the software linked on this forum is likely to be safe to use. If you are unsure, feel free to ask in the relevant topics, or send a private message to an administrator or moderator. To help curb the problems of false positives, or in the event that you do find actual malware, you can contribute through the article linked here.
Topic: Create an external played track list from radio stream or file metadata (Read 2534 times) previous topic - next topic
0 Members and 1 Guest are viewing this topic.

Create an external played track list from radio stream or file metadata

I was wondering if there currently exists a method/plugin that would allow Foobar to generate a simple external text file that would show a chronological list of tracks played, either tracks from radio stations if the metadata is present, or file track/artist, with the ability to set a cut-off by amount of entries kept and just a simple date/time, title/artist line format.  I guess the tricky part might be that this requires accessing dynamic data for streams like foo_dyndec does.  The AIMP player's "Track info to file" plugin accomplishes this, for example.

 

Re: Create an external played track list from radio stream or file metadata

Reply #1
You could use foo_scheduler and on track change trigger a script to push each played track in your text file.
Requires a bit of tweaking and scripting knowledge but no programming.

Re: Create an external played track list from radio stream or file metadata

Reply #2
You could use the following script for Spider Monkey Panel
The text file (history.txt) will be located in the foobar2000 directory.

Code: [Select]
"use strict";

window.DefinePanel("History File Writer", { author: "zeremy" });

// Use with GdiDrawText()
const DT_CENTER = 0x00000001;
const DT_VCENTER = 0x00000004;
const DT_WORDBREAK = 0x00000010;
const DT_CALCRECT = 0x00000400;
const DT_NOPREFIX = 0x00000800;

// Used in window.GetColorCUI()
const ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};

// Used in window.GetFontCUI()
const FontTypeCUI = {
items: 0,
labels: 1
};

// Used in window.GetColourDUI()
const ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};

// Used in window.GetFontDUI()
const FontTypeDUI = {
defaults: 0,
tabs: 1,
lists: 2,
playlists: 3,
statusbar: 4,
console: 5
};

// Used in window.SetCursor()
const IDC_HAND = 32649;

let g_is_default_ui = window.InstanceType;
let g_font = null;
let g_text = "";
let g_textcolour = 0;
let g_textcolour_hl = 0;
let g_backcolour = 0;
let g_hot = false;

let ww = 0;
let wh = 0;

get_font();
get_colours();

function on_paint(gr) {
gr.FillSolidRect(0, 0, ww, wh, g_backcolour);
gr.GdiDrawText(g_text, g_font, g_hot ? g_textcolour_hl : g_textcolour, 0, 0, ww, wh, DT_VCENTER | DT_CENTER | DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);
}

function on_size(width, height) {
ww = width;
wh = height;
}

function on_mouse_lbtn_up(x, y) {
window.ShowConfigure();
}

function on_mouse_move() {
if (!g_hot) {
g_hot = true;
window.SetCursor(IDC_HAND);
window.Repaint();
}
}

function on_mouse_leave() {
if (g_hot) {
g_hot = false;
window.Repaint();
}
}

function on_font_changed() {
get_font();
window.Repaint();
}

function on_colours_changed() {
get_colours();
window.Repaint();
}

function get_font() {
if (g_is_default_ui) { // DUI
g_font = window.GetFontDUI(FontTypeDUI.defaults);
} else { // CUI
g_font = window.GetFontCUI(FontTypeCUI.items);
}
}

function get_colours() {
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);
}
}

let fso = new ActiveXObject('Scripting.FileSystemObject');
let savefilepath = fb.FoobarPath + "history.txt";
if (!utils.FileTest(savefilepath, "e")) utils.WriteTextFile(savefilepath, "");
let count = 0;
let tf;

let max = 1000;

function on_playback_new_track() {
history_write();
window.Repaint();
}

function on_playback_dynamic_info_track() {
history_write();
window.Repaint();
}

function on_playback_stop() {
g_text = "";
window.Repaint();
}

function history_count() {
count = 0;
let ts = fso.OpenTextFile(savefilepath, 1);
while (!ts.AtEndOfStream) {
ts.ReadLine();
count++;
}
ts.Close();
}

function history_write() {
history_count();
tf = fb.TitleFormat("%artist% - %title%").Eval();
g_text = '[' + new Date().toUTCString() + ']' + " " + tf;
if (count < max) {
let ts = fso.OpenTextFile(savefilepath, 8, true);
ts.WriteLine(g_text);
ts.Close();
} else {
let ts = fso.OpenTextFile(savefilepath, 2, true);
ts.WriteLine(g_text);
ts.Close();
}
}

Re: Create an external played track list from radio stream or file metadata

Reply #3
Thank you NEMO7538 and zeremy for your suggestions, much appreciated!  I had neither foo_scheduler nor Spider Monkey Panel installed previously, so decided to give the latter a try first as my scripting ability leaves a lot to be desired.  Zeremy I pasted your boss code into a SMP panel and saved, and it works great for streams and has all the line info I need!  I did notice though that it creates double (duplicate) entries for each played track in the history.txt file--any ideas where I can change that in the script?

I'm going to see what I can come up with with foo_scheduler also, as the SMP component is so "heavy" it seems overkill for this single task, but as long as I'm running it I'll be exploring the multitude of other things I see it can do as well.  At least I'm learning something here, thanks again to both of you!

Re: Create an external played track list from radio stream or file metadata

Reply #4
I did notice though that it creates double (duplicate) entries for each played track in the history.txt file--any ideas where I can change that in the script?
Forgot to add, this is only in the case of dynamic radio stream metadata, not with actual files:

[Mon, 08 Jul 2019 02:51:33 GMT] Solitary Experiments - Leb Deinen Traum
[Mon, 08 Jul 2019 02:51:33 GMT] Solitary Experiments - Leb Deinen Traum
[Mon, 08 Jul 2019 02:53:22 GMT] G.O.T.H - Only one
[Mon, 08 Jul 2019 02:53:22 GMT] G.O.T.H - Only one
[Mon, 08 Jul 2019 02:53:36 GMT] Mystigma - A Thousand Rains
[Mon, 08 Jul 2019 02:53:36 GMT] Mystigma - A Thousand Rains

Re: Create an external played track list from radio stream or file metadata

Reply #5
The function on_playback_dynamic_info_track() is called whenever dynamic radio stream metadata is received.
Added suppression of writing the entry when the metadata that is received is repeated.

Replace the panel's code with this:

Code: [Select]
"use strict";

window.DefinePanel("History File Writer", {author: "zeremy"});

// Use with GdiDrawText()
const DT_CENTER = 0x00000001;
const DT_VCENTER = 0x00000004;
const DT_WORDBREAK = 0x00000010;
const DT_CALCRECT = 0x00000400;
const DT_NOPREFIX = 0x00000800;

// Used in window.GetColorCUI()
const ColourTypeCUI = {
text: 0,
selection_text: 1,
inactive_selection_text: 2,
background: 3,
selection_background: 4,
inactive_selection_background: 5,
active_item_frame: 6
};

// Used in window.GetFontCUI()
const FontTypeCUI = {
items: 0,
labels: 1
};

// Used in window.GetColourDUI()
const ColourTypeDUI = {
text: 0,
background: 1,
highlight: 2,
selection: 3
};

// Used in window.GetFontDUI()
const FontTypeDUI = {
defaults: 0,
tabs: 1,
lists: 2,
playlists: 3,
statusbar: 4,
console: 5
};

// Used in window.SetCursor()
const IDC_HAND = 32649;

let g_is_default_ui = window.InstanceType;
let g_font = null;
let g_text = "";
let g_textcolour = 0;
let g_textcolour_hl = 0;
let g_backcolour = 0;
let g_hot = false;

let ww = 0;
let wh = 0;

get_font();
get_colours();

function on_paint(gr) {
gr.FillSolidRect(0, 0, ww, wh, g_backcolour);
gr.GdiDrawText(g_text, g_font, g_hot ? g_textcolour_hl : g_textcolour, 0, 0, ww, wh, DT_VCENTER | DT_CENTER | DT_WORDBREAK | DT_CALCRECT | DT_NOPREFIX);
}

function on_size(width, height) {
ww = width;
wh = height;
}

function on_mouse_lbtn_up(x, y) {
window.ShowConfigure();
}

function on_mouse_move() {
if (!g_hot) {
g_hot = true;
window.SetCursor(IDC_HAND);
window.Repaint();
}
}

function on_mouse_leave() {
if (g_hot) {
g_hot = false;
window.Repaint();
}
}

function on_font_changed() {
get_font();
window.Repaint();
}

function on_colours_changed() {
get_colours();
window.Repaint();
}

function get_font() {
if (g_is_default_ui) { // DUI
g_font = window.GetFontDUI(FontTypeDUI.defaults);
} else { // CUI
g_font = window.GetFontCUI(FontTypeCUI.items);
}
}

function get_colours() {
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);
}
}

let fso = new ActiveXObject('Scripting.FileSystemObject');
let savefilepath = fb.FoobarPath + "history.txt";
if (!utils.FileTest(savefilepath, "e")) utils.WriteTextFile(savefilepath, "");
let count = 0;
let tf;
let length;
let tf_last = window.GetProperty("tf_last");

let max = 1000;

function on_playback_new_track() {
history_write();
window.Repaint();
}

function on_playback_dynamic_info_track() {
history_write();
window.Repaint();
}

function on_playback_stop() {
g_text = "";
window.Repaint();
}

function history_count() {
count = 0;
let ts = fso.OpenTextFile(savefilepath, 1);
while (!ts.AtEndOfStream) {
ts.ReadLine();
count++;
}
ts.Close();
}

function history_write() {
history_count();
length = fb.TitleFormat("[%length%]").Eval();
tf = fb.TitleFormat("%artist% - %title%").Eval();

tf_last = window.GetProperty("tf_last");
if (tf == tf_last && !length) return;

g_text = '[' + new Date().toUTCString() + ']' + " " + tf;
if (count < max) {
window.SetProperty("tf_last", tf);
let ts = fso.OpenTextFile(savefilepath, 8, true);
ts.WriteLine(g_text);
ts.Close();
} else {
window.SetProperty("tf_last", tf);
let ts = fso.OpenTextFile(savefilepath, 2, true);
ts.WriteLine(g_text);
ts.Close();
}
}

Re: Create an external played track list from radio stream or file metadata

Reply #6
Thanks zeremy for the revised code, works perfectly to suppress the repeated title!  I'm sure other users with SMP will be glad to add this ability too.  I see that max length of the file before overwriting is easily set with the "let max=" value.  Much appreciated!

Re: Create an external played track list from radio stream or file metadata

Reply #7
Could you make screen record of implementation the script ? I don't know how to do this.

Re: Create an external played track list from radio stream or file metadata

Reply #8
SMP is overkill for this unless you're using it for other things too;  in your case you would be better off using the Now Playing Simple plugin (http://skipyrich.com/store/foo_np_simple.7z) which creates a text file of artist/title metadata for all streams or files played ordered by date/time, like this:

[Wed Feb 03 23:49:54 2021]: Agnes Obel - Broken Sleep
[Wed Feb 03 23:50:09 2021]: Gothic - radiotwinight/greyskycasting
[Wed Feb 03 23:50:10 2021]: Rotersand - Merging Oceans [b0i]
[Wed Feb 03 23:50:21 2021]: Gothic - Schwarze Welle - Das Radio mit den besten dunklen Liedern
[Wed Feb 03 23:50:23 2021]: Das Scheit - Down In The Depth
[Wed Feb 03 23:51:03 2021]: Rotschild - Nosferatu
[Sat Feb 06 19:04:16 2021]: Roxy Music - Avalon

Set it up in Preferences like you see in the attached image.