mirror of
https://github.com/19JVJeffery/tiddl-gui.git
synced 2026-10-23 03:12:17 -05:00
- config.js: add getPreferredFormat/setPreferredFormat (tiddl_preferred_format, default "m4a") - index.html: add Preferred Format select in Download settings section - settings.js: import and bind the new setting in loadSettingsForm/saveSettingsForm - app.js: import getPreferredFormat and upgrade LOW/HIGH to LOSSLESS when FLAC is preferred Co-authored-by: 19JVJeffery <94115228+19JVJeffery@users.noreply.github.com>
219 lines
11 KiB
JavaScript
219 lines
11 KiB
JavaScript
/**
|
|
* tiddl-web — configuration
|
|
*
|
|
* Credentials mirror the ones embedded in the Python CLI (already public in
|
|
* the open-source repository). They are stored the same way — as a single
|
|
* base-64 string that decodes to "clientId;clientSecret".
|
|
*/
|
|
|
|
const _raw = atob(
|
|
"ZlgySnhkbW50WldLMGl4VDsxTm45QWZEQWp4cmdKRkpiS05XTGVBeUtHVkdtSU51WFBQTEhWWEF2eEFnPQ=="
|
|
);
|
|
const [DEFAULT_CLIENT_ID, DEFAULT_CLIENT_SECRET] = _raw.split(";");
|
|
|
|
export const AUTH_URL = "https://auth.tidal.com/v1/oauth2";
|
|
export const API_URL = "https://api.tidal.com/v1";
|
|
|
|
// ─── Credentials ─────────────────────────────────────────────────────────────
|
|
|
|
export function getClientId() {
|
|
return localStorage.getItem("tiddl_client_id") || DEFAULT_CLIENT_ID;
|
|
}
|
|
export function getClientSecret() {
|
|
return localStorage.getItem("tiddl_client_secret") || DEFAULT_CLIENT_SECRET;
|
|
}
|
|
export function setClientId(v) {
|
|
if (v) localStorage.setItem("tiddl_client_id", v);
|
|
else localStorage.removeItem("tiddl_client_id");
|
|
}
|
|
export function setClientSecret(v) {
|
|
if (v) localStorage.setItem("tiddl_client_secret", v);
|
|
else localStorage.removeItem("tiddl_client_secret");
|
|
}
|
|
|
|
// ─── CORS proxy ───────────────────────────────────────────────────────────────
|
|
|
|
/** CORS proxy prefix — every request to Tidal is sent through this URL. */
|
|
export function getCorsProxy() {
|
|
return localStorage.getItem("tiddl_cors_proxy") ?? "https://corsproxy.io/?url=";
|
|
}
|
|
export function setCorsProxy(v) {
|
|
localStorage.setItem("tiddl_cors_proxy", v);
|
|
}
|
|
|
|
/** Wrap a target URL with the configured CORS proxy. */
|
|
export function proxied(url) {
|
|
const proxy = getCorsProxy().trim();
|
|
if (!proxy) return url;
|
|
return proxy + encodeURIComponent(url);
|
|
}
|
|
|
|
// ─── Appearance ───────────────────────────────────────────────────────────────
|
|
|
|
/** "dark" | "light" | "system" */
|
|
export function getTheme() {
|
|
return localStorage.getItem("tiddl_theme") || "system";
|
|
}
|
|
export function setTheme(v) {
|
|
localStorage.setItem("tiddl_theme", v);
|
|
}
|
|
|
|
/** Hex accent colour, e.g. "#4fd08c" */
|
|
export function getAccentColor() {
|
|
return localStorage.getItem("tiddl_accent") || "#4fd08c";
|
|
}
|
|
export function setAccentColor(v) {
|
|
localStorage.setItem("tiddl_accent", v);
|
|
}
|
|
|
|
/** "full" | "reduced" | "minimal" | "classic" */
|
|
export function getUiEffects() {
|
|
return localStorage.getItem("tiddl_ui_effects") || "full";
|
|
}
|
|
export function setUiEffects(v) {
|
|
localStorage.setItem("tiddl_ui_effects", v);
|
|
}
|
|
|
|
// ─── Download settings ────────────────────────────────────────────────────────
|
|
|
|
function getSetting(key, def) {
|
|
const v = localStorage.getItem(key);
|
|
return v === null ? def : v;
|
|
}
|
|
function setSetting(key, v) {
|
|
localStorage.setItem(key, String(v));
|
|
}
|
|
|
|
export function getTrackQuality() { return getSetting("tiddl_track_quality", "HIGH"); }
|
|
export function setTrackQuality(v) { setSetting("tiddl_track_quality", v); }
|
|
|
|
export function getVideoQuality() { return getSetting("tiddl_video_quality", "fhd"); }
|
|
export function setVideoQuality(v) { setSetting("tiddl_video_quality", v); }
|
|
|
|
export function getThreadsCount() { return parseInt(getSetting("tiddl_threads", "4"), 10); }
|
|
export function setThreadsCount(v) { setSetting("tiddl_threads", v); }
|
|
|
|
export function getSkipExisting() { return getSetting("tiddl_skip_existing", "true") === "true"; }
|
|
export function setSkipExisting(v) { setSetting("tiddl_skip_existing", v ? "true" : "false"); }
|
|
|
|
export function getSinglesFilter() { return getSetting("tiddl_singles_filter", "none"); }
|
|
export function setSinglesFilter(v) { setSetting("tiddl_singles_filter", v); }
|
|
|
|
export function getVideosFilter() { return getSetting("tiddl_videos_filter", "none"); }
|
|
export function setVideosFilter(v) { setSetting("tiddl_videos_filter", v); }
|
|
|
|
export function getUpdateMtime() { return getSetting("tiddl_update_mtime", "false") === "true"; }
|
|
export function setUpdateMtime(v) { setSetting("tiddl_update_mtime", v ? "true" : "false"); }
|
|
|
|
export function getRewriteMetadata() { return getSetting("tiddl_rewrite_metadata", "false") === "true"; }
|
|
export function setRewriteMetadata(v) { setSetting("tiddl_rewrite_metadata", v ? "true" : "false"); }
|
|
|
|
// ─── Metadata settings ────────────────────────────────────────────────────────
|
|
|
|
export function getMetadataEnable() { return getSetting("tiddl_meta_enable", "true") === "true"; }
|
|
export function setMetadataEnable(v) { setSetting("tiddl_meta_enable", v ? "true" : "false"); }
|
|
|
|
export function getMetadataLyrics() { return getSetting("tiddl_meta_lyrics", "false") === "true"; }
|
|
export function setMetadataLyrics(v) { setSetting("tiddl_meta_lyrics", v ? "true" : "false"); }
|
|
|
|
export function getMetadataCover() { return getSetting("tiddl_meta_cover", "false") === "true"; }
|
|
export function setMetadataCover(v) { setSetting("tiddl_meta_cover", v ? "true" : "false"); }
|
|
|
|
export function getMetadataAlbumReview() { return getSetting("tiddl_meta_album_review", "false") === "true"; }
|
|
export function setMetadataAlbumReview(v){ setSetting("tiddl_meta_album_review", v ? "true" : "false"); }
|
|
|
|
// ─── Cover art settings ───────────────────────────────────────────────────────
|
|
|
|
export function getCoverSave() { return getSetting("tiddl_cover_save", "false") === "true"; }
|
|
export function setCoverSave(v) { setSetting("tiddl_cover_save", v ? "true" : "false"); }
|
|
|
|
export function getCoverSize() { return parseInt(getSetting("tiddl_cover_size", "1280"), 10); }
|
|
export function setCoverSize(v) { setSetting("tiddl_cover_size", v); }
|
|
|
|
export function getCoverAllowed() { return JSON.parse(getSetting("tiddl_cover_allowed", "[]")); }
|
|
export function setCoverAllowed(v) { setSetting("tiddl_cover_allowed", JSON.stringify(v)); }
|
|
|
|
// ─── M3U settings ─────────────────────────────────────────────────────────────
|
|
|
|
export function getM3uSave() { return getSetting("tiddl_m3u_save", "false") === "true"; }
|
|
export function setM3uSave(v) { setSetting("tiddl_m3u_save", v ? "true" : "false"); }
|
|
|
|
export function getM3uAllowed() { return JSON.parse(getSetting("tiddl_m3u_allowed", '["album","mix","playlist"]')); }
|
|
export function setM3uAllowed(v) { setSetting("tiddl_m3u_allowed", JSON.stringify(v)); }
|
|
|
|
// ─── Advanced mode ────────────────────────────────────────────────────────────
|
|
|
|
export function getAdvancedMode() { return getSetting("tiddl_advanced_mode", "false") === "true"; }
|
|
export function setAdvancedMode(v) { setSetting("tiddl_advanced_mode", v ? "true" : "false"); }
|
|
|
|
// ─── Experimental: all-qualities mode ────────────────────────────────────────
|
|
|
|
/** When enabled, every queue item is downloaded in all four quality tiers. */
|
|
export function getAllQualitiesMode() { return getSetting("tiddl_all_qualities", "false") === "true"; }
|
|
export function setAllQualitiesMode(v) { setSetting("tiddl_all_qualities", v ? "true" : "false"); }
|
|
|
|
// ─── Preferred format ─────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* "m4a" — use the quality tier as-is (LOW/HIGH produce AAC/M4A).
|
|
* "flac" — automatically upgrade LOW/HIGH quality to LOSSLESS so downloads
|
|
* are always in FLAC format.
|
|
*/
|
|
export function getPreferredFormat() { return getSetting("tiddl_preferred_format", "m4a"); }
|
|
export function setPreferredFormat(v) { setSetting("tiddl_preferred_format", v); }
|
|
|
|
/** Labels for all quality tiers. */
|
|
export const QUALITY_LABELS = {
|
|
LOW: "Low", HIGH: "High", LOSSLESS: "HiFi", HI_RES_LOSSLESS: "Max",
|
|
};
|
|
|
|
/** Detailed option text for quality tier selects. */
|
|
export const QUALITY_DESCRIPTIONS = {
|
|
LOW: "Low — 96 kbps · M4A",
|
|
HIGH: "High — 320 kbps · M4A",
|
|
LOSSLESS: "HiFi — FLAC 16-bit",
|
|
HI_RES_LOSSLESS: "Max — FLAC 24-bit",
|
|
};
|
|
|
|
/** Available quality tiers, highest first. */
|
|
export const QUALITY_STANDARD = ["HI_RES_LOSSLESS", "LOSSLESS", "HIGH", "LOW"];
|
|
|
|
// ─── Search history ───────────────────────────────────────────────────────────
|
|
|
|
const SEARCH_HISTORY_KEY = "tiddl_search_history";
|
|
const SEARCH_HISTORY_MAX = 12;
|
|
|
|
export function loadSearchHistory() {
|
|
try { return JSON.parse(localStorage.getItem(SEARCH_HISTORY_KEY) || "[]"); }
|
|
catch { return []; }
|
|
}
|
|
export function saveToSearchHistory(q) {
|
|
if (!q?.trim()) return;
|
|
const h = loadSearchHistory().filter(x => x !== q.trim());
|
|
h.unshift(q.trim());
|
|
localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(h.slice(0, SEARCH_HISTORY_MAX)));
|
|
}
|
|
export function clearSearchHistory() {
|
|
localStorage.removeItem(SEARCH_HISTORY_KEY);
|
|
}
|
|
|
|
// ─── File path templates ──────────────────────────────────────────────────────
|
|
|
|
const TEMPLATE_DEFAULTS = {
|
|
default: "{album.artist}/{album.title}/{item.title}",
|
|
track: "",
|
|
video: "videos/{item.title}",
|
|
album: "artists/{album.artist}/{album.title}/{item.title}",
|
|
playlist: "{playlist.title}/{playlist.index}. {item.artist} - {item.title}",
|
|
mix: "mixes/{mix_id}/{item.artist} - {item.title}",
|
|
};
|
|
|
|
export function getTemplate(type) {
|
|
const v = localStorage.getItem(`tiddl_tpl_${type}`);
|
|
return v !== null ? v : (TEMPLATE_DEFAULTS[type] ?? "");
|
|
}
|
|
export function setTemplate(type, v) {
|
|
localStorage.setItem(`tiddl_tpl_${type}`, v);
|
|
}
|
|
export { TEMPLATE_DEFAULTS };
|