使用python下载wallpaper Engine订阅的壁纸/视频

news2024/11/24 20:23:39

一、为什么想下载wallpaper Engine的壁纸

  在游戏平台steam上,有一个壁纸软件wallpaper Engine,人称小红车,里面有各种好看的动态壁纸和视频,可以给我们的电脑设置动态桌面,非常好用。
  用过几次后,我有了一些痛点,就是软件只能启动的时候才有这个桌面壁纸(当然这非常合理),但是我很喜欢这张壁纸,希望开机后,或不启动steam和wallpaper Engine的时候,也可以用这个壁纸当桌面。
  同时有些视频我很喜欢,但是又不想当壁纸,就想下载下来放到其他文件夹里,所以就产生了这个需求,把wallpaper里面的壁纸和视频下载一下。
wallpaper Engine
动态壁纸展示

二、 这些代码能做到什么

  在有了下载的想法以后,我着手研究起来,首先我想下载的是:壁纸和视频,视频文件的话还好说,在本地的文件夹里就有,但是壁纸文件时pkg封装好的,因为很多壁纸里有一些动态效果,这个应该是它的统一格式。
在这里插入图片描述

  于是我在网上找到了大佬写的解包exe程序
  repkg包地址:https://github.com/notscuffed/repkg/releases
  根据这个程序,我进行了二次开发,可以批量的解压pkg的图片,然后放入必定文件夹中,加入了一些去重、重命名的功能,以及可以指定白名单不加入下载队列中。
在这里插入图片描述

三、代码展示和下载

  这里我给出了我的代码仓库地址,github和gitcode,具体使用方法在readme文件中有介绍。
https://gitcode.net/CCGGAAG/Python
https://github.com/CCGGAAG/wallpaper_download

  这里要注意的是,直接复制我的代码不能跑,因为缺一个repkg.exe,从我上面给出的仓库地址下载就行了。

# -*- coding:utf-8 -*-
import os
import shutil
import yaml
import hashlib
import random


class CopyWallpaper:

    def __init__(self, steam_url, copy_dir):
        """
        类的初始化,两个地址必需传递为本地电脑的绝对路径
        :param steam_url: wallpaper的数据文件夹,例如:D:/**/Steam/steamapps/workshop/content/431960
        :param copy_dir:  你要转移存储文件的地址
        """
        self.steam_url = steam_url
        self.copy_dir = copy_dir
        self.file_format = [".mp4", ".MP4", ".MOV", ".mov", ".avi", ".AVI",  ".webm", ".WEBM", ".pkg"]
        self.video_format = [".mp4", ".MP4", ".MOV", ".mov", ".avi", ".AVI", ".webm", ".WEBM", ".mp3"]
        self.pkg_file_format = [".png", ".PNG", ".jpg", ".JPG", ".jpeg", ".JPEG", ".gif", ".GIF"]
        if "img" not in os.listdir(self.copy_dir):
            os.makedirs(self.copy_dir + "/img")

    def get_repkg_img(self, list_pkg):
        """
        通过本地的pkg文件地址列表,将pkg解压后的图片文件移动到指定文件夹(copy_dir)下
        :param list_pkg: 本地的pkg文件地址列表
        :return:
        """
        pkg_path = os.getcwd() + "/repkg"
        base_driver = pkg_path[0]
        for i in list_pkg:
            if "dispose" not in os.listdir(pkg_path):
                os.makedirs(pkg_path + "/dispose")
            self.file_copy([i], "./repkg/dispose")
            print("-----------------------------------------------------------")
            print("pkg文件%s" % i)
            pkg_name = i[str(i).rfind("/") + 1:]
            cmd_line = "%s: && cd %s && RePKG.exe extract -o ./dispose ./dispose/%s" % (base_driver, pkg_path, pkg_name)
            os.system(cmd_line)
            img_list = self.get_format_file_list(dir_path=pkg_path + "/dispose/materials", file_format=self.pkg_file_format)
            [self.file_copy([j], self.copy_dir + "/img") for j in img_list if os.path.getsize(j) >= 100000]
            shutil.rmtree("./repkg/dispose/")

    def file_copy(self, file_list, copy_dir=None):
        """
        一个复制文件的方法,把列表中地址的文件拷贝到指定文件夹
        :param file_list: 一个本地文件地址的列表
        :param copy_dir: 默认是self.copy_dir
        :return:
        """
        if copy_dir is None:
            copy_dir = self.copy_dir
        for i in file_list:
            copy_file_list = os.listdir(copy_dir)
            file_name = i[str(i).rfind("/") + 1:]
            if file_name in copy_file_list:
                new_name = str(i).replace(file_name, ("重复%s" % random.randint(10000, 19999) + file_name))
                shutil.copy(i, new_name)
                shutil.move(new_name, copy_dir)
                print("移动文件:%s" % new_name)
            else:
                shutil.copy(i, copy_dir)
                print("拷贝文件:%s" % i)

    def get_format_file_list(self, dir_path, file_list=None, file_format=None):
        """
        通过一个目录地址,递归获取目录下所有‘规定格式’的文件的地址(默认文件类型:视频、图片、pkg)
        :param dir_path:文件夹绝对地址
        :param file_list:默认None
        :param file_format:默认None
        :return: file_list
        """
        if file_list is None:
            file_list = []
        if file_format is None:
            file_format = self.file_format + self.pkg_file_format

        file_in_dir_list = os.listdir(dir_path)
        for file_name in file_in_dir_list:
            url_join = dir_path + '/' + file_name
            file_type = os.path.splitext(url_join)[1]
            if os.path.isdir(url_join):
                self.get_format_file_list(url_join, file_list)
            elif file_type in file_format:
                file_list.append(url_join)
            else:
                pass
        return file_list

    def split_list(self, file_list):
        """
        处理单个wallpaper地址列表,变为视频和pkg文件地址的两个列表
        :param file_list:
        :return: mp4_list, pkg_list
        """
        list_mp4 = [x for x in file_list if os.path.splitext(x)[1] in self.video_format]
        list_pkg = [y for y in file_list if ".pkg" == os.path.splitext(y)[1]]
        img = [z for z in file_list if os.path.splitext(z)[1] in self.pkg_file_format]
        list_img = [m for m in img if m.find("preview.jpg") == -1]
        return list_mp4, list_pkg, list_img

    def start_get_wallpaper_file(self, pkg_only=False, mp4_only=False, new_file_only=False):
        """
        一键获取所有wallpaper文件
        :param pkg_only: 是否获取pkg图片文件
        :param mp4_only: 是否获取视频文件
        :param new_file_only: 是否仅获取新订阅的文件
        :return:
        """
        whole_file_list = self.get_format_file_list(self.steam_url)
        if new_file_only:
            self.init_installed_file_list()
            with open("./repkg/file_path_list.yaml", 'rb') as f:
                path_list = yaml.load(f, Loader=yaml.FullLoader)
            with open("./repkg/md5_list.yaml", 'rb') as f:
                md5_list = yaml.load(f, Loader=yaml.FullLoader)
            update_file_list = [i for i in whole_file_list if i not in path_list and self.get_md5(i) not in md5_list]
            print(update_file_list)
        else:
            update_file_list = whole_file_list
        list_mp4, list_pkg, list_img = self.split_list(update_file_list)
        if pkg_only:
            self.get_repkg_img(list_pkg)
            [self.file_copy([j], self.copy_dir + "/img") for j in list_img if os.path.getsize(j) >= 100000]
        if mp4_only:
            self.file_copy(list_mp4)
        if not pkg_only and not mp4_only:
            print("请设置拷贝图片还是视频")

    @staticmethod
    def get_md5(filename):
        """
        获取文件md5值
        :param filename: 文件路径
        :return: md5值
        """
        md5_handle = hashlib.md5()
        md5_file = open(filename, "rb")
        md5_handle.update(md5_file.read())
        md5_file.close()
        md5_value = md5_handle.hexdigest()
        return md5_value

    def init_installed_file_list(self):
        """初始化已经订阅的所有壁纸信息,并保存为文件"""
        whole_file_list = self.get_format_file_list(self.steam_url)
        if "file_path_list.yaml" not in os.listdir("./repkg"):
            print("新建file_path文件")
            fd = open("./repkg/file_path_list.yaml", mode="w", encoding="utf-8")
            fd.close()
            data = whole_file_list
            fw = open("./repkg/file_path_list.yaml", 'a', encoding='utf-8')
            yaml.dump(data, fw)
            fw.close()
        if "md5_list.yaml" not in os.listdir("./repkg"):
            print("新建md5文件")
            fd = open("./repkg/md5_list.yaml", mode="w", encoding="utf-8")
            fd.close()
            data = [self.get_md5(i) for i in whole_file_list]
            fw = open("./repkg/md5_list.yaml", 'a', encoding='utf-8')
            yaml.dump(data, fw)
            fw.close()

运行这个程序的代码:

wallpaper_dir = "D:/Program Files (x86)/Steam/steamapps/workshop/content/431960"
output_dir = "D:/test123"
test = CopyWallpaper(wallpaper_dir, output_dir)
# 全部类型拷贝
test.start_get_wallpaper_file(pkg_only=True, mp4_only=True, new_file_only=False)

四、如何使用这个项目

  在你下载好项目后,可以看接下来的文章讲解,也可以看项目本身的readme文件,CSDN和那里的内容是一样的。

1.首先进入当前项目的命令行页面,执行pip install -r requirements.txt
或者 pip install PyYAML,因为本项目只使用了这一个第三方库。

2.打开srart.py文件,将两个参数改成你本地的,

  • wallpaper_dir:你的本地wallpaper软件文件夹地址
  • output_dir:你想拷贝到的文件夹地址

3.使用python运行start.py文件即可

4.如果你想要省劲,修改paper.bat文件中的cmd命令,也就是进入当前项目文件夹,并且运行start.py文件,把这个bat命令做成一个快捷方式,这样只用点击bat命令就可以拷贝文件资源了,非常方便!!!

5.当你多次运行这个文件后,会发现每次都将所有资源下载了,所以在start.py文件中,将test.init_installed_file_list()的注释去掉,然后运行一下即可,会生成一个当前订阅的资源名单,以后再拷贝文件的话,会跳过名单上的资源。

五、项目参数

1.执行获取文件的方法start_get_wallpaper_file():

  • pkg_only,默认为True,指定是否解压并拷贝pkg封装的图片文件
  • mp4_only,默认为True,指定是否拷贝视频文件
  • new_file_only,默认为True,名单中的资源不再下载,只下载名单上没有的

2.将已订阅的壁纸放入不下载名单中init_installed_file_list()
运行这个方法后,会在repkg文件夹中,生成yaml文件,里面是当前已经订阅的壁纸文件地址,下次再运行start_get_wallpaper_file()方法下载文件时,就会忽略这个yaml文件中记录的路径。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/448767.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Doris(14):索引

1 概念 索引用于帮助快速过滤或查找数据。 目前 Doris 主要支持两类索引: 内建的智能索引,包括前缀索引和ZoneMap索引用户创建的二级索引,包括Bloom Filter索引和Bitmap倒排索引。 前缀索引:即在排序的基础上,实现的…

kv server(配置以及性能测试)

首先在 Cargo.toml 里添加 serde 和 toml。我们计划使用 toml 做配置文件,serde 用来处理配置的序列化和反序列化: [dependencies] ... serde { version "1", features ["derive"] } # 序列化/反序列化 ... toml "0.5"…

antd表格a-table滚动失效。x轴滚动失效

目录 antd表格a-table滚动失效。x轴滚动失效 页面html代码如下。实现左右布局,左边侧边栏固定宽度,右边沾满剩余宽度 解决方案:在计算右侧宽度时,左边侧边栏固定宽度,右边沾满剩余宽度 情况1:左侧侧边栏…

第八章 查询和检索:Query DSL

版权声明 本文为Elastic开源社区版权所有,保证独立性和原创性,未获得授权和允许,任何组织和个人不得以任何方式传播或复制或分享。否则必将追究法律责任。 知识内容输出不易,请尊重他人劳动成果。严禁随意传播、复制和盗用他人成果或文章内容用以商业或盈利目的! 1、查询…

5.4 龙贝格算法

为什么有龙贝格算法: 龙贝格算法是一种数值积分方法,用于计算定积分的数值近似值。它是基于复合梯形法和复合辛普森法的推广和拓展,可以达到更高的精度。相较于复合梯形法和复合辛普森法,龙贝格算法的收敛速度更快,且…

nerfstudio介绍及在windows上的配置、使用

nerfstudio提供了一个简单的API,可以简化创建、训练和可视化NeRF的端到端过程。该库通过模块化每个组件来支持可解释的NeRF实现。nerfstudio源码地址: https://github.com/nerfstudio-project/nerfstudio , 通过模块化集成了多个NeRF扩展的实现,持续更新…

JUC-多线程(12. AQS)学习笔记

文章目录 1. 可重入锁1.1. 概述1.2. 可重入锁类型1.3. Synchronized 可重入实现机理 2. LockSupport2.1. LockSupport 是什么2.2. 3种线程等待唤醒的方法2.2.1 Object 的等待与唤醒2.2.2. Condition接口中的等待与唤醒2.2.3. 传统的 synchronized 和 Lock 实现等待唤醒通知的约…

C/C++开发,opencv读写图像与视频

目录 一、opencv的图像缓存表达(cv::mat) 二、图片读写 2.1 图片读写API 2.2 图片读写案例 2.3 案例编译与测试 三、opencv的视频读写: 3.1 视频读写接口 3.2 视频读写案例 3.3 编译与测试 一、opencv的图像缓存表达(cv::mat&am…

2023网络搭建项目改革

好久没更新了,哈哈哈,也废话不多说,直接进入正题。 3月的时候就有人吓我说什么网搭取消了,当时我还觉得高兴,主要是不喜欢这个行业,要是没了我就可以跑路了,哈哈,然后我就觉得很奇怪…

【嵌入式系统与入门】Day02 Arduino 按键、蜂鸣器与湿温度传感器

文章目录 1. 按键控制1.1 认识按键1.2 工作原理1.3 Arduino代码展示1.4 原理图1.5 实现去抖【消抖动延时】 2. 蜂鸣器控制2.1 认识蜂鸣器2.2 分类2.3 工作原理2.4 连线2.5 Arduino代码展示 3. PWM模拟量输出3.2 Arduino代码展示 4. 湿温度测量4.1 认识器件4.2 传感器接口4.3 Ar…

CMU-自主探索导航系统(TARE FAR Planner)学习-All in one

参考引用 Autonomous Exploration Development EnvironmentTARE机器人自主导航系统社区-CSDN社区云TARE机器人自主导航系统公开课1TARE机器人自主导航系统公开课2CMU团队开发的全套开源自主导航算法FAR Planner —— IROS2022 最佳学生论文<论文阅读>TAR…

【源码分析】XXL-JOB的执行器的注册流程

目的:分析xxl-job执行器的注册过程 流程: 获取执行器中所有被注解(xxlJjob)修饰的handler执行器注册过程执行器中任务执行过程 版本:xxl-job 2.3.1 建议:下载xxl-job源码,按流程图debug调试,看堆栈信息…

【ONE·C++ || stack queue (一)】

总言 主要介绍栈和队列的基本函数使用:栈和队列、优先级队列、适配器、反向迭代器。 文章目录 总言1、栈和队列接口基本介绍1.1、基本介绍1.2、相关例题1.2.1、最小栈1.2.2、栈的压入、弹出序列1.2.3、逆波兰表达式求值 2、适配器介绍2.1、引入:如何实现…

儿童用灯哪个品牌好?分享五款儿童护眼台灯品牌

家中有小朋友上了幼儿园就已经戴上了眼镜,太让人心疼了 近视已经成为世界难题,而我国儿童近视形式尤为严峻 据官方数据显示,我国儿童青少年总体近视率竟高达52.7% 如何保护孩子眼睛,儿童用灯哪个品牌好? 那今天&am…

Open vSwitch 入门实践(8) VXLAN实验

目录 什么是VXLAN? VXLAN解决了什么问题? VXLAN网络如何工作? 简单VXLAN实验 主机A 主机B 测试 什么是VXLAN? VXLAN(Virtual eXtensible Local Area Network,虚拟扩展局域网)&#xff0…

Spring依赖注入 - Resource注解详解及与Autowired注解区别

上篇博客我们讲了Spring中的自动注入(byName,byType)和Autowired注解的工作原理以及源码分析,那么这次,我们来分析还没讲完的,剩下的核心的方法: Nullable Object resolveDependency(DependencyDescriptor descriptor, Nullable …

0.96寸OLED液晶显示器

在日常的小项目制作中我们经常会接触到OLED液晶显示器,本文介绍0.96寸液晶显示器的基本原理,辅助我们后续的小项目开发 OLED被称为有机激光二极管,也被称为有机激光显示,OLED采用有机材料涂层和玻璃基板,当有电流通过…

#Chrome扩展程序开发教程--02:Hello Extensions

#Chrome扩展程序开发教程--02:Hello Extensions 引言1、Hello Extensions2、固定扩展程序3、重新加载扩展程序4、查看扩展程序的输出 引言 本系列博客旨在带来最新的Chrome扩展程序开发入门教程。 1、Hello Extensions 本节博客中,笔者将带领读者创建一个…

C++附加篇: 空间适配器

"我有时难过,却还有些抚慰和感动。" 一、我们来谈谈空间适配器 (1) 什么是空间配置器? STL的六大组件,容器、算法、迭代器、适配器、仿函数,最后一个也就是"空间适配器"。 所谓"空间适配器"&#x…

轻松掌握K8S使用kubectl操作配置文件挂载ConfigMap和密钥Secret知识点05

1、挂载应用配置文件配置集ConfigMap 当有许多应用如redis、mysql,希望将它的配置文件挂载出去,以便随时修改,可以用ConfigMap配置集 具体用法查看使用命令行操作里的 3、ConfigMap配置集实战 2、挂载应用配置文件的敏感信息Secret Secre…