10
|
1 #!/usr/bin/env python3
|
|
2 # bing4desktop.py - skrypt tray dla Cinnamon oraz Matte i innych WM
|
|
3 # inspiracja: https://pystray.readthedocs.io/en/latest/usage.html
|
|
4 # oraz 'zasłyszane' w internecie :)
|
|
5 # licencja: Public Domain
|
|
6 # edytor: Geany
|
|
7 # data: 05-II-2024
|
|
8 # napisał: Prymula
|
|
9
|
|
10 import pystray
|
|
11 from pystray import Icon as icon, Menu as menu, MenuItem as item
|
|
12 import tkinter as tk
|
|
13 from tkinter import messagebox
|
|
14 from PIL import ImageTk, Image
|
|
15
|
|
16 import os, sys, subprocess
|
|
17 import requests
|
|
18 import json
|
|
19 import tempfile
|
|
20 import shutil
|
11
|
21 import glob
|
10
|
22
|
33
|
23 ver = "0.240208-2"
|
10
|
24
|
|
25 BING_URI_BASE = "http://www.bing.com"
|
31
|
26 BING_WALLPAPER_PATH = "/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=en-US"
|
10
|
27 full_path=""
|
31
|
28 actualImage = 0
|
10
|
29 COPYRIGHT_TXT = ""
|
11
|
30 TITLE = ""
|
17
|
31 TMP_COPYRIGHT = ""
|
|
32 TMP_TITLE = ""
|
10
|
33
|
|
34 tmp_path = tempfile.mkdtemp()
|
|
35
|
|
36 class WPaper:
|
|
37 def get(self):
|
11
|
38 global full_path, COPYRIGHT_TXT, TITLE
|
10
|
39 # open the Bing HPImageArchive URI and ask for a JSON response
|
|
40 resp = requests.get(BING_URI_BASE + BING_WALLPAPER_PATH)
|
|
41
|
|
42 if resp.status_code == 200:
|
|
43 json_response = json.loads(resp.content)
|
|
44 wallpaper_path = json_response['images'][0]['url']
|
|
45 COPYRIGHT_TXT = json_response['images'][0]['copyright']
|
11
|
46 TITLE = json_response['images'][0]['title']
|
|
47
|
10
|
48 filename = wallpaper_path.split('/')[-1]
|
|
49 wallpaper_uri = BING_URI_BASE + wallpaper_path
|
|
50 filename_short = filename.split('&')
|
|
51 print ("filemname_short", filename_short[0])
|
|
52 # open the actual wallpaper uri, and write the response as an image on the filesystem
|
|
53 response = requests.get(wallpaper_uri)
|
|
54 if resp.status_code == 200:
|
|
55 desktop_env = os.environ.get('DESKTOP_SESSION')
|
|
56 if desktop_env=="windows":
|
|
57 messagebox.showinfo("Błąd","Brak wsparcia dla Windows i Mac !")
|
|
58 cleanup()
|
|
59 exit
|
|
60 else:
|
|
61 full_path = tmp_path + filename_short[0]
|
|
62 with open(full_path, 'wb') as f:
|
|
63 f.write(response.content)
|
|
64 else:
|
|
65 raise ValueError("[ERROR] non-200 response from Bing server for '{}'".format(wallpaper_uri))
|
|
66 COPYRIGHT_TXT = "[ERROR] non-200 response from Bing server for " + str(format(wallpaper_uri))
|
|
67 return False
|
|
68 else:
|
|
69 raise ValueError("[ERROR] non-200 response from Bing server for '{}'".format(BING_URI_BASE + BING_WALLPAPER_PATH))
|
|
70 COPYRIGHT_TXT = "[ERROR] non-200 response from Bing server for " + str(format(BING_URI_BASE + BING_WALLPAPER_PATH))
|
|
71 return False
|
|
72 return True
|
|
73
|
|
74 def set(self,file_loc, first_run):
|
17
|
75 global full_path, TMP_COPYRIGHT, COPYRIGHT_TXT, TMP_TITLE, TITLE
|
10
|
76 desktop_env = os.environ.get('DESKTOP_SESSION')
|
|
77
|
17
|
78 TMP_COPYRIGHT = COPYRIGHT_TXT
|
|
79 TMP_TITLE = TITLE
|
|
80
|
10
|
81 if len(full_path) == 0:
|
|
82 messagebox.showinfo("Błąd","Niewybrano obrazu, najpierw wybierz obraz")
|
|
83 return
|
|
84 try:
|
|
85 if desktop_env in ["gnome-classic", "gnome", "unity", "default"]:
|
|
86 uri = "'file://%s'" % file_loc
|
|
87 try:
|
|
88 SCHEMA = "org.gnome.desktop.background"
|
|
89 KEY = "picture-uri"
|
|
90 gsettings = Gio.Settings.new(SCHEMA)
|
|
91 gsettings.set_string(KEY, uri)
|
|
92 except:
|
|
93 args = ["gsettings", "set", "org.gnome.desktop.background", "picture-uri", uri]
|
|
94 subprocess.Popen(args)
|
|
95 elif desktop_env in ["cinnamon"]:
|
|
96 uri = "'file://%s'" % file_loc
|
|
97 try:
|
|
98 SCHEMA = "org.cinnamon.desktop.background"
|
|
99 KEY = "picture-uri"
|
|
100 gsettings = Gio.Settings.new(SCHEMA)
|
|
101 gsettings.set_string(KEY, uri)
|
|
102 except:
|
|
103 args = ["gsettings", "set", "org.cinnamon.desktop.background", "picture-uri", uri]
|
|
104 subprocess.Popen(args)
|
21
|
105 elif desktop_env in ['mate', 'lightdm-xsession']:
|
10
|
106 try: # MATE >= 1.6
|
|
107 # info from http://wiki.mate-desktop.org/docs:gsettings
|
|
108 args = ["gsettings", "set", "org.mate.background", "picture-filename", "'%s'" % file_loc]
|
|
109 subprocess.Popen(args)
|
|
110 except: # MATE < 1.6
|
|
111 # From https://bugs.launchpad.net/variety/+bug/1033918
|
|
112 args = ["mateconftool-2","-t","string","--set","/desktop/mate/background/picture_filename",'"%s"' %file_loc]
|
|
113 subprocess.Popen(args)
|
|
114 elif desktop_env=="gnome2": # Not tested
|
|
115 # From https://bugs.launchpad.net/variety/+bug/1033918
|
|
116 args = ["gconftool-2","-t","string","--set","/desktop/gnome/background/picture_filename", '"%s"' %file_loc]
|
|
117 subprocess.Popen(args)
|
|
118 ## KDE4 is difficult
|
|
119 ## see http://blog.zx2c4.com/699 for a solution that might work
|
|
120 elif desktop_env in ["kde3", "trinity"]:
|
|
121 # From http://ubuntuforums.org/archive/index.php/t-803417.html
|
|
122 args = 'dcop kdesktop KBackgroundIface setWallpaper 0 "%s" 6' % file_loc
|
|
123 subprocess.Popen(args,shell=True)
|
|
124
|
|
125 elif desktop_env=="xfce4":
|
|
126 #From http://www.commandlinefu.com/commands/view/2055/change-wallpaper-for-xfce4-4.6.0
|
|
127 if first_run:
|
|
128 args0 = ["xfconf-query", "-c", "xfce4-desktop", "-p", "/backdrop/screen0/monitor0/image-path", "-s", file_loc]
|
|
129 args1 = ["xfconf-query", "-c", "xfce4-desktop", "-p", "/backdrop/screen0/monitor0/image-style", "-s", "3"]
|
|
130 args2 = ["xfconf-query", "-c", "xfce4-desktop", "-p", "/backdrop/screen0/monitor0/image-show", "-s", "true"]
|
|
131 subprocess.Popen(args0)
|
|
132 subprocess.Popen(args1)
|
|
133 subprocess.Popen(args2)
|
|
134 args = ["xfdesktop","--reload"]
|
|
135 subprocess.Popen(args)
|
|
136
|
|
137 elif desktop_env in ["fluxbox","jwm","openbox","afterstep"]:
|
|
138 #http://fluxbox-wiki.org/index.php/Howto_set_the_background
|
|
139 # used fbsetbg on jwm too since I am too lazy to edit the XML configuration
|
|
140 # now where fbsetbg does the job excellent anyway.
|
|
141 # and I have not figured out how else it can be set on Openbox and AfterSTep
|
|
142 # but fbsetbg works excellent here too.
|
|
143 try:
|
|
144 args = ["fbsetbg", file_loc]
|
|
145 subprocess.Popen(args)
|
|
146 except:
|
|
147 sys.stderr.write("ERROR: Failed to set wallpaper with fbsetbg!\n")
|
|
148 sys.stderr.write("Please make sre that You have fbsetbg installed.\n")
|
|
149 elif desktop_env=="icewm":
|
|
150 # command found at http://urukrama.wordpress.com/2007/12/05/desktop-backgrounds-in-window-managers/
|
|
151 args = ["icewmbg", file_loc]
|
|
152 subprocess.Popen(args)
|
|
153 elif desktop_env=="blackbox":
|
|
154 # command found at http://blackboxwm.sourceforge.net/BlackboxDocumentation/BlackboxBackground
|
|
155 args = ["bsetbg", "-full", file_loc]
|
|
156 subprocess.Popen(args)
|
32
|
157 elif desktop_env in ['xqt', 'Lubuntu']:
|
|
158 #args = "pcmanfm --set-wallpaper %s --wallpaper-mode=scaled" % file_loc
|
|
159 args = "pcmanfm-qt --set-wallpaper=" + file_loc + " --wallpaper-mode=fit"
|
|
160 print ("ALOCHA: "+args)
|
10
|
161 subprocess.Popen(args,shell=True)
|
|
162 elif desktop_env=="WindowMaker":
|
|
163 # From http://www.commandlinefu.com/commands/view/3857/set-wallpaper-on-windowmaker-in-one-line
|
|
164 args = "wmsetbg -s -u %s" % file_loc
|
|
165 subprocess.Popen(args,shell=True)
|
|
166 elif desktop_env=="windows": #Not tested since I do not run this on Windows
|
|
167 #From https://stackoverflow.com/questions/1977694/change-desktop-background
|
|
168 import ctypes
|
|
169 SPI_SETDESKWALLPAPER = 20
|
|
170 ctypes.windll.user32.SystemParametersInfoA(SPI_SETDESKWALLPAPER, 0, file_loc , 0)
|
|
171 else:
|
|
172 if first_run: #don't spam the user with the same message over and over again
|
|
173 sys.stderr.write("Warning: Failed to set wallpaper. Your desktop environment is not supported.")
|
|
174 sys.stderr.write("You can try manually to set Your wallpaper to %s" % file_loc)
|
|
175 return False
|
|
176 return True
|
|
177 except:
|
|
178 sys.stderr.write("ERROR: Failed to set wallpaper. There might be a bug.\n")
|
|
179 return False
|
|
180
|
|
181
|
|
182 class Gui():
|
17
|
183 global TMP_COPYRIGHT, TMP_TITLE
|
10
|
184
|
|
185 def __init__(self):
|
|
186 self.window = tk.Tk()
|
11
|
187 self.image = None
|
|
188 for ico in ['./bing.ico', '/usr/share/bing4desktop/bing.ico']:
|
|
189 try:
|
|
190 self.image = Image.open(ico)
|
13
|
191 except:
|
|
192 print ('W bieżącym katalogu, brak ikony ' + ico)
|
11
|
193 finally:
|
13
|
194 if self.image != None:
|
|
195 break
|
11
|
196
|
|
197 self.tmp = None
|
10
|
198 self.menu = (
|
|
199 item("Ustaw Tapetę", lambda icon, item: wp.set(full_path, True)),
|
19
|
200 item('Tapeta poprzednia', lambda icon, item: self.change_pic(1, icon)),
|
|
201 item('Tapeta następna', lambda icon, item: self.change_pic(-1, icon)),
|
17
|
202 item('Opis zdjęcia', lambda icon, item: icon.notify(TMP_TITLE + ' --- ' + TMP_COPYRIGHT)),
|
10
|
203 item('O Programie', lambda icon, item: self.about()),
|
|
204 item('Wyjdź', self.quit_window)
|
|
205 )
|
|
206 self.frame = tk.Frame(self.window, width=600, height=400)
|
|
207 self.frame.pack()
|
|
208 self.frame.place(anchor='center', relx=0.5, rely=5)
|
|
209
|
|
210 #self.window.title("Bing4Desktop")
|
|
211 #self.window.geometry('800x600')
|
|
212 #self.window.protocol('WM_DELETE_WINDOW', self.withdraw_window)
|
|
213 self.withdraw_window()
|
|
214 self.window.mainloop()
|
|
215
|
|
216 def about(self):
|
|
217 global ver
|
15
|
218 messagebox.showinfo("Bing4Desktop","Inspiracja:\npystray.readthedocs.io/en/latest/usage.html\n\nNapisał: Prymula\n\nLuty 2024\n\nLicencja:\nPublic Domain\n\nWersja: "+ver)
|
13
|
219 # możliwe że nieprawidlowe po wyjściu z aplikacji zwróci bląd :(
|
10
|
220 self.window.destroy()
|
|
221 self.window.update()
|
|
222
|
19
|
223 def change_pic(self, n, icon):
|
|
224 global actualImage, BING_WALLPAPER_PATH, TITLE, COPYRIGHT_TXT
|
10
|
225 BASE = "/HPImageArchive.aspx?format=js&idx="
|
|
226 OFF = "&n=1&mkt=en-US"
|
17
|
227
|
10
|
228 actualImage = actualImage + n;
|
|
229 if (actualImage < 0):
|
17
|
230 actualImage = 7
|
|
231 elif (actualImage > 7):
|
10
|
232 actualImage = 0
|
|
233
|
|
234 wp=WPaper()
|
|
235 if wp.get():
|
|
236 BING_WALLPAPER_PATH = BASE+str(actualImage)+OFF
|
|
237 if wp.get() == False:
|
|
238 cleanup()
|
|
239 exit
|
|
240
|
11
|
241 # Wszystko pięknie tylko metoda 'show', zmienia nazwę pliku przechowywanego w TMP
|
32
|
242 ## Pozatym nie ubija a nie znalazłem nic lepszego
|
|
243 #print ("GLOB: ", glob.glob( os.path.join('/tmp', '*.PNG')))
|
|
244 #for infile in glob.glob( os.path.join('/tmp', '*.PNG')):
|
|
245 # print ("INFILE: ", infile)
|
|
246 # viewer = subprocess.Popen(['/usr/bin/eom', infile])
|
|
247 # viewer.terminate()
|
|
248 # viewer.kill() # make sure the viewer is gone; not needed on Windows
|
11
|
249
|
10
|
250 img = Image.open(full_path) #.convert('RGBA') # PIL solution
|
11
|
251 self.tmp = img.resize((600, 400), None, None, 3.0)
|
|
252 self.tmp.show()
|
19
|
253 icon.notify(TITLE + ' --- ' + COPYRIGHT_TXT)
|
|
254
|
10
|
255 def quit_window(self):
|
|
256 self.icon.stop()
|
|
257 self.window.destroy()
|
|
258
|
|
259 def show_window(self):
|
|
260 self.icon.stop()
|
|
261 self.window.protocol('WM_DELETE_WINDOW', self.withdraw_window)
|
|
262 self.window.after(0, self.window.deiconify)
|
|
263
|
|
264 def withdraw_window(self):
|
|
265 self.window.withdraw()
|
|
266 self.icon = pystray.Icon("name", self.image, "title", self.menu)
|
|
267 self.icon.run()
|
|
268
|
|
269 def cleanup():
|
|
270 # NIEBEZPIECZNA ! lepiej niczym innym nie nadpisywać tych zmiennych
|
|
271 shutil.rmtree(tmp_path)
|
|
272
|
|
273 if __name__ in '__main__':
|
|
274 wp=WPaper()
|
|
275 if wp.get():
|
|
276 wp.set(full_path, True)
|
|
277 g = Gui()
|
|
278 cleanup()
|