mirror of
https://codeberg.org/ashley/poke.git
synced 2024-11-16 20:14:38 -05:00
add poke desktop
This commit is contained in:
parent
4cee4b8d87
commit
16fa4304d0
1 changed files with 201 additions and 0 deletions
201
poke-gtk-app.py
Normal file
201
poke-gtk-app.py
Normal file
|
@ -0,0 +1,201 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024-20xx Poke! (https://codeberg.org/ashley/poke)
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
import gi
|
||||||
|
import json
|
||||||
|
import vlc
|
||||||
|
import subprocess
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
gi.require_version("Gtk", "3.0")
|
||||||
|
from gi.repository import Gtk, GdkPixbuf, GObject
|
||||||
|
from gi.repository import Gio
|
||||||
|
|
||||||
|
class PokeGtkApp(Gtk.Window):
|
||||||
|
def __init__(self):
|
||||||
|
Gtk.Window.__init__(self, title="Poke Desktop")
|
||||||
|
self.set_default_size(800, 600)
|
||||||
|
|
||||||
|
self.vlc_instance = vlc.Instance('--no-xlib')
|
||||||
|
self.player = self.vlc_instance.media_player_new()
|
||||||
|
self.is_playing = False
|
||||||
|
|
||||||
|
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
|
||||||
|
self.add(vbox)
|
||||||
|
|
||||||
|
self.search_entry = Gtk.Entry()
|
||||||
|
self.search_entry.set_placeholder_text("Enter search query")
|
||||||
|
vbox.pack_start(self.search_entry, False, False, 0)
|
||||||
|
|
||||||
|
hbox_buttons = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
|
||||||
|
vbox.pack_start(hbox_buttons, False, False, 0)
|
||||||
|
|
||||||
|
self.search_button = Gtk.Button(label="Search")
|
||||||
|
self.search_button.connect("clicked", self.on_search_clicked)
|
||||||
|
hbox_buttons.pack_start(self.search_button, True, True, 0)
|
||||||
|
|
||||||
|
self.play_button = Gtk.Button(label="Play")
|
||||||
|
self.play_button.connect("clicked", self.on_play_clicked)
|
||||||
|
hbox_buttons.pack_start(self.play_button, False, False, 0)
|
||||||
|
self.play_button.set_sensitive(False) # Initially disabled
|
||||||
|
|
||||||
|
self.pause_button = Gtk.Button(label="Pause")
|
||||||
|
self.pause_button.connect("clicked", self.on_pause_clicked)
|
||||||
|
hbox_buttons.pack_start(self.pause_button, False, False, 0)
|
||||||
|
self.pause_button.set_sensitive(False) # Initially disabled
|
||||||
|
|
||||||
|
self.bottom_bar_label = Gtk.Label()
|
||||||
|
vbox.pack_end(self.bottom_bar_label, False, False, 0)
|
||||||
|
|
||||||
|
scrolled_window = Gtk.ScrolledWindow()
|
||||||
|
scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
|
||||||
|
vbox.pack_start(scrolled_window, True, True, 0)
|
||||||
|
|
||||||
|
self.video_liststore = Gtk.ListStore(GdkPixbuf.Pixbuf, str, str, str) # Changed the order of columns
|
||||||
|
self.treeview = Gtk.TreeView(model=self.video_liststore)
|
||||||
|
|
||||||
|
thumbnail_column = Gtk.TreeViewColumn("Thumbnail") # Thumbnail column at the first position
|
||||||
|
title_column = Gtk.TreeViewColumn("Title") # Title column at the second position
|
||||||
|
author_column = Gtk.TreeViewColumn("Author")
|
||||||
|
|
||||||
|
self.treeview.append_column(thumbnail_column)
|
||||||
|
self.treeview.append_column(title_column)
|
||||||
|
self.treeview.append_column(author_column)
|
||||||
|
|
||||||
|
thumbnail_cell = Gtk.CellRendererPixbuf()
|
||||||
|
title_cell = Gtk.CellRendererText()
|
||||||
|
author_cell = Gtk.CellRendererText()
|
||||||
|
|
||||||
|
thumbnail_column.pack_start(thumbnail_cell, True)
|
||||||
|
title_column.pack_start(title_cell, True)
|
||||||
|
author_column.pack_start(author_cell, True)
|
||||||
|
|
||||||
|
thumbnail_column.add_attribute(thumbnail_cell, "pixbuf", 0)
|
||||||
|
title_column.add_attribute(title_cell, "text", 1)
|
||||||
|
author_column.add_attribute(author_cell, "text", 2)
|
||||||
|
|
||||||
|
self.treeview.connect("row-activated", self.on_video_selected)
|
||||||
|
|
||||||
|
scrolled_window.add(self.treeview)
|
||||||
|
|
||||||
|
# Tray icon setup
|
||||||
|
self.tray_icon = Gtk.StatusIcon.new()
|
||||||
|
self.tray_icon.set_from_gicon(Gio.ThemedIcon.new("media-playback-start-symbolic")) # Set the icon
|
||||||
|
self.tray_icon.connect("activate", self.on_tray_icon_clicked)
|
||||||
|
self.tray_icon.connect("popup-menu", self.on_tray_icon_popup_menu)
|
||||||
|
|
||||||
|
def on_tray_icon_clicked(self, icon, button):
|
||||||
|
if button == Gdk.BUTTON_PRIMARY:
|
||||||
|
if self.is_playing:
|
||||||
|
self.player.pause()
|
||||||
|
self.tray_icon.set_from_icon_name("media-playback-start")
|
||||||
|
else:
|
||||||
|
self.player.play()
|
||||||
|
self.tray_icon.set_from_icon_name("media-playback-pause")
|
||||||
|
self.is_playing = not self.is_playing
|
||||||
|
|
||||||
|
def on_tray_icon_popup_menu(self, icon, button, time):
|
||||||
|
menu = Gtk.Menu()
|
||||||
|
|
||||||
|
play_pause_item = Gtk.MenuItem("Play/Pause")
|
||||||
|
play_pause_item.connect("activate", self.on_tray_icon_clicked, Gdk.BUTTON_PRIMARY)
|
||||||
|
menu.append(play_pause_item)
|
||||||
|
|
||||||
|
quit_item = Gtk.MenuItem("Quit")
|
||||||
|
quit_item.connect("activate", Gtk.main_quit)
|
||||||
|
menu.append(quit_item)
|
||||||
|
|
||||||
|
menu.show_all()
|
||||||
|
menu.popup(None, None, None, None, button, time)
|
||||||
|
|
||||||
|
def on_search_clicked(self, button):
|
||||||
|
search_query = self.search_entry.get_text()
|
||||||
|
json_data = self.fetch_data(search_query)
|
||||||
|
self.populate_video_list(json_data)
|
||||||
|
|
||||||
|
def on_video_selected(self, treeview, path, column):
|
||||||
|
selection = self.video_liststore[path]
|
||||||
|
video_title, video_url, author_name = selection[1], selection[3], selection[2] # Adjusted index due to column order change
|
||||||
|
|
||||||
|
# Play the selected video
|
||||||
|
self.play_video(video_url)
|
||||||
|
self.update_bottom_bar(video_title)
|
||||||
|
|
||||||
|
def fetch_data(self, search_query):
|
||||||
|
invid_api_url = "https://invid-api.poketube.fun"
|
||||||
|
search_query_encoded = search_query.replace(" ", "+")
|
||||||
|
curl_command = f'curl -s "{invid_api_url}/api/v1/search?q={search_query_encoded}&type=video"'
|
||||||
|
try:
|
||||||
|
output = subprocess.check_output(curl_command, shell=True)
|
||||||
|
data = output.decode("utf-8")
|
||||||
|
return json.loads(data)
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
print(f"Error fetching data: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_video_list(self, json_data):
|
||||||
|
self.video_liststore.clear()
|
||||||
|
for video in json_data:
|
||||||
|
title = video["title"]
|
||||||
|
video_id = video["videoId"]
|
||||||
|
author = video["author"] # Added to retrieve author's name
|
||||||
|
video_url = f"https://poketube.fun/watch?v={video_id}"
|
||||||
|
thumbnail_url = f"https://i.ytimg.com/vi/{video_id}/default.jpg"
|
||||||
|
thumbnail = self.load_thumbnail(thumbnail_url) # Load thumbnail from URL
|
||||||
|
self.video_liststore.append([thumbnail, title, author, video_url])
|
||||||
|
|
||||||
|
def load_thumbnail(self, url):
|
||||||
|
response = urllib.request.urlopen(url)
|
||||||
|
data = response.read()
|
||||||
|
loader = GdkPixbuf.PixbufLoader()
|
||||||
|
loader.write(data)
|
||||||
|
loader.close()
|
||||||
|
return loader.get_pixbuf()
|
||||||
|
|
||||||
|
def play_video(self, video_url):
|
||||||
|
try:
|
||||||
|
command = ['yt-dlp', '-g', video_url]
|
||||||
|
video_direct_url = subprocess.check_output(command).decode('utf-8').strip()
|
||||||
|
media = self.vlc_instance.media_new(video_direct_url)
|
||||||
|
self.player.set_media(media)
|
||||||
|
self.player.play()
|
||||||
|
self.is_playing = True
|
||||||
|
self.play_button.set_sensitive(True) # Enable play button
|
||||||
|
self.pause_button.set_sensitive(True) # Enable pause button
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error playing video: {e}")
|
||||||
|
|
||||||
|
def on_play_clicked(self, button):
|
||||||
|
if self.is_playing:
|
||||||
|
self.player.play()
|
||||||
|
|
||||||
|
def on_pause_clicked(self, button):
|
||||||
|
if self.is_playing:
|
||||||
|
self.player.pause()
|
||||||
|
|
||||||
|
def update_bottom_bar(self, text):
|
||||||
|
self.bottom_bar_label.set_text(text)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
app = PokeGtkApp()
|
||||||
|
app.connect("destroy", Gtk.main_quit)
|
||||||
|
app.show_all()
|
||||||
|
Gtk.main()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in a new issue