Commit e8005647 authored by Bruno Barcarol Guimarães's avatar Bruno Barcarol Guimarães
Browse files

Subscription tags

parent 5e5b01fd
......@@ -96,6 +96,7 @@ only update subscriptions that had a new video less than `s` seconds ago
tag_parser.add_argument('tag', type=str)
tag_parser.add_argument('items', type=str, nargs='*')
tag_parser.add_argument('--remove', action='store_true')
tag_parser.add_argument('--sub', action='store_true')
watched_parser = sub.add_parser('watched')
watched_parser.set_defaults(cmd=Subscriptions.watched)
watched_parser.add_argument('items', type=str, nargs='*')
......@@ -214,7 +215,9 @@ class Subscriptions(object):
def init(self):
c = self._conn.cursor()
c.execute('select name from sqlite_master where type="table"')
tables = {'subs', 'videos', 'tags', 'videos_tags'} - {x[0] for x in c}
tables = (
{'subs', 'videos', 'tags', 'subs_tags', 'videos_tags'}
- {x[0] for x in c})
if 'subs' in tables:
self._log('creating table subs')
c.execute(
......@@ -240,20 +243,31 @@ class Subscriptions(object):
'create table tags ('
'id integer not null primary key,'
' name text not null)')
if 'subs_tags' in tables:
self._log('creating table subs_tags')
c.execute(
'create table subs_tags ('
'id integer not null primary key,'
' sub integer not null,'
' tag integer not null,'
' foreign key(sub) references subs(id),'
' foreign key(tag) references tags(id))')
if 'videos_tags' in tables:
self._log('creating table videos_tags')
c.execute(
'create table videos_tags ('
'id integer not null primary key,'
'video integer not null,'
'tag integer not null,'
'foreign key(video) references videos(id),'
'foreign key(tag) references tags(id))')
' video integer not null,'
' tag integer not null,'
' foreign key(video) references videos(id),'
' foreign key(tag) references tags(id))')
def list(
self, ids: typing.Sequence[str]=(),
self, ids: typing.List[str]=[],
show_id: bool=None, unwatched: bool=None,
tags: typing.List[str]=None,
fields: typing.Optional[typing.Sequence[str]]=None):
args: typing.List[str] = ids or []
q = Query(table='subs')
q.add_order('subs.id')
fields = Subscriptions._parse_fields(
......@@ -266,7 +280,14 @@ class Subscriptions(object):
q.add_filter('name in ({})'.format(Query.make_args(len(ids))))
if unwatched:
q.add_group('subs.id')
c = self._conn.cursor().execute(q.query(), ids)
if tags:
q.add_joins(
'join (tags, subs_tags)'
' on (subs.id == subs_tags.sub and tags.id == subs_tags.tag)')
q.add_filter('(tags.name in ({}))'.format(
Query.make_args(len(tags))))
args.extend(tags)
c = self._conn.cursor().execute(q.query(distinct=bool(tags)), args)
for _ in map(print, map(' '.join, c)): pass
def list_videos(
......@@ -445,6 +466,11 @@ class Subscriptions(object):
c.execute(
'insert into videos (sub, yt_id, title) values (?, ?, ?)',
(sub_id, yt_id, title))
video_id: int = c.execute('select last_insert_rowid()').fetchone()[0]
c.execute(
'insert into videos_tags (video, tag) '
' select ?, tag from subs_tags where sub == ?',
(video_id, sub_id))
def _update_sub(
self, c: sqlite3.Cursor, sub_id: str,
......@@ -459,7 +485,7 @@ class Subscriptions(object):
def tag(
self, tag: str, items: typing.Collection[str]=(),
remove: bool=False):
remove: bool=False, sub: bool=False):
c = self._conn.cursor()
tag_id = \
c.execute('select id from tags where name == ?', (tag,)) \
......@@ -469,19 +495,25 @@ class Subscriptions(object):
else:
c.execute('insert into tags (name) values (?)', (tag,))
tag_id = c.execute('select last_insert_rowid()').fetchone()[0]
if sub:
join, table, field = 'subs_tags', 'subs', 'sub'
else:
join, table, field = 'videos_tags', 'videos', 'video'
if not remove:
c.execute(
'insert into videos_tags (tag, video)'
' select ?, videos.id from videos'
' where videos.yt_id in ({})'.format(
Query.make_args(len(items))),
'insert into {join} (tag, {field})'
' select ?, {table}.id from {table}'
' where {table}.yt_id in ({})'.format(
Query.make_args(len(items)),
join=join, table=table, field=field),
(tag_id, *items))
else:
c.execute(
'delete from videos_tags'
' where tag == ? and video in ('
'select id from videos where yt_id in ({}))'.format(
Query.make_args(len(items))),
'delete from {join}'
' where tag == ? and {field} in ('
'select id from {table} where yt_id in ({}))'.format(
Query.make_args(len(items)),
join=join, table=table, field=field),
(tag_id, *items))
def watched(
......
......@@ -373,8 +373,28 @@ class TestUpdate(unittest.TestCase):
c.execute('select count(*) from videos where sub == 2')
self.assertEqual(c.fetchone()[0], 3)
def test_tags(self):
c = self.conn.cursor()
c.executemany(
'insert into tags (name) values (?)',
(('tag0',), ('tag1',)))
c.executemany(
'insert into subs_tags (sub, tag) values (?, ?)',
((1, 1), (1, 2)))
resp = {
'https://www.youtube.com/channel/yt_id0': {'url': 'yt_id0_url'},
'https://www.youtube.com/channel/yt_id1': {'url': 'yt_id1_url'},
'yt_id0_url': {'entries': (
{'id': 'yt_id8', 'title': 'title6'},
{'id': 'yt_id9', 'title': 'title7'})},
'yt_id1_url': {'entries': ()}}
self.subs.update(
(), client=subs.Client(0, self.FakeYoutubeDL(resp)))
c.execute('select video, tag from videos_tags')
self.assertEqual(c.fetchall(), [(7, 1), (7, 2), (8, 1), (8, 2)])
class TestTag(unittest.TestCase):
class TestTagVideo(unittest.TestCase):
def setUp(self):
self.conn = sqlite3.connect(':memory:')
self.subs = subs.Subscriptions(0, self.conn)
......@@ -451,6 +471,15 @@ class TestTag(unittest.TestCase):
'sub0\n'
' [ ] title1\n')
def test_sub(self):
c = self.conn.cursor()
with wrap_stdout():
self.subs.tag(sub=True, tag='tag0', items=('yt_id0',))
with wrap_stdout() as out:
self.subs.list(tags=('tag0',))
out = out.read()
self.assertEqual(out, 'sub0\n')
class TestWatched(unittest.TestCase):
def setUp(self):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment