I built a simple app using pytube with which you can download Youtube videos.
That's the code:
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from pytube import YouTube
import os
class AVPlayer(App):
def build(self):
self.window = GridLayout()
self.window.cols = 1
self.user = TextInput(
padding_y = (20, 20),
size_hint = (1, 0.5),
)
self.window.add_widget(self.user)
self.window.size_hint = (0.6, 0.2)
self.window.pos_hint = {"center_x": 0.5, "center_y": 0.5}
self.button = Button(
text="Download",
size_hint = (1, 0.5),
background_color = '#398AFF'
)
self.button.bind(on_press=self.callback)
self.window.add_widget(self.button)
return self.window
def callback(self, event):
url = self.user.text
my_video = YouTube(url)
#get Video Title
print("*********************Video Title************************")
print(my_video.title)
#get Thumbnail Image
print("********************Tumbnail Image***********************")
print(my_video.thumbnail_url)
#download
print("********************Download video*************************")
#my_video = my_video.streams.get_highest_resolution().download()
my_video = my_video.streams.filter(res="360p").first().download()
if __name__ == "__main__":
AVPlayer().run()
It just runs on my desktop. But I would like to have it as a mobile app on my iPhone. I could create an iOS app using swift but there is no library like pytube.
I guess kivy would be possible, too, but I do not like it.. so is there an other alternative?
Related
I am new to Kivy and I am sort of stuck. I am using GridLayout to make my app and I am having some trouble putting a video in my background. The code I will post makes an app with a black background. How do I replace the black background with a video, particularly mp4. I would also like to make the video darker if possible. I wanted to use AnchorPoint but I am not quite sure how to put both in there. Any help will be appreciated.
from kivy.app import App
from kivy.uix.video import Video
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
class MZ_Invest(App):
def build(self):
self.root_layout = FloatLayout()
self.window = GridLayout()
self.window.cols = 1
self.window.size_hint = (0.6,0.7)
self.window.pos_hint = {"center_x":0.5, "center_y":0.5}
#add widgets
#Video
video = Video(source='birds.mp4', state='play')
video.opacity = 0.5
#Image
self.window.add_widget(Image(
source="mzi.png",
size_hint = (1.5,1.5)
))
#Label
self.greeting = Label(
text="How much would you like to invest?",
font_size = 18,
color='90EE90'
)
self.window.add_widget(self.greeting)
#User Input
self.user = TextInput(
multiline=False,
padding_y= (20,20),
size_hint = (1, 0.5)
)
self.window.add_widget(self.user)
#Button
self.button = Button(
text="Submit",
size_hint = (1,0.5),
bold = True,
background_color = '90EE90',
)
self.button.bind(on_press=self.callback)
self.window.add_widget(self.button)
#self.root_layout.add_widget(video)
self.root_layout.add_widget(self.window)
return self.root_layout
def callback(self, instance):
if self.user.text.isnumeric() and int(self.user.text) >= 10000:
self.greeting.text = "Calculating: $" + self.user.text
self.greeting.color = '90EE90'
else:
self.greeting.text = "Invalid"
self.greeting.color = "#FF0000"
if __name__ == "__main__":
MZ_Invest().run()
Most Kivy widgets have a transparent background, so you can just display a video and then display your GUI over that. Try adding something like this at the end of your build() method:
self.root_layout = FloatLayout()
video = Video(source='BigBuckBunny.mp4', state='play')
video.opacity = 0.5 # adjust to make the video lighter/darker
self.root_layout.add_widget(video) # add the video first
self.root_layout.add_widget(self.window) # now add the GUI window so it will be drawn over the video
return self.root_layout # return the root_layout instead of the window
I have been trying for the past 8 hours to get my image to show up in my .exe built using pyinstaller. My program is written in kivy. Everything else works, but the image doesn't show up. I have read [this][2] question. That has not worked for me. Or I just followed the answer wrong. If someone can please explain to me how to do it step by step, I would be very grateful. Also, if there is another answer, please consider telling me that as well.
I will include my main.py file:
#!/usr/bin/env python3
import os
import sys
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.slider import Slider
class SayHello(App):
def build(self):
self.window = GridLayout()
self.window.cols = 1
self.window.size_hint = (0.6,0.7)
self.window.pos_hint = {"center_x": 0.5, "center_y": 0.5}
self.window.add_widget(Image(source = "say.png"))
self.greeting = Label(
text = "Hello",
font_size = 40,
color = "#00FFCE"
)
self.window.add_widget(self.greeting)
self.slid = Slider(min = 0, max = 300, orientation = "horizontal")
self.window.add_widget(self.slid)
self.user = TextInput(
multiline = False,
padding_y = (20,20),
size_hint = (1, 0.4)
)
self.window.add_widget(self.user)
self.button = Button(
text = "Click me to greet you!",
size_hint = (1,0.5),
bold = True,
background_color = "00FFCE",
)
self.button.bind(on_press = self.callback)
self.window.add_widget(self.button)
return self.window
def slided(self, event):
self.slid
def callback(self, event):
self.greeting.text = "Hello " + self.user.text + "!"
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(
sys,
'_MEIPASS',
os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
path = resource_path("say.png")
if __name__ == "__main__":
SayHello().run()
[1]: https://stackoverflow.com/questions/31836104/pyinstaller-and-onefile-how-to-include-an-image-in-the-exe-file
[2]: https://stackoverflow.com/questions/48467917/include-kv-json-files-while-packaing-kivy-with-pyinstaller-onefile
Thanks in advance!
The problem is with your attempt to fix the path:
def resource_path(relative_path):
""" Get absolute path to resource, works for dev and for PyInstaller """
base_path = getattr(
sys,
'_MEIPASS',
os.path.dirname(os.path.abspath(__file__)))
return os.path.join(base_path, relative_path)
path = resource_path("say.png")
just replace that code with:
import kivy.resources
if getattr(sys, 'frozen', False):
# this is a Pyinstaller bundle
kivy.resources.resource_add_path(sys._MEIPASS)
I am new to python and more to kivy, with this it turns out that they helped me to create this code (below), it turns out that after my code seems to work well, many told me that for good practices I did not write I will create graphic environments with python that existed for that .kv, with this clearer it turns out that I have not been able to achieve how I do it, I hope you could help me to transcribe it I thank you from the bottom of my heart thank you, below the code, I just want to transcribe what I have thanks.
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
from kivy.graphics.texture import Texture
from kivy.clock import Clock
import cv2
class CvCamera(App):
def build(self): # Construcción de interfaz de usuario, etc
self._cap = cv2.VideoCapture(0)
layout2 = BoxLayout(orientation='horizontal', size_hint=(1.0, 0.1))
self.img1 = Image(size_hint=(1.0, 0.7))
layout = BoxLayout(orientation='vertical')
layout.add_widget(self.img1)
layout.add_widget(layout2)
while not self._cap.isOpened():
pass
Clock.schedule_interval(self.update, 1.0 / 30.0)
return layout
def update(self, dt):
ret, img = self._cap.read()
img = cv2.flip(img, 0)
texture1 = Texture.create(size=(img.shape[1], img.shape[0]), colorfmt='bgr')
texture1.blit_buffer(img.tostring(), colorfmt='bgr', bufferfmt='ubyte')
self.img1.texture = texture1
if __name__ == '__main__':
CvCamera().run()
Here is the equivalent using kv language:
# -*- coding: utf-8 -*-
from kivy.app import App
from kivy.lang import Builder
from kivy.graphics.texture import Texture
from kivy.clock import Clock
import cv2
kv = '''
BoxLayout:
orientation: 'vertical'
Image:
id: img1
size_hint: 1.0, 0.7
BoxLayout:
orientation: 'horizontal'
size_hint: 1.0, 0.1
'''
class CvCamera(App):
def build(self): # Construcción de interfaz de usuario, etc
self._cap = cv2.VideoCapture(0)
layout = Builder.load_string(kv)
while not self._cap.isOpened():
pass
Clock.schedule_interval(self.update, 1.0 / 30.0)
return layout
def update(self, dt):
ret, img = self._cap.read()
img = cv2.flip(img, 0)
texture1 = Texture.create(size=(img.shape[1], img.shape[0]), colorfmt='bgr')
texture1.blit_buffer(img.tostring(), colorfmt='bgr', bufferfmt='ubyte')
self.root.ids.img1.texture = texture1
if __name__ == '__main__':
CvCamera().run()
Note that, in general, the arguments in () of the Widgets become entries below and indented from the Widget name.
I'm trying to output text from button presses and add it to a textbox each time it's pressed as well as delete the text when the delete button is pressed - in normal python.
I've been trying to use kivy.uix.textinput, but I'm not sure on how to output the value from the buttons as well as delete it.
This is what I've done so far.
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
class CodeScreen(Screen):
def __init__(self):
super(CodeScreen, self).__init__(name='code_screen')
main_grid_lay = GridLayout(cols=2,cols_minimum={0:640, 1:175})
self.add_widget(main_grid_lay)
#Code ouput display
display_code = TextInput(text='Code!', readonly = True, id=output)
main_grid_lay.add_widget(display_code)
#Options Buttons
box_lay = BoxLayout(orientation='vertical')
main_grid_lay.add_widget(box_lay)
delete_button = Button(
text='Delete',
size_hint_x= None,
width=160,
id='' #unsure on how to delete
)
box_lay.add_widget(delete_button)
base_left = Button(
text='Base Left',
#on_release= b_left(),
#id='left',
)
base_right = Button(
text='Base Right',
on_release=self.degree_popup,
#on_release= b_right(),
)
#b_left = self.ids.output.text='left'
#b_left = self.ids.output.text='right'
box_lay.add_widget(base_left)
box_lay.add_widget(base_right)
# The app class
class MyMain(App):
def build(self):
return CodeScreen()
# Runs the App
if __name__ == '__main__':
MyMain().run()
It currently sends an error and is probably because of the ids. Not fully sure how ids work without using kv language. Any help is appreciated.
The id only makes sense in .kv, in python they are useless. In this case the solution is to access the objects in the methods connected to on_release but for this they must be class attributes.
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
class CodeScreen(Screen):
def __init__(self):
super(CodeScreen, self).__init__(name="code_screen")
self.display_code = TextInput(text="Code!", readonly=True)
self.delete_button = Button(
text="Delete", size_hint_x=None, width=160, on_release=self.delete_clicked
)
self.base_left = Button(text="Base Left", on_release=self.left_clicked)
self.base_right = Button(text="Base Right", on_release=self.right_clicked)
main_grid_lay = GridLayout(cols=2, cols_minimum={0: 640, 1: 175})
main_grid_lay.add_widget(self.display_code)
self.add_widget(main_grid_lay)
box_lay = BoxLayout(orientation="vertical")
box_lay.add_widget(self.delete_button)
main_grid_lay.add_widget(box_lay)
box_lay.add_widget(self.base_left)
box_lay.add_widget(self.base_right)
def delete_clicked(self, instance):
self.display_code.text = ""
def left_clicked(self, instance):
self.display_code.text += "left"
def right_clicked(self, instance):
self.display_code.text += "right"
# The app class
class MyMain(App):
def build(self):
return CodeScreen()
# Runs the App
if __name__ == "__main__":
MyMain().run()
I am building a multiple screen App with Kivy and I would like to use the ScreenManager to navigate between the multiple screens. I have seen examples and documentation for how to create the screens within a .kv file, but I want to know how to create them within the .py file.
Problem: When I create the screen subclasses as shown below, my app
window returns a blank screen.
Question: What is the correct way to
create the Screen subclasses within a .py file?
Right now I have two Screen subclasses defined: 'welcomeScreen', and 'functionScreen'. Each consists of a layout with some widgets.
kivy.require('1.9.1')
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
import kivy.uix.boxlayout
import kivy.uix.button
from kivy.uix.screenmanager import ScreenManager, Screen
class PanelBuilderApp(App): # display the welcome screen
def build(self):
# Create the screen manager and add widgets to the base sm widget
sm = kivy.uix.screenmanager.ScreenManager()
sm.add_widget(Screen(name='welcomeScreen'))
sm.add_widget(Screen(name='functionScreen'))
# sm.current= 'welcomeScreen'
return sm
class welcomeScreen(Screen): #welcomeScreen subclass
def __init__(self, **kwargs): #constructor method
super(welcomeScreen, self).__init__(**kwargs) #init parent
welcomePage = FloatLayout()
box = kivy.uix.boxlayout.BoxLayout(orientation='vertical', size_hint=(0.4, 0.3),
padding=8, pos_hint={'top': 0.5, 'center_x': 0.5})
welcomeLabel = Label(text='Hello and welcome to the Panel Builder version 1.0.\nApp by John Vorsten\nClick below to continue',
halign= 'center', valign= 'center', size_hint= (0.4, 0.2), pos_hint= {'top': 1, 'center_x': 0.5})
welcomeBox = kivy.uix.button.Button(text= 'Click to continue')
welcomeBox.bind(on_press= self.callback)
welcomeBox2 = kivy.uix.button.Button(text='not used')
welcomePage.add_widget(welcomeLabel)
box.add_widget(welcomeBox)
box.add_widget(welcomeBox2)
welcomePage.add_widget(box)
self.add_widget(welcomePage)
def callback(instance):
print('The button has been pressed')
sm.switch_to(Screen(name= 'functionScreen'))
# sm.current = Screen(name= 'functionScreen')
class functionScreen(Screen): #For later function navigation
def __init__(self, **kwargs): #constructor method
super(functionScreen, self).__init__(**kwargs) #init parent
functionPage = kivy.uix.floatlayout.FloatLayout()
functionLabel = Label(text='Welcome to the function page. Here you will choose what functions to use',
halign='center', valign='center', size_hint=(0.4,0.2), pox_hint={'top': 1, 'center_x': 0.5})
functionPage.add_widget(functionLabel)
self.add_widget(functionPage)
# sm.add_widget('Name') #Add more names later when you create more screens
# OR#
# for i in ScreenDirectory:
# sm.add_widget(ScreenDirectory[i])
PanelBuilderApp().run()
if __name__ == '__main__':
pass
I understand I can add the definitions to a .kv file, and I will probably do this as the app grows. However, I like being explicit as I am learning how to use kivy.
I think you think using Screen(name='welcomeScreen') you are using welcomeScreen but that is not true, if you want to use welcomeScreen you should use it directly.
On the other hand you have typographical errors so I have corrected, I recommend you follow the kivy tutorials, obviously you must have a solid OOP base (and I think you do not have it so your task is to reinforce).
import kivy
kivy.require('1.9.1')
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
class PanelBuilderApp(App): # display the welcome screen
def build(self):
sm = ScreenManager()
sm.add_widget(WelcomeScreen(name='welcomeScreen'))
sm.add_widget(FunctionScreen(name='functionScreen'))
return sm
class WelcomeScreen(Screen): #welcomeScreen subclass
def __init__(self, **kwargs): #constructor method
super(WelcomeScreen, self).__init__(**kwargs) #init parent
welcomePage = FloatLayout()
box = BoxLayout(orientation='vertical', size_hint=(0.4, 0.3),
padding=8, pos_hint={'top': 0.5, 'center_x': 0.5})
welcomeLabel = Label(text='Hello and welcome to the Panel Builder version 1.0.\nApp by John Vorsten\nClick below to continue',
halign= 'center', valign= 'center', size_hint= (0.4, 0.2), pos_hint= {'top': 1, 'center_x': 0.5})
welcomeBox = Button(text= 'Click to continue', on_press=self.callback)
welcomeBox2 = Button(text='not used')
welcomePage.add_widget(welcomeLabel)
box.add_widget(welcomeBox)
box.add_widget(welcomeBox2)
welcomePage.add_widget(box)
self.add_widget(welcomePage)
def callback(self, instance):
print('The button has been pressed')
self.manager.current = 'functionScreen'
class FunctionScreen(Screen): #For later function navigation
def __init__(self, **kwargs): #constructor method
super(FunctionScreen, self).__init__(**kwargs) #init parent
functionPage = FloatLayout()
functionLabel = Label(text='Welcome to the function page. Here you will choose what functions to use',
halign='center', valign='center', size_hint=(0.4,0.2), pos_hint={'top': 1, 'center_x': 0.5})
functionPage.add_widget(functionLabel)
self.add_widget(functionPage)
if __name__ == '__main__':
PanelBuilderApp().run()