about summary refs log tree commit diff
path: root/c/dynotify.c
blob: ec7cea8eb703e9062393cc6aa6232126c7072f57 (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
139
140
141
142
143
144
// curl:
// man curl_easy_init CURLOPT_URL curl_easy_setopt CURLOPT_WRITEFUNCTION libcurl-errors curl_easy_strerror
// 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)
{
	// man libcurl-errors
	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);
				// man curl_easy_strerror
				if(res != CURLE_OK)
				{
					fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
					free(chunk.response);
					break;
				}
				//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;
}