Page MenuHomePhorge

No OneTemporary

diff --git a/CHANGELOG b/CHANGELOG
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,51 +1,53 @@
@%@~LICENSE:OK~@%@
+saw_052322_1 - [polog] Starting to implement player rack.
+
saw_052122_2 - [yelawolf] Remove the UNIQUE constraint on caption start time
because some files are actually marked with multiple captions
occurring at the same time. Add some more deferred downloads.
saw_052122_1 - [yelawolf] Implemented deferred downloads and seeded the database
with some videos. Beginning of a label system for tagging videos.
Channels, videos, and labels added by the user now start at
id=1000 to leave room for seeded entries. Database now enforces
foreign key constraints and patches use transactions. We now
perform a VACUUM operation on the database after patching or
application exit. Player explicitly disables key repeat on key
press. Debug DIP switch has been changed to the plus sign (+).
saw_051622_2 - [nin] Partial implementation of full-screen mode without meta.
saw_051622_1 - [nin] Improve database performance. Moved audio extraction step
to the main video download routine so we no longer have to wait
for audio extraction upon first play.
saw_051522_1 - [nin] Add switch.py to easily start with DIP switches set.
saw_042422_1 - [controldenied] Beginning to get replay captures to play.
saw_042222_1 - [controldenied] Reworking the replay system so we can now
capture keyboard and mouse actions. The command-line options
(dip switches) should now be specified as the first option only
and without spaces.
saw_041222_1 - [theprodigy] Minor changes wrap up this series.
saw_040822_1 - [theprodigy] Just a little bit better.
saw_040722_1 - [theprodigy] Introducing: ImageEngine (imagine)! Add more
command-line options (see README). Status bar now with separate
UIManager (sui). Player NUM-pad key improvements. Get FPS/avg
score readouts with TAB key.
saw_040422_1 - We now have a working sequence/segment editor.
saw_040222_1 - Implemented replay system. Improved player performance.
saw_033022_2 - Fix kush prompt paint (cursor overlap problem).
saw_033022_1 - Migration to the media/fragment system and versioned database.
saw_032622_2 - Rename directories.
saw_032622_1 - First commit.
diff --git a/k/__init__.py b/k/__init__.py
--- a/k/__init__.py
+++ b/k/__init__.py
@@ -1,665 +1,680 @@
''' Operating (oK) System '''
from k.ui import *
print('YO '+c.Style.BRIGHT+'[esc]'+c.Style.NORMAL+'APE QUITS and ' \
+ c.Style.BRIGHT+'<ctrl-c>'+c.Style.NORMAL+' to exit')
import k.cmd
import k.db as kdb
import k.imagine as kimg
import k.home as home
import k.video as video
#import k.game as game
import k.project as project
import k.replay as replay
from k.replay.ops import *
import k.online as online
import k.player as player
from k.player.ops import Commands
import sys
from datetime import datetime
import traceback
import time
class OS:
def __init__(self):
self.init_start = datetime.now()
self.go = False
self.testing = False
self.imagine = True
self.local = False
self.clock = Clock()
self.square = False
self.replays = True
self.fullscreen = False
if OS.dip('+'):
print('THIS IS A TEST')
self.testing = True
if OS.dip('1'):
print('no imagination')
self.imagine = None
if OS.dip('2'):
print('stay local')
self.local = True
if OS.dip('3'):
print('fps//no limits')
self.clock = NullClock()
if OS.dip('4'):
print('square up')
self.square = True
if OS.dip('6'):
print('replay nix')
self.replays = False
if OS.dip('9'):
print('full-screen')
self.fullscreen = True
#self.peeking = False
pygame.mixer.pre_init(SAMPLE_RATE, -16, 1)
pygame.init()
pygame.display.set_caption('k-os')
if self.imagine:
self.imagine = kimg.ImageEngine()
self.imagine.start()
self.init_stop = datetime.now()
@staticmethod
def dip(switch):
if len(sys.argv) < 2:
return False
return switch in sys.argv[1]
def chaos(self):
self.init()
try:
while self.go:
for event in pygame.event.get():
with self.rate_kick:
self.kick(event)
with self.rate_tick:
self.tick()
if self.imagine:
with self.rate_burn:
ie = self.imagine.burn(self.screen,
pygame.image.frombuffer)
if ie:
self.lit.append(ie)
self.see()
if not self.clock.ready():
self.clock.wait()
# self.update_status()
#if self.player.players and self.player.players[-1].playing:
# time.sleep(1)
except KeyboardInterrupt:
print('got keyboard interrupt')
self.go = False
finally:
self.kill()
def init(self, screen=None):
if screen is None:
if not self.fullscreen:
screen = pygame.display.set_mode((WIDTH, HEIGHT))
else:
screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
pygame.scrap.init()
self.screen = screen
self.gui = KGUI((WIDTH, HEIGHT - STATUS))
self.sui = KGUI((WIDTH, STATUS))
self.lit = [ ]
self.bg = pygame.Surface((WIDTH, HEIGHT-STATUS))
self.bg.fill(BLACK)
pygame.draw.line(self.bg, WHITE,
(WIDTH-PWIDTH-1, 0), (WIDTH-PWIDTH-1, HEIGHT-STATUS-1))
pygame.draw.line(self.bg, WHITE,
(0, HEIGHT-STATUS-1), (WIDTH, HEIGHT-STATUS-1))
self.bglit = None
self.btn_home = pygame_gui.elements.UIButton(text='?!',
manager=self.gui, relative_rect=SPACER)
self.panel_home = home.Panel(self,
target(self.btn_home, 'top'))
self.cur_btn = self.btn_home
self.cur_btn.disable()
self.cur_panel = self.panel_home
self.cur_panel.show()
- self.jobs = []
+ self.jobs = [ ]
self.status_updated = self.init_start
self.status('B')
self.btn_video = pygame_gui.elements.UIButton(text='Video',
anchors=target(self.btn_home),
manager=self.gui, relative_rect=SPACER)
self.panel_video = video.Panel(self,
target(self.btn_video, 'top'))
#self.btn_game = pygame_gui.elements.UIButton(text='Game',
# anchors=target(self.btn_video),
# manager=self.gui, relative_rect=SPACER)
#self.panel_game = game.Panel(self,
# target(self.btn_replay, 'top'))
self.btn_project = pygame_gui.elements.UIButton(text='Project',
#anchors=target(self.btn_game),
anchors=target(self.btn_video),
manager=self.gui, relative_rect=SPACER)
self.panel_project = project.Panel(self,
target(self.btn_project, 'top'))
if self.replays:
self.btn_replay = pygame_gui.elements.UIButton(text='Replay',
anchors=target(self.btn_project),
manager=self.gui, relative_rect=SPACER)
self.panel_replay = replay.Panel(self,
target(self.btn_replay, 'top'))
if not self.local:
self.panel_online = online.Panel(self,
target(self.btn_project, 'top'))
#self.lbl_pstatus = pygame_gui.elements.UILabel(
# text='',
# manager=self.gui,
# relative_rect=pygame.Rect((200, HEIGHT-30), (-1, -1)))
self.confirm = None
self.player = player.Stack(self)
k.cmd.install('player', Commands(self))
self.rate_kick = Counter()
self.rate_tick = Counter()
self.rate_burn = Counter()
self.rate_lit = Counter()
self.status('N')
self.clicked = False
self.hovering = None
self.escaping = False
#if self.replays:
# self.gui.update(0)
# self.paint()
# self.replay_screen()
self.init_stop = datetime.now()
self.go = True
def tick(self, gui=True):
#print('.', end='')
#sys.stdout.flush()
tdelta = self.clock.tick()
if self.replays:
self.panel_replay.tick()
if self.player.big:
gui = False
if gui:
#studio = self.panel_project.panel_studio
#if studio.project_id is None:
# self.lbl_pstatus.set_text("NO PROJECT")
#elif studio.started:
# self.lbl_pstatus.set_text(str(datetime.now()-studio.started))
#else:
# self.lbl_pstatus.set_text('PAUSED')
self.gui.update(tdelta)
self.paint()
for job in self.jobs:
- self.status(job[1])
self.see()
+ self.status(job[2])
try:
- job[0]()
+ if job[1] is None:
+ job[0]()
+ else:
+ job[0](*job[1])
+
self.status('N')
except Exception as e:
self.bug(e)
#self.status('E')
tdelta = self.clock.tick()
self.gui.update(tdelta)
self.paint()
- self.jobs = []
+ self.jobs = [ ]
if not self.local:
self.panel_online.tick()
self.player.tick()
if self.clicked:
self.clicked = False
self.replay_screen()
def kick(self, event):
#print(event)
#debug_event(event)
if event.type == pygame.QUIT:
self.go = False
elif event.type == pygame.WINDOWEXPOSED:
self.status()
#self.peek()
elif event.type == pygame.WINDOWENTER:
pass
elif event.type == pygame.WINDOWLEAVE:
pass
elif event.type == pygame.WINDOWFOCUSGAINED:
##self.peek()
pass
elif event.type == pygame.WINDOWFOCUSLOST:
#self.peek(False, 500)
pass
elif event.type == pygame.KEYDOWN:
self.replay_op(KeyDown(event.scancode))
alt = event.mod & pygame.KMOD_ALT
ctrl = event.mod & pygame.KMOD_CTRL
shift = event.mod & pygame.KMOD_SHIFT \
or event.mod & pygame.KMOD_LSHIFT \
or event.mod & pygame.KMOD_RSHIFT
nomod = not alt and not ctrl and not shift
if event.key == pygame.K_ESCAPE:
self.escaping = True
if self.player.big:
self.player.size_normal()
elif self.confirm:
self.confirm[0].kill()
self.confirm = None
elif self.player.is_playing(True):
self.player.killall()
else:
#self.go = False
pass
else:
self.escaping = False
if event.key == pygame.K_BREAK:
if nomod and self.replays:
self.replay_break()
self.job(self.panel_replay.refresh)
elif event.key == pygame.K_TAB:
if nomod:
self.score()
else:
self.player.keydown(event.key, event.mod)
if not self.player.big:
self.cur_panel.keydown(event.key, event.mod)
elif event.type == pygame.KEYUP:
self.replay_op(KeyUp(event.scancode))
if self.escaping:
self.go = False
elif not self.confirm:
self.player.keyup(event.key, event.mod)
if not self.player.big:
self.cur_panel.keyup(event.key, event.mod)
elif event.type == pygame.MOUSEMOTION:
self.replay_op(MouseMove(event.pos[0], event.pos[1]))
elif event.type == pygame.MOUSEBUTTONDOWN:
self.replay_op(MouseDown(event.button))
self.player.mouse_down(event)
if not self.local:
self.panel_online.mouse_button_down(event)
elif event.type == pygame.MOUSEBUTTONUP:
self.replay_op(MouseUp(event.button))
self.player.mouse_up(event)
if event.button == pygame.BUTTON_RIGHT:
self.replay_capture_toggle()
elif event.button == pygame.BUTTON_WHEELUP \
or event.button == pygame.BUTTON_WHEELDOWN:
self.clicked = True
elif event.type == pygame_gui.UI_BUTTON_ON_HOVERED:
if not self.hovering is event.ui_element:
self.hovering = event.ui_element
self.replay_screen()
elif event.type == pygame_gui.UI_BUTTON_ON_UNHOVERED:
if self.hovering is event.ui_element:
self.hovering = None
self.replay_screen()
elif event.type == pygame_gui.UI_BUTTON_START_PRESS:
self.replay_screen()
elif event.type == pygame_gui.UI_BUTTON_PRESSED:
if not self.player.big:
if event.ui_element == self.btn_home:
self.panel_swap(self.btn_home, self.panel_home)
elif event.ui_element == self.btn_video:
self.panel_swap(self.btn_video, self.panel_video)
#elif event.ui_element == self.btn_game:
# self.panel_swap(self.btn_game, self.panel_game)
elif event.ui_element == self.btn_project:
self.panel_swap(self.btn_project, self.panel_project)
elif self.replays and event.ui_element == self.btn_replay:
self.panel_swap(self.btn_replay, self.panel_replay)
else:
self.cur_panel.click(event.ui_element)
self.player.click(event.ui_element)
self.clicked = True
elif event.type == pygame_gui.UI_TEXT_ENTRY_CHANGED:
self.replay_screen()
elif event.type == pygame_gui.UI_TEXT_BOX_LINK_CLICKED:
- self.cur_panel.click(event.ui_element, event.link_target)
- self.player.click(event.ui_element, event.link_target)
-
if event.link_target.lower().startswith('http://') \
or event.link_target.lower().startswith('https://'):
self.click_link(event.link_target)
+ else:
+ self.cur_panel.click(event.ui_element, event.link_target)
+ self.player.click(event.ui_element, event.link_target)
+
elif event.type == pygame_gui.UI_WINDOW_CLOSE:
if self.confirm and event.ui_element == self.confirm[0]:
self.confirm = None
elif event.type == pygame_gui.UI_CONFIRMATION_DIALOG_CONFIRMED:
if self.confirm and event.ui_element == self.confirm[0]:
self.confirm[1]()
self.confirm = None
if not self.player.big:
self.gui.process_events(event)
def paint(self):
lit = self.screen.blit(self.bg, (0, 0))
if self.bglit:
self.lit.extend(self.bglit)
else:
self.lit.append(pygame.Rect(lit))
self.gui.draw_ui(self.screen)
def blit(self, surface, position):
lit = self.screen.blit(surface, position)
self.lit.append(pygame.Rect(lit))
def see(self):
if self.lit:
with self.rate_lit:
pygame.display.update(self.lit)
self.lit = [ ]
def status(self, mode=None):
update = datetime.now()
if mode == 'N':
pygame.mouse.set_cursor(*pygame.cursors.arrow)
elif mode == 'B':
pygame.mouse.set_cursor(*pygame.cursors.tri_left)
elif mode == 'D':
pygame.mouse.set_cursor(*pygame.cursors.tri_right)
elif mode == 'E':
pygame.mouse.set_cursor(*pygame.cursors.broken_x)
if mode is not None:
for status in self.panel_home.status:
self.panel_home.status[status].hide()
self.panel_home.status[mode].show()
self.sui.update((update - self.status_updated).total_seconds())
self.status_updated = update
bar = pygame.Surface((WIDTH, STATUS))
self.sui.draw_ui(bar)
lit = self.screen.blit(bar, (0, HEIGHT-STATUS))
pygame.display.update(lit)
def panel_swap(self, btn, panel):
self.status('B')
#if self.cur_panel == self.panel_project:
# if self.panel_project.cur_panel == self.panel_project.panel_studio:
# self.panel_project.panel_studio.suspend()
if self.cur_btn:
self.cur_btn.enable()
self.cur_btn = btn
if self.cur_btn:
self.cur_btn.disable()
self.cur_panel.hide()
self.cur_panel = panel
self.cur_panel.show()
self.status('N')
def click_link(self, link):
print(f'LINK CLICK: {link}')
llink = link.lower()
start = llink.index('://') + 3
llink = llink[start:]
if llink.startswith('www.'):
llink = llink[4:]
if llink.startswith('youtube.com/watch?v=') \
or llink.startswith('youtu.be/'):
self.panel_swap(self.btn_video, self.panel_video)
panel = self.panel_video
panel.panel_swap(panel.btn_youtube, panel.panel_youtube)
panel = panel.panel_youtube
panel.clear_results()
panel.input.set_text(link)
panel.btn_video.disable()
self.job(panel.get_video, 'D')
def bug(self, e):
print('*!*!* UNCAUGHT EXCEPTION *!*!*')
print(e)
print(traceback.format_exc())
self.status('E')
def score(self):
print(' '+c.Style.DIM+'[ ]'+c.Style.NORMAL \
+ ' scores are fps/% in 1s, 5s, 15s increments:')
score = ' '+c.Style.DIM+'[OK]'+c.Style.NORMAL \
+ ' '+c.Fore.WHITE+c.Back.BLACK+c.Style.BRIGHT+'tick' \
+ c.Style.RESET_ALL+f' {self.rate_tick}' \
+ ' '+c.Fore.WHITE+c.Back.BLACK+c.Style.BRIGHT+'kick' \
+ c.Style.RESET_ALL+f' {self.rate_kick}'
if self.imagine:
score += ' '+c.Fore.WHITE+c.Back.BLACK+c.Style.BRIGHT+'burn' \
+ c.Style.RESET_ALL+f' {self.rate_burn}'
score += ' '+c.Fore.WHITE+c.Back.BLACK+c.Style.BRIGHT+'lit' \
+ c.Style.RESET_ALL+f' {self.rate_lit}'
print(score)
if self.imagine:
self.imagine.score()
self.status()
def job(self, fn, mode='B'):
- self.jobs.append((fn, mode))
+ self.jobs.append((fn, None, mode))
+
+ def jab(self, fn, args, mode='B'):
+ self.jobs.append((fn, args, mode))
+
+ def focus_video(self, video_id):
+ video = self.panel_video
+ library = video.panel_library
+ library.refresh_video(video_id)
+ video.panel_swap(video.btn_library, library)
+ self.panel_swap(self.btn_video, video)
def project(self):
return self.panel_project.panel_studio.init_project()
def frag(self, media, source, begin=None, end=None):
project = self.project()
return kdb.insert_frag(project, media, source, begin, end)
def clip(self, frag, loop, loop_begin, loop_end, jumps):
loop = '1' if loop else '0'
loop += f',{loop_begin}'
loop += f',{loop_end}'
jumps = ','.join([str(j) for j in jumps])
kdb.insert_clip(frag, loop, jumps)
self.panel_project.panel_studio.panel_clip.add_clip(frag)
def clip_naked(self, frag):
kdb.insert_clip(frag, None, None)
self.panel_project.panel_studio.panel_clip.add_clip(frag)
def focus_clip(self, clip):
self.panel_swap(self.btn_project, self.panel_project)
panel = self.panel_project
panel.panel_swap(panel.btn_studio, panel.panel_studio)
panel = panel.panel_studio
panel.panel_swap(panel.btn_clip, panel.panel_clip)
def seq(self):
return self.panel_project.panel_studio.panel_seq.panel_editor.init_seq()
def seg(self, frag):
seq = self.seq()
idx = kdb.get_last_segment_idx(seq)
if idx is None:
idx = 0
else:
idx += 1
kdb.insert_segment(seq, idx, frag)
self.panel_project.panel_studio.panel_seq.panel_editor.add_seg(idx)
return idx
def focus_seg(self, seg):
self.panel_swap(self.btn_project, self.panel_project)
panel = self.panel_project
panel.panel_swap(panel.btn_studio, panel.panel_studio)
panel = panel.panel_studio
panel.panel_swap(panel.btn_seq, panel.panel_seq)
panel = panel.panel_seq
panel.panel_swap(panel.btn_editor, panel.panel_editor)
def replay_op(self, op):
if self.replays:
self.panel_replay.op(op)
def replay_screen(self):
if self.replays:
self.panel_replay.screen()
def replay_capture_toggle(self):
if self.replays:
if self.panel_replay.toggle_capture():
self.panel_replay.init_replay()
self.clicked = True
else:
self.panel_replay.screen()
self.panel_replay.op(StopCapture())
self.panel_replay.update_timer()
def replay_break(self):
if self.replays:
self.panel_replay.break_replay()
'''
def peek(self, me=True, delay=None):
if self.player.is_playing():
return
if self.peeking and self.peeking.poll() is None:
# previous peek() process is still running
return
self.peeking = media.focus_peek(me=me, delay=delay)
'''
def kill(self):
self.go = False
self.replay_break()
if not self.local:
self.panel_online.go_offline()
''' Nope: bad idea... '''
#for job in self.jobs:
# self.status(job[1])
# try:
# job[0]()
# except Exception as e:
# self.bug(e)
if self.imagine:
print('choke image engine... ', end='')
sys.stdout.flush()
self.imagine.choke()
self.imagine.join()
print('clean up database... ', end='')
sys.stdout.flush()
kdb.close()
print('done')
#pygame.quit()
print('graceful death')
diff --git a/k/db.py b/k/db.py
--- a/k/db.py
+++ b/k/db.py
@@ -1,1378 +1,1379 @@
import sqlite3
from datetime import datetime
VERSION = 6
DATABASE = 'chaos.db'
# meta table entries
META_VERSION = 'db_version'
# media table entries
MEDIA_VIDEO = 10
print(f'databasing "{DATABASE}" ...')
-con = sqlite3.connect(DATABASE, isolation_level=None)
+con = sqlite3.connect(DATABASE, isolation_level=None,
+ detect_types=sqlite3.PARSE_DECLTYPES)
con.row_factory = sqlite3.Row
sqlite3.register_adapter(bool, int)
sqlite3.register_converter('BOOLEAN', lambda v: bool(int(v)))
cur = con.cursor()
#cur.execute('.dbconfig defensive on')
cur.execute('PRAGMA journal_mode=WAL')
cur.execute('PRAGMA synchronous=NORMAL')
cur.execute('PRAGMA temp_store=MEMORY')
#cur.execute('PRAGMA locking_mode=EXCLUSIVE')
cur.execute('PRAGMA foreign_keys=ON')
def cur_fetch():
for row in cur:
return row # returns first row only
return None # if there were no rows
def cur_fetchcol(name):
row = cur_fetch()
if not row:
return None
return row[name]
def cur_fetchall():
rows = [ ]
for row in cur:
rows.append(row)
return rows
def close():
cur.execute('VACUUM')
con.close()
###
### META
###
def _is_version_zero_():
''' The original database had no meta table, so this function checks for a
table known to have existed at the time (i.e. channel) and for the lack
of the meta table. This is done in order to differentiate between a
brand new database versus an existing pre-meta database.'''
try:
cur.execute('SELECT id FROM channel WHERE id < 0')
except sqlite3.OperationalError:
return False
try:
cur.execute('SELECT name FROM meta WHERE name = 1')
return False
except sqlite3.OperationalError:
return True
_version_zero_ = _is_version_zero_()
cur.execute('''
CREATE TABLE IF NOT EXISTS meta (
name TEXT PRIMARY KEY,
value TEXT
)
''')
cur.executemany('''
INSERT OR IGNORE INTO meta (
name,
value
)
VALUES (
?, ?
)
''', [
(META_VERSION, VERSION if not _version_zero_ else 0),
])
def get_meta(name):
cur.execute('''
SELECT value
FROM meta
WHERE name = ?
''', (
name,
))
return cur_fetchcol('value')
def set_meta(name, value):
cur.execute('''
UPDATE meta
SET value = ?
WHERE name = ?
''', (
value,
name
))
def _upgrade_if_needed_():
v = int(get_meta(META_VERSION))
if v < VERSION:
from k.patch import upgrade
upgrade(DATABASE, cur, cur_fetchall, set_meta, META_VERSION, v, VERSION)
_upgrade_if_needed_() # pause here and patch the db before continuing
###
### CHANNEL
###
cur.execute('''
CREATE TABLE IF NOT EXISTS channel (
id INTEGER PRIMARY KEY,
ytid TEXT NOT NULL UNIQUE,
name TEXT,
url TEXT
)
''')
cur.executemany('''
INSERT OR IGNORE INTO channel (
id,
ytid,
name
)
VALUES (
?, ?, ?
)
''', [
(10, 'UCk9H1u4QMFNbBOj96A9DGHw', 'Marcel'),
(20, 'UCTdw38Cw6jcm0atBPA39a0Q', 'NDC Conferences'),
(30, 'UCMXjSvsqlx1CMoNY-i7Pmyw', 'Space Feather'),
(40, 'UCpwvZwUam-URkxB7g4USKpg', 'RT'),
(50, 'UCfAOh2t5DpxVrgS9NQKjC7A', 'The Onion'),
(100, 'UCqFzWxSCi39LnW1JKFR3efg', 'Saturday Night Live'),
(999, 'UC604kMqi2n6y47YLHQ2a8mg', "mix'd k-os")
])
def insert_channel(channel):
cur.execute('''
INSERT INTO channel (
ytid,
name,
url
) VALUES (
?, ?, ?
)
''', (
channel.channel_id,
channel.channel_name,
channel.vanity_url
))
return cur.lastrowid
def update_channel(channel_id, channel):
cur.execute('''
UPDATE channel
SET
name = ?,
url = ?
WHERE id = ?
''', (
channel.channel_name,
channel.vanity_url,
channel_id
))
def get_channel(channel_id):
cur.execute('''
SELECT *
FROM channel
WHERE id = ?
''', (
channel_id,
))
return cur_fetch()
def id_channel(ytid):
cur.execute('''
SELECT id
FROM channel
WHERE ytid = ?
''', (
ytid,
))
return cur_fetchcol('id')
def list_channels():
cur.execute('''
SELECT *
FROM channel
ORDER BY name COLLATE NOCASE
''')
return cur_fetchall()
LIST_CHANNELS_SQL = '''
SELECT
c.id AS 'id',
c.ytid AS 'ytid',
c.name AS 'name',
c.url AS 'url'
FROM channel c
LEFT JOIN video v ON v.channel = c.id
'''
LIST_CHANNELS_SQL_GROUP_BY = '''
GROUP BY c.id
ORDER BY c.name COLLATE NOCASE
'''
def list_channels_by_label(labels):
sql = LIST_CHANNELS_SQL
if labels:
for i in range(len(labels)):
sql += f' LEFT JOIN label_video l{i}'
sql += f' ON l{i}.video = v.id AND l{i}.label = {labels[i]}'
sep = ' WHERE '
for i in range(len(labels)):
sql += sep + f'l{i}.video IS NOT NULL'
sep = ' AND '
sql += LIST_CHANNELS_SQL_GROUP_BY
cur.execute(sql)
return cur_fetchall()
###
### VIDEO
###
cur.execute('''
CREATE TABLE IF NOT EXISTS video (
id INTEGER PRIMARY KEY,
channel INTEGER NOT NULL,
ytid TEXT NOT NULL UNIQUE,
author TEXT,
title TEXT,
description TEXT,
length INTEGER,
published TIMESTAMP,
thumb_url TEXT,
retrieved TIMESTAMP,
FOREIGN KEY (channel) REFERENCES channel (id)
)
''')
cur.executemany('''
INSERT OR IGNORE INTO video (
id,
channel,
ytid,
title
)
VALUES (
?, ?, ?, ?
)
''', [
(10, 10, 'yJDv-zdhzMY',
'The Mother of All Demos, presented by Douglas Engelbart (1968)'),
(20, 20, '6avJHaC3C2U', 'The Art of Code - Dylan Beattie'),
(30, 30, 'GsDrXc94NGU',
'On Max Headroom: The Most Misunderstood Joke on TV'),
(40, 40, 'D95LqdndUM8',
'‘There Will Be No Winners’ If War Breaks Out - Putin'),
(50, 50, 'vm1U5E44W90',
'Putin Learns Putin Behind Plot To Assassinate Putin'),
(100, 100, 'gaoQ5mMRDhg', 'Shud the Mermaid - SNL'),
(101, 100, 'XD66suMp3J4', 'Billionaire Star Trek - SNL'),
(997, 999, 'I7t1bTgFlyU', 'image engine idles | pygame/k-os'),
(998, 999, 'm004JwfzCK4',
'"The sun is gradually expanding" feat. Elex Muscman'),
(999, 999, 'LpnFGAo3oXs', 'gen-z fidget spinner... a work in progress')
])
def insert_video(channel_id, video):
cur.execute('''
INSERT INTO video (
channel,
ytid,
author,
title,
description,
length,
published,
thumb_url,
retrieved
)
VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?
)
''', (
channel_id,
video.video_id,
video.author,
video.title,
video.description,
video.length,
video.publish_date,
video.thumbnail_url,
datetime.now()
))
return cur.lastrowid
def update_video(video_id, video):
cur.execute('''
UPDATE video
SET
author = ?,
title = ?,
description = ?,
length = ?,
published = ?,
thumb_url = ?,
retrieved = ?
WHERE id = ?
''', (
video.author,
video.title,
video.description,
video.length,
video.publish_date,
video.thumbnail_url,
datetime.now(),
video_id
))
def get_video(video_id):
cur.execute('''
SELECT *
FROM video
WHERE id = ?
''', (
video_id,
))
return cur_fetch()
def id_video(ytid):
cur.execute('''
SELECT id
FROM video
WHERE ytid = ?
''', (
ytid,
))
return cur_fetchcol('id')
LIST_VIDEOS_SQL = '''
SELECT
v.id AS 'id',
ch.ytid AS 'cytid',
v.ytid AS 'ytid',
v.title AS 'title',
v.retrieved AS 'retrieved'
FROM video v
LEFT JOIN channel ch ON ch.id = v.channel
'''
LIST_VIDEOS_SQL_JOIN_EXTRA = '''
LEFT JOIN captions cap ON cap.video = v.id
LEFT JOIN keyword k ON k.video = v.id
'''
LIST_VIDEOS_SQL_GROUP_BY = '''
GROUP BY v.id
ORDER BY v.title COLLATE NOCASE
'''
def list_video(video_id):
sql = LIST_VIDEOS_SQL
sql += ' WHERE v.id = ?'
cur.execute(sql, (video_id,))
return cur_fetch()
def list_videos(labels=None, channel_id=None, search_title=None,
search_description=None, search_keyword=None,
search_captions=None):
sql = LIST_VIDEOS_SQL + LIST_VIDEOS_SQL_JOIN_EXTRA
if labels:
for i in range(len(labels)):
sql += f' LEFT JOIN label_video l{i}'
sql += f' ON l{i}.video = v.id AND l{i}.label = {labels[i]}'
sep = ' WHERE '
args = [ ]
if channel_id is not None:
sql += sep + 'v.channel = ?'
sep = ' AND '
args.append(channel_id)
if search_title is not None:
sql += sep + 'v.title LIKE ?'
sep = ' AND '
args.append('%' + search_title + '%')
if search_description is not None:
sql += sep + 'v.description LIKE ?'
sep = ' AND '
args.append('%' + search_description + '%')
if search_keyword is not None:
sql += sep + 'k.keyword LIKE ?'
sep = ' AND '
args.append('%' + search_keyword + '%')
if search_captions is not None:
sql += sep + 'cap.txt LIKE ?'
sep = ' AND '
args.append('%' + search_captions + '%')
if labels:
for i in range(len(labels)):
sql += sep + f'l{i}.video IS NOT NULL'
sep = ' AND '
sql += LIST_VIDEOS_SQL_GROUP_BY
cur.execute(sql, tuple(args))
return cur_fetchall()
###
### KEYWORD
###
cur.execute('''
CREATE TABLE IF NOT EXISTS keyword (
id INTEGER PRIMARY KEY,
video INTEGER NOT NULL,
keyword TEXT NOT NULL,
FOREIGN KEY (video) REFERENCES video (id),
UNIQUE (video, keyword)
)
''')
def insert_keyword(video_id, keyword):
cur.execute('''
INSERT INTO keyword (
video,
keyword
)
VALUES (
?, ?
)
''', (
video_id,
keyword
))
return cur.lastrowid
###
### STREAM
###
cur.execute('''
CREATE TABLE IF NOT EXISTS stream (
id INTEGER PRIMARY KEY,
video INTEGER NOT NULL,
itag INTEGER NOT NULL,
type TEXT,
subtype TEXT,
vcodec TEXT,
acodec TEXT,
resolution TEXT,
fps INTEGER,
bitrate INTEGER,
is_otf BOOLEAN,
is_dash BOOLEAN,
is_prog BOOLEAN,
is_3d BOOLEAN,
is_hdr BOOLEAN,
is_live BOOLEAN,
FOREIGN KEY (video) REFERENCES video (id),
UNIQUE (video, itag)
)
''')
def insert_stream(video_id, stream):
cur.execute('''
INSERT INTO stream (
video,
itag,
type,
subtype,
vcodec,
acodec,
resolution,
fps,
bitrate,
is_otf,
is_dash,
is_prog,
is_3d,
is_hdr,
is_live
)
VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
)
''', (
video_id,
stream.itag,
stream.type,
stream.subtype,
stream.video_codec,
stream.audio_codec,
stream.resolution,
stream.fps,
stream.bitrate,
stream.is_otf,
stream.is_dash,
stream.is_progressive,
stream.is_3d,
stream.is_hdr,
stream.is_live
))
return cur.lastrowid
def list_video_streams(video_id):
cur.execute('''
SELECT *
FROM stream
WHERE video = ? AND type = 'video'
ORDER BY resolution
''', (
video_id,
))
return cur_fetchall()
###
### CAPTIONS
###
cur.execute('''
CREATE TABLE IF NOT EXISTS captions (
id INTEGER PRIMARY KEY,
video INTEGER NOT NULL,
lang INTEGER NOT NULL,
txt TEXT,
FOREIGN KEY (video) REFERENCES video (id),
UNIQUE (video, lang)
)
''')
def insert_captions(video_id, captions, text):
cur.execute('''
INSERT INTO captions (
video,
lang,
txt
)
VALUES (
?, ?, ?
)
''', (
video_id,
captions.code,
#captions.xml_captions
text
))
return cur.lastrowid
def get_captions(video_id):
cur.execute('''
SELECT *
FROM captions
WHERE video = ?
''', (
video_id,
))
return cur_fetch()
def id_captions(video_id):
cur.execute('''
SELECT id
FROM captions
WHERE video = ?
''', (
video_id,
))
return cur_fetchcol('id')
cur.execute('''
CREATE TABLE IF NOT EXISTS caption (
id INTEGER PRIMARY KEY,
captions INTEGER NOT NULL,
start INTEGER NOT NULL,
txt TEXT,
FOREIGN KEY (captions) REFERENCES captions (id)
)
''')
INSERT_CAPTION_SQL = '''
INSERT INTO caption (
captions,
start,
txt
)
VALUES (
?, ?, ?
)
'''
def insert_caption(captions_id, start, text):
cur.execute(INSERT_CAPTION_SQL, (
captions_id,
start,
text
))
return cur.lastrowid
def insert_caption_list(caps):
cur.executemany(INSERT_CAPTION_SQL, caps)
return cur.rowcount
def list_captions(captions_id):
cur.execute('''
SELECT *
FROM caption
WHERE captions = ?
ORDER BY start, id
''', (
captions_id,
))
return cur_fetchall()
###
### PROJECT
###
cur.execute('''
CREATE TABLE IF NOT EXISTS project (
id INTEGER PRIMARY KEY,
name TEXT,
created TIMESTAMP,
updated TIMESTAMP
)
''')
def insert_project():
t = datetime.now()
cur.execute('''
INSERT INTO project (
created,
updated
) VALUES (
?, ?
)
''', (
t, t
))
return cur.lastrowid
def get_project(project_id):
cur.execute('''
SELECT *
FROM project
WHERE id = ?
''', (
project_id,
))
return cur_fetch()
def list_projects():
cur.execute('''
SELECT *
FROM project
ORDER BY name COLLATE NOCASE, updated DESC
''')
return cur_fetchall()
def set_project_name(project_id, name):
cur.execute('''
UPDATE project
SET name = ?, updated = ?
WHERE id = ?
''', (
name,
datetime.now(),
project_id
))
def touch_project(project_id):
cur.execute('''
UPDATE project
SET updated = ?
WHERE id = ?
''', (
datetime.now(),
project_id
))
#def delete_project(project_id):
# cur.execute('''
# DELETE
# FROM clip
# WHERE project = ?
# ''', (
# project_id,
# ))
#
# cur.execute('''
# DELETE
# FROM project
# WHERE id = ?
# ''', (
# project_id,
# ))
###
### MEDIA FRAGMENT
###
cur.execute('''
CREATE TABLE IF NOT EXISTS media (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL
)
''')
cur.executemany('''
INSERT OR IGNORE INTO media (
id,
name
)
VALUES (
?, ?
)
''', [
(MEDIA_VIDEO, 'video'),
])
cur.execute('''
CREATE TABLE IF NOT EXISTS fragment (
id INTEGER PRIMARY KEY,
project INTEGER NOT NULL,
media INTEGER NOT NULL,
source INTEGER NOT NULL,
start INTEGER,
stop INTEGER,
FOREIGN KEY (project) REFERENCES project (id),
FOREIGN KEY (media) REFERENCES media (id)
)
''')
def insert_frag(project_id, media_id, source_id, start, stop):
cur.execute('''
INSERT INTO fragment (
project,
media,
source,
start,
stop
)
VALUES (
?, ?, ?, ?, ?
)
''', (
project_id,
media_id,
source_id,
start,
stop
))
return cur.lastrowid
def get_frag(frag_id):
cur.execute('''
SELECT *
FROM fragment
WHERE id = ?
''', (
frag_id,
))
return cur_fetch()
###
### CLIP
###
cur.execute('''
CREATE TABLE IF NOT EXISTS clip (
fragment INTEGER PRIMARY KEY,
name TEXT,
key INTEGER,
loop TEXT,
jumps TEXT,
created TIMESTAMP,
updated TIMESTAMP,
FOREIGN KEY (fragment) REFERENCES fragment (id)
)
''')
def insert_clip(frag_id, loop, jumps):
t = datetime.now()
cur.execute('''
INSERT INTO clip (
fragment,
loop,
jumps,
created,
updated
)
VALUES (
?, ?, ?, ?, ?
)
''', (
frag_id,
loop,
jumps,
t, t
))
return cur.lastrowid
def get_clip(frag_id):
cur.execute('''
SELECT *
FROM clip
WHERE fragment = ?
''', (
frag_id,
))
return cur_fetch()
CLIP_LIST_SQL = '''
SELECT
f.id AS 'id',
f.project AS 'project',
f.start AS 'start',
f.stop AS 'stop',
c.name AS 'name',
c.key AS 'key',
c.loop AS 'loop',
c.jumps AS 'jumps'
FROM clip c
LEFT JOIN fragment f ON f.id = c.fragment
'''
CLIP_LIST_SQL_ORDER = '''
ORDER BY c.name COLLATE NOCASE, c.updated DESC
'''
def get_clip_listing(frag_id):
cur.execute(
CLIP_LIST_SQL + 'WHERE c.fragment = ?',
(frag_id,))
return cur_fetch()
def list_clips(project_id):
cur.execute(
CLIP_LIST_SQL + 'WHERE f.project = ?' + CLIP_LIST_SQL_ORDER,
(project_id,))
return cur_fetchall()
def set_clip_name(frag_id, name):
cur.execute('''
UPDATE clip
SET name = ?
WHERE fragment = ?
''', (
name,
frag_id
))
def set_clip_key(frag_id, key):
cur.execute('''
UPDATE clip
SET key = ?
WHERE fragment = ?
''', (
key,
frag_id
))
def set_clip_loop(frag_id, loop):
cur.execute('''
UPDATE clip
SET loop = ?
WHERE fragment = ?
''', (
loop,
frag_id
))
def set_clip_jumps(frag_id, jumps):
cur.execute('''
UPDATE clip
SET jumps = ?
WHERE fragment = ?
''', (
jumps,
frag_id
))
def touch_clip(frag_id):
cur.execute('''
UPDATE clip
SET updated = ?
WHERE fragment = ?
''', (
datetime.now(),
frag_id
))
#def delete_clip(clip_id):
# cur.execute('''
# DELETE
# FROM clip
# WHERE fragment = ?
# ''', (
# clip_id,
# ))
###
### SEQUENCE SEGMENT
###
cur.execute('''
CREATE TABLE IF NOT EXISTS sequence (
id INTEGER PRIMARY KEY,
project INTEGER NOT NULL,
name TEXT,
created TIMESTAMP,
updated TIMESTAMP,
FOREIGN KEY (project) REFERENCES project (id)
)
''')
def insert_sequence(project_id):
t = datetime.now()
cur.execute('''
INSERT INTO sequence (
project,
created,
updated
)
VALUES (
?, ?, ?
)
''', (
project_id,
t, t
))
return cur.lastrowid
def get_sequence(seq_id):
cur.execute('''
SELECT *
FROM sequence
WHERE id = ?
''', (
seq_id,
))
return cur_fetch()
def list_sequences(project_id):
cur.execute('''
SELECT *
FROM sequence
WHERE project = ?
ORDER BY name COLLATE NOCASE, updated DESC
''', (
project_id,
))
return cur_fetchall()
def set_sequence_name(seq_id, name):
cur.execute('''
UPDATE sequence
SET name = ?
WHERE id = ?
''', (
name,
seq_id
))
def touch_sequence(seq_id):
cur.execute('''
UPDATE sequence
SET updated = ?
WHERE id = ?
''', (
datetime.now(),
seq_id
))
cur.execute('''
CREATE TABLE IF NOT EXISTS segment (
sequence INTEGER NOT NULL,
idx INTEGER NOT NULL,
fragment INTEGER NOT NULL,
PRIMARY KEY (sequence, idx),
FOREIGN KEY (sequence) REFERENCES sequence (id),
FOREIGN KEY (fragment) REFERENCES fragment (id)
)
''')
def insert_segment(seq_id, idx, frag_id):
cur.execute('''
INSERT INTO segment (
sequence,
idx,
fragment
)
VALUES (
?, ?, ?
)
''', (
seq_id,
idx,
frag_id
))
return cur.lastrowid
def get_segment(seq_id, idx):
cur.execute('''
SELECT *
FROM segment
WHERE sequence = ? AND idx = ?
''', (
seq_id,
idx
))
return cur_fetch()
SEGMENT_LIST_SQL = '''
SELECT
s.sequence AS 'sequence',
s.idx AS 'idx',
s.fragment AS 'fragment',
f.project AS 'project',
f.start AS 'start',
f.stop AS 'stop'
FROM segment s
LEFT JOIN fragment f ON f.id = s.fragment
'''
SEGMENT_LIST_SQL_ORDER = '''
ORDER BY s.idx
'''
def get_segment_listing(seq_id, idx):
cur.execute(
SEGMENT_LIST_SQL + 'WHERE s.sequence = ? AND s.idx = ?',
(seq_id, idx))
return cur_fetch()
def list_segments(seq_id):
cur.execute(
SEGMENT_LIST_SQL + 'WHERE s.sequence = ?' + SEGMENT_LIST_SQL_ORDER,
(seq_id,))
return cur_fetchall()
def get_last_segment_idx(seq_id):
cur.execute('''
SELECT idx
FROM segment
WHERE sequence = ?
ORDER BY idx DESC
LIMIT 1
''', (
seq_id,
))
return cur_fetchcol('idx')
def set_segment_idx(seq_id, old_idx, new_idx):
cur.execute('''
UPDATE segment
SET idx = ?
WHERE sequence = ? AND idx = ?
''', (
new_idx,
seq_id,
old_idx
))
###
### REPLAY
###
cur.execute('''
CREATE TABLE IF NOT EXISTS replay (
id INTEGER PRIMARY KEY,
name TEXT,
start INTEGER,
stop INTEGER,
data TEXT
)
''')
def insert_replay(start):
cur.execute('''
INSERT INTO replay (
start
) VALUES (
?
)
''', (
start,
))
return cur.lastrowid
def get_replay(replay_id):
cur.execute('''
SELECT *
FROM replay
WHERE id = ?
''', (
replay_id,
))
return cur_fetch()
def list_replays():
cur.execute('''
SELECT
id,
name,
start,
stop
FROM replay
ORDER BY name COLLATE NOCASE, start DESC
''')
return cur_fetchall()
def finish_replay(replay_id, stop, data):
cur.execute('''
UPDATE replay
SET stop = ?, data = ?
WHERE id = ?
''', (
stop,
data,
replay_id
))
def set_replay_name(replay_id, name):
cur.execute('''
UPDATE replay
SET name = ?
WHERE id = ?
''', (
name,
replay_id
))
cur.execute('''
CREATE TABLE IF NOT EXISTS replay_video (
replay INTEGER NOT NULL,
video INTEGER NOT NULL,
PRIMARY KEY (replay, video),
FOREIGN KEY (replay) REFERENCES replay (id),
FOREIGN KEY (video) REFERENCES video (id)
)
''')
def insert_replay_video(replay, video):
cur.execute('''
INSERT INTO replay_video (
replay,
video
) VALUES (
?, ?
)
''', (
replay,
video
))
return cur.lastrowid
def list_replay_videos(replay_id):
cur.execute('''
SELECT *
FROM replay_video
WHERE replay = ?
''', (
replay_id,
))
return cur_fetchall()
###
### LABEL
###
cur.execute('''
CREATE TABLE IF NOT EXISTS label (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL UNIQUE
)
''')
cur.executemany('''
INSERT OR IGNORE INTO label (
id,
name
)
VALUES (
?, ?
)
''', [
(9, 'LANNOCC'),
(420, 'funny'),
(999, 'k-os')
])
def insert_label(name):
cur.execute('''
INSERT INTO label (
name
)
VALUES (
?
)
''', (
name,
))
return cur.lastrowid
def get_label(label_id):
cur.execute('''
SELECT *
FROM label
WHERE id = ?
''', (
label_id,
))
return cur_fetch()
def list_labels():
cur.execute('''
SELECT *
FROM label
ORDER BY name COLLATE NOCASE
''')
return cur_fetchall()
def delete_label(label_id):
cur.execute('''
DELETE
FROM label_video
WHERE label = ?
''', (
label_id,
))
cur.execute('''
DELETE
FROM label
WHERE id = ?
''', (
label_id,
))
cur.execute('''
CREATE TABLE IF NOT EXISTS label_video (
label INTEGER NOT NULL,
video INTEGER NOT NULL,
PRIMARY KEY (label, video),
FOREIGN KEY (label) REFERENCES label (id),
FOREIGN KEY (video) REFERENCES video (id)
)
''')
cur.executemany('''
INSERT OR IGNORE INTO label_video (
label,
video
)
VALUES (
?, ?
)
''', [
(9, 10),
(9, 20),
(9, 30),
(9, 40),
(9, 50),
(9, 100),
(9, 101),
(9, 997),
(420, 50),
(420, 100),
(420, 101),
(420, 998),
(420, 999),
(999, 997),
(999, 998),
(999, 999)
])
print('db ready :-)')
diff --git a/k/home.py b/k/home.py
--- a/k/home.py
+++ b/k/home.py
@@ -1,95 +1,100 @@
from k.ui import *
from version import *
import k.storage as media
from k.labels import Panel as Labels
INFO = '''ORDER IN CHAOS
This is the "K" Operating System. K in this context stands in for many things such as keyframe or knife, or ken, but also generically.
Purpose:
- make art
- play video
- hack python
- perform musicly
- train logic (AI)
- grow fun community
'''
EXTRA='''
From a complete and fully-formed object / idea to noise, randomness, or the absense of anything... there are those points where change occurs and entropy is added; that is K.
_________
'''
-SIGNED='THANK YOU for running this program. Email ' + SAW + ' ' + ME + ' if you want to help... --shawn' #lannocc
+SIGNED='THANK YOU for running this program.\n' \
+ + 'Email ' + SAW + ' @ ' + THEY + ' if you want to help...\n' \
+ + ' --' + ME
+
+IMAGE=media.get_gfx('title.png')
+
class Panel(KPanel):
def __init__(self, k, anchors):
super().__init__(k, anchors)
- self.title = pygame_gui.elements.UIImage(
- image_surface=media.get_gfx('title.png'),
+ self.image = pygame_gui.elements.UIImage(
+ image_surface=IMAGE,
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((10, 10), (180, 180)))
self.tagline = pygame_gui.elements.UILabel(
text='> Disorderly Conduct ^',
manager=k.gui,
container=self.container,
- anchors=target(self.title, 'top'),
+ anchors=target(self.image, 'top'),
relative_rect=SPACER)
- self.info = pygame_gui.elements.UITextBox(
- html_text=(INFO+EXTRA+SIGNED).replace('\n', '<br>'),
- manager=k.gui,
- container=self.container,
- relative_rect=pygame.Rect((9, 234), (420, 333)))
-
if self.k.testing:
self.btn_testing = pygame_gui.elements.UIButton(
- text='Testing',
+ text='TEST ME',
manager=k.gui,
container=self.container,
- relative_rect=pygame.Rect((250, 0), (-1, -1)))
+ relative_rect=pygame.Rect((250, 111), (-1, -1)))
else:
self.btn_testing = None
self.btn_labels = pygame_gui.elements.UIButton(
text='Labels',
manager=k.gui,
container=self.container,
- relative_rect=pygame.Rect((250, 30), (-1, -1)))
+ relative_rect=pygame.Rect((420, 200), (90, -1)))
+
+ self.info = pygame_gui.elements.UITextBox(
+ html_text=(INFO+EXTRA+SIGNED).replace('\n', '<br>'),
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((9, 234), (WIDTH-PWIDTH-36, 333)))
self.version = pygame_gui.elements.UILabel(
text=f'v/{CHAOS}',
#manager=k.gui,
#relative_rect=pygame.Rect((WIDTH/2 - 125, HEIGHT-30), (250, -1)))
manager=k.sui,
relative_rect=pygame.Rect((WIDTH/2 - 125, 3), (250, -1)))
#self.status_rect = pygame.Rect((5, HEIGHT-27), (152, 20))
self.status_rect = pygame.Rect((5, 5), (152, 20))
self.status = {}
for mode in MODES:
status = pygame_gui.elements.UIImage(
image_surface=media.get_gfx(MODES[mode]),
manager=k.sui,
relative_rect=self.status_rect)
status.hide()
self.status[mode] = status
self.panel_labels = Labels(k, target(k.btn_home, 'top'))
def click(self, element, target=None):
if element == self.btn_testing:
from k.player.testing import Player
self.k.player.open(Player(self.k))
elif element == self.btn_labels:
self.k.panel_swap(None, self.panel_labels)
diff --git a/k/imagine/__init__.py b/k/imagine/__init__.py
--- a/k/imagine/__init__.py
+++ b/k/imagine/__init__.py
@@ -1,179 +1,179 @@
from k.ui import c, Counter
from .caching import Dream
import cv2
import threading
import queue
import sys
class ImageEngine(threading.Thread):
def __init__(self):
self.go = True
self.rate = Counter()
self.videos = { }
self.load = queue.SimpleQueue()
self.loaded = threading.Event()
self.ready = threading.Event()
self.trip = queue.SimpleQueue()
self.fire = queue.SimpleQueue()
self.ember = None
self.stoked = False
super().__init__(name="imagination")
def run(self):
print("imagine running wild")
while self.go:
# combustion
with self.rate:
target = None
try:
while idea := self.trip.get_nowait():
if idea[0] is None:
self.odometer()
elif idea[2] is not None and idea[3] is not None:
target = idea
except queue.Empty:
pass
if target is not None:
res = target[0]
frame = target[1]
pos = target[2]
size = target[3]
try:
spark = self.videos[res].it(frame, size)
self.fire.put_nowait((pos, spark.tobytes(), size))
self.ember = (pos, None, size)
except KeyError:
# resource has been removed
self.ember = None
# refuel
gassed = True
try:
while res := self.load.get_nowait():
if not self.go:
self.loaded.set()
break
print(f' [IE] video file load: {res.vfn}')
dream = Dream(cv2.VideoCapture(res.vfn))
res.frames = int(dream.mind.get(cv2.CAP_PROP_FRAME_COUNT))
res.fps = dream.mind.get(cv2.CAP_PROP_FPS)
res.size = dream.cache[0].shape[0]
res.video = dream
self.videos[res] = dream
self.loaded.set()
except queue.Empty:
gassed = False
# idle
if target is None and not gassed and self.ember:
self.fire.put_nowait(self.ember)
elif self.go:
self.ready.wait()
self.ready.clear()
print("I.E. "+c.Fore.BLACK+c.Style.BRIGHT+"exhausted"+c.Style.RESET_ALL)
def unplug(self, resource):
dreaming = self.videos[resource]
del self.videos[resource]
dreaming.awake()
def rev(self):
self.ready.set()
def odometer(self):
think = Counter()
have = Counter()
know = Counter()
find = Counter()
for dream in self.videos.values():
think += dream.rate_size
have += dream.rate_have
know += dream.rate_know
find += dream.rate_find
cb = c.Fore.BLACK + c.Back.WHITE + c.Style.DIM
bc = c.Style.RESET_ALL
print(' '+c.Style.DIM+'[IE]'+c.Style.NORMAL \
#+ f' {cb}have{bc} @ {have} {cb}know{bc} @ {know}' \
#+ f' {cb}find{bc} @ {find} {cb}think{bc} @ {think}')
+ f' {cb}think{bc} {think} {cb}have{bc} {have}' \
+ f' {cb}know{bc} {know} {cb}find{bc} {find}')
self.stoked = False
def choke(self):
self.go = False
self.rev()
def fuel(self, resource):
self.load.put_nowait(resource)
self.rev()
while resource not in self.videos:
if not self.go:
return
self.loaded.wait()
self.loaded.clear()
def throttle(self, resource, frame):
self.trip.put_nowait((resource, frame, None, None))
def speed(self, resource, frame, pos, size):
self.trip.put_nowait((resource, frame, pos, size))
def burn(self, pipe, muffler, housing=None):
flame = None
try:
while flame := self.fire.get_nowait():
pass
except queue.Empty:
pass
if flame is None or not self.go:
return None
mounted = flame[0]
spark = flame[1]
bang = flame[2]
if housing:
mounted[0] += housing[0]
mounted[1] += housing[1]
if spark is None:
if self.stoked:
print('.', end='')
else:
- print('stoking ember', end='')
+ print('stoking ember.', end='')
self.stoked = True
sys.stdout.flush()
# FIXME: half-fade / glow
return None
else:
return pipe.blit(muffler(spark, bang, "BGR"), mounted)
def score(self):
self.trip.put_nowait((None, None, None, None))
self.rev()
diff --git a/k/player/ui.py b/k/player/ui.py
--- a/k/player/ui.py
+++ b/k/player/ui.py
@@ -1,584 +1,587 @@
from k.ui import *
import k.db as kdb
from .core import get_size_to_fit
PRECT = pygame.Rect((WIDTH-PWIDTH, 0), (PWIDTH, HEIGHT))
+PRACK = pygame.Rect((140, 370), (PWIDTH-150, HEIGHT-STATUS-380))
MOD_MAN = 666
class Player(KPanel):
def __init__(self, k, tracker, thumbnail=None, loop=None, jumps=None):
super().__init__(k, relative_rect=PRECT, visible=1)
self.trk = tracker
self.progress = pygame_gui.elements.UIHorizontalSlider(
start_value=0,
value_range=(0, self.trk.frames-1),
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((0, 315), (PWIDTH, 20)))
self.btn_pp = pygame_gui.elements.UIButton(
text='',
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((10, 335), (80, -1)))
if hasattr(self, 'save'):
self.btn_save = pygame_gui.elements.UIButton(
text='Save*',
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((110, 335), (80, -1)))
else:
self.btn_save = None
if hasattr(self, 'clip'):
self.btn_clip = pygame_gui.elements.UIButton(
text='Clip',
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((200, 335), (60, -1)))
else:
self.btn_clip = None
if hasattr(self, 'seq'):
self.btn_seq = pygame_gui.elements.UIButton(
text='Seq',
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((260, 335), (50, -1)))
else:
self.btn_seq = None
self.lbl_frame = pygame_gui.elements.UILabel(
text='',
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((420, 335), (-1, -1)))
if loop:
loop = loop.split(',')
self.loop = True if int(loop[0])==1 else False
self.loop_begin = int(loop[1])
self.loop_end = int(loop[2])
else:
self.loop = False
self.loop_begin = 0
self.loop_end = self.trk.frames - 1
if jumps:
self.jumps = [int(j) for j in jumps.split(',')]
else:
self.jumps = []
for j in range(1, 10):
self.jumps.append(int(j * self.trk.frames / 10))
self.lbl_jumps = []
for j, frame in enumerate(self.jumps):
x = 28+round((PWIDTH-65)*frame/self.trk.frames)
self.lbl_jumps.append(pygame_gui.elements.UILabel(
text=str(j+1),
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((x, 295), (-1, -1))))
self.loop_bar = pygame.Surface((PWIDTH, 3))
self.draw_loop_bar()
self.thumb_orig = thumbnail
self.thumb = self.thumb_orig
self.reset()
def reset(self):
self.progress.disable()
self.progress.set_current_value(0)
self.btn_pp.set_text('Play')
self.lbl_frame.set_text(f'[{self.trk.frames}]')
#self.holding = 0
self.holding = [ ]
self.pdrag = False
self.trk.reset()
self.img = None
self.playing = None
def kill(self, replace=False):
self.stop(replace)
self.progress.kill()
self.btn_pp.kill()
if self.btn_save:
self.btn_save.kill()
if self.btn_clip:
self.btn_clip.kill()
if self.btn_seq:
self.btn_seq.kill()
self.lbl_frame.kill()
for lbl_jump in self.lbl_jumps:
lbl_jump.kill()
super().kill()
def play(self):
if self.playing:
return
self.op_start()
self.progress.enable()
self.btn_pp.set_text('Pause')
self.trk.play()
self.playing = True
def pause(self):
if not self.playing:
return
self.op_stop()
self.btn_pp.set_text('Resume')
self.trk.pause()
self.playing = False
def stop(self, replace=False):
if self.playing is None:
return
self.reset()
if not replace:
self.op_stop()
self.k.replay_break()
def seek(self, frame):
if self.playing and self.pdrag \
and frame + self.trk.begin == self.trk.end:
frame -= 1
self.trk.seek(frame + self.trk.begin)
self.update_frame(frame)
if self.playing and not self.pdrag and self.holding:
self.op_seek()
def update_frame(self, frame):
self.progress.set_current_value(frame)
self.lbl_frame.set_text(str(frame))
def tick(self):
if self.playing is not None:
pframe = round(self.progress.get_current_value())
if pframe != self.trk.frame - self.trk.begin:
#print(f'seeking pframe {pframe}')
self.seek(pframe)
elif self.playing and self.pdrag:
self.seek(self.trk.frame - self.trk.begin - 1)
#elif self.holding < 0:
# self.seek(self.flast)
elif self.holding:
if len(self.holding) > 1:
self.seek(self.flast)
for key in self.holding:
self.keydown(key, MOD_MAN)
elif self.holding[0] == pygame.K_KP_PERIOD:
self.seek(self.flast)
elif self.loop and (pframe < self.loop_begin \
or pframe > self.loop_end):
#if self.holding == 0:
if not self.holding:
self.seek(self.loop_begin)
tock = self.trk.tick()
if tock is None:
self.stop()
elif tock is not False:
self.img = tock
self.update_frame(self.trk.frame - self.trk.begin)
self.paint()
def paint(self):
if not self.k.player.big:
self.paint_loop_bar()
if self.playing is None:
if self.thumb is not None:
self.paint_thumb()
else:
self.paint_video()
def paint_thumb(self):
self.paint_image(self.thumb, self.thumb.get_width(),
self.thumb.get_height())
def paint_video(self):
self.paint_image(self.img, self.trk.size[0], self.trk.size[1])
def paint_image(self, img, w, h):
if self.k.player.big:
x = int((WIDTH - w) / 2)
y = int((HEIGHT - STATUS - h) / 2)
else:
x = PRECT[0]
y = PRECT[1]
if img is True:
self.trk.res.ie.speed(self.trk.res, self.trk.frame, (x, y), (w, h))
else:
self.k.blit(img, (x, y))
def paint_loop_bar(self):
self.k.blit(self.loop_bar, (PRECT[0], 313))
def draw_loop_bar(self):
self.loop_bar.fill(BLACK)
color = RED if self.loop else GREEN
width = PWIDTH-65
x_begin = round(width * self.loop_begin / self.trk.frames)
x_end = round(width * (1+self.loop_end) / self.trk.frames)
if x_begin > width-3:
x_begin = width-3
if x_end - x_begin < 3:
x_end = x_begin+3
pygame.draw.rect(self.loop_bar, color,
pygame.Rect((32+x_begin, 0), (x_end-x_begin, 3)))
def size_to_fit(self, width, height):
self.trk.size_to_fit(width, height)
bg = pygame.Surface((width, height))
bg.fill((9, 81, 18))
if self.thumb_orig:
size = get_size_to_fit(self.thumb_orig.get_size(), (width, height))
self.thumb = pygame.transform.smoothscale(self.thumb_orig, size)
tw = self.thumb.get_width()
th = self.thumb.get_height()
if tw < width or th < height:
x = int((width - tw) / 2)
y = int((height - th) / 2)
bg.blit(self.thumb, (x, y))
self.thumb = bg
else:
self.thumb = bg
def click(self, element, target=None):
if element == self.btn_pp:
- if self.playing:
- self.pause()
- else:
- self.play()
+ self.pause() if self.playing else self.play()
elif element == self.btn_save:
self.k.job(self.save)
elif element == self.btn_clip:
self.k.job(self.clip)
elif element == self.btn_seq:
self.k.job(self.seq)
+ else:
+ return False
+
+ return True
+
def mouse_down(self, event):
if self.playing is None:
return
if event.button != pygame.BUTTON_LEFT:
return
pos = event.pos
prect = self.progress.get_relative_rect()
srect = self.progress.sliding_button.get_relative_rect()
bw = self.progress.arrow_button_width
if pos[0] > PRECT[0] + prect[0] + bw \
and pos[0] < PRECT[0] + prect[0] + prect[2] - bw \
and pos[1] > PRECT[1] + prect[1] \
and pos[1] < PRECT[1] + prect[1] + prect[3]:
self.pdrag = True
self.op_hold()
if not (pos[0] >= PRECT[0] + srect[0] \
and pos[0] <= PRECT[0] + srect[0] + srect[2]):
x = pos[0] - PRECT[0] - bw
w = prect[2] - 2*bw
f = int((x / w) * self.trk.frames)
self.seek(f)
def mouse_up(self, event):
if event.button != pygame.BUTTON_LEFT:
return
self.pdrag = False
if self.playing:
self.op_seek()
def keydown(self, key, mod):
#print(f'{self.holding} DOWN {key}')
pygame.key.set_repeat(0)
man = False
alt = False
ctrl = False
shift = False
if mod == MOD_MAN:
man = True
else:
alt = mod & pygame.KMOD_ALT
ctrl = mod & pygame.KMOD_CTRL
shift = mod & pygame.KMOD_SHIFT or mod & pygame.KMOD_LSHIFT \
or mod & pygame.KMOD_RSHIFT
nomod = not alt and not ctrl and not shift
if key == pygame.K_KP_ENTER:
if self.playing:
self.pause()
else:
self.play()
elif key == pygame.K_HOME:
self.stop()
self.play()
elif key == pygame.K_END:
self.stop()
elif key == pygame.K_UP:
if not man:
self.keyhold(key)
if self.playing:
if nomod:
self.seek(self.trk.frame + 3)
elif ctrl:
self.seek(self.trk.frame + 42)
elif shift:
self.seek(self.trk.frame + 666)
else:
if nomod:
self.seek(self.trk.frame + 1)
elif ctrl:
self.seek(self.trk.frame + 3333)
elif shift:
self.seek(self.trk.frame + 10000)
elif key == pygame.K_DOWN:
if not man:
self.keyhold(key)
if self.playing:
if nomod:
self.seek(self.trk.frame - 3)
elif ctrl:
self.seek(self.trk.frame - 42)
elif shift:
self.seek(self.trk.frame - 666)
else:
if nomod:
self.seek(self.trk.frame - 1)
elif ctrl:
self.seek(self.trk.frame - 3333)
elif shift:
self.seek(self.trk.frame - 10000)
elif key == pygame.K_LEFT:
if not man:
self.keyhold(key)
if nomod:
self.seek(self.trk.frame - 10)
elif ctrl:
self.seek(self.trk.frame - 100)
elif shift:
self.seek(self.trk.frame - 1000)
elif key == pygame.K_RIGHT:
if not man:
self.keyhold(key)
if nomod:
self.seek(self.trk.frame + 10)
elif ctrl:
self.seek(self.trk.frame + 100)
elif shift:
self.seek(self.trk.frame + 1000)
elif key == pygame.K_KP0:
if nomod:
if not man:
self.keyhold(key, True)
if self.loop:
self.seek(0)
else:
self.seek(self.loop_begin)
elif key >= pygame.K_KP1 and key <= pygame.K_KP9:
if nomod:
if not man:
self.keyhold(key, True)
self.seek(self.jumps[key - pygame.K_KP1])
elif ctrl and not man:
idx = key - pygame.K_KP1
frame = self.trk.frame - self.trk.begin
self.jumps[idx] = frame
self.lbl_jumps[idx].set_relative_position(
(28 + int((PWIDTH-65) * frame / self.trk.frames),
295))
elif key == pygame.K_KP_PERIOD:
if self.playing:
#if self.holding == 0 or self.holding is None:
# self.op_hold()
# self.flast = self.trk.frame
# self.holding = -1 * key
#elif self.holding > 0:
# self.op_hold()
# self.holding = -1 * self.holding
#else:
# #print('how did this happen (key already down)?')
# pass
if man:
self.seek(self.flast)
else:
self.keyhold(key, True)
#self.holding.append(key)
elif key == pygame.K_KP_DIVIDE:
if nomod:
self.loop_begin = self.trk.frame - self.trk.begin
if self.loop_begin > self.loop_end:
self.loop_end = self.trk.end - self.trk.begin
self.draw_loop_bar()
#if self.btn_save:
# self.btn_save.enable()
elif key == pygame.K_KP_MULTIPLY:
if nomod:
self.loop_end = self.trk.frame - self.trk.begin
if self.loop_end < self.loop_begin:
self.loop_begin = 0
self.draw_loop_bar()
#if self.btn_save:
# self.btn_save.enable()
elif key == pygame.K_KP_PLUS:
if nomod:
if not self.loop:
self.loop = True
self.draw_loop_bar()
#if self.btn_save:
# self.btn_save.enable()
#self.keyhold(key)
self.seek(self.loop_begin)
elif key == pygame.K_KP_MINUS:
if nomod:
if self.loop:
self.loop = False
self.draw_loop_bar()
#if self.btn_save:
# self.btn_save.enable()
if not man:
self.keyhold(key)
self.seek(self.loop_end)
def keyup(self, key, mod):
#print(f'{self.holding} UP {key}')
if key == pygame.K_ESCAPE:
self.k.player.killall()
return
#if self.holding < 0:
# self.holding = -1 * self.holding
# if self.holding == key:
# self.holding = 0
# self.op_unhold()
#elif self.holding == 0:
# if key == pygame.K_KP0:
# self.seek(self.loop_begin)
# elif key >= pygame.K_KP1 and key <= pygame.K_KP9:
# self.seek(self.jumps[key - pygame.K_KP1])
#else:
# self.holding = 0
while key in self.holding:
idx = self.holding.index(key)
del self.holding[idx]
if idx > 0:
if self.loop and key == pygame.K_KP_PERIOD:
self.seek(self.flast)
else:
self.keydown(self.holding[idx-1], MOD_MAN)
def keyhold(self, key, magic=False):
#if self.holding < 0:
# self.holding = -1 * key
#elif magic and self.holding == 0:
# self.flast = self.trk.frame - self.trk.begin
# self.holding = key
#elif magic and (self.holding >= pygame.K_KP1 \
# and self.holding <= pygame.K_KP9) \
# or self.holding == pygame.K_KP0:
# self.holding = -1 * self.holding
#else:
# self.holding = key
if magic:
self.flast = self.trk.frame - self.trk.begin
self.holding.append(key)
def op_start(self):
#self.k.replay_op(self.trk.res.video_id, kdb.OP_START,
# self.trk.frame + self.trk.begin)
pass
def op_stop(self):
#self.k.replay_op(self.trk.res.video_id, kdb.OP_STOP,
# self.trk.frame + self.trk.begin)
pass
def op_seek(self):
self.op_start()
def op_hold(self):
#self.k.replay_op(self.trk.res.video_id, kdb.OP_HOLD,
# self.trk.frame + self.trk.begin)
pass
def op_unhold(self):
self.op_start()
diff --git a/k/player/video.py b/k/player/video.py
--- a/k/player/video.py
+++ b/k/player/video.py
@@ -1,51 +1,264 @@
from k.ui import *
import k.db as kdb
import k.storage as media
+from k.home import IMAGE
from .core import Resource, Tracker
-from .ui import Player as UI
+from .ui import Player as UI, PRACK
+
+from html import escape
class Player(UI):
def __init__(self, k, source, loop=None, jumps=None):
video_id = source
if isinstance(source, Tracker):
trk = source
video_id = trk.res.video_id
else:
res = Resource(video_id, k.imagine)
trk = Tracker(res)
self.video_id = video_id
- video = kdb.get_video(video_id)
- channel = kdb.get_channel(video['channel'])
- thumb = media.get_video_thumbnail(channel['ytid'], video['ytid'])
+ self.video = kdb.get_video(video_id)
+ self.channel = kdb.get_channel(self.video['channel'])
+ thumb = media.get_video_thumbnail(
+ self.channel['ytid'], self.video['ytid'])
thumb = pygame.image.load(thumb)
super().__init__(k, trk, thumb, loop, jumps)
+ self.btn_chaos = pygame_gui.elements.UIButton(
+ text='?!',
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((10, 420), (120, 25)))
+ self.panel_chaos = Chaos(self)
+
+ self.btn_general = pygame_gui.elements.UIButton(
+ text='General',
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((10, 445), (120, 25)))
+
+ self.btn_desc = pygame_gui.elements.UIButton(
+ text='Description',
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((10, 470), (120, 25)))
+
+ self.btn_streams = pygame_gui.elements.UIButton(
+ text='Streams',
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((10, 495), (120, 25)))
+
+ self.btn_keywords = pygame_gui.elements.UIButton(
+ text='Keywords',
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((10, 520), (120, 25)))
+
+ self.btn_caps = pygame_gui.elements.UIButton(
+ text='Captions',
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((10, 545), (120, 25)))
+
+ self.btn_labels = pygame_gui.elements.UIButton(
+ text='Labels',
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((10, 570), (120, 25)))
+
+ self.cur_btn = self.btn_chaos
+ self.cur_btn.disable()
+ self.cur_panel = self.panel_chaos
+
def kill(self, replace=False):
super().kill(replace)
self.trk.res.kill()
def save(self):
frag = self.k.frag(kdb.MEDIA_VIDEO, self.video_id, self.trk.begin,
self.trk.end)
media.copy_thumbnail(self.video_id, self.k.project(), frag)
self.k.clip(frag, self.loop, self.loop_begin, self.loop_end, self.jumps)
self.k.focus_clip(frag)
def clip(self):
frag = self.k.frag(kdb.MEDIA_VIDEO, self.video_id, self.loop_begin,
self.loop_end)
media.copy_thumbnail(self.video_id, self.k.project(), frag)
self.k.clip_naked(frag)
self.k.focus_clip(frag)
def seq(self):
frag = self.k.frag(kdb.MEDIA_VIDEO, self.video_id, self.loop_begin,
self.loop_end)
media.copy_thumbnail(self.video_id, self.k.project(), frag)
seg = self.k.seg(frag)
self.k.focus_seg(seg)
+ def panel_swap(self, btn, panel):
+ super().panel_swap(btn, panel, self.cur_panel is not self.panel_chaos)
+
+ def click(self, element, target):
+ if element is self.btn_chaos:
+ self.panel_swap(self.btn_chaos, self.panel_chaos)
+
+ if element is self.btn_general:
+ self.k.job(self.click_general)
+
+ elif element is self.btn_desc:
+ self.k.job(self.click_desc)
+
+ elif element is self.btn_streams:
+ self.panel_swap(self.btn_streams, None)
+
+ elif element is self.btn_keywords:
+ self.panel_swap(self.btn_keywords, None)
+
+ elif element is self.btn_caps:
+ self.panel_swap(self.btn_caps, None)
+
+ elif element is self.btn_labels:
+ self.panel_swap(self.btn_labels, None)
+
+ else:
+ if not self.cur_panel.click(element, target):
+ return super().click(element, target)
+
+ return True
+
+ def click_general(self):
+ self.panel_swap(self.btn_general, General(self))
+
+ def click_desc(self):
+ self.panel_swap(self.btn_desc, Description(self))
+
+
+class Chaos(KPanel):
+ def __init__(self, p):
+ super().__init__(p.k, None, p.container, PRACK, 1)
+
+ self.image = pygame_gui.elements.UIImage(
+ image_surface=IMAGE,
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((0, 0), (PRACK[2], PRACK[3])))
+
+
+class General(KPanel):
+ def __init__(self, p):
+ super().__init__(p.k, None, p.container, PRACK, 1)
+
+ self.lbl_title = pygame_gui.elements.UILabel(
+ text='Title:',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((33, 5), (-1, -1)))
+
+ self.txt_title = pygame_gui.elements.UITextBox(
+ html_text=escape(p.video['title']),
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((80, 0), (PRACK[2]-80, 110)))
+
+ self.lbl_author = pygame_gui.elements.UILabel(
+ text='Author:',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((24, 115), (-1, -1)))
+
+ self.txt_author = pygame_gui.elements.UITextEntryLine(
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((80, 110), (PRACK[2]-80, -1)))
+ self.txt_author.set_text(p.video['author'])
+ self.txt_author.disable()
+
+ self.lbl_length = pygame_gui.elements.UILabel(
+ text='Length:',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((24, 150), (-1, -1)))
+
+ self.txt_length = pygame_gui.elements.UITextEntryLine(
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((80, 145), (80, -1)))
+ self.txt_length.set_text(hhmmss(p.video['length']))
+ self.txt_length.disable()
+
+ self.lbl_pub = pygame_gui.elements.UILabel(
+ text='Published:',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((180, 150), (-1, -1)))
+
+ self.txt_pub = pygame_gui.elements.UITextEntryLine(
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((260, 145), (PRACK[2]-260, -1)))
+ self.txt_pub.set_text(str(p.video['published'].date())) # no time
+ self.txt_pub.disable()
+
+ self.lbl_url = pygame_gui.elements.UILabel(
+ text='URL:',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((48, 185), (-1, -1)))
+
+ url = 'https://youtu.be/' + p.video['ytid']
+ self.txt_url = pygame_gui.elements.UITextBox(
+ html_text=f'<a href="{url}">{url}</a>',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((80, 180), (PRACK[2]-80, 35)))
+
+ self.lbl_id = pygame_gui.elements.UILabel(
+ text='ID:',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((266, 220), (-1, -1)))
+
+ self.txt_id = pygame_gui.elements.UITextBox(
+ html_text=f'<a href="{p.video_id}">{p.video_id}</a>',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((290, 215), (PRACK[2]-290, 35)))
+
+ self.lbl_ret = pygame_gui.elements.UILabel(
+ text='Retrieved:',
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((0, 220), (-1, -1)))
+
+ self.txt_ret = pygame_gui.elements.UITextEntryLine(
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((80, 215), (165, -1)))
+ self.txt_ret.set_text(date_time(p.video['retrieved']))
+ self.txt_ret.disable()
+
+ def click(self, element, target):
+ if element is self.txt_id:
+ self.k.focus_video(target)
+
+ else:
+ return False
+
+ return True
+
+
+class Description(KPanel):
+ def __init__(self, p):
+ super().__init__(p.k, None, p.container, PRACK, 1)
+
+ self.txt = pygame_gui.elements.UITextBox(
+ html_text=escape(p.video['description']),
+ manager=self.k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((0, 0), (PRACK[2], PRACK[3])))
+
diff --git a/k/ui.py b/k/ui.py
--- a/k/ui.py
+++ b/k/ui.py
@@ -1,339 +1,343 @@
import colorama as c
print('U.I. '+c.Fore.BLACK+c.Style.BRIGHT+'chaos'+c.Style.RESET_ALL+' begins')
import pygame
import pygame_gui
from contextlib import AbstractContextManager
import time
WIDTH = 1042
HEIGHT = 666
STATUS = 33 # status bar height
PWIDTH = 505 # player width
PHEIGHT = 284 # player height
MODES = {
'N': 'normal.png', # nothing specifically
'E': 'error.png', # something went wrong
'B': 'busy.png', # generic "doing something"
'D': 'txfr.png', # downloading
}
LOG_DISABLE = [
'meta tick',
'meta kick',
'kush key',
]
BLACK = ( 0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = ( 0, 255, 0)
BLUE = ( 0, 0, 255)
YELLOW = (255, 255, 0)
ORANGE = (255, 128, 0)
SPACER = pygame.Rect((10, 10), (-1, -1))
PANEL_SPACER = pygame.Rect((10, 10), (WIDTH-20, HEIGHT-100)) #FIXME
ANCHOR = {"left":"left", "top":"top", "right":"left", "bottom":"top"}
SAMPLE_RATE = 44100
# A generic object
class Meta():
def __init__(self):
pass
def target(element, direction='left', anchors=ANCHOR):
anchors = anchors.copy()
anchors[direction+'_target'] = element
return anchors
def scroll_to_bottom(container):
scroll = container.vert_scroll_bar
if not scroll:
return
scroll.scroll_position = scroll.bottom_limit \
- scroll.sliding_button.relative_rect.height
scroll.start_percentage = scroll.scroll_position \
/ scroll.scrollable_height
scroll.has_moved_recently = True
scroll.redraw_scrollbar()
def hhmmss(secs, millis=False):
s = int(secs % 60)
m = int(secs / 60)
h = int(m / 60)
m = m % 60
if s < 10:
s = f'0{s}'
if m < 10:
m = f'0{m}'
if h < 10:
h = f'0{h}'
text = f'{h}:{m}:{s}'
if millis:
millis = int((secs % 1) * 1000)
text += f'.{millis}'
return text
+def date_time(dt):
+ return dt.strftime('%Y-%m-%d %H:%M:%S')
+
class KGUI(pygame_gui.UIManager):
def __init__(self, resolution):
super().__init__(resolution)
def set_focus_set(self, focus):
old_set = self.focused_set
super().set_focus_set(focus)
new_set = self.focused_set
fix_text = False
if old_set is not None:
for item in old_set:
if isinstance(item, pygame_gui.elements.UITextEntryLine):
fix_text = True
break
if fix_text:
if new_set is not None:
for item in new_set:
if isinstance(item, pygame_gui.elements.UITextEntryLine):
fix_text = False
break
if fix_text:
#print('resetting key repeat')
pygame.key.set_repeat(0)
class KPanel:
def __init__(self, k, anchors=None, container=None,
relative_rect=PANEL_SPACER, visible=0):
self.k = k
self.container = pygame_gui.core.UIContainer(
manager=k.gui,
container=container,
anchors=anchors,
relative_rect=relative_rect,
visible=visible)
def kill(self):
self.container.kill()
def show(self):
self.container.show()
def hide(self):
self.container.hide()
def keydown(self, key, mod):
- pass
+ return False
def keyup(self, key, mod):
- pass
+ return False
def click(self, element, target=None):
- pass
+ return False
def get_rect(self):
return self.container.get_relative_rect()
def set_position(self, pos):
self.container.set_relative_position(pos)
def move_by(self, dx, dy):
pos = self.get_rect()
x = pos[0] + dx
y = pos[1] + dy
self.set_position((x, y))
- def panel_swap(self, btn, panel):
- self.cur_btn.enable()
+ def panel_swap(self, btn, panel, kill=False):
+ if self.cur_btn: self.cur_btn.enable()
self.cur_btn = btn
- self.cur_btn.disable()
+ if self.cur_btn: self.cur_btn.disable()
- self.cur_panel.hide()
+ if self.cur_panel:
+ self.cur_panel.kill() if kill else self.cur_panel.hide()
self.cur_panel = panel
- self.cur_panel.show()
+ if self.cur_panel: self.cur_panel.show()
class Clock():
def __init__(self, fps=999):
self.fps = fps
self.reset()
def reset(self):
self.started = time.perf_counter()
self.last = self.started
self.last_frame = 0
def tick(self):
last = self.last
self.last = time.perf_counter()
return self.last - last
def ready(self):
next_frame = self._next_()
if self.last >= next_frame:
#self.last_frame = self.last
self._set_()
return True
else:
return False
def wait(self):
next_frame = self._next_()
now = time.perf_counter()
#print(f' {next_frame} {now}')
delta = next_frame - now
#print(f' {delta}')
if delta > 0:
#print('waiting')
time.sleep(delta)
self._set_()
def _next_(self):
frames = int((self.last_frame - self.started) * self.fps)
next_frame = self.started + ((frames + 1) / self.fps)
#print(f'{frames} {self.last} {self.last_frame} {next_frame}')
return next_frame
def _set_(self):
self.last_frame = time.perf_counter()
#def get(self):
# return 1 / (time.perf_counter() - self.last)
class NullClock(Clock):
def __init__(self):
super().__init__(fps=None)
def _next_(self):
return 0
class Counter(AbstractContextManager):
def __init__(self):
super().__init__()
self.score = [ ]
self.start()
def __enter__(self):
self.start()
return self
def __exit__(self, exc_type=None, exc_value=None, traceback=None):
self.stop()
return None
def start(self):
self.started = time.perf_counter()
def stop(self):
now = time.perf_counter()
self.score.append((now, now - self.started))
cut = 0
for then, count in self.score:
if now - then < 15:
break
cut += 1
del self.score[:cut]
def score1(self):
return self._scoreX_(1)
def score5(self):
return self._scoreX_(5)
def score15(self):
return self._scoreX_(15)
def _scoreX_(self, x):
now = time.perf_counter()
entries = 0
score = 0
for then, count in reversed(self.score):
if now - then >= x:
break
entries += 1
score += count
return (entries/x, score/x)
@staticmethod
def _score_(score):
fc = c.Style.BRIGHT + f'{round(score[0])}' + c.Style.RESET_ALL
pc = f'{score[1]*100:.0f}'
ipc = int(pc)
if ipc == '0':
pc = c.Fore.WHITE + c.Back.GREEN + c.Style.BRIGHT + pc
elif ipc < 10:
pc = c.Fore.GREEN + c.Style.BRIGHT + pc
elif ipc <= 18:
pc = c.Fore.GREEN + pc
elif ipc <= 42:
pc = c.Fore.YELLOW + c.Style.BRIGHT + pc
elif ipc < 81:
pc = c.Fore.YELLOW + pc # looks like orange in my terminal
elif ipc < 90:
pc = c.Fore.RED + c.Style.BRIGHT + pc # dark orange --lannocc
else:
pc = c.Fore.RED + pc
pc += c.Style.RESET_ALL
return f'{fc}/{pc}'
def __str__(self):
s1 = Counter._score_(self.score1())
s5 = Counter._score_(self.score5())
s15 = Counter._score_(self.score15())
return f'{s1} {s5} {s15}'
def __add__(self, other):
result = Counter()
result.score = sorted(self.score + other.score)
return result
DEBUG_EVENTS = {
pygame_gui.UI_BUTTON_PRESSED: 'UI_BUTTON_PRESSED',
pygame_gui.UI_BUTTON_START_PRESS: 'UI_BUTTON_START_PRESS',
pygame_gui.UI_BUTTON_DOUBLE_CLICKED: 'UI_BUTTON_DOUBLE_CLICKED',
pygame_gui.UI_BUTTON_ON_HOVERED: 'UI_BUTTON_ON_HOVERED',
pygame_gui.UI_BUTTON_ON_UNHOVERED: 'UI_BUTTON_ON_UNHOVERED',
pygame_gui.UI_TEXT_ENTRY_CHANGED: 'UI_TEXT_ENTRY_CHANGED',
pygame_gui.UI_TEXT_ENTRY_FINISHED: 'UI_TEXT_ENTRY_FINISHED',
pygame_gui.UI_HORIZONTAL_SLIDER_MOVED: 'UI_HORIZONTAL_SLIDER_MOVED',
}
def debug_event(event):
if event.type in DEBUG_EVENTS:
print(f'^{DEBUG_EVENTS[event.type]}')
diff --git a/k/video/library.py b/k/video/library.py
--- a/k/video/library.py
+++ b/k/video/library.py
@@ -1,399 +1,392 @@
from k.ui import *
import k.db as kdb
import k.storage as media
from k.player.video import Player
from html import escape
class Panel(KPanel):
def __init__(self, k, anchors, container):
super().__init__(k, anchors, container)
self.con_channels = None
self.con_labels = None
self.con_videos = None
self.label_filter = [ ]
#self.lbl_label = pygame_gui.elements.UILabel(
# text='Label:',
# manager=self.k.gui,
# container=self.container,
# relative_rect=pygame.Rect((250, 0), (-1, -1)))
self.lbl_search = pygame_gui.elements.UILabel(
text='Search:',
manager=self.k.gui,
container=self.container,
relative_rect=pygame.Rect((250, 130), (60, -1)))
self.inp_search = pygame_gui.elements.UITextEntryLine(
manager=self.k.gui,
container=self.container,
relative_rect=pygame.Rect((310, 125), (190, -1)))
self.btn_title = pygame_gui.elements.UIButton(
text='Title',
manager=self.k.gui,
container=self.container,
relative_rect=pygame.Rect((255, 160), (120, 25)))
self.btn_desc = pygame_gui.elements.UIButton(
text='Description',
manager=self.k.gui,
container=self.container,
relative_rect=pygame.Rect((375, 160), (120, 25)))
self.btn_keyword = pygame_gui.elements.UIButton(
text='Keyword',
manager=self.k.gui,
container=self.container,
relative_rect=pygame.Rect((255, 185), (120, 25)))
self.btn_captions = pygame_gui.elements.UIButton(
text='Captions',
manager=self.k.gui,
container=self.container,
relative_rect=pygame.Rect((375, 185), (120, 25)))
self.refresh()
def refresh(self, labels=True, visible=False):
if self.con_channels:
self.con_channels.kill()
if self.con_videos:
self.con_videos.kill()
self.con_channels = pygame_gui.elements.UIScrollingContainer(
manager=self.k.gui,
container=self.container,
anchors=ANCHOR,
relative_rect=pygame.Rect((10, 10), (230, 200)))
self.btn_all_channels = pygame_gui.elements.UIButton(
text='(all channels)',
manager=self.k.gui,
container=self.con_channels.get_container(),
relative_rect=pygame.Rect((0, 0), (200, 25)))
self.cur_btn_channel = None
self.channels = [ ]
y = 25
if self.label_filter:
channels = kdb.list_channels_by_label(self.label_filter)
else:
channels = kdb.list_channels()
for channel in channels:
entry = ChannelEntry(self.k,
self.con_channels.get_container(), y, channel)
self.channels.append(entry)
y += entry.get_rect().height
self.con_channels.set_scrollable_area_dimensions((200, y))
if visible:
self.con_channels.hide()
self.con_channels.show()
if labels:
if self.con_labels:
self.con_labels.kill()
self.con_labels = pygame_gui.elements.UIScrollingContainer(
manager=self.k.gui,
container=self.container,
anchors=ANCHOR,
relative_rect=pygame.Rect((260, 10), (230, 100)))
self.btn_any_label = pygame_gui.elements.UIButton(
text='(any label)',
manager=self.k.gui,
container=self.con_labels.get_container(),
relative_rect=pygame.Rect((0, 0), (200, 25)))
self.btn_any_label.disable()
self.labels = [ ]
y = 25
for label in kdb.list_labels():
entry = LabelEntry(self.k,
self.con_labels.get_container(), y, label)
self.labels.append(entry)
y += entry.get_rect().height
self.con_labels.set_scrollable_area_dimensions((200, y))
if visible:
self.con_labels.hide()
self.con_labels.show()
self.inp_search.set_text('')
def refresh_videos(self, channel_id=None, search_title=None,
search_description=None, search_keyword=None,
search_captions=None):
if not search_title and not search_description and not search_keyword \
and not search_captions:
self.inp_search.set_text('')
if self.con_videos:
self.con_videos.kill()
self.con_videos = pygame_gui.elements.UIScrollingContainer(
manager=self.k.gui,
container=self.container,
anchors=target(self.con_channels, 'top'),
relative_rect=pygame.Rect((10, 10), (500, 300)))
self.videos = [ ]
y = 0
for video in kdb.list_videos(self.label_filter, channel_id,
search_title, search_description, search_keyword,
search_captions):
entry = VideoEntry(self.k,
self.con_videos.get_container(), y, video)
self.videos.append(entry)
y += entry.get_rect().height
self.con_videos.set_scrollable_area_dimensions((470, y))
def refresh_video(self, video_id):
if self.cur_btn_channel:
self.cur_btn_channel.enable()
self.cur_btn_channel = None
self.inp_search.set_text('')
if self.con_videos:
self.con_videos.kill()
self.con_videos = pygame_gui.elements.UIScrollingContainer(
manager=self.k.gui,
container=self.container,
anchors=target(self.con_channels, 'top'),
relative_rect=pygame.Rect((10, 10), (500, 300)))
self.videos = [ ]
entry = VideoEntry(self.k, self.con_videos.get_container(), 0,
kdb.list_video(video_id))
self.videos.append(entry)
self.con_videos.set_scrollable_area_dimensions(
(470, entry.get_rect().height))
def click(self, element, target=None):
if element == self.btn_all_channels:
if self.cur_btn_channel:
self.cur_btn_channel.enable()
self.cur_btn_channel = self.btn_all_channels
self.cur_btn_channel.disable()
self.k.job(self.refresh_videos)
elif element == self.btn_any_label:
self.k.job(self.clear_labels)
elif element == self.btn_title:
search = self.inp_search.get_text()
if not search:
return
if self.cur_btn_channel:
self.cur_btn_channel.enable()
self.cur_btn_channel = None
self.refresh_videos(search_title=search)
elif element == self.btn_desc:
search = self.inp_search.get_text()
if not search:
return
if self.cur_btn_channel:
self.cur_btn_channel.enable()
self.cur_btn_channel = None
self.refresh_videos(search_description=search)
elif element == self.btn_keyword:
search = self.inp_search.get_text()
if not search:
return
if self.cur_btn_channel:
self.cur_btn_channel.enable()
self.cur_btn_channel = None
self.refresh_videos(search_keyword=search)
elif element == self.btn_captions:
search = self.inp_search.get_text()
if not search:
return
if self.cur_btn_channel:
self.cur_btn_channel.enable()
self.cur_btn_channel = None
self.refresh_videos(search_captions=search)
else:
for channel in self.channels:
channel.click(element, target)
for label in self.labels:
label.click(element, target)
if self.con_videos:
for video in self.videos:
video.click(element, target)
def clear_labels(self):
self.label_filter = [ ]
self.refresh(True, True)
class ChannelEntry(KPanel):
def __init__(self, k, container, y, channel):
super().__init__(k, container=container, relative_rect=pygame.Rect(
(0, y), (200, 25)))
self.channel_id = channel['id']
self.btn_name = pygame_gui.elements.UIButton(
text=channel['name'],
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((0, 0), (200, 25)))
def click(self, element, target=None):
if element == self.btn_name:
panel = self.k.panel_video.panel_library
if panel.cur_btn_channel:
panel.cur_btn_channel.enable()
panel.cur_btn_channel = self.btn_name
panel.cur_btn_channel.disable()
self.k.job(self.refresh)
def refresh(self):
self.k.panel_video.panel_library.refresh_videos(self.channel_id)
class LabelEntry(KPanel):
def __init__(self, k, container, y, label):
super().__init__(k, container=container, relative_rect=pygame.Rect(
(0, y), (200, 25)))
self.label_id = label['id']
self.name = label['name']
try:
panel = self.k.panel_video.panel_library
x = 'x' if self.label_id in panel.label_filter else ' '
except AttributeError:
x = ' '
self.btn_name = pygame_gui.elements.UIButton(
text=f'[{x}] {self.name}',
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((0, 0), (200, 25)))
def click(self, element, target=None):
if element == self.btn_name:
self.k.job(self.toggle)
def toggle(self):
panel = self.k.panel_video.panel_library
if self.label_id in panel.label_filter:
idx = panel.label_filter.index(self.label_id)
del panel.label_filter[idx]
self.btn_name.set_text(f'[ ] {self.name}')
if not panel.label_filter:
panel.btn_any_label.disable()
else:
panel.label_filter.append(self.label_id)
self.btn_name.set_text(f'[x] {self.name}')
panel.btn_any_label.enable()
panel.refresh(False, True)
class VideoEntry(KPanel):
def __init__(self, k, container, y, video):
super().__init__(k, container=container, relative_rect=pygame.Rect(
(0, y), (470, 80)), visible=1)
self.video_id = video['id']
self.ready = video['retrieved'] is not None
self.img_thumb = pygame_gui.elements.UIImage(
image_surface=pygame.image.load(
media.get_video_thumbnail(video['cytid'], video['ytid'])),
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((0, 0), (100, 75)))
self.txt_title = pygame_gui.elements.UITextBox(
html_text=escape(video['title']),
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((100, 0), (290, 75)))
self.btn_play = pygame_gui.elements.UIButton(
text=('Play' if self.ready else 'Get'),
manager=k.gui,
container=self.container,
- relative_rect=pygame.Rect((390, 0), (80, 25)))
-
- self.btn_info = pygame_gui.elements.UIButton(
- text='Info',
- manager=k.gui,
- container=self.container,
- relative_rect=pygame.Rect((390, 25), (80, 25)))
- self.btn_info.disable() #FIXME
+ relative_rect=pygame.Rect((390, 0), (80, 50)))
self.btn_delete = pygame_gui.elements.UIButton(
text='Delete',
manager=k.gui,
container=self.container,
relative_rect=pygame.Rect((390, 50), (80, 25)))
self.btn_delete.disable() #FIXME
def click(self, element, target=None):
if element == self.btn_play:
if self.ready:
self.k.job(self.play)
else:
self.btn_play.set_text('...')
self.btn_play.disable()
self.k.job(self._get_, 'D')
def play(self):
self.k.player.open(Player(self.k, self.video_id))
self.k.player.play()
def _get_(self):
try:
media.finish_adding_video(self.video_id)
self.ready = True
self.k.job(self._get_audio_, 'B')
except Exception as e:
self.btn_play.enable()
self.btn_play.set_text('!!!')
raise e
def _get_audio_(self):
try:
media.extract_audio_from_video(self.video_id)
self.btn_play.enable()
self.btn_play.set_text('Play')
print('FINISHED ADDING')
except Exception as e:
self.btn_play.enable()
self.btn_play.set_text('!!!')
diff --git a/k/video/youtube.py b/k/video/youtube.py
--- a/k/video/youtube.py
+++ b/k/video/youtube.py
@@ -1,271 +1,268 @@
from k.ui import *
import k.db as kdb
import k.storage as media
from pytube import YouTube, Channel, Playlist, Search
from pytube.exceptions import *
from urllib.request import urlretrieve
YT_RESULT_HEIGHT = 100
class Panel(KPanel):
def __init__(self, k, anchors, container):
super().__init__(k, anchors, container)
self.btn_clear = pygame_gui.elements.UIButton(
text='X',
manager=k.gui,
container=self.container,
anchors=ANCHOR,
relative_rect=SPACER)
self.btn_paste = pygame_gui.elements.UIButton(
text='P',
manager=k.gui,
container=self.container,
anchors=target(self.btn_clear),
relative_rect=pygame.Rect((0, 10), (-1, -1)))
self.input = pygame_gui.elements.UITextEntryLine(
manager=k.gui,
container=self.container,
anchors=target(self.btn_paste),
relative_rect=pygame.Rect((10, 10), (420, -1)))
self.btn_video = pygame_gui.elements.UIButton(
text='Video',
manager=k.gui,
container=self.container,
anchors=target(self.input, 'top', target(self.btn_paste)),
relative_rect=SPACER)
self.btn_channel = pygame_gui.elements.UIButton(
text='Channel',
manager=k.gui,
container=self.container,
anchors=target(self.input, 'top', target(self.btn_video)),
relative_rect=SPACER)
self.btn_playlist = pygame_gui.elements.UIButton(
text='Playlist',
manager=k.gui,
container=self.container,
anchors=target(self.input, 'top', target(self.btn_channel)),
relative_rect=SPACER)
self.btn_search = pygame_gui.elements.UIButton(
text='Search',
manager=k.gui,
container=self.container,
anchors=target(self.input, 'top', target(self.btn_playlist)),
relative_rect=SPACER)
self.results = None
self.ytresults = None
def click(self, element, target=None):
if element == self.btn_clear:
self.clear_results()
self.input.set_text('')
self.input.focus()
elif element == self.btn_paste:
for scrap in pygame.scrap.get_types():
print(scrap)
if scrap.startswith('text/'):
text = str(pygame.scrap.get(scrap))
if text:
self.input.set_text(text)
self.input.focus()
elif element == self.btn_video:
self.btn_video.disable()
self.k.job(self.get_video, 'D')
elif element == self.btn_channel:
self.btn_channel.disable()
self.k.job(self.get_channel, 'D')
elif element == self.btn_playlist:
self.btn_playlist.disable()
self.k.job(self.get_playlist, 'D')
elif element == self.btn_search:
self.btn_search.disable()
self.k.job(self.get_search, 'D')
elif self.ytresults:
for result in self.ytresults:
result.click(element, target)
def get_video(self):
self.clear_results()
url = self.input.get_text()
try:
yt = YouTube(url)
self.show_results([yt])
except PytubeError:
print('check video url')
self.btn_video.enable()
def get_channel(self):
self.clear_results()
url = self.input.get_text()
try:
yt = Channel(url)
self.show_results(yt.videos)
except PytubeError:
print('check channel url')
self.btn_channel.enable()
def get_playlist(self):
self.clear_results()
url = self.input.get_text()
try:
yt = Playlist(url)
self.show_results(yt.videos)
except PytubeError:
print('check playlist url')
except KeyError:
print('check playlist url')
self.btn_playlist.enable()
def get_search(self):
self.clear_results()
query = self.input.get_text()
try:
yt = Search(query)
self.show_results(yt.results)
except PytubeError:
print('something went wrong')
self.btn_search.enable()
def clear_results(self):
if self.results:
self.ytresults = None
self.results.kill()
self.results = None
def show_results(self, videos):
self.results = pygame_gui.elements.UIScrollingContainer(
manager=self.k.gui,
container=self.container,
anchors=target(self.btn_search, 'top'),
relative_rect=pygame.Rect((10, 10), (500, 400)))
self.results.set_scrollable_area_dimensions((480,
YT_RESULT_HEIGHT*len(videos)))
self.ytresults = []
row = 0
for video in videos:
#print(video)
- self.ytresults.append(Result(self.k,
+ self.ytresults.append(Entry(self.k,
self.results.get_container(),
pygame.Rect((9, row*YT_RESULT_HEIGHT), (480, YT_RESULT_HEIGHT)),
video, row))
row+=1
-class Result(KPanel):
+class Entry(KPanel):
def __init__(self, k, container, relative_rect, video, index):
super().__init__(k, container=container,
relative_rect=relative_rect, visible=1)
self.video_id = None
self.video = video
self.thumb = f'/tmp/k-os.thumb-{index}' #FIXME
urlretrieve(video.thumbnail_url, self.thumb)
- self.img_thumb = pygame_gui.elements.UIImage(
- image_surface=pygame.image.load(self.thumb),
- manager=k.gui,
- container=self.container,
- relative_rect=pygame.Rect((0, 0), (128, 96)))
-
self.lbl_name = pygame_gui.elements.UILabel(
text=video.title,
manager=k.gui,
container=self.container,
- relative_rect=pygame.Rect((133, 0), (340, -1)))
+ relative_rect=pygame.Rect((0, 0), (480, -1)))
+
+ self.img_thumb = pygame_gui.elements.UIImage(
+ image_surface=pygame.image.load(self.thumb),
+ manager=k.gui,
+ container=self.container,
+ relative_rect=pygame.Rect((0, 25), (100, 75)))
self.lbl_author = pygame_gui.elements.UILabel(
- text=f'by: {video.author}',
+ text=video.author,
manager=k.gui,
container=self.container,
- relative_rect=pygame.Rect((133, 20), (340, -1)))
+ relative_rect=pygame.Rect((100, 30), (280, -1)))
self.lbl_published = pygame_gui.elements.UILabel(
- text=f'on: {video.publish_date}',
+ text=str(video.publish_date.date()),
manager=k.gui,
container=self.container,
- relative_rect=pygame.Rect((133, 40), (340, -1)))
+ relative_rect=pygame.Rect((100, 50), (280, -1)))
self.lbl_runtime = pygame_gui.elements.UILabel(
- text=f'{video.length} seconds',
+ text=hhmmss(video.length),
manager=k.gui,
container=self.container,
- relative_rect=pygame.Rect((133, 60), (340, -1)))
+ relative_rect=pygame.Rect((100, 75), (280, -1)))
self.btn_add = pygame_gui.elements.UIButton(
text='Get',
manager=k.gui,
container=self.container,
- relative_rect=pygame.Rect((380, 20), (77, 66)))
+ relative_rect=pygame.Rect((380, 25), (88, 75)))
self.video_id = kdb.id_video(video.video_id)
if self.video_id:
self.btn_add.set_text('Show')
def click(self, element, target=None):
if element == self.btn_add:
if not self.video_id:
self.btn_add.set_text('...')
self.btn_add.disable()
self.k.job(self._get_, 'D')
else:
- panel = self.k.panel_video.panel_library
- panel.refresh_video(self.video_id)
- self.k.panel_video.panel_swap(self.k.panel_video.btn_library,
- panel)
+ self.k.focus_video(self.video_id)
def _get_(self):
#print(f'video: {self.video}')
try:
self.video_id = media.add_video_to_library(self.video)
self.k.job(self._get_audio_, 'B')
except Exception as e:
self.btn_add.enable()
self.btn_add.set_text('!!!')
raise e
def _get_audio_(self):
try:
media.extract_audio_from_video(self.video_id)
self.k.panel_video.panel_library.refresh()
self.btn_add.enable()
self.btn_add.set_text('Show')
print('FINISHED ADDING')
except Exception as e:
self.btn_add.enable()
self.btn_add.set_text('!!!')
raise e
diff --git a/version.py b/version.py
--- a/version.py
+++ b/version.py
@@ -1,6 +1,8 @@
-CHAOS="5.21 yelawolf 12+13/2"
+CHAOS="5.23 polog 04+20/2"
+THEY="yahoo.com"
SAW="LANNOCC"
-ME="@ yahoo.com"
+ME="shawn"
+
print(CHAOS+' --'+SAW)
'''can you help?'''

File Metadata

Mime Type
text/x-diff
Expires
Sun, Sep 13, 9:26 AM (2 w, 3 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3508
Default Alt Text
(118 KB)

Event Timeline