API自动换壁纸

查看 59|回复 6
作者:Skyearth1   
壁纸自动更换工具使用说明
开源代码(为了防止被误认为打广告,API相关代码和网址不开源)
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import requests
import os
import time
import threading
import ctypes
from PIL import Image, ImageTk, ImageDraw, ImageFont
import io
import sys
import pystray
from pystray import MenuItem as item
import winshell
from win32com.client import Dispatch
import webbrowser
import hashlib
import glob
import shutil
class SplashScreen:
    def __init__(self, root, main_app):
        self.root = root
        self.main_app = main_app
        self.splash = tk.Toplevel(root)
        self.splash.title("壁纸更换工具")
        self.splash.geometry("400x300")
        self.splash.overrideredirect(True)
        screen_width = root.winfo_screenwidth()
        screen_height = root.winfo_screenheight()
        x = (screen_width - 400) // 2
        y = (screen_height - 300) // 2
        self.splash.geometry(f"400x300+{x}+{y}")
        self.splash.configure(bg="#2c3e50")
        self.create_content()
        self.splash.after(2000, self.close_splash)
    def create_content(self):
        title_label = tk.Label(self.splash, text="壁纸更换工具",
                              font=("微软雅黑", 24, "bold"),
                              fg="#ecf0f1", bg="#2c3e50")
        title_label.pack(pady=40)
        subtitle_label = tk.Label(self.splash, text="Wallpaper Changer",
                                font=("微软雅黑", 12),
                                fg="#bdc3c7", bg="#2c3e50")
        subtitle_label.pack(pady=10)
        self.progress = ttk.Progressbar(self.splash, mode='indeterminate', length=300)
        self.progress.pack(pady=30)
        self.progress.start()
        version_label = tk.Label(self.splash, text="版本 1.0",
                               font=("微软雅黑", 8),
                               fg="#7f8c8d", bg="#2c3e50")
        version_label.pack(side=tk.BOTTOM, pady=10)
    def close_splash(self):
        self.splash.destroy()
        self.main_app.show_main_window()
class WallpaperCache:
    def __init__(self):
        self.cache_dir = "wp-52pojie"
        self.max_cache_size = 100
        self.api_error_shown = {}
        self.setup_cache_dirs()
    def setup_cache_dirs(self):
        if not os.path.exists(self.cache_dir):
            os.makedirs(self.cache_dir)
    def get_api_cache_dir(self, api_name):
        api_dir = os.path.join(self.cache_dir, api_name)
        if not os.path.exists(api_dir):
            os.makedirs(api_dir)
        return api_dir
    def calculate_image_hash(self, image_data):
        return hashlib.md5(image_data).hexdigest()
    def save_image_to_cache(self, api_name, image_data, image_url=None):
        try:
            api_dir = self.get_api_cache_dir(api_name)
            image_hash = self.calculate_image_hash(image_data)
            existing_files = glob.glob(os.path.join(api_dir, "*.jpg"))
            existing_files.extend(glob.glob(os.path.join(api_dir, "*.png")))
            for file_path in existing_files:
                with open(file_path, 'rb') as f:
                    if self.calculate_image_hash(f.read()) == image_hash:
                        return file_path
            timestamp = int(time.time())
            filename = f"{timestamp}_{image_hash}.jpg"
            filepath = os.path.join(api_dir, filename)
            with open(filepath, 'wb') as f:
                f.write(image_data)
            self.cleanup_cache(api_name)
            return filepath
        except Exception as e:
            print(f"保存缓存失败: {e}")
            return None
    def cleanup_cache(self, api_name):
        try:
            api_dir = self.get_api_cache_dir(api_name)
            image_files = []
            for ext in ['*.jpg', '*.png']:
                image_files.extend(glob.glob(os.path.join(api_dir, ext)))
            if len(image_files) > self.max_cache_size:
                image_files.sort(key=os.path.getmtime)
                files_to_delete = image_files[:len(image_files) - self.max_cache_size]
                for file_path in files_to_delete:
                    try:
                        os.remove(file_path)
                    except:
                        pass
        except Exception as e:
            print(f"清理缓存失败: {e}")
    def get_latest_cached_image(self, api_name):
        try:
            api_dir = self.get_api_cache_dir(api_name)
            image_files = []
            for ext in ['*.jpg', '*.png']:
                image_files.extend(glob.glob(os.path.join(api_dir, ext)))
            if not image_files:
                return None
            latest_file = max(image_files, key=os.path.getmtime)
            return latest_file
        except:
            return None
    def get_cached_image_count(self, api_name):
        try:
            api_dir = self.get_api_cache_dir(api_name)
            image_files = []
            for ext in ['*.jpg', '*.png']:
                image_files.extend(glob.glob(os.path.join(api_dir, ext)))
            return len(image_files)
        except:
            return 0
    def clear_cache(self, api_name=None):
        try:
            if api_name:
                api_dir = self.get_api_cache_dir(api_name)
                if os.path.exists(api_dir):
                    shutil.rmtree(api_dir)
            else:
                if os.path.exists(self.cache_dir):
                    shutil.rmtree(self.cache_dir)
                self.setup_cache_dirs()
            return True
        except Exception as e:
            print(f"清除缓存失败: {e}")
            return False
class WallpaperChanger:
    def __init__(self, root):
        self.root = root
        self.root.title("壁纸自动更换工具")
        self.root.geometry("800x700")
        self.root.resizable(True, True)
        self.root.configure(bg="#ecf0f1")
        self.root.withdraw()
        self.font_title = ("微软雅黑", 16, "bold")
        self.font_subtitle = ("微软雅黑", 12, "bold")
        self.font_normal = ("微软雅黑", 11)
        self.font_small = ("微软雅黑", 9)
        self.color_primary = "#3498db"
        self.color_secondary = "#2ecc71"
        self.color_danger = "#e74c3c"
        self.color_warning = "#f39c12"
        self.color_dark = "#2c3e50"
        self.color_light = "#ecf0f1"
        self.cache = WallpaperCache()
        self.setup_styles()
        self.current_api = tk.StringVar(value="bing")
        self.refresh_interval = tk.IntVar(value=60)
        self.auto_start = tk.BooleanVar(value=False)
        self.is_running = False
        self.timer_thread = None
        self.tray_icon = None
        self.apis = {
            此处为API列表,为了防止被误认广告已删除
        }
        self.custom_apis = {}
        self.log_messages = []
        self.notebook = ttk.Notebook(self.root)
        self.notebook.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        self.create_main_tab()
        self.create_settings_tab()
        self.create_about_tab()
        self.root.protocol('WM_DELETE_WINDOW', self.minimize_to_tray)
        self.check_auto_start()
        self.splash = SplashScreen(self.root, self)
    def show_main_window(self):
        self.root.update()
        width = 800
        height = 700
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        x = (screen_width - width) // 2
        y = (screen_height - height) // 2
        self.root.geometry(f"{width}x{height}+{x}+{y}")
        self.root.deiconify()
    def setup_styles(self):
        style = ttk.Style()
        style.configure("TNotebook", background=self.color_light)
        style.configure("TNotebook.Tab", font=self.font_subtitle, padding=[10, 5])
        style.configure("Primary.TButton", font=self.font_normal, background=self.color_primary, padding=10)
        style.configure("Success.TButton", font=self.font_normal, background=self.color_secondary, padding=10)
        style.configure("Danger.TButton", font=self.font_normal, background=self.color_danger, padding=10)
        style.configure("Warning.TButton", font=self.font_normal, background=self.color_warning, padding=10)
        style.configure("TLabelframe", background=self.color_light)
        style.configure("TLabelframe.Label", font=self.font_subtitle, background=self.color_light)
        style.configure("TLabel", background=self.color_light, font=self.font_normal)
        style.configure("TRadiobutton", background=self.color_light, font=self.font_normal)
        style.configure("TCheckbutton", background=self.color_light, font=self.font_normal)
    def create_main_tab(self):
        self.main_frame = ttk.Frame(self.notebook, padding="15")
        self.notebook.add(self.main_frame, text="壁纸更换")
        api_frame = ttk.LabelFrame(self.main_frame, text="选择壁纸源", padding="10")
        api_frame.pack(fill=tk.X, pady=10)
        api_buttons_frame = ttk.Frame(api_frame)
        api_buttons_frame.pack(fill=tk.X, pady=5)
        for i, (api_key, api_info) in enumerate(self.apis.items()):
            ttk.Radiobutton(api_buttons_frame, text=api_info["name"], variable=self.current_api,
                           value=api_key, command=self.load_preview_image).grid(row=0, column=i, sticky=tk.W, padx=10)
        custom_frame = ttk.Frame(api_buttons_frame)
        custom_frame.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E), pady=5)
        ttk.Radiobutton(custom_frame, text="自定义API", variable=self.current_api,
                       value="custom", command=self.load_preview_image).grid(row=0, column=0, sticky=tk.W)
        ttk.Button(custom_frame, text="管理自定义API",
                  command=self.manage_custom_apis, style="Primary.TButton").grid(row=0, column=1, padx=10)
        preview_frame = ttk.LabelFrame(self.main_frame, text="壁纸预览", padding="10")
        preview_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        self.preview_label = ttk.Label(preview_frame, text="点击刷新预览...", font=self.font_normal)
        self.preview_label.pack(expand=True, fill=tk.BOTH, pady=20)
        self.preview_label.bind("[B]", lambda e: self.load_preview_image())
        control_frame = ttk.LabelFrame(self.main_frame, text="控制设置", padding="10")
        control_frame.pack(fill=tk.X, pady=10)
        interval_frame = ttk.Frame(control_frame)
        interval_frame.pack(fill=tk.X, pady=5)
        ttk.Label(interval_frame, text="更换间隔(分钟):", font=self.font_normal).grid(row=0, column=0, sticky=tk.W)
        scale_input_frame = ttk.Frame(interval_frame)
        scale_input_frame.grid(row=0, column=1, sticky=(tk.W, tk.E))
        ttk.Scale(scale_input_frame, from_=1, to=240, variable=self.refresh_interval,
                 orient=tk.HORIZONTAL, length=200).grid(row=0, column=0, padx=10)
        self.interval_entry = ttk.Entry(scale_input_frame, width=5, font=self.font_normal)
        self.interval_entry.grid(row=0, column=1, padx=5)
        self.interval_entry.insert(0, "60")
        self.interval_entry.bind("", self.update_interval_from_entry)
        ttk.Label(scale_input_frame, textvariable=self.refresh_interval, font=self.font_normal).grid(row=0, column=2, padx=5)
        cache_frame = ttk.Frame(interval_frame)
        cache_frame.grid(row=1, column=0, columnspan=3, sticky=tk.W, pady=5)
        ttk.Button(cache_frame, text="清理缓存",
                  command=self.clear_cache, style="Warning.TButton").grid(row=0, column=0, padx=5)
        self.cache_info_label = ttk.Label(cache_frame, text="", font=self.font_small)
        self.cache_info_label.grid(row=0, column=1, padx=10)
        button_frame = ttk.Frame(control_frame)
        button_frame.pack(fill=tk.X, pady=10)
        ttk.Button(button_frame, text="立即更换壁纸",
                  command=self.apply_wallpaper, style="Primary.TButton").grid(row=0, column=0, padx=10, ipadx=10)
        ttk.Button(button_frame, text="开始自动更换",
                  command=self.start_auto_change, style="Success.TButton").grid(row=0, column=1, padx=10, ipadx=10)
        ttk.Button(button_frame, text="停止自动更换",
                  command=self.stop_auto_change, style="Danger.TButton").grid(row=0, column=2, padx=10, ipadx=10)
        ttk.Button(button_frame, text="恢复默认壁纸",
                  command=self.restore_default_wallpaper, style="Warning.TButton").grid(row=0, column=3, padx=10, ipadx=10)
        log_frame = ttk.LabelFrame(self.main_frame, text="操作日志", padding="10")
        log_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        self.log_text = tk.Text(log_frame, wrap=tk.WORD, font=self.font_small, height=8)
        scrollbar = ttk.Scrollbar(log_frame, orient=tk.VERTICAL, command=self.log_text.yview)
        self.log_text.configure(yscrollcommand=scrollbar.set)
        self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.log("程序启动完成")
        self.update_cache_info()
        interval_frame.columnconfigure(1, weight=1)
    def create_settings_tab(self):
        self.settings_frame = ttk.Frame(self.notebook, padding="15")
        self.notebook.add(self.settings_frame, text="设置")
        system_frame = ttk.LabelFrame(self.settings_frame, text="系统设置", padding="10")
        system_frame.pack(fill=tk.X, pady=10)
        ttk.Checkbutton(system_frame, text="开机自启动",
                       variable=self.auto_start, command=self.toggle_auto_start).grid(row=0, column=0, sticky=tk.W, pady=5)
        ttk.Button(system_frame, text="最小化到托盘",
                  command=self.minimize_to_tray, style="Primary.TButton").grid(row=0, column=1, padx=20, pady=5, ipadx=10)
        cache_settings_frame = ttk.LabelFrame(self.settings_frame, text="缓存设置", padding="10")
        cache_settings_frame.pack(fill=tk.X, pady=10)
        ttk.Label(cache_settings_frame, text="最大缓存数量:", font=self.font_normal).grid(row=0, column=0, sticky=tk.W)
        self.max_cache_var = tk.StringVar(value=str(self.cache.max_cache_size))
        max_cache_entry = ttk.Entry(cache_settings_frame, textvariable=self.max_cache_var, width=10, font=self.font_normal)
        max_cache_entry.grid(row=0, column=1, padx=10)
        max_cache_entry.bind("", self.update_max_cache)
        ttk.Button(cache_settings_frame, text="应用",
                  command=self.update_max_cache, style="Primary.TButton").grid(row=0, column=2, padx=5)
        help_frame = ttk.LabelFrame(self.settings_frame, text="使用说明", padding="10")
        help_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        help_text = """
使用说明:
1. 选择壁纸源:
   - 必应每日壁纸:每天更新的必应精美壁纸(大量)
   - 原神官图:原神官方发布的精美图片(中等数量)
   - NASA天文图片:NASA提供的天文图片(少量)
   - 其他API:上方未列出的API寻找自网络,任何标注(非作者API)的API作者只进行了几轮检查,不保证所有图片适宜且图片内容与作者无关
   - 自定义API:使用您自己的图片API
2. 设置更换间隔:
   - 使用滑块或直接输入分钟数
   - 最小1分钟,最大240分钟(4小时)
3. 控制功能:
   - 立即更换壁纸:手动更换当前壁纸
   - 开始自动更换:按照设定间隔自动更换壁纸
   - 停止自动更换:停止自动更换功能
   - 恢复默认壁纸:恢复系统默认壁纸
4. 缓存功能:
   - 自动保存下载的壁纸到缓存
   - 避免重复下载相同图片
   - API失败时自动使用缓存图片
   - 可设置最大缓存数量
5. 系统设置:
   - 开机自启动:程序随系统启动
   - 最小化到托盘:关闭窗口时最小化到系统托盘
6. 托盘操作:
   - 右键点击托盘图标可显示菜单
   - 支持快速更换壁纸和退出程序
        """
        help_label = tk.Text(help_frame, wrap=tk.WORD, font=self.font_normal, bg=self.color_light,
                           relief=tk.FLAT, height=15)
        help_label.pack(fill=tk.BOTH, expand=True)
        help_label.insert(tk.END, help_text)
        help_label.config(state=tk.DISABLED)
    def create_about_tab(self):
        self.about_frame = ttk.Frame(self.notebook, padding="15")
        self.notebook.add(self.about_frame, text="关于")
        info_frame = ttk.LabelFrame(self.about_frame, text="程序信息", padding="10")
        info_frame.pack(fill=tk.X, pady=10)
        info_text = """
壁纸自动更换工具
版本: 1.0
作者: 52pojie_Skyeath1
发布日期: 2025年
郑重声明:本页面提供的所有API均不保证可用性
        """
        info_label = tk.Text(info_frame, wrap=tk.WORD, font=self.font_normal, bg=self.color_light,
                           relief=tk.FLAT, height=10)
        info_label.pack(fill=tk.BOTH, expand=True)
        info_label.insert(tk.END, info_text)
        info_label.config(state=tk.DISABLED)
        contact_frame = ttk.LabelFrame(self.about_frame, text="联系信息", padding="10")
        contact_frame.pack(fill=tk.X, pady=10)
        contact_text = """
如果您在使用过程中遇到任何问题或有任何建议,请通过以下方式联系我们:
吾爱破解论坛:https://www.52pojie.cn/home.php?mod=space&uid=2344986
        """
        contact_label = tk.Text(contact_frame, wrap=tk.WORD, font=self.font_normal, bg=self.color_light,
                              relief=tk.FLAT, height=6)
        contact_label.pack(fill=tk.BOTH, expand=True)
        contact_label.insert(tk.END, contact_text)
        contact_label.config(state=tk.DISABLED)
        button_frame = ttk.Frame(self.about_frame)
        button_frame.pack(fill=tk.X, pady=10)
        ttk.Button(button_frame, text="访问",
                  command=lambda: webbrowser.open("https://www.52pojie.cn/home.php?mod=space&uid=2344986"),
                  style="Primary.TButton").pack(side=tk.LEFT, padx=10, ipadx=10)
    def update_cache_info(self):
        api_name = self.get_current_api_name()
        count = self.cache.get_cached_image_count(api_name)
        self.cache_info_label.config(text=f"当前API缓存: {count}张图片")
    def update_max_cache(self, event=None):
        try:
            new_size = int(self.max_cache_var.get())
            if new_size  100:
            self.log_messages.pop(0)
        self.log_text.delete(1.0, tk.END)
        for msg in self.log_messages[-20:]:
            self.log_text.insert(tk.END, msg + "\n")
        self.log_text.see(tk.END)
    def update_interval_from_entry(self, event=None):
        try:
            interval = int(self.interval_entry.get())
            if 1  1 and frame_height > 1:
                image.thumbnail((frame_width - 20, frame_height - 20), Image.Resampling.LANCZOS)
            photo = ImageTk.PhotoImage(image)
            self.preview_label.configure(image=photo)
            self.preview_label.image = photo
        except Exception as e:
            self.preview_label.configure(text="预览加载失败")
    def apply_wallpaper(self):
        threading.Thread(target=self._apply_wallpaper_thread, daemon=True).start()
    def _apply_wallpaper_thread(self):
        try:
            self.log("正在获取壁纸...")
            api_url = self.get_current_api_url()
            api_name = self.get_current_api_name()
            try:
                response = requests.get(api_url, timeout=10)
                if response.status_code == 200:
                    image_data = response.content
                    cached_path = self.cache.save_image_to_cache(api_name, image_data, api_url)
                    if cached_path:
                        self.log(f"图片已保存到缓存: {os.path.basename(cached_path)}")
                    temp_path = os.path.join(os.environ['TEMP'], 'wallpaper.jpg')
                    with open(temp_path, 'wb') as f:
                        f.write(image_data)
                    self._set_wallpaper(temp_path)
                    self.root.after(0, lambda: self.log("壁纸设置成功"))
                    self.root.after(0, self.update_cache_info)
                    if api_name in self.cache.api_error_shown:
                        del self.cache.api_error_shown[api_name]
                else:
                    raise Exception(f"API返回状态码: {response.status_code}")
            except Exception as api_error:
                self.log(f"API请求失败: {str(api_error)}")
                cached_image = self.cache.get_latest_cached_image(api_name)
                if cached_image:
                    self.log("使用缓存中的图片")
                    self._set_wallpaper(cached_image)
                    self.root.after(0, lambda: self.log("使用缓存图片设置壁纸成功"))
                    if api_name not in self.cache.api_error_shown:
                        self.root.after(0, lambda api_error=api_error: messagebox.showwarning("API错误", f"{self.current_api.get()} API无法访问,已使用缓存中的图片。\n错误信息: {str(api_error)}"))
                        self.cache.api_error_shown[api_name] = True
                else:
                    self.root.after(0, lambda: self.log("错误: API无法访问且无缓存图片可用"))
                    self.root.after(0, lambda: messagebox.showerror("错误",
                        f"{self.current_api.get()} API无法访问且无缓存图片可用。\n错误信息: {str(api_error)}"))
        except Exception as e:
            error_msg = str(e)
            self.root.after(0, lambda msg=error_msg: self.log(f"错误: {msg}"))
    def _set_wallpaper(self, image_path):
        try:
            ctypes.windll.user32.SystemParametersInfoW(20, 0, image_path, 3)
        except Exception as e:
            messagebox.showerror("错误", f"设置壁纸失败: {str(e)}")
    def start_auto_change(self):
        if not self.is_running:
            self.is_running = True
            self.timer_thread = threading.Thread(target=self._auto_change_loop, daemon=True)
            self.timer_thread.start()
            self.log("自动更换已启动")
    def stop_auto_change(self):
        self.is_running = False
        self.log("自动更换已停止")
    def _auto_change_loop(self):
        while self.is_running:
            self.apply_wallpaper()
            time.sleep(self.refresh_interval.get() * 60)
    def restore_default_wallpaper(self):
        try:
            ctypes.windll.user32.SystemParametersInfoW(20, 0, "", 3)
            self.log("已恢复默认壁纸")
        except Exception as e:
            messagebox.showerror("错误", f"恢复默认壁纸失败: {str(e)}")
    def check_auto_start(self):
        try:
            startup_path = winshell.startup()
            shortcut_path = os.path.join(startup_path, "WallpaperChanger.lnk")
            if os.path.exists(shortcut_path):
                self.auto_start.set(True)
        except:
            pass
    def toggle_auto_start(self):
        try:
            startup_path = winshell.startup()
            shortcut_path = os.path.join(startup_path, "WallpaperChanger.lnk")
            if self.auto_start.get():
                target_path = sys.executable
                wd = os.path.dirname(os.path.abspath(__file__))
                shell = Dispatch('WScript.Shell')
                shortcut = shell.CreateShortCut(shortcut_path)
                shortcut.Targetpath = target_path
                shortcut.Arguments = f'"{os.path.abspath(__file__)}"'
                shortcut.WorkingDirectory = wd
                shortcut.save()
                self.log("已设置开机自启动")
            else:
                if os.path.exists(shortcut_path):
                    os.remove(shortcut_path)
                    self.log("已取消开机自启动")
        except Exception as e:
            messagebox.showerror("错误", f"设置开机自启动失败: {str(e)}")
            self.auto_start.set(not self.auto_start.get())
    def minimize_to_tray(self):
        self.root.withdraw()
        self.create_tray_icon()
    def create_tray_icon(self):
        try:
            image = Image.new('RGB', (64, 64), color='#3498db')
            menu = (
                item('显示主窗口', self.restore_from_tray),
                item('立即更换壁纸', self.apply_wallpaper),
                item('退出', self.quit_application)
            )
            self.tray_icon = pystray.Icon("wallpaper_changer", image, "壁纸更换工具", menu)
            threading.Thread(target=self.tray_icon.run, daemon=True).start()
        except Exception as e:
            self.quit_application()
    def restore_from_tray(self, icon=None, item=None):
        if self.tray_icon:
            self.tray_icon.stop()
            self.tray_icon = None
        self.root.after(0, self.root.deiconify)
    def quit_application(self, icon=None, item=None):
        self.stop_auto_change()
        if self.tray_icon:
            self.tray_icon.stop()
        self.root.quit()
        self.root.destroy()
    def check_for_updates(self):
        messagebox.showinfo("检查更新", "当前已是最新版本!")
class CustomApiDialog:
    def __init__(self, parent, custom_apis, font):
        self.top = tk.Toplevel(parent)
        self.top.title("管理自定义API")
        self.top.geometry("500x400")
        self.top.resizable(False, False)
        self.top.transient(parent)
        self.top.grab_set()
        self.custom_apis = custom_apis.copy()
        self.result = None
        self.font = font
        self.create_widgets()
        self.update_listbox()
    def create_widgets(self):
        main_frame = ttk.Frame(self.top, padding="15")
        main_frame.pack(fill=tk.BOTH, expand=True)
        list_frame = ttk.LabelFrame(main_frame, text="自定义API列表", padding="10")
        list_frame.pack(fill=tk.BOTH, expand=True, pady=10)
        self.listbox = tk.Listbox(list_frame, font=self.font, height=8)
        self.listbox.pack(fill=tk.BOTH, expand=True, padx=5, pady=5)
        button_frame = ttk.Frame(main_frame)
        button_frame.pack(fill=tk.X, pady=10)
        ttk.Button(button_frame, text="添加API",
                  command=self.add_api, style="Primary.TButton").pack(side=tk.LEFT, padx=5, ipadx=5)
        ttk.Button(button_frame, text="编辑API",
                  command=self.edit_api, style="Primary.TButton").pack(side=tk.LEFT, padx=5, ipadx=5)
        ttk.Button(button_frame, text="删除API",
                  command=self.delete_api, style="Danger.TButton").pack(side=tk.LEFT, padx=5, ipadx=5)
        bottom_frame = ttk.Frame(main_frame)
        bottom_frame.pack(fill=tk.X, pady=10)
        ttk.Button(bottom_frame, text="确定",
                  command=self.save_and_close, style="Success.TButton").pack(side=tk.RIGHT, padx=5, ipadx=10)
        ttk.Button(bottom_frame, text="取消",
                  command=self.cancel, style="Primary.TButton").pack(side=tk.RIGHT, padx=5, ipadx=10)
    def update_listbox(self):
        self.listbox.delete(0, tk.END)
        for name, url in self.custom_apis.items():
            self.listbox.insert(tk.END, f"{name}: {url}")
    def add_api(self):
        dialog = ApiDetailDialog(self.top, "", "", self.font)
        self.top.wait_window(dialog.top)
        if dialog.result:
            name, url = dialog.result
            self.custom_apis[name] = url
            self.update_listbox()
    def edit_api(self):
        selection = self.listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个API")
            return
        index = selection[0]
        name = list(self.custom_apis.keys())[index]
        url = self.custom_apis[name]
        dialog = ApiDetailDialog(self.top, name, url, self.font)
        self.top.wait_window(dialog.top)
        if dialog.result:
            new_name, new_url = dialog.result
            del self.custom_apis[name]
            self.custom_apis[new_name] = new_url
            self.update_listbox()
    def delete_api(self):
        selection = self.listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个API")
            return
        index = selection[0]
        name = list(self.custom_apis.keys())[index]
        if messagebox.askyesno("确认", f"确定要删除API '{name}' 吗?"):
            del self.custom_apis[name]
            self.update_listbox()
    def save_and_close(self):
        self.result = self.custom_apis
        self.top.destroy()
    def cancel(self):
        self.top.destroy()
class ApiDetailDialog:
    def __init__(self, parent, name, url, font):
        self.top = tk.Toplevel(parent)
        self.top.title("API详情" if name else "添加API")
        self.top.geometry("400x200")
        self.top.resizable(False, False)
        self.top.transient(parent)
        self.top.grab_set()
        self.result = None
        self.font = font
        self.create_widgets(name, url)
    def create_widgets(self, name, url):
        main_frame = ttk.Frame(self.top, padding="15")
        main_frame.pack(fill=tk.BOTH, expand=True)
        ttk.Label(main_frame, text="API名称:", font=self.font).grid(row=0, column=0, sticky=tk.W, pady=10)
        self.name_var = tk.StringVar(value=name)
        name_entry = ttk.Entry(main_frame, textvariable=self.name_var, width=30, font=self.font)
        name_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=10, padx=10)
        ttk.Label(main_frame, text="API URL:", font=self.font).grid(row=1, column=0, sticky=tk.W, pady=10)
        self.url_var = tk.StringVar(value=url)
        url_entry = ttk.Entry(main_frame, textvariable=self.url_var, width=30, font=self.font)
        url_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=10, padx=10)
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=2, column=0, columnspan=2, pady=20)
        ttk.Button(button_frame, text="确定",
                  command=self.save, style="Success.TButton").pack(side=tk.RIGHT, padx=10, ipadx=10)
        ttk.Button(button_frame, text="取消",
                  command=self.cancel, style="Primary.TButton").pack(side=tk.RIGHT, padx=10, ipadx=10)
        main_frame.columnconfigure(1, weight=1)
    def save(self):
        name = self.name_var.get().strip()
        url = self.url_var.get().strip()
        if not name:
            messagebox.showwarning("警告", "请输入API名称")
            return
        if not url:
            messagebox.showwarning("警告", "请输入API URL")
            return
        self.result = (name, url)
        self.top.destroy()
    def cancel(self):
        self.top.destroy()
def main():
    root = tk.Tk()
    try:
        ctypes.windll.shcore.SetProcessDpiAwareness(1)
    except:
        pass
    app = WallpaperChanger(root)
    root.mainloop()
if __name__ == "__main__":
    main()
下载
[/color" target="_blank" rel="noopener noreferrer nofollow">https://wwkz.lanzoum.com/iOjQi39fncve
密码:eaeb
主要功能
控制
  • 手动更换 - 立即更换当前壁纸
  • 自动更换 - 设置时间间隔自动更换壁纸(1-240分钟)
  • 恢复默认 - 一键恢复系统默认壁纸
  • 开机自启 - 程序随系统自动启动

    缓存系统
  • 自动缓存 - 下载的壁纸自动保存到本地
  • 重复检测 - 通过哈希值避免重复存储相同图片
  • 容量管理 - 可设置最大缓存数量(默认100张)
  • 容错机制 - API不可用时自动使用缓存图片
  • 分类存储 - 按不同API分别存储管理

    安装要求
    系统要求
  • Windows 7/10/11 操作系统
  • Python 3.6 或更高版本
  • 网络连接(用于获取壁纸)

    依赖库安装
    在运行程序前,请先安装所需依赖:
    pip install requests pillow pystray pywin32 winshell
    使用指南
    首次运行
    [ol]
  • 启动程序后,首先看到开屏动画
  • 进入主界面后,选择喜欢的壁纸源
  • 点击"立即更换壁纸"测试功能
  • 根据需要设置自动更换间隔
    [/ol]
    壁纸源选择
  • 在主界面选择壁纸源单选按钮
  • 支持三种内置API和自定义API
  • 点击"管理自定义API"添加自己的图片接口

    自动更换设置
  • 使用滑块或直接输入框设置更换间隔
  • 点击"开始自动更换"启用自动功能
  • 点击"停止自动更换"停止自动更换

    缓存管理
  • 程序自动在wp-52pojie目录下创建缓存
  • 每个API有独立的缓存文件夹
  • 点击"清理缓存"可清除当前API的缓存
  • 在设置页面可调整最大缓存数量

    系统集成
  • 勾选"开机自启动"让程序随系统启动
  • 关闭窗口自动最小化到系统托盘
  • 右键托盘图标可快速操作

    故障排除
    常见问题
    Q: 壁纸无法正常设置
    A: 请检查程序是否以管理员权限运行,某些系统设置需要管理员权限。
    Q: API无法访问
    A: 程序会自动使用缓存中的图片,并提示用户。检查网络连接或尝试其他壁纸源。
    Q: 预览图加载失败
    A: 可能是网络问题或API暂时不可用,点击预览图区域可重新加载。
    Q: 开机自启动不生效
    A: 某些安全软件可能会阻止程序创建启动项,请检查安全软件设置。
    缓存位置
  • 缓存目录:程序所在目录下的wp-52pojie文件夹
  • 目录结构:
    wp-52pojie/
    ├── bing/          # 必应壁纸缓存
    ├── genshin/       # 原神图片缓存
    ├── nasa/          # NASA图片缓存
    └── custom_xxx/    # 自定义API缓存

    联系支持
    如果您在使用过程中遇到问题或有改进建议,请联系我们:

    缓存, 壁纸

  • Skyearth1
    OP
      

    附:自定义API要求必须直接返回图片(重定向到图片链接也可以),但是不可以返回url,程序无法解析
    ystysy   

    感谢分享,实用工具
    x179   

    大神真多
    zxyzy   

    感谢分享,实用工具
    YLSpace   

    感谢分享,实用工具
    BrutusScipio   

    好粗糙的面向过程 不过只是包装接口也够用了
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部