mirror of
https://github.com/timeshiftsauce/CeruMusic.git
synced 2025-11-25 03:15:07 +08:00
feat:修改了软件下载源
This commit is contained in:
@@ -11,15 +11,163 @@ function scrollToFeatures() {
|
||||
});
|
||||
}
|
||||
|
||||
// GitHub repository configuration
|
||||
// Alist API configuration
|
||||
const ALIST_BASE_URL = 'http://47.96.72.224:5244';
|
||||
const ALIST_USERNAME = 'ceruupdate';
|
||||
const ALIST_PASSWORD = '123456';
|
||||
|
||||
// GitHub repository configuration (for fallback)
|
||||
const GITHUB_REPO = 'timeshiftsauce/CeruMusic';
|
||||
const GITHUB_API_URL = `https://api.github.com/repos/${GITHUB_REPO}/releases/latest`;
|
||||
|
||||
// Cache for release data
|
||||
let releaseData = null;
|
||||
let releaseDataTimestamp = null;
|
||||
let alistToken = null;
|
||||
const CACHE_DURATION = 5 * 60 * 1000; // 5 minutes
|
||||
|
||||
// Alist authentication
|
||||
async function getAlistToken() {
|
||||
if (alistToken) {
|
||||
return alistToken;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`${ALIST_BASE_URL}/api/auth/login`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: ALIST_USERNAME,
|
||||
password: ALIST_PASSWORD
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200) {
|
||||
alistToken = data.data.token;
|
||||
return alistToken;
|
||||
} else {
|
||||
throw new Error(`Alist authentication failed: ${data.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Alist authentication error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Get available versions from Alist
|
||||
async function getAlistVersions() {
|
||||
try {
|
||||
const token = await getAlistToken();
|
||||
|
||||
const response = await fetch(`${ALIST_BASE_URL}/api/fs/list`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
path: '/',
|
||||
password: '',
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
refresh: false
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200) {
|
||||
// Filter directories that look like version numbers
|
||||
const versions = data.data.content
|
||||
.filter(item => item.is_dir && /^v?\d+\.\d+\.\d+/.test(item.name))
|
||||
.sort((a, b) => b.name.localeCompare(a.name)); // Sort by version desc
|
||||
|
||||
return versions;
|
||||
} else {
|
||||
throw new Error(`Failed to get versions: ${data.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get Alist versions:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Get files in a specific version directory
|
||||
async function getAlistVersionFiles(version) {
|
||||
try {
|
||||
const token = await getAlistToken();
|
||||
|
||||
const response = await fetch(`${ALIST_BASE_URL}/api/fs/list`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
path: `/${version}`,
|
||||
password: '',
|
||||
page: 1,
|
||||
per_page: 100,
|
||||
refresh: false
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200) {
|
||||
return data.data.content.filter(item => !item.is_dir);
|
||||
} else {
|
||||
throw new Error(`Failed to get version files: ${data.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get version files:', error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// Get direct download URL from Alist
|
||||
async function getAlistDownloadUrl(version, fileName) {
|
||||
try {
|
||||
const token = await getAlistToken();
|
||||
const filePath = `/${version}/${fileName}`;
|
||||
|
||||
const response = await fetch(`${ALIST_BASE_URL}/api/fs/get`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Authorization': token,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
path: filePath
|
||||
})
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.code === 200) {
|
||||
const fileInfo = data.data;
|
||||
|
||||
// Try different URL formats
|
||||
if (fileInfo.raw_url) {
|
||||
return fileInfo.raw_url;
|
||||
} else if (fileInfo.sign) {
|
||||
return `${ALIST_BASE_URL}/d${filePath}?sign=${fileInfo.sign}`;
|
||||
} else {
|
||||
return `${ALIST_BASE_URL}/d${filePath}`;
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Failed to get download URL: ${data.message}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to get Alist download URL:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Download functionality
|
||||
async function downloadApp(platform) {
|
||||
const button = event.target;
|
||||
@@ -35,38 +183,53 @@ async function downloadApp(platform) {
|
||||
button.disabled = true;
|
||||
|
||||
try {
|
||||
// Get latest release data
|
||||
const release = await getLatestRelease();
|
||||
// Try Alist first
|
||||
const versions = await getAlistVersions();
|
||||
|
||||
if (!release) {
|
||||
throw new Error('无法获取最新版本信息');
|
||||
if (versions.length > 0) {
|
||||
const latestVersion = versions[0];
|
||||
const files = await getAlistVersionFiles(latestVersion.name);
|
||||
|
||||
// Find the appropriate file for the platform
|
||||
const fileName = findFileForPlatform(files, platform);
|
||||
|
||||
if (fileName) {
|
||||
const downloadUrl = await getAlistDownloadUrl(latestVersion.name, fileName);
|
||||
|
||||
// Show success notification
|
||||
showNotification(`正在下载 ${getPlatformName(platform)} 版本 ${latestVersion.name}...`, 'success');
|
||||
|
||||
// Start download
|
||||
window.open(downloadUrl, '_blank');
|
||||
|
||||
// Track download
|
||||
trackDownload(platform, latestVersion.name);
|
||||
|
||||
return; // Success, exit function
|
||||
}
|
||||
}
|
||||
|
||||
// Find the appropriate download asset
|
||||
const downloadUrl = findDownloadAsset(release.assets, platform);
|
||||
|
||||
if (!downloadUrl) {
|
||||
throw new Error(`暂无 ${getPlatformName(platform)} 版本下载`);
|
||||
}
|
||||
|
||||
// Show success notification
|
||||
showNotification(`正在下载 ${getPlatformName(platform)} 版本 v${release.tag_name}...`, 'success');
|
||||
|
||||
// Start download
|
||||
window.open('https://gh.bugdey.us.kg/'+downloadUrl, '_blank');
|
||||
|
||||
// Track download
|
||||
trackDownload(platform, release.tag_name);
|
||||
// Fallback to GitHub if Alist fails
|
||||
console.log('Alist download failed, trying GitHub fallback...');
|
||||
await downloadFromGitHub(platform);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Download error:', error);
|
||||
showNotification(`下载失败: ${error.message}`, 'error');
|
||||
|
||||
// Fallback to GitHub releases page
|
||||
setTimeout(() => {
|
||||
showNotification('正在跳转到GitHub下载页面...', 'info');
|
||||
window.open(`https://gh.bugdey.us.kg/https://github.com/${GITHUB_REPO}/releases/latest`, '_blank');
|
||||
}, 2000);
|
||||
// Try GitHub fallback
|
||||
try {
|
||||
console.log('Trying GitHub fallback...');
|
||||
await downloadFromGitHub(platform);
|
||||
} catch (fallbackError) {
|
||||
console.error('GitHub fallback also failed:', fallbackError);
|
||||
showNotification(`下载失败: ${error.message}`, 'error');
|
||||
|
||||
// Final fallback to GitHub releases page
|
||||
setTimeout(() => {
|
||||
showNotification('正在跳转到GitHub下载页面...', 'info');
|
||||
window.open(`https://github.com/${GITHUB_REPO}/releases/latest`, '_blank');
|
||||
}, 2000);
|
||||
}
|
||||
} finally {
|
||||
// Restore button state
|
||||
setTimeout(() => {
|
||||
@@ -76,6 +239,30 @@ async function downloadApp(platform) {
|
||||
}
|
||||
}
|
||||
|
||||
// GitHub fallback function
|
||||
async function downloadFromGitHub(platform) {
|
||||
const release = await getLatestRelease();
|
||||
|
||||
if (!release) {
|
||||
throw new Error('无法获取最新版本信息');
|
||||
}
|
||||
|
||||
const downloadUrl = findDownloadAsset(release.assets, platform);
|
||||
|
||||
if (!downloadUrl) {
|
||||
throw new Error(`暂无 ${getPlatformName(platform)} 版本下载`);
|
||||
}
|
||||
|
||||
// Show success notification
|
||||
showNotification(`正在下载 ${getPlatformName(platform)} 版本 v${release.tag_name}...`, 'success');
|
||||
|
||||
// Start download
|
||||
window.open(downloadUrl, '_blank');
|
||||
|
||||
// Track download
|
||||
trackDownload(platform, release.tag_name);
|
||||
}
|
||||
|
||||
// Get latest release from GitHub API
|
||||
async function getLatestRelease() {
|
||||
// Check cache first
|
||||
@@ -104,6 +291,64 @@ async function getLatestRelease() {
|
||||
}
|
||||
}
|
||||
|
||||
// Find appropriate file for platform from Alist files
|
||||
function findFileForPlatform(files, platform) {
|
||||
if (!files || !Array.isArray(files)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Define file patterns for each platform
|
||||
const patterns = {
|
||||
windows: [
|
||||
/\\.exe$/i,
|
||||
/windows.*\\.zip$/i,
|
||||
/win32.*\\.zip$/i,
|
||||
/win.*x64.*\\.zip$/i
|
||||
],
|
||||
macos: [
|
||||
/\\.dmg$/i,
|
||||
/darwin.*\\.zip$/i,
|
||||
/macos.*\\.zip$/i,
|
||||
/mac.*\\.zip$/i,
|
||||
/osx.*\\.zip$/i
|
||||
],
|
||||
linux: [
|
||||
/\\.AppImage$/i,
|
||||
/linux.*\\.zip$/i,
|
||||
/linux.*\\.tar\\.gz$/i,
|
||||
/\\.deb$/i,
|
||||
/\\.rpm$/i
|
||||
]
|
||||
};
|
||||
|
||||
const platformPatterns = patterns[platform] || [];
|
||||
|
||||
// Try to find exact match
|
||||
for (const pattern of platformPatterns) {
|
||||
const file = files.find(file => pattern.test(file.name));
|
||||
if (file) {
|
||||
return file.name;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback: look for any file that might match the platform
|
||||
const fallbackPatterns = {
|
||||
windows: /win|exe/i,
|
||||
macos: /mac|darwin|dmg/i,
|
||||
linux: /linux|appimage|deb|rpm/i
|
||||
};
|
||||
|
||||
const fallbackPattern = fallbackPatterns[platform];
|
||||
if (fallbackPattern) {
|
||||
const file = files.find(file => fallbackPattern.test(file.name));
|
||||
if (file) {
|
||||
return file.name;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Find appropriate download asset based on platform
|
||||
function findDownloadAsset(assets, platform) {
|
||||
if (!assets || !Array.isArray(assets)) {
|
||||
@@ -460,6 +705,36 @@ window.addEventListener('error', (e) => {
|
||||
// Update version information on page
|
||||
async function updateVersionInfo() {
|
||||
try {
|
||||
// Try to get version info from Alist first
|
||||
const versions = await getAlistVersions();
|
||||
|
||||
if (versions.length > 0) {
|
||||
const latestVersion = versions[0];
|
||||
const versionElement = document.querySelector('.version');
|
||||
const versionInfoElement = document.querySelector('.version-info p');
|
||||
|
||||
if (versionElement) {
|
||||
versionElement.textContent = latestVersion.name;
|
||||
}
|
||||
|
||||
if (versionInfoElement) {
|
||||
const modifyDate = new Date(latestVersion.modified);
|
||||
const formattedDate = modifyDate.toLocaleDateString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long'
|
||||
});
|
||||
versionInfoElement.innerHTML = `当前版本: <span class="version">${latestVersion.name}</span> | 更新时间: ${formattedDate}`;
|
||||
}
|
||||
|
||||
// Update download button text with file info from Alist
|
||||
const files = await getAlistVersionFiles(latestVersion.name);
|
||||
updateDownloadButtonsWithAlistFiles(files);
|
||||
|
||||
return; // Success, exit function
|
||||
}
|
||||
|
||||
// Fallback to GitHub if Alist fails
|
||||
console.log('Alist version info failed, trying GitHub fallback...');
|
||||
const release = await getLatestRelease();
|
||||
if (release) {
|
||||
const versionElement = document.querySelector('.version');
|
||||
@@ -486,6 +761,29 @@ async function updateVersionInfo() {
|
||||
}
|
||||
}
|
||||
|
||||
// Update download buttons with Alist file information
|
||||
function updateDownloadButtonsWithAlistFiles(files) {
|
||||
if (!files || !Array.isArray(files)) return;
|
||||
|
||||
const downloadCards = document.querySelectorAll('.download-card');
|
||||
const platforms = ['windows', 'macos', 'linux'];
|
||||
|
||||
downloadCards.forEach((card, index) => {
|
||||
const platform = platforms[index];
|
||||
const fileName = findFileForPlatform(files, platform);
|
||||
|
||||
if (fileName) {
|
||||
const file = files.find(f => f.name === fileName);
|
||||
const button = card.querySelector('.btn-download');
|
||||
const sizeText = formatFileSize(file.size);
|
||||
const originalText = button.innerHTML;
|
||||
|
||||
// Add file size info
|
||||
button.innerHTML = originalText.replace(/下载 \..*?$/, `下载 .${getFileExtension(fileName)} (${sizeText})`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Update download buttons with asset information
|
||||
function updateDownloadButtonsWithAssets(assets) {
|
||||
if (!assets || !Array.isArray(assets)) return;
|
||||
|
||||
Reference in New Issue
Block a user