Bandcamp Album Duration

Calculates and displays the total duration of a Bandcamp album on its page.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name        Bandcamp Album Duration
// @namespace   Violentmonkey Scripts
// @match       https://*.bandcamp.com/album/*
// @grant       none
// @version     1.0
// @author      Gemini
// @description Calculates and displays the total duration of a Bandcamp album on its page.
// @license     MIT
// ==/UserScript==

(() => {
  // --- SCRIPT START ---

  // Find the table containing the track list.
  const trackTable = document.getElementById('track_table');
  if (!trackTable) {
    console.log("Bandcamp Album Duration: Could not find track table.");
    return;
  }

  // Find the body of the table where tracks are listed.
  const trackTableBody = trackTable.querySelector('tbody');
  if (!trackTableBody) {
    console.log("Bandcamp Album Duration: Could not find track table body.");
    return;
  }

  // Select all elements that contain track durations.
  // Bandcamp uses a <span> with the class 'time' for this.
  const timeElements = trackTable.querySelectorAll('tr.track_row_view .time');
  if (timeElements.length === 0) {
    console.log("Bandcamp Album Duration: No track times found on this page.");
    return;
  }

  let totalSeconds = 0;

  // Iterate over each time element to sum up the duration.
  timeElements.forEach(timeEl => {
    // Get the time string (e.g., "03:40") and remove whitespace.
    const timeString = timeEl.textContent.trim();
    const parts = timeString.split(':');

    // Make sure the format is correct (MM:SS) before parsing.
    if (parts.length === 2) {
      const minutes = parseInt(parts[0], 10);
      const seconds = parseInt(parts[1], 10);

      // Add the duration of the current track (in seconds) to the total.
      if (!isNaN(minutes) && !isNaN(seconds)) {
        totalSeconds += (minutes * 60) + seconds;
      }
    }
  });

  // Function to format the total seconds back into a readable HH:MM:SS or MM:SS format.
  function formatDuration(totalSeconds) {
    const hours = Math.floor(totalSeconds / 3600);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const seconds = totalSeconds % 60;

    // Helper to pad numbers with a leading zero if they are less than 10 (e.g., 5 -> "05").
    const pad = (num) => num.toString().padStart(2, '0');

    let formattedString = `${pad(minutes)}:${pad(seconds)}`;
    if (hours > 0) {
      formattedString = `${pad(hours)}:${formattedString}`;
    }

    return formattedString;
  }

  const formattedTime = formatDuration(totalSeconds);

  // --- Create and insert the new element ---

  // Create a new table row `<tr>` to hold our total duration info.
  const totalRow = document.createElement('tr');
  totalRow.style.borderTop = '1px solid rgba(255, 255, 255, 0.1)'; // Add a subtle separator line.

  // Create a table cell `<td>`. We use colspan="3" so it spans across
  // the play button, track number, and title columns.
  const totalCell = document.createElement('td');
  totalCell.colSpan = 3;

  // Style the cell to align the text to the right, similar to the track times.
  totalCell.style.textAlign = 'right';
  totalCell.style.padding = '8px 8px 8px 0'; // Give it some spacing.
  totalCell.style.fontWeight = 'bold';

  // Create a `<span>` for the text itself.
  const textSpan = document.createElement('span');

  // Use the 'secondaryText' class from Bandcamp to match the font color and style.
  textSpan.className = 'secondaryText';
  textSpan.textContent = `Total duration: ${formattedTime}`;

  // Assemble the elements: span -> cell -> row.
  totalCell.appendChild(textSpan);
  totalRow.appendChild(totalCell);

  // Add an empty cell to align with the "buy track" column.
  const emptyCell = document.createElement('td');
  emptyCell.colSpan = 2;
  totalRow.appendChild(emptyCell);

  // Append the newly created row to the end of the track list.
  trackTableBody.appendChild(totalRow);

  // --- SCRIPT END ---
})();