1
qinghuazs 31 天前
花见?
|
![]() |
2
Magicdove 31 天前
我都到壁纸网站下载到本地看
|
![]() |
3
Frankcox 31 天前
unsplash, wallhaven.cc
|
![]() |
4
julio867 31 天前
以前逛 wallhaven ,现在定期到 unsplash 找自己喜欢的,然后批量下载,自己还专门写了一个浏览器扩展方便获取原图地址,然后迅雷批量下~~😄
|
5
xiangshuaaaa 31 天前
@julio867 扩展发布了嘛,白嫖下( bushi )
|
![]() |
6
julio867 31 天前
@xiangshuaaaa 注册开发者比较麻烦,目前仅自己在本地使用~
之前放了一个 wallhaven 的在 github 上: https://github.com/zoujia/WallhavenAssistant (写的不好,只保证了能用😅) unsplash 的抽空再把它放到 github 上吧~ |
![]() |
7
since2021 31 天前
偶尔去 reddit 上自己找
|
![]() |
8
mohuani 31 天前
|
9
Weyeeep 31 天前 via Android
只用过 unsplash
|
10
wfhtqp 31 天前
bing wallpaper 每天换新
|
11
565656 31 天前
win11 自带了 设置 windows 聚焦每天自动换
|
![]() |
12
timothyye 31 天前 via Android
做过一个 bing wallpaper 的开源项目
https://github.com/TimothyYe/bing-wallpaper |
![]() |
13
fuyun 31 天前
https://www.ifuyun.com/wallpaper 除了壁纸,还有壁纸背后的故事,支持中英文,支持全文搜索。
前台开源( https://github.com/ifuyun/ifuyun.com ),API 闭源。 |
![]() |
14
JensenQian 30 天前
壁纸我用的 steam 上 19 块小红车
不过不认识的别乱下,最近在闹赛博梅毒 |
![]() |
15
senzyo 30 天前
那得推荐一下 https://github.com/rocksdanister/lively ,完全能替代 Wallpaper Engine
|
16
nrq 30 天前
楼上的好东西,感谢分享
|
![]() |
17
LitterGopher 30 天前 ![]() pexels 和 unsplash 有提供 API, 你自己註冊一個開發者帳號(免費), 然後寫一個腳本自動獲取就可以了.
我自己是使用 shell + crontab 實現定期獲取隨機圖片並設置爲桌面背景. |
![]() |
18
zhj0326 30 天前
unsplash
|
![]() |
19
1Z3KYa0qBLvei98o 29 天前
import axios from 'axios';
import fs from 'fs'; import path from 'path'; import os from 'os'; import crypto from 'crypto'; import { setWallpaper } from 'wallpaper'; import readline from 'readline'; import { SocksProxyAgent } from 'socks-proxy-agent'; const UNSPLASH_API_URL = 'https://api.unsplash.com/photos/random'; const ACCESS_KEY = 'Z_GQ0Jd3V27mew6lRc1MB-1ojS0e9s9W7B5FPN6XoZc'; // Replace with your Unsplash access key const INTERVAL = 5 * 60 * 1000; // 5 minutes const DOWNLOAD_TIMEOUT = 60 * 1000; // 1 minute const THREAD_COUNT = 4; // Number of threads for parallel download const RETRY_LIMIT = 3; // Retry limit for failed downloads const PROGRESS_TIMEOUT = 10 * 1000; // 10 seconds timeout for progress check const MIN_SPEED = 10; // Minimum speed in KB/s to consider as stalled // SOCKS5 Proxy setup const proxyUrl = 'socks5h://127.0.0.1:1080'; // Replace with your SOCKS5 proxy server address and port const agent = new SocksProxyAgent(proxyUrl); // Keywords list const originalKeywords = [ 'mountain', 'africa', 'middle east', 'snow', 'travel', 'Caribbean', 'Hubble Space Telescope', 'roman', 'Soviets', 'Aegean Sea', 'Bahrain', 'Eritrea', 'Iran', 'Iraq', 'Israel', 'Jordan', 'Kuwait', 'Lebanon', 'Oman', 'Qatar', 'Saudi Arabia', 'Syria', 'United Arab Emirates', 'Yemen', // Europe 'Albania', 'Andorra', 'Austria', 'Belarus', 'Belgium', 'Bosnia and Herzegovina', 'Bulgaria', 'Iceland', 'Ireland', 'Italy', 'Kosovo', 'Latvia', 'Lithuania', 'Luxembourg', 'Malta', 'Monaco', 'Moldova', 'Norway', 'Netherlands', 'Portugal', 'Romania', 'Russia', 'San Marino', 'Serbia', 'Cyprus', 'Slovakia', 'Slovenia', 'Spain', 'Switzerland', 'Ukraine', 'United Kingdom', 'Vatican City', // Asia 'Afghanistan', 'United Arab Emirates', 'Armenia', 'China', 'Georgia', 'India', 'Indonesia', 'Iran', 'Iraq', 'Israel', 'Japan', 'Jordan', 'Kazakhstan', 'South Korea', 'Kuwait', 'Kyrgyzstan', 'Lebanon', 'Maldives', 'Mongolia', 'Myanmar', 'Nepal', 'Macau', 'Malaysia', 'Pakistan', 'Philippines', 'Russia', 'Saudi Arabia', 'Singapore', 'Sri Lanka', 'Syria', 'Tajikistan', 'Thailand', 'Timor-Leste', 'Turkey', 'Turkmenistan', 'Uzbekistan', 'Yemen', // Caribbean and South America 'Antigua and Barbuda', 'Bahamas', 'Barbados', 'Bolivia', 'Colombia', 'Cuba', 'Dominica', 'Dominican Republic', 'Grenada', 'Guyana', 'Haiti', 'Honduras', 'Jamaica', 'Nicaragua', 'Paraguay', 'Peru', 'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'Suriname', 'Trinidad and Tobago', 'Venezuela' ]; // Create a copy of the original keywords to keep track of unused ones let unusedKeywords = [...originalKeywords]; // Function to generate a random hash function generateHash(length = 8) { return crypto.randomBytes(length).toString('hex'); } // Function to get the path for temporary file function getTempFilePath(partIndex) { const tempDir = os.tmpdir(); return path.join(tempDir, `wallpaper_part${partIndex}.tmp`); } // Function to get a random keyword function getRandomKeyword() { if (unusedKeywords.length === 0) { unusedKeywords = [...originalKeywords]; // Reset the list when all keywords have been used console.log('All keywords used, resetting keyword list.'); } const randomIndex = Math.floor(Math.random() * unusedKeywords.length); const keyword = unusedKeywords[randomIndex]; unusedKeywords.splice(randomIndex, 1); // Remove the keyword from the list return keyword; } async function downloadPart(photoUrl, start, end, partIndex, totalLength, downloadedParts, startTime) { let retryCount = 0; let lastProgress = 0; let progressTimer; const tempFilePath = getTempFilePath(partIndex); // Read previous progress if (fs.existsSync(tempFilePath)) { downloadedParts[partIndex] = fs.statSync(tempFilePath).size; } while (retryCount < RETRY_LIMIT) { try { let currentStart = start + downloadedParts[partIndex]; const response = await axios.get(photoUrl, { headers: { 'Range': `bytes=${currentStart}-${end}`, }, responseType: 'arraybuffer', httpAgent: agent, // Apply the SOCKS5 agent httpsAgent: agent, // Apply the SOCKS5 agent onDownloadProgress: (progressEvent) => { const newBytes = progressEvent.loaded - downloadedParts[partIndex]; downloadedParts[partIndex] += newBytes; updateProgress(downloadedParts, totalLength, startTime); const elapsedTime = (Date.now() - startTime) / 1000; // in seconds const speed = (newBytes / 1024 / elapsedTime).toFixed(2); // in KB/s // Reset progress timer on new data clearTimeout(progressTimer); progressTimer = setTimeout(() => { if (downloadedParts[partIndex] <= lastProgress || speed < MIN_SPEED) { console.log(`\nPart ${partIndex + 1} is stalled or too slow, retrying...`); retryCount++; if (retryCount >= RETRY_LIMIT) { throw new Error(`Failed to download part ${partIndex + 1} after ${RETRY_LIMIT} attempts.`); } lastProgress = downloadedParts[partIndex]; downloadPart(photoUrl, start, end, partIndex, totalLength, downloadedParts, startTime); } }, PROGRESS_TIMEOUT); } }); // Append data to temp file fs.writeFileSync(tempFilePath, response.data, { flag: 'a' }); clearTimeout(progressTimer); break; // Exit the loop if download was successful } catch (error) { console.error(`Part ${partIndex + 1} failed, retrying... (${retryCount}/${RETRY_LIMIT})`); if (retryCount >= RETRY_LIMIT) { throw new Error(`Failed to download part ${partIndex + 1} after ${RETRY_LIMIT} attempts.`); } } } } async function downloadRandomPhoto() { console.log('Attempting to download a new wallpaper...'); try { const keyword = getRandomKeyword(); // Select a random keyword console.log(`Using keyword: ${keyword}`); const response = await axios.get(UNSPLASH_API_URL, { headers: { Authorization: `Client-ID ${ACCESS_KEY}` }, params: { query: keyword, }, httpAgent: agent, // Apply the SOCKS5 agent httpsAgent: agent, // Apply the SOCKS5 agent }); console.log('Received response from Unsplash API.'); const photoUrl = response.data.urls.full; console.log(`Photo URL: ${photoUrl}`); const headResponse = await axios.head(photoUrl, { httpAgent: agent, httpsAgent: agent }); const totalLength = parseInt(headResponse.headers['content-length'], 10); const tempDir = os.tmpdir(); const hash = generateHash(); const fileName = path.join(tempDir, `wallpaper_${hash}.jpg`); console.log(`Total size: ${totalLength} bytes`); console.log(`Saving photo to: ${fileName}`); const partSize = Math.ceil(totalLength / THREAD_COUNT); const downloadedParts = new Array(THREAD_COUNT).fill(0); let startTime = Date.now(); const promises = []; for (let i = 0; i < THREAD_COUNT; i++) { const start = i * partSize; const end = Math.min(start + partSize - 1, totalLength - 1); console.log(`Downloading part ${i + 1}: bytes ${start}-${end}`); const promise = downloadPart(photoUrl, start, end, i, totalLength, downloadedParts, startTime); promises.push(promise); } await Promise.all(promises); // Combine all parts into a single file const writeStream = fs.createWriteStream(fileName); for (let i = 0; i < THREAD_COUNT; i++) { const tempFilePath = getTempFilePath(i); const data = fs.readFileSync(tempFilePath); writeStream.write(data); fs.unlinkSync(tempFilePath); // Delete part file after merging } writeStream.end(); console.log('\nPhoto download complete. Setting wallpaper...'); setWallpaper(fileName).then(() => { console.log('Wallpaper updated successfully!'); }).catch(err => { console.error('Failed to set wallpaper:', err); }); } catch (error) { console.error('Error in downloadRandomPhoto function:', error); } } function updateProgress(downloadedParts, totalLength, startTime) { const downloadedLength = downloadedParts.reduce((acc, val) => acc + val, 0); const percent = ((downloadedLength / totalLength) * 100).toFixed(2); const elapsedTime = (Date.now() - startTime) / 1000; // in seconds const speed = (downloadedLength / 1024 / elapsedTime).toFixed(2); // in KB/s readline.clearLine(process.stdout, 0); readline.cursorTo(process.stdout, 0); process.stdout.write(`Download progress: ${percent}% | Speed: ${speed} KB/s`); } downloadRandomPhoto(); setInterval(() => { console.log('Starting new wallpaper update cycle...'); downloadRandomPhoto(); }, INTERVAL); |
![]() |
20
1Z3KYa0qBLvei98o 29 天前
自己去搞一个 access_key
|
![]() |
21
1Z3KYa0qBLvei98o 29 天前
纯 ai 生成, 微调了一下
|