Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
videolan
vlc
Commits
052ce0ee
Commit
052ce0ee
authored
Jul 31, 2011
by
Rafaël Carré
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
audioscrobbler: reorder functions to remove declarations
parent
b357472a
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
394 additions
and
405 deletions
+394
-405
modules/misc/audioscrobbler.c
modules/misc/audioscrobbler.c
+394
-405
No files found.
modules/misc/audioscrobbler.c
View file @
052ce0ee
...
@@ -115,18 +115,6 @@ static int Open ( vlc_object_t * );
...
@@ -115,18 +115,6 @@ static int Open ( vlc_object_t * );
static
void
Close
(
vlc_object_t
*
);
static
void
Close
(
vlc_object_t
*
);
static
void
Run
(
intf_thread_t
*
);
static
void
Run
(
intf_thread_t
*
);
static
int
ItemChange
(
vlc_object_t
*
,
const
char
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
static
int
PlayingChange
(
vlc_object_t
*
,
const
char
*
,
vlc_value_t
,
vlc_value_t
,
void
*
);
static
void
AddToQueue
(
intf_thread_t
*
);
static
int
Handshake
(
intf_thread_t
*
);
static
void
ReadMetaData
(
intf_thread_t
*
);
static
void
DeleteSong
(
audioscrobbler_song_t
*
);
static
int
ParseURL
(
char
*
,
char
**
,
char
**
,
int
*
);
static
void
HandleInterval
(
mtime_t
*
,
unsigned
int
*
);
/*****************************************************************************
/*****************************************************************************
* Module descriptor
* Module descriptor
****************************************************************************/
****************************************************************************/
...
@@ -173,287 +161,178 @@ vlc_module_begin ()
...
@@ -173,287 +161,178 @@ vlc_module_begin ()
vlc_module_end
()
vlc_module_end
()
/*****************************************************************************
/*****************************************************************************
*
Open: initialize and create stuff
*
DeleteSong : Delete the char pointers in a song
*****************************************************************************/
*****************************************************************************/
static
int
Open
(
vlc_object_t
*
p_this
)
static
void
DeleteSong
(
audioscrobbler_song_t
*
p_song
)
{
{
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
FREENULL
(
p_song
->
psz_a
);
intf_sys_t
*
p_sys
=
calloc
(
1
,
sizeof
(
intf_sys_t
)
);
FREENULL
(
p_song
->
psz_b
);
FREENULL
(
p_song
->
psz_t
);
FREENULL
(
p_song
->
psz_m
);
FREENULL
(
p_song
->
psz_n
);
}
if
(
!
p_sys
)
/*****************************************************************************
return
VLC_ENOMEM
;
* ReadMetaData : Read meta data when parsed by vlc
*****************************************************************************/
static
void
ReadMetaData
(
intf_thread_t
*
p_this
)
{
input_thread_t
*
p_input
;
input_item_t
*
p_item
;
p_intf
->
p_sys
=
p_sys
;
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
vlc_mutex_init
(
&
p_sys
->
lock
);
p_input
=
playlist_CurrentInput
(
pl_Get
(
p_this
)
);
vlc_cond_init
(
&
p_sys
->
wait
);
if
(
!
p_input
)
return
;
var_AddCallback
(
pl_Get
(
p_intf
),
"item-current"
,
ItemChange
,
p_intf
);
p_item
=
input_GetItem
(
p_input
);
if
(
!
p_item
)
{
vlc_object_release
(
p_input
);
return
;
}
p_intf
->
pf_run
=
Run
;
#define ALLOC_ITEM_META( a, b ) do { \
char *psz_meta = input_item_Get##b( p_item ); \
if( psz_meta && *psz_meta ) \
a = encode_URI_component( psz_meta ); \
free( psz_meta ); \
} while(0)
return
VLC_SUCCESS
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
}
/*****************************************************************************
p_sys
->
b_meta_read
=
true
;
* Close: destroy interface stuff
*****************************************************************************/
static
void
Close
(
vlc_object_t
*
p_this
)
{
playlist_t
*
p_playlist
=
pl_Get
(
p_this
);
input_thread_t
*
p_input
;
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
var_DelCallback
(
p_playlist
,
"item-current"
,
ItemChange
,
p_intf
);
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_a
,
Artist
);
if
(
!
p_sys
->
p_current_song
.
psz_a
)
{
msg_Dbg
(
p_this
,
"No artist.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
p_input
=
playlist_CurrentInput
(
p_playlist
);
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_t
,
Title
);
if
(
p_inpu
t
)
if
(
!
p_sys
->
p_current_song
.
psz_
t
)
{
{
if
(
p_sys
->
b_state_cb
)
msg_Dbg
(
p_this
,
"No track name.."
);
var_DelCallback
(
p_input
,
"intf-event"
,
PlayingChange
,
p_intf
);
DeleteSong
(
&
p_sys
->
p_current_song
);
vlc_object_release
(
p_input
)
;
goto
end
;
}
}
int
i
;
/* Now we have read the mandatory meta data, so we can submit that info */
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
p_sys
->
b_submit
=
true
;
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
free
(
p_sys
->
psz_submit_host
);
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_b
,
Album
);
free
(
p_sys
->
psz_submit_file
);
if
(
!
p_sys
->
p_current_song
.
psz_b
)
#if 0 //NOT USED
p_sys
->
p_current_song
.
psz_b
=
calloc
(
1
,
1
);
free( p_sys->psz_nowp_host );
free( p_sys->psz_nowp_file );
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_m
,
TrackID
);
#endif
if
(
!
p_sys
->
p_current_song
.
psz_m
)
vlc_cond_destroy
(
&
p_sys
->
wait
);
p_sys
->
p_current_song
.
psz_m
=
calloc
(
1
,
1
);
vlc_mutex_destroy
(
&
p_sys
->
lock
);
free
(
p_sys
);
p_sys
->
p_current_song
.
i_l
=
input_item_GetDuration
(
p_item
)
/
1000000
;
}
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_n
,
TrackNum
);
if
(
!
p_sys
->
p_current_song
.
psz_n
)
p_sys
->
p_current_song
.
psz_n
=
calloc
(
1
,
1
);
#undef ALLOC_ITEM_META
msg_Dbg
(
p_this
,
"Meta data registered"
);
end:
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_object_release
(
p_input
);
}
/*****************************************************************************
/*****************************************************************************
*
Run : call Handshake() then submit songs
*
AddToQueue: Add the played song to the queue to be submitted
*****************************************************************************/
*****************************************************************************/
static
void
Run
(
intf_thread_t
*
p_intf
)
static
void
AddToQueue
(
intf_thread_t
*
p_this
)
{
{
char
*
psz_submit
,
*
psz_submit_song
,
*
psz_submit_tmp
;
mtime_t
played_time
;
int
i_net_ret
;
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
int
i_song
;
uint8_t
p_buffer
[
1024
];
char
*
p_buffer_pos
;
int
i_post_socket
;
int
canc
=
vlc_savecancel
();
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
!
p_sys
->
b_submit
)
goto
end
;
/*
main loop
*/
/*
wait for the user to listen enough before submitting
*/
for
(
;;
)
played_time
=
mdate
()
-
p_sys
->
p_current_song
.
i_start
-
{
p_sys
->
time_total_pauses
;
bool
b_wait
=
false
;
played_time
/=
1000000
;
/* µs → s */
/*HACK: it seam that the preparsing sometime fail,
so use the playing time as the song length */
if
(
p_sys
->
p_current_song
.
i_l
==
0
)
p_sys
->
p_current_song
.
i_l
=
played_time
;
vlc_restorecancel
(
canc
);
/* Don't send song shorter than 30s */
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
p_sys
->
p_current_song
.
i_l
<
30
)
mutex_cleanup_push
(
&
p_sys
->
lock
);
{
msg_Dbg
(
p_this
,
"Song too short (< 30s), not submitting"
);
goto
end
;
}
if
(
mdate
()
<
p_sys
->
next_exchange
)
/* Send if the user had listen more than 240s OR half the track length */
/* wait until we can resubmit, i.e. */
if
(
(
played_time
<
240
)
&&
b_wait
=
vlc_cond_timedwait
(
&
p_sys
->
wait
,
&
p_sys
->
lock
,
(
played_time
<
(
p_sys
->
p_current_song
.
i_l
/
2
)
)
)
p_sys
->
next_exchange
)
==
0
;
{
else
msg_Dbg
(
p_this
,
"Song not listened long enough, not submitting"
);
/* wait for data to submit */
goto
end
;
/* we are signaled each time there is a song to submit */
}
vlc_cond_wait
(
&
p_sys
->
wait
,
&
p_sys
->
lock
);
vlc_cleanup_run
();
canc
=
vlc_savecancel
();
if
(
b_wait
)
/* Check that all meta are present */
continue
;
/* holding on until next_exchange */
if
(
!
p_sys
->
p_current_song
.
psz_a
||
!*
p_sys
->
p_current_song
.
psz_a
||
!
p_sys
->
p_current_song
.
psz_t
||
!*
p_sys
->
p_current_song
.
psz_t
)
{
msg_Dbg
(
p_this
,
"Missing artist or title, not submitting"
);
goto
end
;
}
/* handshake if needed */
if
(
p_sys
->
i_songs
>=
QUEUE_MAX
)
if
(
!
p_sys
->
b_handshaked
)
{
{
msg_Warn
(
p_this
,
"Submission queue is full, not submitting"
);
msg_Dbg
(
p_intf
,
"Handshaking with last.fm ..."
);
goto
end
;
}
switch
(
Handshake
(
p_intf
)
)
msg_Dbg
(
p_this
,
"Song will be submitted."
);
{
case
VLC_ENOMEM
:
return
;
case
VLC_ENOVAR
:
#define QUEUE_COPY( a ) \
/* username not set */
p_sys->p_queue[p_sys->i_songs].a = p_sys->p_current_song.a
dialog_Fatal
(
p_intf
,
_
(
"Last.fm username not set"
),
"%s"
,
_
(
"Please set a username or disable the "
"audioscrobbler plugin, and restart VLC.
\n
"
"Visit http://www.last.fm/join/ to get an account."
)
);
return
;
case
VLC_SUCCESS
:
#define QUEUE_COPY_NULL( a ) \
msg_Dbg
(
p_intf
,
"Handshake successfull :)"
);
QUEUE_COPY( a ); \
p_sys
->
b_handshaked
=
true
;
p_sys->p_current_song.a = NULL
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
break
;
case
VLC_AUDIOSCROBBLER_EFATAL
:
QUEUE_COPY
(
i_l
);
msg_Warn
(
p_intf
,
"Exiting..."
);
QUEUE_COPY_NULL
(
psz_n
);
return
;
QUEUE_COPY_NULL
(
psz_a
);
QUEUE_COPY_NULL
(
psz_t
);
QUEUE_COPY_NULL
(
psz_b
);
QUEUE_COPY_NULL
(
psz_m
);
QUEUE_COPY
(
date
);
#undef QUEUE_COPY_NULL
#undef QUEUE_COPY
case
VLC_EGENERIC
:
p_sys
->
i_songs
++
;
default:
/* protocol error : we'll try later */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
break
;
}
/* if handshake failed let's restart the loop */
if
(
!
p_sys
->
b_handshaked
)
continue
;
}
msg_Dbg
(
p_intf
,
"Going to submit some data..."
);
/* signal the main loop we have something to submit */
vlc_cond_signal
(
&
p_sys
->
wait
);
/* The session may be invalid if there is a trailing \n */
end:
char
*
psz_ln
=
strrchr
(
p_sys
->
psz_auth_token
,
'\n'
);
DeleteSong
(
&
p_sys
->
p_current_song
);
if
(
psz_ln
)
p_sys
->
b_submit
=
false
;
*
psz_ln
=
'\0'
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
}
if
(
!
asprintf
(
&
psz_submit
,
"s=%s"
,
p_sys
->
psz_auth_token
)
)
/*****************************************************************************
{
/* Out of memory */
* PlayingChange: Playing status change callback
return
;
*****************************************************************************/
}
static
int
PlayingChange
(
vlc_object_t
*
p_this
,
const
char
*
psz_var
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
/* forge the HTTP POST request */
{
vlc_mutex_lock
(
&
p_sys
->
lock
);
VLC_UNUSED
(
oldval
);
audioscrobbler_song_t
*
p_song
;
for
(
i_song
=
0
;
i_song
<
p_sys
->
i_songs
;
i_song
++
)
{
p_song
=
&
p_sys
->
p_queue
[
i_song
];
if
(
!
asprintf
(
&
psz_submit_song
,
"&a%%5B%d%%5D=%s"
"&t%%5B%d%%5D=%s"
"&i%%5B%d%%5D=%u"
"&o%%5B%d%%5D=P"
"&r%%5B%d%%5D="
"&l%%5B%d%%5D=%d"
"&b%%5B%d%%5D=%s"
"&n%%5B%d%%5D=%s"
"&m%%5B%d%%5D=%s"
,
i_song
,
p_song
->
psz_a
,
i_song
,
p_song
->
psz_t
,
i_song
,
(
unsigned
)
p_song
->
date
,
/* HACK: %ju (uintmax_t) unsupported on Windows */
i_song
,
i_song
,
i_song
,
p_song
->
i_l
,
i_song
,
p_song
->
psz_b
,
i_song
,
p_song
->
psz_n
,
i_song
,
p_song
->
psz_m
)
)
{
/* Out of memory */
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
;
}
psz_submit_tmp
=
psz_submit
;
if
(
!
asprintf
(
&
psz_submit
,
"%s%s"
,
psz_submit_tmp
,
psz_submit_song
)
)
{
/* Out of memory */
free
(
psz_submit_tmp
);
free
(
psz_submit_song
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
;
}
free
(
psz_submit_song
);
free
(
psz_submit_tmp
);
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
i_post_socket
=
net_ConnectTCP
(
p_intf
,
p_sys
->
psz_submit_host
,
p_sys
->
i_submit_port
);
if
(
i_post_socket
==
-
1
)
{
/* If connection fails, we assume we must handshake again */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
p_sys
->
b_handshaked
=
false
;
free
(
psz_submit
);
continue
;
}
/* we transmit the data */
i_net_ret
=
net_Printf
(
p_intf
,
i_post_socket
,
NULL
,
POST_REQUEST
,
p_sys
->
psz_submit_file
,
(
unsigned
)
strlen
(
psz_submit
),
p_sys
->
psz_submit_host
,
VERSION
,
psz_submit
);
free
(
psz_submit
);
if
(
i_net_ret
==
-
1
)
{
/* If connection fails, we assume we must handshake again */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
p_sys
->
b_handshaked
=
false
;
continue
;
}
i_net_ret
=
net_Read
(
p_intf
,
i_post_socket
,
NULL
,
p_buffer
,
1023
,
false
);
if
(
i_net_ret
<=
0
)
{
/* if we get no answer, something went wrong : try again */
continue
;
}
net_Close
(
i_post_socket
);
p_buffer
[
i_net_ret
]
=
'\0'
;
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"FAILED"
);
if
(
p_buffer_pos
)
{
msg_Warn
(
p_intf
,
"%s"
,
p_buffer_pos
);
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"BADSESSION"
);
if
(
p_buffer_pos
)
{
msg_Err
(
p_intf
,
"Authentication failed (BADSESSION), are you connected to last.fm with another program ?"
);
p_sys
->
b_handshaked
=
false
;
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"OK"
);
if
(
p_buffer_pos
)
{
int
i
;
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
p_sys
->
i_songs
=
0
;
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
msg_Dbg
(
p_intf
,
"Submission successful!"
);
}
else
{
msg_Err
(
p_intf
,
"Authentication failed, handshaking again (%s)"
,
p_buffer
);
p_sys
->
b_handshaked
=
false
;
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
}
vlc_restorecancel
(
canc
);
}
/*****************************************************************************
* PlayingChange: Playing status change callback
*****************************************************************************/
static
int
PlayingChange
(
vlc_object_t
*
p_this
,
const
char
*
psz_var
,
vlc_value_t
oldval
,
vlc_value_t
newval
,
void
*
p_data
)
{
VLC_UNUSED
(
oldval
);
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_data
;
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_data
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
...
@@ -549,86 +428,63 @@ static int ItemChange( vlc_object_t *p_this, const char *psz_var,
...
@@ -549,86 +428,63 @@ static int ItemChange( vlc_object_t *p_this, const char *psz_var,
}
}
/*****************************************************************************
/*****************************************************************************
*
AddToQueue: Add the played song to the queue to be submitted
*
Open: initialize and create stuff
*****************************************************************************/
*****************************************************************************/
static
void
AddToQueue
(
intf_thread
_t
*
p_this
)
static
int
Open
(
vlc_object
_t
*
p_this
)
{
{
mtime_t
played_time
;
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
intf_sys_t
*
p_sys
=
calloc
(
1
,
sizeof
(
intf_sys_t
)
);
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
!
p_sys
->
b_submit
)
goto
end
;
/* wait for the user to listen enough before submitting */
played_time
=
mdate
()
-
p_sys
->
p_current_song
.
i_start
-
p_sys
->
time_total_pauses
;
played_time
/=
1000000
;
/* µs → s */
/*HACK: it seam that the preparsing sometime fail,
so use the playing time as the song length */
if
(
p_sys
->
p_current_song
.
i_l
==
0
)
p_sys
->
p_current_song
.
i_l
=
played_time
;
/* Don't send song shorter than 30s */
if
(
p_sys
->
p_current_song
.
i_l
<
30
)
{
msg_Dbg
(
p_this
,
"Song too short (< 30s), not submitting"
);
goto
end
;
}
/* Send if the user had listen more than 240s OR half the track length */
if
(
!
p_sys
)
if
(
(
played_time
<
240
)
&&
return
VLC_ENOMEM
;
(
played_time
<
(
p_sys
->
p_current_song
.
i_l
/
2
)
)
)
{
msg_Dbg
(
p_this
,
"Song not listened long enough, not submitting"
);
goto
end
;
}
/* Check that all meta are present */
p_intf
->
p_sys
=
p_sys
;
if
(
!
p_sys
->
p_current_song
.
psz_a
||
!*
p_sys
->
p_current_song
.
psz_a
||
!
p_sys
->
p_current_song
.
psz_t
||
!*
p_sys
->
p_current_song
.
psz_t
)
{
msg_Dbg
(
p_this
,
"Missing artist or title, not submitting"
);
goto
end
;
}
if
(
p_sys
->
i_songs
>=
QUEUE_MAX
)
vlc_mutex_init
(
&
p_sys
->
lock
);
{
vlc_cond_init
(
&
p_sys
->
wait
);
msg_Warn
(
p_this
,
"Submission queue is full, not submitting"
);
goto
end
;
}
msg_Dbg
(
p_this
,
"Song will be submitted."
);
var_AddCallback
(
pl_Get
(
p_intf
),
"item-current"
,
ItemChange
,
p_intf
);
#define QUEUE_COPY( a ) \
p_intf
->
pf_run
=
Run
;
p_sys->p_queue[p_sys->i_songs].a = p_sys->p_current_song.a
#define QUEUE_COPY_NULL( a ) \
return
VLC_SUCCESS
;
QUEUE_COPY( a ); \
}
p_sys->p_current_song.a = NULL
QUEUE_COPY
(
i_l
);
/*****************************************************************************
QUEUE_COPY_NULL
(
psz_n
);
* Close: destroy interface stuff
QUEUE_COPY_NULL
(
psz_a
);
*****************************************************************************/
QUEUE_COPY_NULL
(
psz_t
);
static
void
Close
(
vlc_object_t
*
p_this
)
QUEUE_COPY_NULL
(
psz_b
);
{
QUEUE_COPY_NULL
(
psz_m
);
playlist_t
*
p_playlist
=
pl_Get
(
p_this
);
QUEUE_COPY
(
date
)
;
input_thread_t
*
p_input
;
#undef QUEUE_COPY_NULL
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
#undef QUEUE_COPY
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
p_sys
->
i_songs
++
;
var_DelCallback
(
p_playlist
,
"item-current"
,
ItemChange
,
p_intf
)
;
/* signal the main loop we have something to submit */
p_input
=
playlist_CurrentInput
(
p_playlist
);
vlc_cond_signal
(
&
p_sys
->
wait
);
if
(
p_input
)
{
if
(
p_sys
->
b_state_cb
)
var_DelCallback
(
p_input
,
"intf-event"
,
PlayingChange
,
p_intf
);
vlc_object_release
(
p_input
);
}
end:
int
i
;
DeleteSong
(
&
p_sys
->
p_current_song
);
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
p_sys
->
b_submit
=
false
;
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
free
(
p_sys
->
psz_submit_host
);
free
(
p_sys
->
psz_submit_file
);
#if 0 //NOT USED
free( p_sys->psz_nowp_host );
free( p_sys->psz_nowp_file );
#endif
vlc_cond_destroy
(
&
p_sys
->
wait
);
vlc_mutex_destroy
(
&
p_sys
->
lock
);
free
(
p_sys
);
}
}
/*****************************************************************************
/*****************************************************************************
* ParseURL : Split an http:// URL into host, file, and port
* ParseURL : Split an http:// URL into host, file, and port
*
*
...
@@ -912,105 +768,238 @@ proto:
...
@@ -912,105 +768,238 @@ proto:
return
VLC_EGENERIC
;
return
VLC_EGENERIC
;
}
}
/*****************************************************************************
* DeleteSong : Delete the char pointers in a song
*****************************************************************************/
static
void
DeleteSong
(
audioscrobbler_song_t
*
p_song
)
{
FREENULL
(
p_song
->
psz_a
);
FREENULL
(
p_song
->
psz_b
);
FREENULL
(
p_song
->
psz_t
);
FREENULL
(
p_song
->
psz_m
);
FREENULL
(
p_song
->
psz_n
);
}
/*****************************************************************************
static
void
HandleInterval
(
mtime_t
*
next
,
unsigned
int
*
i_interval
)
* ReadMetaData : Read meta data when parsed by vlc
*****************************************************************************/
static
void
ReadMetaData
(
intf_thread_t
*
p_this
)
{
{
input_thread_t
*
p_input
;
if
(
*
i_interval
==
0
)
input_item_t
*
p_item
;
{
/* first interval is 1 minute */
*
i_interval
=
1
;
}
else
{
/* else we double the previous interval, up to 120 minutes */
*
i_interval
<<=
1
;
if
(
*
i_interval
>
120
)
*
i_interval
=
120
;
}
*
next
=
mdate
()
+
(
*
i_interval
*
1000000
*
60
);
}
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
/*****************************************************************************
* Run : call Handshake() then submit songs
*****************************************************************************/
static
void
Run
(
intf_thread_t
*
p_intf
)
{
char
*
psz_submit
,
*
psz_submit_song
,
*
psz_submit_tmp
;
int
i_net_ret
;
int
i_song
;
uint8_t
p_buffer
[
1024
];
char
*
p_buffer_pos
;
int
i_post_socket
;
int
canc
=
vlc_savecancel
();
p_input
=
playlist_CurrentInput
(
pl_Get
(
p_this
)
);
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
if
(
!
p_input
)
return
;
p_item
=
input_GetItem
(
p_input
);
/* main loop */
if
(
!
p_item
)
for
(
;;
)
{
{
vlc_object_release
(
p_input
);
bool
b_wait
=
false
;
return
;
}
#define ALLOC_ITEM_META( a, b ) do { \
char *psz_meta = input_item_Get##b( p_item ); \
if( psz_meta && *psz_meta ) \
a = encode_URI_component( psz_meta ); \
free( psz_meta ); \
} while(0)
vlc_mutex_lock
(
&
p_sys
->
lock
);
vlc_restorecancel
(
canc
);
vlc_mutex_lock
(
&
p_sys
->
lock
);
mutex_cleanup_push
(
&
p_sys
->
lock
);
p_sys
->
b_meta_read
=
true
;
if
(
mdate
()
<
p_sys
->
next_exchange
)
/* wait until we can resubmit, i.e. */
b_wait
=
vlc_cond_timedwait
(
&
p_sys
->
wait
,
&
p_sys
->
lock
,
p_sys
->
next_exchange
)
==
0
;
else
/* wait for data to submit */
/* we are signaled each time there is a song to submit */
vlc_cond_wait
(
&
p_sys
->
wait
,
&
p_sys
->
lock
);
vlc_cleanup_run
();
canc
=
vlc_savecancel
();
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_a
,
Artist
);
if
(
b_wait
)
if
(
!
p_sys
->
p_current_song
.
psz_a
)
continue
;
/* holding on until next_exchange */
{
msg_Dbg
(
p_this
,
"No artist.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_t
,
Title
);
/* handshake if needed */
if
(
!
p_sys
->
p_current_song
.
psz_t
)
if
(
!
p_sys
->
b_handshaked
)
{
{
msg_Dbg
(
p_this
,
"No track name.."
);
msg_Dbg
(
p_intf
,
"Handshaking with last.fm ..."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
/* Now we have read the mandatory meta data, so we can submit that info */
switch
(
Handshake
(
p_intf
)
)
p_sys
->
b_submit
=
true
;
{
case
VLC_ENOMEM
:
return
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_b
,
Album
);
case
VLC_ENOVAR
:
if
(
!
p_sys
->
p_current_song
.
psz_b
)
/* username not set */
p_sys
->
p_current_song
.
psz_b
=
calloc
(
1
,
1
);
dialog_Fatal
(
p_intf
,
_
(
"Last.fm username not set"
),
"%s"
,
_
(
"Please set a username or disable the "
"audioscrobbler plugin, and restart VLC.
\n
"
"Visit http://www.last.fm/join/ to get an account."
)
);
return
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_m
,
TrackID
);
case
VLC_SUCCESS
:
if
(
!
p_sys
->
p_current_song
.
psz_m
)
msg_Dbg
(
p_intf
,
"Handshake successfull :)"
);
p_sys
->
p_current_song
.
psz_m
=
calloc
(
1
,
1
);
p_sys
->
b_handshaked
=
true
;
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
break
;
p_sys
->
p_current_song
.
i_l
=
input_item_GetDuration
(
p_item
)
/
1000000
;
case
VLC_AUDIOSCROBBLER_EFATAL
:
msg_Warn
(
p_intf
,
"Exiting..."
);
return
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_n
,
TrackNum
);
case
VLC_EGENERIC
:
if
(
!
p_sys
->
p_current_song
.
psz_n
)
default:
p_sys
->
p_current_song
.
psz_n
=
calloc
(
1
,
1
);
/* protocol error : we'll try later */
#undef ALLOC_ITEM_META
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
break
;
}
/* if handshake failed let's restart the loop */
if
(
!
p_sys
->
b_handshaked
)
continue
;
}
msg_Dbg
(
p_this
,
"Meta data registered
"
);
msg_Dbg
(
p_intf
,
"Going to submit some data...
"
);
end:
/* The session may be invalid if there is a trailing \n */
vlc_mutex_unlock
(
&
p_sys
->
lock
);
char
*
psz_ln
=
strrchr
(
p_sys
->
psz_auth_token
,
'\n'
);
vlc_object_release
(
p_input
);
if
(
psz_ln
)
}
*
psz_ln
=
'\0'
;
static
void
HandleInterval
(
mtime_t
*
next
,
unsigned
int
*
i_interval
)
if
(
!
asprintf
(
&
psz_submit
,
"s=%s"
,
p_sys
->
psz_auth_token
)
)
{
{
/* Out of memory */
if
(
*
i_interval
==
0
)
return
;
{
}
/* first interval is 1 minute */
*
i_interval
=
1
;
/* forge the HTTP POST request */
}
vlc_mutex_lock
(
&
p_sys
->
lock
);
else
audioscrobbler_song_t
*
p_song
;
{
for
(
i_song
=
0
;
i_song
<
p_sys
->
i_songs
;
i_song
++
)
/* else we double the previous interval, up to 120 minutes */
{
*
i_interval
<<=
1
;
p_song
=
&
p_sys
->
p_queue
[
i_song
];
if
(
*
i_interval
>
120
)
if
(
!
asprintf
(
&
psz_submit_song
,
*
i_interval
=
120
;
"&a%%5B%d%%5D=%s"
"&t%%5B%d%%5D=%s"
"&i%%5B%d%%5D=%u"
"&o%%5B%d%%5D=P"
"&r%%5B%d%%5D="
"&l%%5B%d%%5D=%d"
"&b%%5B%d%%5D=%s"
"&n%%5B%d%%5D=%s"
"&m%%5B%d%%5D=%s"
,
i_song
,
p_song
->
psz_a
,
i_song
,
p_song
->
psz_t
,
i_song
,
(
unsigned
)
p_song
->
date
,
/* HACK: %ju (uintmax_t) unsupported on Windows */
i_song
,
i_song
,
i_song
,
p_song
->
i_l
,
i_song
,
p_song
->
psz_b
,
i_song
,
p_song
->
psz_n
,
i_song
,
p_song
->
psz_m
)
)
{
/* Out of memory */
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
;
}
psz_submit_tmp
=
psz_submit
;
if
(
!
asprintf
(
&
psz_submit
,
"%s%s"
,
psz_submit_tmp
,
psz_submit_song
)
)
{
/* Out of memory */
free
(
psz_submit_tmp
);
free
(
psz_submit_song
);
vlc_mutex_unlock
(
&
p_sys
->
lock
);
return
;
}
free
(
psz_submit_song
);
free
(
psz_submit_tmp
);
}
vlc_mutex_unlock
(
&
p_sys
->
lock
);
i_post_socket
=
net_ConnectTCP
(
p_intf
,
p_sys
->
psz_submit_host
,
p_sys
->
i_submit_port
);
if
(
i_post_socket
==
-
1
)
{
/* If connection fails, we assume we must handshake again */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
p_sys
->
b_handshaked
=
false
;
free
(
psz_submit
);
continue
;
}
/* we transmit the data */
i_net_ret
=
net_Printf
(
p_intf
,
i_post_socket
,
NULL
,
POST_REQUEST
,
p_sys
->
psz_submit_file
,
(
unsigned
)
strlen
(
psz_submit
),
p_sys
->
psz_submit_host
,
VERSION
,
psz_submit
);
free
(
psz_submit
);
if
(
i_net_ret
==
-
1
)
{
/* If connection fails, we assume we must handshake again */
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
p_sys
->
b_handshaked
=
false
;
continue
;
}
i_net_ret
=
net_Read
(
p_intf
,
i_post_socket
,
NULL
,
p_buffer
,
1023
,
false
);
if
(
i_net_ret
<=
0
)
{
/* if we get no answer, something went wrong : try again */
continue
;
}
net_Close
(
i_post_socket
);
p_buffer
[
i_net_ret
]
=
'\0'
;
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"FAILED"
);
if
(
p_buffer_pos
)
{
msg_Warn
(
p_intf
,
"%s"
,
p_buffer_pos
);
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"BADSESSION"
);
if
(
p_buffer_pos
)
{
msg_Err
(
p_intf
,
"Authentication failed (BADSESSION), are you connected to last.fm with another program ?"
);
p_sys
->
b_handshaked
=
false
;
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
p_buffer_pos
=
strstr
(
(
char
*
)
p_buffer
,
"OK"
);
if
(
p_buffer_pos
)
{
int
i
;
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
p_sys
->
i_songs
=
0
;
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
msg_Dbg
(
p_intf
,
"Submission successful!"
);
}
else
{
msg_Err
(
p_intf
,
"Authentication failed, handshaking again (%s)"
,
p_buffer
);
p_sys
->
b_handshaked
=
false
;
HandleInterval
(
&
p_sys
->
next_exchange
,
&
p_sys
->
i_interval
);
continue
;
}
}
}
*
next
=
mdate
()
+
(
*
i_interval
*
1000000
*
60
);
vlc_restorecancel
(
canc
);
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment