Commit ec90455e authored by bbguimaraes's avatar bbguimaraes
Browse files

tmp

parent e3d5b441
CPPFLAGS := -D _POSIX_C_SOURCE
CFLAGS := -std=c18 -O2 -Wall -Wextra -Wpedantic -Wconversion
CFLAGS := -std=c17 -O2 -g3 -Wall -Wextra -Wpedantic -Wconversion
OUTPUT_OPTION = -MMD -MP -o $@
LDLIBS = \
$(shell pkg-config --libs libcjson) \
......@@ -8,10 +8,10 @@ LDLIBS = \
$(shell pkg-config --libs lua)
TESTS := tests/subs
BIN := subs.new $(TESTS)
BIN := subs $(TESTS)
all: $(BIN)
subs.new: \
subs: \
src/db.o \
src/http.o \
src/log.o \
......
This diff is collapsed.
#!/bin/bash
set -euo pipefail
DIR=$HOME/v
get_lbry() {
local x name ext uri ret
while read x; do
j=$(lbrynet claim search --claim_ids "$x")
name=$(jq --raw-output '.items[0].value.title' <<< "$j")
ext=$(jq --raw-output '.items[0].value.source.name' <<< "$j")
uri=$(jq --raw-output '.items[0].permanent_url' <<< "$j")
ext=${ext##*.}
lbrynet get --download_directory=$DIR --file_name "$name.$ext" "$uri" &
done
ret=0
for x in $(jobs -p); do
wait "$x" || ret=1
done
return "$ret"
}
get_youtube() {
(cd ~/v && exec xargs -n 1 -P 0 youtube-dl)
}
s=subs
cmd=${1:-}
case "$cmd" in
lbry)
cmd='videos{
watched = false,
type = "lbry",
fields = {"videos.yt_id"},
fmt = "join",
}'
"$s" lua "$cmd" | get_lbry;;
youtube)
cmd='videos{
watched = false,
type = "youtube",
fmt = "url",
}'
"$s" lua "$cmd" | get_youtube;;
*)
echo >&2 "Usage: $0 lbry|youtube"
exit 1;;
esac
[x] UCjo1uN-aM3rmBV46xj7l2KA John Stossel @johnstossel
[x] UCL9PlYkRD3Q-RZca6CCnPKw Project Veritas @ProjectVeritas
[x] UCL_f53ZEJxp8TtlOkHwMV9Q Jordan B Peterson @JordanBPeterson
[x] UCYO_jab_esuFRV4b17AJtAw 3Blue1Brown @3Blue1Brown
[x] UCi5N_uAqApEUIlg32QzkPlg Bret Weinstein @BretWeinstein
[x] UCPn4FsiQP15nudug9FDhluA Ivor Cummins @IvorCummins
[ ] UChPynqGC9rmaf97gDpGGeZQ bbguimaraes
[ ] UC2RijHkcWRTCYRcZsdCfnMQ RexTV
[ ] UCyhEZKz-LOwgktptEOh6_Iw The Andrew Klavan Show
[ ] UCxHAlbZQNFU2LgEtiqd2Maw Jason Turner
[ ] UC8kGsMa0LygSX9nkBcBH1Sg PeterAttiaMD
[ ] UCaeO5vkdj5xOQHp4UmIN6dw The Daily Wire
[ ] UCVFkW-chclhuyYRbmmfwt6w Matrixdotorg
[ ] UCR85PW_B_7_Aisx5vNS7Gjw Eric Weinstein
[ ] UCnQC_G5Xsjhp9fEJKuIcrSw Ben Shapiro
[ ] UC0YbmGeNSGPd-StauM1qajg The Khronos Group
[ ] UCMlGfpWw-RUdWX_JbLCukXg CppCon
[ ] UC0JB7TSe49lg56u6qH8y_MQ GDC
[ ] UCRCkL89mcxMETTcqou5o5ow ChrisThile
[ ] UCmxizguBfwRFe8thw97aExA Yamandu Costa
[ ] UC6107grRI4m0o2-emgoDnAA SmarterEveryDay
[ ] UC9-y-6csu5WGm29I7JiwpnA Computerphile
[ ] UCZWlSUNDvCCS1hBiXV0zKcA PragerU
[ ] UCdlniljY9Zfz990G8WeOosg Verdict with Ted Cruz
[ ] UCgBg0LcHfnJDPmFTTf677Pw Paul Saladino, MD
[ ] UCuCjADS4u3uJDTqUaG0H9dA CppCast
[ ] UC5e__RG9K3cHrPotPABnrwg BoostCon
[ ] UCr4kgAUTFkGIwlWSodg43QA Michael Knowles
[ ] UCZAfyXSKgK_HzXiWuiisAAQ Dr. Doug McGuff
[ ] UCgqj2go45P8ase0ISG1iwig Young Heretics
[ ] UCO01ytfzgXYy4glnPJm4PPQ Matt Walsh
[ ] UCSHZKyawb77ixDdsGog4iWA Lex Fridman
[ ] UCyF-Ubm2ALNTtSiYdG-Ezqg Victor Sorrentino
[ ] UC6oHoqiE6IXic99ACa6E_iw Paddy Milner
[ ] UCdDCxqAiyPNqKZzJiEXWgLQ Dan Burnett
[ ] UCh1vNDTd-d60UEJRf6BAUZA Matt Johnson Jamiroquai
[ ] UCMpdzAF0D92pgLEQzNeUv0g Professor Leonardo Guimarães
[ ] UCbfYPyITQ-7l4upoX8nvctg Two Minute Papers
[ ] UCzlMsy46uESj-SKro7oFYJw François Leduc
[ ] UC4w9Hp4nwRUNk2A27J4e5vA Multitrack World
[ ] UCjTp0lRHlPqqRIzzn0Ys45Q BreshDigitalTV
[ ] UCu_Nfz50qfu5pM5vFRLWeTg Joe K. Walsh
[ ] UCKRNfvuKDTqN5qreqabaERw DomMazzetti
[ ] UCbcGOV_MlxkdRVyJvOJQupg Mean Mary
[ ] UC3R-xanNgtoa8b7gpVexVlA Smarthistory
[ ] UCL-0gAth4u6Wp-9_98XU3nA Tommy Emmanuel
[ ] UCUrd25AGg0KyuJgdHdxIEGQ GenerationZ
[ ] UCJdKr0Bgd_5saZYqLCa9mng The Rubin Report
[ ] UCiNPMjtEkUtOue1_0szgj4w Guilherme Basso
[ ] UCduKuJToxWPizJ7I2E6n1kA BroScienceLife
[ ] UCXf45vaawUEnp0L0tXF3R3g Edna Golandsky
[ ] UCjH5KQP_rtYkxKiCDl4UO1Q baldurkarlsson
[ ] UCe0TLA0EsQbE-MjuHXevj2A ATHLEAN-X™
[ ] UCA3FB1fOtY4Vd8yqLaUvolg Sleep Diplomat
[ ] UC8R8FRt1KcPiR-rtAflXmeg Nahre Sol
[ ] UCEo1hmwZXUqFK34ZerW_uqQ christelle berthon
[ ] UCfVFSjHQ57zyxajhhRc7i0g GameHut
[ ] UCyRxqdZ58nsqpgQHUFgelvA Valmor Pedretti Jr.
[ ] UCMjlDOf0UO9wSijFqPE9wBw Modern History TV
[ ] UCV6eZKvhVPz2EAeHwQqYjiA Morgan James
[ ] UCWYGJvJ1-9JeK1XlnQYjyLQ Jim Richter
[ ] UCIDxRRdowWusv8-IO0lpVfg Banjo Ben Clark
[ ] UCLa-1xUQNaNmQA4dcGs3XBA Andy Wood Music
[ ] UCzLu8RUSAlLAL2ByCOBROLg Tony Monaco
[ ] UC4xYcl6mKTwdnuMV76lb_vQ Troy Grady
[ ] UCXoPP_wiMrp1xkHpQnpbt-Q Toni Lindgren
[ ] UCGQ2PS7v6rcc6kK18tTiXnw Peghead Nation
[ ] UCHP-KQAJgXu4Wo2Xq4-eNow Reverb
[ ] UCs13WCSCDmQTNcPlt5XxKYw Tchelinux
[ ] UC4eYXhJI4-7wSWc8UNRwD4A NPR Music
[ ] UCmYAcjJNtB8UsSZjXqyx4Zg Cottereau
[ ] UCoNRSwYHJdy-yV1b82ZdHfQ SethEverman
[ ] UCp5Sz0Iwjpz6Hh9bgbXoyaA John Cleese
[ ] UCgssf4iaflqIBjT1ZtY6roA Hamilton de Holanda Oficial
[ ] UCSyamEaVNrAig7Hxa1kzizg TokArts
[ ] UCcdCryk-WFvzfBnw53-Et_g Marcel Girgis
[ ] UCGm3CO6LPcN-Y7HIuyE0Rew Monty Python
[ ] UCnDB09jnZsXyJFuaGnZ1tFQ Ryan Cook
[ ] UC0IsNB1gnUFWn-3rMZG_ihQ Anna Ash
[ ] UCGtXXSDqlPFv1zx8CFGaA8Q sierrahullmusic
[ ] UCc9h8iZUvWkkwxSh_A5f54A Rounder Records
[ ] UCImcy57uN-d25Uy7pRP8N3A Joey Dosik
[ ] UCSE6yilNScIz1SLTNQvrXMw Vinheteiro
[ ] UCSVyKC72Dh4xsIa_QnlcrjQ Dr. Claudio Rhein
[ ] UCiUuvUInZEgnaaw6btKuFGg Josh Turner
[ ] UCRxt82qGgUASnftwSCQCWZw Cory Henry
[ ] UCwAnOhvfNwgJLXl2j_AOn9A JAZZEDGE CORP
[ ] UCITem85L03q8TY94fVWQrVA Thaïs Morell
[ ] UCGwtC5MuvpqkxWyyV90olFQ Chris Fisher
[ ] UCtWuB1D_E3mcyYThA9iKggQ Vulf
[ ] UCMOFHuVzh3n_JBgICCgtnCg Derek Paravicini
[ ] UCghUHcmX5_BIPkiFEAq-3sg Eddie Landsberg
[ ] UCDGRFR2ljLFWk3jnf83-Thg Deirdré Straughan
[ ] UC3Wj9aO8VS5ZuXrtWfJf81w Josh Turner Guitar
[ ] UCzkAZvgXfeRBvZB5YYJxxJA Jude Perl
[ ] UCbw5Vh0CPwyL9zd6Bqvldww Shaun Martin
[ ] UCwNj2xUWyWqYN21BxKiBfnQ Scott Bradlee
[ ] UCE5AUcemMPLDAJJqFVC08Eg Dan Burnett
[ ] UCiJoq9HunRKUEK3BV8x-jRg groovewindow
[ ] UC3NNxg_9By6eRFSwNPnPCmw allendale1962
[ ] UCXTI3qBA34t1dPRGdx-vbZg Lawrence Wright
[ ] UCTsnTp-g5Rj3VY7Tlm2XQ6A Estas Tonne
[ ] UCjfLK4RXzmIskCSqJmWxY9w Estas Tonne TOURING
[ ] UC5c2IrhA8XUjAXjSWT57jDw Steve Losh
[ ] UCRPWhn87SkELYZN4Xq-kV3A Hiram Fros
[ ] UCAEoU8SivxunnO5zJkMHgIA Shawn Simonson
[ ] UCORIeT1hk6tYBuntEXsguLg PostmodernJukebox
[ ] UCvKLrpen70sLbTe8sg5TWtQ ronaldjenkees
[ ] UC2M_FMyAd0T4vw2-JXGeRFA Studio Chamberlin
[ ] UCPSu8IosaYxsVx5TOGFtjCg Dirty Loops
[ ] UCa2hOfy8Ng0kSf7ApKTslDg hebronsawyers
[ ] UCOGeU-1Fig3rrDjhm9Zs_wg Vihart
[ ] UCt3QIly_CdcnTtau_7xD5sA vihartvihart
[ ] UCZ1UXf-i7A3QHr9ifr6iOCQ Patrick O'Connor
[ ] UCmsl4cmQw1t5RWG8NFOuEag Bruno Lara
[ ] UCSlrbSqnRHSPV9uDkNi-ifA SecretsOfGrindea
[ ] UCacTCNco8pdGXwBBue4vtCg Play Piano In A Flash / PianoGuyTV
[ ] UCoYUIPTIH_7gmdci52Wse2A Nelson Mello
[ ] UCRDU71BLWwww_NgT5VBGZYQ Elysian Shadows
[ ] UCxn8csYeZg6awRnZS-aqg0g Diablo
[ ] UC9u-VcO7OaDt5fz4f0Z-p0Q Jonathon Wilson
[ ] UCashDLiIPkjgurjkyoYkMcQ JAZZEDGE
[ ] UC3_6NesMWOPqY5o-NijV0Sg CoderRach
[ ] UCBuJrSSPIU9LTOZnBU6tVlA SCconferenceseries
[ ] UCpclfjrR7U_8Iplslfpnesw Imagination Technologies
[ ] UCiEHVhv0SBMpP75JbzJShqw Lectures by Walter Lewin
[ ] UCzWwWbbKHg4aodl0S35R6XA HooverInstitution
[ ] UC1wVRtx2w72rj56EDuFJODQ Woody Goss
[ ] UC70SrI3VkT1MXALRtf0pcHg Thomas DeLauer
[ ] UCIe2pR6PE0dae9BunJ38F7w Dr. Sten Ekberg
[ ] UC1Aq3T1GmKcObLqo1YIU_Ww Bulletproof
[ ] UCPGkyRmN5CaXxlY076HiKmQ IWOCL & SYCLcon
[ ] UCHQDjDDW8w2RieO-IuqYlyg AMD
[ ] UC9PBzalIcEQCsiIkq36PyUA Digital Foundry
[ ] UCxoxShg3clxxwKg9nKQeHNw Sam Bush
[ ] UCG08EqOAXJk_YXPDsAvReSg Unity
[ ] UCLjcPQo6Tn1Iwfdr8X7S2CA Ami Horowitz
[ ] UCjvunqlUBcErAinx5AyLX9w Ana Paula Sensolo
[ ] UC0vRRwAVY4mhk7HDtMQt-nw Impakt
[ ] UCkY047vYjF92-8HcoVTXAOg Coding Secrets
[ ] UCjFmUGYGlh7o9T6_VHsyIsA Lua in Moscow
[ ] UCmZ2iiega7fb7vriOS-jjfA Kirk Fletcher
[ ] UCGT2HOTTRk-ovvQXu73WmSg Carson McKee
[ ] UChBeA8mF_vtVZ5yeLz3Gs2A Marcelo Bolinha Carnes
[ ] UCJpMLydEYA08vusDkq3FmjQ Meeting Cpp
[ ] UCDDG9vOcmgwlslJJpCWjqOg Salvatore Sanfilippo
[ ] UCfGIWnnZY79KO0b12O57byw Cem Yuksel
[ ] UCbPn0sw5rIgfT0vlSBvCWlA The PhD
[ ] UCAql2DyGU2un1Ei2nMYsqOA Donald J Trump
[ ] UClo-U5gvXPRy-4VqWEkkRDg Primitive Building
[ ] UCOTZ-6H1rri1lSsj6IzhUyw Senator Ted Cruz
[ ] UC1Esh5OiaDMUt-iEHYCbQCg Dr. SHIVA Ayyadurai, MIT PhD
[ ] UCxscQY7X0mtnaCbkGTjZ17g Mercola
[ ] UC9xjqe-9_yKeIGx-mpMWR3A C++ London
[ ] UCU0Rt8VHO5-YNQXwIjkf-1g code::dive conference
[ ] UCxJfIsPGHFS3_nRDv1u-Q8g Andreas Fertig
[ ] UC-lNlWEq0kpMcThO-I81ZdQ CopperSpice
[ ] UCsefcSZGxO9lTBqFbsV3sJg Cpp.chat
[ ] UCM2RhfMLoLqG24e_DYgTQeA John Lin
curl --header 'Content-Type: application/json' --data '{"method":"resolve","params":{"urls":"@BretWeinstein"}}' http://localhost:5279
{
"jsonrpc": "2.0",
"result": {
"@BretWeinstein": {
"address": "bLUxJ4FvF6i7pr8LfULn1khPvDqzf1NTQW",
"amount": "0.005",
"canonical_url": "lbry://@BretWeinstein#f",
"claim_id": "f6ec70315c2681a3bad9a0eef1017478f6ebed3c",
"claim_op": "update",
"confirmations": 43012,
"has_signing_key": false,
"height": 980903,
"meta": {
"activation_height": 979954,
"claims_in_channel": 280,
"creation_height": 979954,
"creation_timestamp": 1623880679,
"effective_amount": "40763.306625",
"expiration_height": 3082354,
"is_controlling": true,
"reposted": 6,
"support_amount": "40763.301625",
"take_over_height": 979954,
"trending_global": 0.0,
"trending_group": 0,
"trending_local": 0.0,
"trending_mixed": 0.00493721105158329
},
"name": "@BretWeinstein",
"normalized_name": "@bretweinstein",
"nout": 0,
"permanent_url": "lbry://@BretWeinstein#f6ec70315c2681a3bad9a0eef1017478f6ebed3c",
"short_url": "lbry://@BretWeinstein#f",
"timestamp": 1624032396,
"txid": "a629ab9ea3bde5a560a3eb5cac298b514cacfce84f832d504961f79c9e00b0d2",
"type": "claim",
"value": {
"cover": {
"url": "https://thumbnails.lbry.com/banner-UCi5N_uAqApEUIlg32QzkPlg"
},
"description": "Videos about adaptive evolution, good governance, the breakdown of civil discourse and subsequent mayhem at Evergreen and other college campuses, and about the emerging Coalition of the Reasonable.",
"public_key": "3056301006072a8648ce3d020106052b8104000a0342000497fa752ad572ecb692aa8a8c34a18f2289d79cb4ec717cbd3e479ba7fea2e5f4b466b8017a311c1a3d4d41a44e7847b178ac2149a9a21a86afb59e50873497be",
"public_key_id": "bJc5SKu5Kd6KkNDCQj5VcxcX5MK1aDqFWs",
"thumbnail": {
"url": "https://thumbnails.lbry.com/UCi5N_uAqApEUIlg32QzkPlg"
},
"title": "Bret Weinstein"
},
"value_type": "channel"
}
}
}
{ pkgs ? import <nixpkgs> {} }:
pkgs.mkShell {
nativeBuildInputs = [
pkgs.pkg-config
];
buildInputs = [
pkgs.cjson
pkgs.curl
pkgs.gcc11
pkgs.lua5_4
pkgs.sqlite
];
}
#ifndef SUBS_CONST_H
#define SUBS_CONST_H
enum {
SUBS_MAX_PATH = 4096,
};
#endif
......@@ -20,14 +20,16 @@ static void usage(void) {
" -h, --help This help text.\n"
" -v Increase previous log level, can appear multiple\n"
" times.\n"
" --log-level n Set log level to `n`.\n"
" --log-level N Set log level to `N`.\n"
" -f, --file DB Use database file `DB`, default: $XDG_DATA_HOME/subs/db.\n"
"\n"
"Commands:\n"
" ls List subscriptions.\n"
" videos List videos.\n"
" add Add a subscription.\n"
" watched Mark videos as watched\n"
" update Fetch new videos from subscriptions.\n",
" add NAME ID Add a subscription.\n"
" watched ID Mark videos as watched\n"
" update [OPTIONS]\n"
" Fetch new videos from subscriptions.\n",
PROG_NAME);
}
......@@ -99,28 +101,59 @@ enum subs_type subs_parse_type(const char *s) {
}
static bool init_from_env(struct subs *s);
static const char *find_db(const char *path, char v[static SUBS_MAX_PATH]);
bool subs_init(struct subs *s) {
if(!init_from_env(s))
return false;
const char *db_path = s->db_path ? s->db_path : ":memory:";
char tmp_db_path[SUBS_MAX_PATH] = {0};
const char *const db_path = find_db(s->db_path, tmp_db_path);
if(!db_path)
return false;
sqlite3 *db = NULL;
if(!db_init(&db, db_path))
return false;
s->db = db;
if(!s->db_path)
s->db_path = db_path;
if(db_path != s->db_path)
strcpy(s->db_path, tmp_db_path);
if(!s->url)
s->url = "localhost:5279";
return true;
}
static bool init_from_env(struct subs *s) {
bool init_from_env(struct subs *s) {
if(!parse_log_level(getenv("SUBS_LOG_LEVEL"), &s->log_level))
return false;
return true;
}
const char *find_db(const char *path, char v[static SUBS_MAX_PATH]) {
if(*path)
return path;
#define B "/subs/db"
const char *const base = B;
const char *const home_base = "/.local/share" B;
#undef B
const char *const xdg_home = getenv("XDG_DATA_HOME");
if(xdg_home) {
if(!join_path(v, 2, xdg_home, base))
return false;
} else {
const char *const home = getenv("HOME");
if(!home)
goto end;
if(!join_path(v, 2, home, home_base))
return false;
}
FILE *const f = fopen(v, "r");
if(!f)
goto end;
fclose(f);
return v;
end:
return ":memory:";
}
bool subs_init_from_argv(struct subs *s, int *argc_p, char ***argv_p) {
enum { CMD_HELP = 1, LOG_LEVEL = 0 };
const char short_opts[] = "+f:hv";
......@@ -142,7 +175,17 @@ bool subs_init_from_argv(struct subs *s, int *argc_p, char ***argv_p) {
break;
switch(c) {
case '?': break;
case 'f': s->db_path = optarg; continue;
case 'f': {
const size_t n = strlen(optarg);
if(SUBS_MAX_PATH <= n) {
log_err(
"database path too long (%zu >= %zu): %s\n",
n, SUBS_MAX_PATH, optarg);
goto end;
}
memcpy(s->db_path, optarg, n + 1);
continue;
}
case 'h': cmd = CMD_HELP; continue;
case 'v': ++log_level; continue;
case LOG_LEVEL:
......@@ -307,6 +350,7 @@ static bool cmd_update(struct subs *s, int argc, char **argv) {
"Usage: %s [options] update [options]\n"
"\n"
"Options:\n"
" -h, --help This help text.\n"
" --deep Fetch all pages when updating. By default, updates stop\n"
" on the first page that does not contain new entries.\n",
PROG_NAME);
......@@ -325,10 +369,14 @@ end:
bool subs_exec(struct subs *s, int argc, char **argv) {
if(!s->db)
return true;
if(!argc || strcmp(*argv, "ls") == 0)
if(!argc)
return subs_list(s, stdout);
if(!argc || strcmp(*argv, "videos") == 0)
return subs_list_videos(s, stdout);
if(strcmp(*argv, "ls") == 0)
return check_argc("ls", --argc, 0)
&& subs_list(s, stdout);
if(strcmp(*argv, "videos") == 0)
return check_argc("videos", --argc, 0)
&& subs_list_videos(s, stdout);
if(strcmp(*argv, "add") == 0) {
--argc, ++argv;
enum subs_type t = 0;
......@@ -337,11 +385,14 @@ bool subs_exec(struct subs *s, int argc, char **argv) {
&& subs_add(s, t, argv[1], argv[2]);
}
if(strcmp(*argv, "watched") == 0) {
--argc, ++argv;
if(!*++argv)
return log_err("watched: at least one arguument required\n"), false;
int64_t id = 0;
return check_argc("watched", argc, 1)
&& ((id = parse_i64(argv[0])) != -1)
&& subs_watched(s, id);
do {
if(((id = parse_i64(*argv)) == -1) || !subs_watched(s, id))
return false;
} while(*++argv);
return true;
}
if(strcmp(*argv, "update") == 0)
return cmd_update(s, argc, argv);
......
......@@ -7,6 +7,8 @@
#include <sqlite3.h>
#include "const.h"
struct http_client;
enum subs_type {
......@@ -20,10 +22,10 @@ enum subs_flags {
};
struct subs {
const char *db_path;
const char *url;
sqlite3 *db;
uint32_t log_level;
char db_path[SUBS_MAX_PATH];
const char *url;
};
const char *subs_type_name(enum subs_type type);
......
#include "util.h"
#include <assert.h>
#include "log.h"
bool join_path(char v[static SUBS_MAX_PATH], int n, ...) {
va_list args;
va_start(args, n);
char *p = v, *const e = v + SUBS_MAX_PATH;
for(int i = 0; i != n; ++i) {
size_t ni = strlcpy(p, va_arg(args, const char*), (size_t)(e - p));
if(e[-1])
goto err;
p += ni;
}
assert(p <= e);
assert(!e[-1]);
va_end(args);
return true;
err:
va_end(args);
log_err("%s: path too long: %s\n", __func__, v);
return false;
}
#ifndef SUBS_UTIL_H
#define SUBS_UTIL_H
#include <stdbool.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "const.h"
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x)))
#define ARRAY_END(x) ((x) + ARRAY_SIZE((x)))
static size_t strlcpy(char *restrict dst, const char *restrict src, size_t n);
static int64_t parse_i64(const char *s);
bool join_path(char v[static SUBS_MAX_PATH], int n, ...);
static inline size_t strlcpy(
char *restrict dst, const char *restrict src, size_t n
) {
const char *const p = dst;
while(n && (*dst++ = *src++))
--n;
return (size_t)(dst - p);
for(const char *const e = dst + n;; ++dst, ++src)
if(!(*dst = *src))
return n - (size_t)(e - dst);
}
static inline int64_t parse_i64(const char *s) {
......
......@@ -342,7 +342,7 @@ class Subscriptions(object):
def add(self, yt_id: str, name: str):
self._conn.cursor().execute(
'insert into subs (yt_id, name) values (?, ?)',
'insert into subs (yt_id, name, type) values (?, ?, 2)',
(yt_id, name))
def update(
......@@ -358,7 +358,7 @@ class Subscriptions(object):
q = Query('subs')
args: typing.List[typing.Any] = []
q.add_fields('subs.id', 'subs.name', 'subs.yt_id')
q.add_filter('last_update < ?')
q.add_filter('type == 2 and last_update < ?')
args.append(cache)
if tags:
q.add_joins(
......
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