sub.c - sub - subscene.com subtitle search
(HTM) git clone git://git.codemadness.org/sub
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
sub.c (3649B)
---
1 #include <sys/types.h>
2
3 #include <ctype.h>
4 #include <errno.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <strings.h>
9 #ifdef __OpenBSD__
10 #include <unistd.h>
11 #else
12 #define pledge(a,b) 0
13 #endif
14
15 #include "util.h"
16 #include "xml.h"
17
18 struct sub {
19 int issub;
20 char title[256];
21 char lang[256];
22 int hi;
23 int files;
24 char author[256];
25 char authorurl[256];
26 char description[256];
27 char url[4096];
28 };
29
30 static XMLParser parser; /* XML parser state */
31 static struct sub sub;
32 static char curclass[64];
33 static char spanclass[64];
34
35 static int
36 istag(const char *s1, const char *s2)
37 {
38 return !strcasecmp(s1, s2);
39 }
40
41 static int
42 isattr(const char *s1, const char *s2)
43 {
44 return !strcasecmp(s1, s2);
45 }
46
47 static void
48 xml_handler_data(XMLParser *p, const char *data, size_t datalen)
49 {
50 char *s = "";
51 char buf[1024];
52 size_t len;
53
54 if (!curclass[0])
55 return;
56
57 /* skip leading space */
58 for (s = (char *)data; *s && isspace((unsigned char)*s); s++)
59 ;
60 strlcpy(buf, s, sizeof(buf));
61 for (s = buf; *s; s++) {
62 if (*s == '\r' || *s == '\n')
63 *s = ' ';
64 }
65 /* trim remaining space */
66 len = strlen(buf);
67 for (; len > 0; len--) {
68 if (!isspace((unsigned char)buf[len - 1]))
69 break;
70 buf[len - 1] = '\0';
71 }
72
73 s = buf;
74 if (!*s)
75 return;
76 if (strcmp(curclass, "a1") == 0) {
77 /* link */
78 if (strcmp(spanclass, "") == 0)
79 strlcpy(sub.title, s, sizeof(sub.title));
80 else
81 strlcpy(sub.lang, s, sizeof(sub.lang));
82 } else if (strcmp(curclass, "a3") == 0) {
83 /* files */
84 sub.files = atoi(s);
85 } else if (strcmp(curclass, "a41") == 0) {
86 /* hearing impaired? */
87 sub.hi = 1;
88 } else if (strcmp(curclass, "a5") == 0) {
89 /* author / user profile */
90 strlcpy(sub.author, s, sizeof(sub.author));
91 } else if (strcmp(curclass, "a6") == 0) {
92 /* description */
93 strlcpy(sub.description, s, sizeof(sub.description));
94 }
95 }
96
97 static void
98 xml_handler_start_element(XMLParser *p, const char *tag, size_t taglen)
99 {
100 (void)p;
101 (void)taglen;
102
103 if (istag(tag, "tr"))
104 memset(&sub, 0, sizeof(sub));
105 }
106
107 static void
108 xml_handler_end_element(XMLParser *p, const char *tag, size_t taglen,
109 int isshort)
110 {
111 (void)p;
112 (void)taglen;
113 (void)isshort;
114
115 if (istag(tag, "tr") && sub.issub == 1) {
116 printf("LANG:%s\tTITLE:%s\tURL:https://subscene.com%s\tHI:%d\tFILES:%d\tAUTHOR:%s\n",
117 sub.lang, sub.title, sub.url, sub.hi, sub.files, sub.author);
118 } else if (istag(tag, "td")) {
119 curclass[0] = '\0';
120 } else if (istag(tag, "span")) {
121 spanclass[0] = '\0';
122 }
123 }
124
125 static void
126 xml_handler_attr(XMLParser *p, const char *tag, size_t taglen,
127 const char *name, size_t namelen, const char *value, size_t valuelen)
128 {
129 (void)p;
130 (void)taglen;
131 (void)namelen;
132 (void)valuelen;
133
134 if (istag(tag, "td")) {
135 if (isattr(name, "class")) {
136 strlcpy(curclass, value, sizeof(curclass));
137 /* link */
138 if (strcmp(value, "a1") == 0)
139 sub.issub = 1;
140 }
141 } else if (istag(tag, "span")) {
142 if (strcmp(curclass, "a1") == 0) {
143 if (isattr(name, "class"))
144 strlcpy(spanclass, value, sizeof(spanclass));
145 }
146 } else if (istag(tag, "a")) {
147 /* subtitle / author profile url */
148 if (strcmp(name, "href") == 0) {
149 if ((strcmp(curclass, "a1") == 0))
150 strlcpy(sub.url, value, sizeof(sub.url));
151 else if ((strcmp(curclass, "a5") == 0))
152 strlcpy(sub.authorurl, value, sizeof(sub.authorurl));
153 }
154 }
155 }
156
157 int
158 main(void)
159 {
160 if (pledge("stdio", NULL) < 0) {
161 fprintf(stderr, "pledge: %s\n", strerror(errno));
162 return 1;
163 }
164
165 parser.xmltagstart = xml_handler_start_element;
166 parser.xmltagend = xml_handler_end_element;
167 parser.xmlattr = xml_handler_attr;
168 parser.xmldata = xml_handler_data;
169
170 parser.getnext = getchar;
171
172 xml_parse(&parser);
173
174 return 0;
175 }