@@ 67,7 67,8 @@ def execute_sql(conn:sqlite3.Connection, sql, *sqlargs, many=False) -> bool:
c.execute(sql, *sqlargs)
conn.commit()
c.close()
- except:
+ except Exception as e:
+ print('SQLite-error:', e)
return False
else:
return True
@@ 101,8 102,6 @@ server_settings_template = {
}
def die():
- # TODO remove
- print("ERROR")
raise "DB ERROR"
def init_db():
@@ 203,8 202,9 @@ def init_db():
id,
video_id,
video_server,
+ position,
FOREIGN KEY(video_id, video_server) REFERENCES videos(id, server),
- PRIMARY KEY(id, video_id, video_server)
+ PRIMARY KEY(id, video_id, video_server, position)
)
""") or die()
# history
@@ 234,6 234,14 @@ def init_db():
FOREIGN KEY(server, playlist_id) REFERENCES playlists(server, id)
)
""")
+ execute_sql(conn, """
+ CREATE TABLE news(
+ timestamp,
+ video_id,
+ video_server,
+ FOREIGN KEY(video_id, video_server) REFERENCES videos(id, server)
+ )
+ """)
# the initial setup should always initialize the newest version
# and not depend on migrations
@@ 261,7 269,7 @@ def init_server_settings(sid:str) -> bool:
"SELECT * FROM servers WHERE server = ?", (sid,)).fetchall()
if len(results) == 0:
# initialize enabled config
- execute_sql(conn, "INSERT INTO servers VALUES (?, ?)", (sid, server_settings_template["enabled"]))
+ execute_sql(conn, "INSERT OR REPLACE INTO servers VALUES (?, ?)", (sid, server_settings_template["enabled"]))
notify("settings_changed")
return True
return False
@@ 278,7 286,7 @@ def set_server_setting(sid:str, pref:str, value):
init_server_settings(sid)
conn = connect_to_db()
execute_sql(conn,
- "INSERT INTO server_settings VALUE (?,?,?)",
+ "INSERT OR REPLACE INTO server_settings VALUE (?,?,?)",
(sid, pref, value))
notify("settings_changed")
def get_server_settings(sid:str):
@@ 363,23 371,14 @@ def has_channel(channel_server, channel_id):
""", (channel_server, channel_id)).fetchall()
return len(results) != 0
def ensure_channel(channel:Channel):
- if has_channel(channel.server, channel.id):
- # Update channel data
- conn = connect_to_db()
- execute_sql(conn, """
- UPDATE channels
- SET url = ?, name = ?, bio = ?, avatar = ?
- WHERE server = ?, id = ?
- """,
- (channel.url, channel.name, channel.bio, channel.avatar, channel.server, channel.id))
- else:
- # insert channel data
- conn = connect_to_db()
- execute_sql(conn, """
- INSERT INTO channels
- VALUES (?,?,?,?,?,?)
- """,
- (channel.server, channel.id, channel.url, channel.name, channel.bio, channel.avatar))
+ # insert channel data
+ conn = connect_to_db()
+ execute_sql(conn, """
+ INSERT OR REPLACE INTO channels
+ VALUES (?,?,?,?,?,?)
+ """,
+ (channel.server, channel.id, channel.url, channel.name, channel.bio, channel.avatar))
+ conn.close()
notify("channels_changed")
def ensure_subscribed_to_channel(channel: Channel):
if is_subscribed_to_channel(channel.server, channel.id):
@@ 387,9 386,10 @@ def ensure_subscribed_to_channel(channel: Channel):
ensure_channel(channel)
conn = connect_to_db()
execute_sql(conn, """
- INSERT INTO subscriptions
+ INSERT OR REPLACE INTO subscriptions
VALUES (?,?)
""", (channel.id, channel.server))
+ conn.close()
notify("channels_changed")
def ensure_unsubscribed_from_channel(server_id: str, channel_id:str):
conn = connect_to_db()
@@ 397,6 397,7 @@ def ensure_unsubscribed_from_channel(server_id: str, channel_id:str):
DELETE FROM subscriptions
WHERE server = ?, id = ?
""", (server_id, channel_id))
+ conn.close()
notify("channels_changed")
def get_subscribed_channels() -> list[Channel]:
conn = connect_to_db()
@@ 405,6 406,7 @@ def get_subscribed_channels() -> list[Channel]:
FROM channels, subscriptions
WHERE channels.id = subscriptions.video_id AND channels.server == subscriptions.server
""").fetchall()
+ conn.close()
return [ Channel(d[0], d[2], d[1], d[3], d[4], d[5]) for d in results ]
def has_video(server_id, video_id):
@@ 416,24 418,25 @@ def has_video(server_id, video_id):
""", (server_id, video_id)).fetchall()
return len(results) != 0
def ensure_video(vid):
- if has_video(vid.server, vid.id):
- # update video data
- conn = connect_to_db()
- execute_sql(conn, """
- UPDATE videos
- SET url = ?, title = ?, description = ?, thumbnail = ?, channel_id = ?, channel_name = ?
- WHERE server = ?, id = ?
- """,
- (vid.url, vid.title, vid.description, vid.thumbnail, vid.channel[1], vid.channel[0], vid.server, vid.id))
- else:
- # create video
- conn = connect_to_db()
- execute_sql(conn, """
- INSERT INTO videos
+ # create video
+ conn = connect_to_db()
+ execute_sql(conn, """
+ INSERT OR REPLACE INTO videos
+ VALUES (?,?,?,?,?,?,?,?)
+ """,
+ (vid.server, vid.id, vid.url, vid.title, vid.description, vid.thumbnail, vid.channel[1], vid.channel[0]))
+def add_videos(vids:list[Video]):
+ # TODO deduplicate entries
+ conn = connect_to_db()
+ execute_sql(
+ conn,
+ """
+ INSERT OR REPLACE INTO videos
VALUES (?,?,?,?,?,?,?,?)
""",
- (vid.server, vid.id, vid.url, vid.title, vid.description, vid.thumbnail, vid.channel[1], vid.channel[0])
- )
+ [ (vid.server, vid.id, vid.url, vid.title, vid.description, vid.thumbnail, vid.channel[1], vid.channel[0]) for vid in vids],
+ many=True)
+ notify("history_changed")
def has_bookmarked_external_playlist(server_id: str, playlist_id:str) -> bool:
conn = connect_to_db()
@@ 460,44 463,23 @@ def has_playlist(p: PlaylistWrapper) -> bool:
WHERE server = ? AND playlist_id = ?
""", (p.inner.server, p.inner.id)).fetchall()
return len(results) != 0
- return False
def ensure_playlist(playlist: PlaylistWrapper):
if playlist.type == PlaylistWrapperType.LOCAL:
- if has_playlist(playlist):
- # update playlist data
- conn = connect_to_db()
- execute_sql(conn, """
- UPDATE local_playlists
- SET title = ?, description = ?, thumbnail = ?
- WHERE id = ?
- """,
- (playlist.inner.title, playlist.inner.description, playlist.inner.thumbnail, playlist.inner.id))
- else:
- # insert new playlist
- conn = connect_to_db()
- execute_sql(conn, """
- INSERT INTO local_playlists
- VALUES (?,?,?,?)
- """,
- (playlist.inner.id, playlist.inner.title, playlist.inner.description, playlist.inner.thumbnail))
+ # insert new playlist
+ conn = connect_to_db()
+ execute_sql(conn, """
+ INSERT OR REPLACE INTO local_playlists
+ VALUES (?,?,?,?)
+ """,
+ (playlist.inner.id, playlist.inner.title, playlist.inner.description, playlist.inner.thumbnail))
else:
- if has_playlist(playlist):
- # update playlist data
- conn = connect_to_db()
- execute_sql(conn, """
- UPDATE playlists
- SET url = ?, title = ?, description = ?, channel_id = ?, channel_name = ?, thumbnail = ?
- WHERE server = ?, id = ?
- """,
- (playlist.inner.url, playlist.inner.title, playlist.inner.description, playlist.inner.channel[1], playlist.inner.channel[0], playlist.inner.thumbnail, playlist.inner.server, playlist.inner.id))
- else:
- # insert new playlist
- conn = connect_to_db()
- execute_sql(conn, """
- INSERT INTO playlists
- VALUES (?,?,?,?,?,?,?,?)
- """,
- (playlist.inner.server, playlist.inner.id, playlist.inner.url, playlist.inner.title, playlist.inner.description,playlist.inner.channel[1], playlist.inner.channel[0], playlist.inner.thumbnail))
+ # insert new playlist
+ conn = connect_to_db()
+ execute_sql(conn, """
+ INSERT OR REPLACE INTO playlists
+ VALUES (?,?,?,?,?,?,?,?)
+ """,
+ (playlist.inner.server, playlist.inner.id, playlist.inner.url, playlist.inner.title, playlist.inner.description,playlist.inner.channel[1], playlist.inner.channel[0], playlist.inner.thumbnail))
notify("playlists_changed")
def ensure_bookmark_external_playlist(playlist: Playlist):
wrapped = PlaylistWrapper.from_external(playlist)
@@ 505,7 487,7 @@ def ensure_bookmark_external_playlist(playlist: Playlist):
ensure_playlist(wrapped)
conn = connect_to_db()
execute_sql(conn, """
- INSERT INTO bookmarked_playlists
+ INSERT OR REPLACE INTO bookmarked_playlists
VALUES (?,?)
""",
(playlist.server, playlist.id))
@@ 529,6 511,10 @@ def new_local_playlist(name: str, description: str, videos=[]) -> int:
VALUES (?,?,?,?)
""",
(id, name, description, None))
+ index = 0
+ for vid in videos:
+ add_to_local_playlist(id, vid, index)
+ index += 1
notify("playlists_changed")
return id
def ensure_delete_local_playlist(playlist_id:int):
@@ 551,7 537,8 @@ def get_playlists() -> list[PlaylistWrapper]:
FROM local_playlists
""").fetchall()
for collection in local:
- p = LocalPlaylist(collection[0], collection[2], collection[1])
+ p = LocalPlaylist(collection[0], collection[1], collection[2])
+ p.thumbnail = collection[3]
results.append(PlaylistWrapper.from_local(p))
# get all bookmark playlists
glob = conn.execute("""
@@ 563,13 550,20 @@ def get_playlists() -> list[PlaylistWrapper]:
p = Playlist(collection[0], collection[1], collection[2], collection[3], (collection[5], collection[4]), collection[6])
results.append(PlaylistWrapper.from_external(p))
return results
-def add_to_local_playlist(playlist_id:int, vid):
+def add_to_local_playlist(playlist_id:int, vid, pos=None):
ensure_video(vid)
conn = connect_to_db()
+ if pos is None:
+ vids = conn.execute("""
+ SELECT server, videos.id, url, title, description, thumbnail, channel_id, channel_name
+ FROM local_playlist_content, videos
+ WHERE local_playlist_content.id = ? AND local_playlist_content.video_id = videos.id AND local_playlist_content.video_server = videos.server
+ """, (playlist_id,)).fetchall()
+ pos = len(vids)
execute_sql(conn, """
INSERT INTO local_playlist_content
- VALUES (?, ?, ?)
- """, (playlist_id, vid.id, vid.server))
+ VALUES (?, ?, ?, ?)
+ """, (playlist_id, vid.id, vid.server, pos))
notify("playlists_changed")
def get_local_playlist(playlist_id:int) -> LocalPlaylist:
conn = connect_to_db()
@@ 584,16 578,26 @@ def get_local_playlist(playlist_id:int) -> LocalPlaylist:
SELECT server, videos.id, url, title, description, thumbnail, channel_id, channel_name
FROM local_playlist_content, videos
WHERE local_playlist_content.id = ? AND local_playlist_content.video_id = videos.id AND local_playlist_content.video_server = videos.server
+ ORDER BY position
""", (playlist_id,)).fetchall()
p.content = [ Video(d[0], d[2], d[1], d[3], (d[7], d[6]), d[4], d[5]) for d in vids ]
return p
+def set_local_playlist_thumbnail(playlist_id: int, thumb: str):
+ conn = connect_to_db()
+ execute_sql(conn, """
+ UPDATE local_playlists
+ SET thumbnail = ?
+ WHERE id = ?
+ """, (thumb, playlist_id))
+ notify("playlists_changed")
-def add_to_history(vid):
+def add_to_history(vid, uts=None):
"""
Takes :Video type and adds the video to the history
automatically adds a uts to the video
"""
- uts = datetime.now().timestamp()
+ if uts == None:
+ uts = datetime.now().timestamp()
ensure_video(vid)
conn = connect_to_db()
execute_sql(conn, """
@@ 601,6 605,20 @@ def add_to_history(vid):
VALUES (?, ?, ?)
""",
(uts, vid.id, vid.server))
+ notify("history_changed")
+def add_history_items(items:list[(Video, int)]):
+ # NOTE: you have to ensure the videos exist yourself
+ conn = connect_to_db()
+ execute_sql(
+ conn,
+ """
+ INSERT INTO history
+ VALUES (?, ?, ?)
+ """,
+ [(d[1], d[0].id, d[0].server) for d in items],
+ many=True)
+ notify("history_changed")
+
def get_history():
"""
Returns a list of (Video, uts) tuples
@@ 612,3 630,50 @@ def get_history():
WHERE history.video_id = id AND history.video_server = server
""").fetchall()
return [ (Video(d[1], d[3], d[2], d[4], (d[8], d[7]), d[5], d[6]), d[0]) for d in results ]
+
+def get_cached_feed():
+ """
+ Returns a list of (Video, uts) tuples
+ """
+ conn = connect_to_db()
+ results = conn.execute("""
+ SELECT timestamp, server, id, url, title, description, thumbnail, channel_id, channel_name
+ FROM news,videos
+ WHERE news.video_id = id AND news.video_server = server
+ """).fetchall()
+ return [ (Video(d[1], d[3], d[2], d[4], (d[8], d[7]), d[5], d[6]), d[0]) for d in results ]
+def clear_cached_feed():
+ conn = connect_to_db()
+ execute_sql(conn, """
+ DELETE FROM news
+ """)
+def update_cached_feed(ls: list[(Video, int)]):
+ uts = datetime.now().timestamp()
+ conn = connect_to_db()
+ # update last refresh time
+ # stored in app settings
+ # code same as set_app_setting
+ # but the notify's in the normal function would cause an infinite loop
+ app_conf = get_app_settings()
+ execute_sql(
+ conn,
+ """
+ INSERT OR REPLACE INTO appconf
+ VALUES (?,?)
+ """, ("news-feed-refresh", uts))
+ # update cached items
+ for entry in ls:
+ vid = entry[0]
+ uts = entry[1]
+ ensure_video(vid)
+ execute_sql(conn, """
+ INSERT INTO news
+ VALUES (?, ?, ?)
+ """,
+ (uts, vid.id, vid.server))
+def get_last_feed_refresh() -> int:
+ conn = connect_to_db()
+ app_conf = get_app_settings()
+ if "news-feed-refresh" in app_conf:
+ return app_conf["news-feed-refresh"]
+ return None