summaryrefslogtreecommitdiff
path: root/dynotify.c
blob: 3839e35b600ec0e04e4d25789b1b52863cbc0aa6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// curl:
// man curl_easy_init CURLOPT_URL curl_easy_setopt CURLOPT_WRITEFUNCTION
// https://curl.se/libcurl/
// https://curl.se/libcurl/c/
// https://curl.se/libcurl/c/libcurl-tutorial.html
// https://stackoverflow.com/a/2329792

// json-c:
// pacman -Qs json c
// https://github.com/json-c/json-c#using
// https://github.com/json-c/json-c/blob/master/tests/test2.c
// https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/legacy.md
// https://github.com/rbtylee/tutorial-jsonc/blob/master/tutorial/parsing2.md

// libnotify:
// https://gitlab.gnome.org/GNOME/libnotify/-/blob/master/tests/test-basic.c?ref_type=heads
// https://gnome.pages.gitlab.gnome.org/libnotify/index.html

// compile, maybe wrong:
// https://stackoverflow.com/a/39120702
// cc -Wall -lcurl -ljson-c $(pkg-config --cflags --libs libnotify) ./dynotify.c
// or:
// cc -Wall $(pkg-config --cflags --libs libnotify libcurl json-c) ./dynotify.c
// misc:
// /usr/lib/pkgconfig/libnotify.pc

#include<stdio.h> // for sprintf
#include<stdbool.h> // for bool
#include<stdlib.h> // for realloc
#include<string.h> // for memcpy
#include<unistd.h> // for sleep
#include<curl/curl.h> // MIT
#include<json-c/json.h> // MIT
#include<libnotify/notify.h> //LGPL

#define DYROOM_ID_LEN 9
// utf-8 most chinese characters 3 bytes, my longest name currently is 2 chinese characters, 2*3=6, +1 for \0
// but gcc will not error when not consider \0, maybe the complier auto add one more element?
#define DYROOM_NAME_LEN 6

struct memory {
	char *response;
	size_t size;
};

struct dyroom {
	// another way: `const char *name;`
	const char name[DYROOM_NAME_LEN];
	const unsigned int id;
	bool up;
};

// /home/xyz/archive/programs/private_archive_codes/c/c_primer_plus/practices/Chapter14/14-1monthStruct.c 
struct dyroom room[5]={
	{"阿冉",4605243,false},
	{"甜汤",2766480,false},
	{"少君",9640128,false},
	{"她她",236288,false},
	{"郑正",10883525,false}
};

// copy from `man CURLOPT_WRITEFUNCTION`
static size_t cb(char *data, size_t size, size_t nmemb, void *clientp)
{
	size_t realsize = size * nmemb;
	struct memory *mem = (struct memory *)clientp;

	char *ptr = realloc(mem->response, mem->size + realsize + 1);
	if(!ptr)
		return 0;  /* out of memory! */

	mem->response = ptr;
	memcpy(&(mem->response[mem->size]), data, realsize);
	mem->size += realsize;
	mem->response[mem->size] = 0;

	return realsize;
}

int main (void)
{
	// https://curl.se/libcurl/c/libcurl-errors.html
	//CURLcode res;
	// `man curl_easy_init`: "It is encouraged to reuse easy handles for repeated transfers.", so I choose to reuse it
	CURL *curl = curl_easy_init();
	NotifyNotification *n;
	notify_init ("dynotify");

	if(curl) {
		for(;;)
		{
			for(int i=0;i<5;i++)
			{
				// manpage assign 0 to struct, it seems because C11 when cast 0 to void* is same as NULL? see:
				// https://www.geeksforgeeks.org/null-pointer-in-c/
				struct memory chunk = {0};
				char url[29+DYROOM_ID_LEN];
				sprintf(url, "https://www.douyu.com/betard/%d", room[i].id);

				curl_easy_setopt(curl, CURLOPT_URL, url);
				curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cb);
				curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&chunk);
				//res = curl_easy_perform(curl);
				curl_easy_perform(curl);
				//printf("%s\n",chunk.response);

				json_object *root;
				root=json_tokener_parse(chunk.response);
				if (json_object_get_int(json_object_object_get(json_object_object_get(root,"room"),"show_status")) == 1)
				{
					if(!room[i].up)
					{
						// 开播 is 2*3=6 bytes
						char msg[DYROOM_NAME_LEN+6];
						sprintf(msg,"%s开播",room[i].name);

						n = notify_notification_new (msg, NULL, NULL);
						notify_notification_set_urgency(n, NOTIFY_URGENCY_CRITICAL);
						notify_notification_show (n, NULL);

						room[i].up=true;
					}
				}
				else if(room[i].up)
					room[i].up=false;

				free(chunk.response);
				// must call json_object_put to free *root, else memory leak!
				json_object_put(root);
			}
			sleep(60);
		}
		curl_easy_cleanup(curl);
	}

	g_object_unref (G_OBJECT (n));
	return 0;
}