A foobar2000 component (x86 and x64) that turns country codes or names stored in your tags into flag-related title formatting fields.
The component exposes five sets of fields, plus %countryflag_lookup% (see Artist tables).
| Source | Default input script | Field names |
|---|---|---|
| Source 1 | %country% |
%countryflag_emoji%, %countryflag_path%, %countryflag_name%, %countryflag_iso2%, %countryflag_iso3%, %countryflag_region%, %countryflag_subregion% |
| Source 2 | %artistcountry% (fallback: $if3(%artist%,%album artist%)) |
%countryflag_artist_emoji%, %countryflag_artist_path%, %countryflag_artist_name%, %countryflag_artist_iso2%, %countryflag_artist_iso3%, %countryflag_artist_region%, %countryflag_artist_subregion% |
| Source 3 | Empty | %countryflag_3_emoji%, %countryflag_3_path%, %countryflag_3_name%, %countryflag_3_iso2%, %countryflag_3_iso3%, %countryflag_3_region%, %countryflag_3_subregion% |
| Source 4 | Empty | %countryflag_4_emoji%, %countryflag_4_path%, %countryflag_4_name%, %countryflag_4_iso2%, %countryflag_4_iso3%, %countryflag_4_region%, %countryflag_4_subregion% |
| Source 5 | Empty | %countryflag_5_emoji%, %countryflag_5_path%, %countryflag_5_name%, %countryflag_5_iso2%, %countryflag_5_iso3%, %countryflag_5_region%, %countryflag_5_subregion% |
Each set contains these values:
emoji: flag emoji built from regional-indicator characters.path: full path to the flag image, only if the file exists.name: English country name.iso2: uppercase ISO 3166-1 alpha-2 code, e.g.GR.iso3: uppercase ISO 3166-1 alpha-3 code, e.g.GRC.region,subregion: cultural region of the country, e.g.Europe/Southern Europe(see Cultural regions).argument: the raw result of the source's titleformat script, exactly as evaluated (e.g.%countryflag_artist_argument%, or%countryflag_argument%for Source 1). Use it to debug long scripts.fallbackargument: the raw result of the source's fallback script (e.g.%countryflag_artist_fallbackargument%). It is empty when the fallback did not run because the main script already returned a country.
If no country can be determined for a source, that source's fields are empty, so $if(%countryflag_iso2%,...) works as expected. The two debug fields are the exception: argument and fallbackargument show what the scripts returned even when no country was found (they are empty only when the script itself returned nothing, or, for fallbackargument, did not run).
A script result may list several countries, separated by ,, ;, / or + (for example US+DE or GB, SE). Each part is looked up separately, duplicates are dropped, and the fields list every country: emoji is space-separated (🇺🇸 🇩🇪), the other fields are separated by ; , and path lists every flag image that exists.
If a part is not a recognised country, it is skipped. If no part is recognised, the source counts as having no country and the fallback script runs. For example US+DE was not recognised in earlier versions, so the fallback ran and its artist lookup could return a single flag; + is now treated as a separator, so both countries are returned. Check %countryflag_<suffix>_argument% to see what the script returned, and %countryflag_<suffix>_fallbackargument% to see whether the fallback ran.
Open Preferences > Tools > Country Flags to configure the component. The page has two tabs:
-
Sources: one block per source, five blocks stacked on the page (no scrolling). Each block has three rows: the source name (Source 1 to Source 5) with its Suffix box, then the Titleformat string, then the optional Fallback string (see fallback scripts). The ... button next to each script opens a larger, resizable editor for long scripts. A short help text below the last source repeats the rules below.
-
Folders: the flag image folder and the two artist tables, each with a Browse button and a found / not found marker (see Paths), plus the choice of which artist table wins.
-
Source 1 keeps the original, unsuffixed field names (
%countryflag_emoji%,%countryflag_path%, etc.). Its field names are fixed. -
Sources 2–5 use the required
countryflag_prefix plus the suffix entered by the user. Enter only the suffix value; do not typecountryflag_. -
Example: entering
artistproduces%countryflag_artist_emoji%,%countryflag_artist_path%,%countryflag_artist_name%,%countryflag_artist_iso2%, and%countryflag_artist_iso3%. -
Default suffixes are
artist,3,4, and5for Sources 2–5. Only letters, digits and_are kept (any other character is removed), leading and trailing_are trimmed, and an empty suffix falls back to the default. -
Restart foobar2000 after changing suffixes. The available title-formatting field names are enumerated by foobar2000 and do not update immediately when the suffix setting changes.
-
Source scripts are title-formatting expressions that return a country code or country name, for example
%artistcountry%. The defaults only apply to fresh settings.
A source script should return a country alpha-2 code (GR), alpha-3 code (GRC) or English name (Greece). Common aliases such as UK, Czech Republic and Russian Federation are also understood. MusicBrainz-style bracketed values such as [Europe] and [Worldwide] work too.
Every source has an optional fallback script. It runs only when the source script returns no recognised country (an empty result, or a value that is not a country). The fallback script must return an artist name, which is then looked up in the artist tables. If the name is not found as a whole, it is split on &, and, versus, vs., vs, +, , , ; , / and x and the first part found wins, so Simon & Garfunkel can be an entry of its own while Artist A & Artist B falls back to Artist A.
Example for a group header: Source 1 = $if3(%albumartistcountry%,%artistcountry%,%country%), fallback = your own album-artist expression. If the tags give no country, the country of that album artist is taken from the tables.
- The fallback may be any title-formatting expression, including long ones with
$puts/$getand$meta(). It is evaluated for the track the field is requested for. For the playing track,%isplaying%is1, and for a playing stream%artist%,%title%and$meta(artist,0),$meta(title,0)(and other fields present in the stream's dynamic metadata) return the live stream values, so expressions written for a now-playing display behave the same here. Expressions that rely on other title-formatting functions or fields set elsewhere (for example a custom%stationswap%) see exactly what the track entry provides. - Results are cached per track and source for up to 10 seconds, and the cache is dropped earlier when the track's info, the settings, an artist table or the stream metadata change, so a row that shows several fields evaluates the scripts once.
- Do not use this component's own
%countryflag_*%per-source fields inside a script (they are ignored to prevent endless recursion). - Default: only Source 2 has a fallback,
$if3(%artist%,%album artist%). The field%countryflag_lookup%(ISO2 code(s) of the track's artist tags and the stream artist, looked up in the artist tables) remains available for use in any script, for example$if2(%artistcountry%,%countryflag_lookup%).
Click the ... button next to a Titleformat or Fallback box to edit it in a resizable multi-line editor (Ctrl+A selects all; OK keeps the change, Cancel discards it).
The editor has a Test on selected track button. It evaluates the script as it is in the editor (it does not have to be saved or applied) for the selected playlist item, or for the playing track when nothing is selected, and shows in the result box:
- the track used, the raw result of the script, and
- for a Titleformat script, the countries it resolves to (or that none were recognised, so the fallback would run); for a Fallback script, the countries found for the returned artist name in the artist tables (or that the artist was not found).
For a playing stream the test sees the same dynamic (ICY) artist and title as the fields do. Long scripts can be written readably, with one part per line, indentation and // comment lines:
// country of the album artist
$if3(%albumartistcountry%,
%artistcountry%,
%country%)
Before a script is compiled, the component removes whole-line // comments, strips leading and trailing whitespace from every line and joins the lines. The box on the page shows this flattened form, which is exactly what gets compiled. Two things to keep in mind:
- Do not rely on line breaks inside quoted text; they are removed.
- The full multi-line text is stored in the settings. If you type directly into the box on the page, your typing replaces the stored text with the one-line form, so use the editor to keep the line structure.
Two optional JSON files map artist names to countries, so tracks without a country tag can still get a flag. When an artist is in both files, the table chosen by the radio buttons at the bottom of the Folders tab wins; the other one is only used for artists the first does not contain. The default is worldMap.json first, because it can be corrected (for example by clicking on the map), while a generated table such as country_codes.json can only be corrected by editing the file. The choice applies right after Apply.
| File | Format |
|---|---|
worldMap.json |
array: [{"artist": "Abba", "val": ["Stockholm", "Sweden"]}], last item of val is the country |
country_codes.json |
flat object: {"abba": "SE", "aftermath": "US-NJ"} |
- Location: by default
worldMap.jsonis read fromprofile\js_data\worldMap.json(inside the foobar2000 profile folder) and, if it is not there, from next to the DLL.country_codes.jsonis read from next to the DLL. To keep them elsewhere set the path of each table in preferences (see Paths). A changed path takes effect right after Apply. - Keys are matched case-insensitively (including accented letters) with surrounding spaces ignored.
The Cultalso matches acult, thekey and the other way round. worldMap.json: the last item ofvalis the country and can be a name, ISO2 or ISO3 code (United States,US,USA); other items (city, region) and other keys are ignored. Entries whose last item is not a recognised country are skipped. If an artist appears more than once, the last entry wins.country_codes.json: values may be an ISO2/ISO3 code or a country name. A region suffix such asUS-NJis accepted and ignored, andXEmeans Europe. Unknown codes (for exampleXG,YU) are skipped unless you add them tocountries.txt. If a key appears more than once, the last one wins.- Both files are UTF-8 with or without BOM, and are re-read automatically within a few seconds of being saved; no restart is needed. A missing file simply contributes nothing; an invalid file keeps the previously loaded data.
- Streams: for the track that is playing, the artist from the stream's dynamic metadata (for example ICY
StreamTitleon internet radio) is searched first by%countryflag_lookup%, and updates when the stream's track changes. %countryflag_lookup%returns the ISO2 code(s) of the track's artists: every value of theartisttag, oralbum artistwhen none is found.
All three path settings (flag folder and both artist tables) accept:
%fb2k_profile_path%: the foobar2000 profile folder, e.g.%fb2k_profile_path%\foo_uie_jsplitter\package_data\{GUID}\country_codes.json. The same setting then works for portable and non-portable installs and for any username.%fb2k_component_path%: the folder of this component's DLL.%fb2k_path%: the foobar2000 program folder.- Any Windows environment variable such as
%APPDATA%. - Relative paths: tried against the foobar2000 program folder first (as before, so an existing
profile\...setting keeps working on portable installs), then against the profile folder. - Browse writes a path inside the profile folder back as
%fb2k_profile_path%\...automatically.
A marker left of each path box shows whether the entered file or folder exists: a green ✓ when it does, a red ✗ when it does not. An empty box checks the default location (profile\js_data\worldMap.json, then next to the DLL, for worldMap.json; next to the DLL for the other files); a grey ✗ means that default is missing too (fine if you do not use that file). The marker only checks that the file exists, not that its content is valid.
%countryflag_region% and %countryflag_subregion% (and %countryflag_artist_region%, %countryflag_3_subregion%, ... for the other sources) give the cultural region of the country, so a query on a region matches every country in it:
| Country | region |
subregion |
|---|---|---|
SLE (Sierra Leone) |
Africa | West Africa |
GR (Greece) |
Europe | Southern Europe |
US (United States) |
America | North America |
%countryflag_subregion% IS Eastern Europe
%countryflag_region% IS Africa
%countryflag_subregion% HAS Maghreb
- If a source resolves to several countries, or a country belongs to several regions, the field lists each region once, separated by
;. UseHASrather thanISto match tracks that have other regions as well. - The built-in table is the (revised) "cultural regions" table of the Music Graph country descriptors, using ISO 3166-1 alpha-3 codes. Its groupings apply as given: for example
EgyptisAfrica/Maghreb,TurkeyisMashriq/Anatolia, andSouth KoreaisAsia/East Asia. - Russia belongs to two regions:
regionisAsia; EuropeandsubregionisNorth Asia; Eastern Europe, so%countryflag_subregion% HAS Eastern EuropeandHAS North Asiaboth match Russian artists, whileIS Eastern Europedoes not (useHAS). - Europe (
EU/XE) has the regionEuropeand no subregion; Worldwide has neither.ANT(Netherlands Antilles) is in the table but not in the built-in country list, so it is ignored. - Override or extend it with an optional
regions.txtnext to the DLL, oneISO|Region|Subregionper line (ISO2 or ISO3 code,#starts a comment, the file is UTF-8). The first line for a country replaces its built-in entries and further lines for the same country add more regions; a line with an empty region and subregion removes the country's regions. Example:
# Turkey: replace the built-in entry, then add a second region
TUR|Mashriq|Anatolia
TUR|Europe|Southern Europe
# no region for Antarctica
ATA||
regions.txtis read once at startup, like the optionalcountries.txt; restart foobar2000 after editing it.
Built-in regions and subregions:
| Region | Subregion | Countries |
|---|---|---|
| Antarctica | Antarctica | 1 |
| Africa | West Africa | 16 |
| Africa | Maghreb | 6 |
| Africa | Central Africa | 9 |
| Africa | East Africa | 8 |
| Africa | South Africa | 21 |
| Asia | Central Asia | 6 |
| Asia | East Asia | 7 |
| Asia | West Asia | 3 |
| Asia | South Asia | 16 |
| Asia | North Asia | 3 |
| Europe | Eastern Europe | 13 |
| Europe | Southern Europe | 9 |
| Europe | Central Europe | 9 |
| Europe | Western Europe | 10 |
| Europe | Northern Europe | 12 |
| Mashriq | Arabian Peninsula | 6 |
| Mashriq | Anatolia | 4 |
| Mashriq | Levant | 6 |
| Mashriq | Mesopotamia | 2 |
| America | Caribbean | 25 |
| America | North America | 8 |
| America | Central America | 8 |
| America | South America | 15 |
| Oceania | Australasia | 5 |
| Oceania | Melanesia | 5 |
| Oceania | Micronesia | 6 |
| Oceania | Polynesia | 13 |
These alternative names are built in and are matched case-insensitively, in addition to the names of the built-in country list. Add more with a countries.txt override file: a line US|USA|America makes America the name of the United States and keeps United States working as an alias. To add an alias without renaming, put its line first and the line with the name you want to keep after it (the last line for an ISO2 code sets the displayed name).
| Alias | Resolves to | iso2 |
|---|---|---|
United States of America |
United States | US |
Czech Republic |
Czechia | CZ |
Turkiye, Türkiye |
Turkey | TR |
Burma |
Myanmar | MM |
Ivory Coast |
Côte d'Ivoire | CI |
Cape Verde |
Cabo Verde | CV |
Vatican |
Vatican City | VA |
Macedonia |
North Macedonia | MK |
Swaziland |
Eswatini | SZ |
East Timor |
Timor-Leste | TL |
Russian Federation |
Russia | RU |
Korea |
South Korea | KR |
Great Britain, UK, England, Scotland, Wales |
United Kingdom | GB |
Holland |
Netherlands | NL |
Hellas |
Greece | GR |
Aland Islands |
Åland Islands | AX |
St. Barts, St. Barths, St. Barth, Saint Barthelemy |
Saint Barthélemy | BL |
Bonaire |
Bonaire, Sint Eustatius and Saba | BQ |
Curacao |
Curaçao | CW |
European Union, Europe, XE |
Europe | EU |
World, Worldwide |
Worldwide | XW |
These non-ISO values are built in, so they work without any countries.txt (an entry for the same code in that file takes precedence):
| Input | iso2 |
iso3 |
name |
emoji |
path |
|---|---|---|---|---|---|
XE, EU, Europe, European Union |
EU |
EUR |
Europe | European Union flag | flags\eu.png, or flags\xe.png if that is missing |
XW, Worldwide, World |
XW |
XWW |
Worldwide | Globe (U+1F310) | flags\xw.png |
XE is folded into EU, so XE/EU in one tag yields a single Europe entry rather than two.
-
Install
foo_countryflags.fb2k-componentvia Preferences > Components > Install, or double-click it. -
Restart foobar2000.
-
Make sure the optional
countries.txt,worldMap.json/country_codes.jsonand aflagsfolder containing PNG images named by lowercase ISO2 code (gr.png,us.png, ...) sit next to the DLL:- 64-bit foobar2000:
user-components-x64\foo_countryflags\ - 32-bit foobar2000:
user-components\foo_countryflags\
The component looks for these files relative to its own DLL, so each architecture needs its own copy (the package below already includes both). The country list is built into the DLL, so no data file is required. If you use a custom flag folder in preferences, nothing has to sit next to the DLL except the optional
countries.txt,country_codes.jsonandworldMap.json(the last two unless you set their locations in preferences). - 64-bit foobar2000:
Text:
$if(%countryflag_iso2%,[%countryflag_iso2%] ,)%artist% - %title%
Image in a panel that can load images from a path (JScript Panel):
var path = fb.TitleFormat('%countryflag_path%').Eval(true);
var img = path ? gdi.Image(path) : null;- Emoji on Windows: the default Windows emoji font shows flag emoji as two letters (e.g. "GR") instead of a flag.
%countryflag_emoji%only renders real flags with a flag-capable font such as Twemoji Country Flags. For reliable results, use%countryflag_path%with PNG images. - No
$function()syntax: foobar2000 does not let components register global title formatting functions, only fields. A call like$flag(%x%)is therefore not possible; set the source tags in preferences instead. - Caching and restart: changing source suffixes requires restarting foobar2000 so its title-formatting field list is updated. Flag image existence is checked again after about 30 seconds, so adding or deleting a flag image while foobar2000 is running is picked up within that time (or immediately if you change the flag folder setting).
- Thread safety: fields are evaluated from multiple threads. The component reads its data once, lazily, and only reads configuration afterwards.
regions.txt: optional, overrides/extends the built-in cultural regions; not included in the zip.countries.txt(optional): the country list is built into the component (ISO 3166-1, plus Kosovo using the user-assigned codeXKX). If this file exists next to the DLL it is read at startup as an override: one country per line in the formatISO2|ISO3|Name. A line for an ISO2 code that is already built in replaces its name and ISO3 code (the old name and ISO3 code keep working as aliases); a line with a new code adds a country. Restart foobar2000 after editing it. Back it up before updating the component, as component updates may replace the file. An unchanged copy of the full list has no effect, so you can delete it and keep only your own lines.country_codes.json: optional artist table (see Artist tables);worldMap.json: optional artist table (default location:profile\js_data\worldMap.json, otherwise next to the DLL) (see Artist tables); by default it takes precedence overcountry_codes.json;flags\*.png: not bundled. flag-icons (MIT) is one source; export its SVGs to PNG and keep its license file.
- Visual Studio 2022, C++17
- Build two configurations: Win32 (x86) and x64
- Link against
foobar2000_SDK,foobar2000_component_clientandpfc, built for the same platform as the component - Output name for both:
foo_countryflags.dll
MIT License