Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
V
vlc-gpu
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-gpu
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 * );
static
void
Close
(
vlc_object_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
****************************************************************************/
...
...
@@ -173,287 +161,178 @@ vlc_module_begin ()
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
;
intf_sys_t
*
p_sys
=
calloc
(
1
,
sizeof
(
intf_sys_t
)
);
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
);
}
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
);
vlc_cond_init
(
&
p_sys
->
wait
);
p_input
=
playlist_CurrentInput
(
pl_Get
(
p_this
)
);
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
);
/*****************************************************************************
* 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
;
p_sys
->
b_meta_read
=
true
;
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
);
if
(
p_inpu
t
)
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_t
,
Title
);
if
(
!
p_sys
->
p_current_song
.
psz_
t
)
{
if
(
p_sys
->
b_state_cb
)
var_DelCallback
(
p_input
,
"intf-event"
,
PlayingChange
,
p_intf
);
vlc_object_release
(
p_input
)
;
msg_Dbg
(
p_this
,
"No track name.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
int
i
;
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
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
);
}
/* Now we have read the mandatory meta data, so we can submit that info */
p_sys
->
b_submit
=
true
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_b
,
Album
);
if
(
!
p_sys
->
p_current_song
.
psz_b
)
p_sys
->
p_current_song
.
psz_b
=
calloc
(
1
,
1
);
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_m
,
TrackID
);
if
(
!
p_sys
->
p_current_song
.
psz_m
)
p_sys
->
p_current_song
.
psz_m
=
calloc
(
1
,
1
);
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
;
int
i_net_ret
;
int
i_song
;
uint8_t
p_buffer
[
1024
];
char
*
p_buffer_pos
;
int
i_post_socket
;
int
canc
=
vlc_savecancel
();
mtime_t
played_time
;
intf_sys_t
*
p_sys
=
p_this
->
p_sys
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
vlc_mutex_lock
(
&
p_sys
->
lock
);
if
(
!
p_sys
->
b_submit
)
goto
end
;
/*
main loop
*/
for
(
;;
)
{
bool
b_wait
=
false
;
/*
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
;
vlc_restorecancel
(
canc
);
vlc_mutex_lock
(
&
p_sys
->
lock
);
mutex_cleanup_push
(
&
p_sys
->
lock
);
/* 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
;
}
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
();
/* Send if the user had listen more than 240s OR half the track length */
if
(
(
played_time
<
240
)
&&
(
played_time
<
(
p_sys
->
p_current_song
.
i_l
/
2
)
)
)
{
msg_Dbg
(
p_this
,
"Song not listened long enough, not submitting"
);
goto
end
;
}
if
(
b_wait
)
continue
;
/* holding on until next_exchange */
/* Check that all meta are present */
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
->
b_handshaked
)
{
msg_Dbg
(
p_intf
,
"Handshaking with last.fm ..."
);
if
(
p_sys
->
i_songs
>=
QUEUE_MAX
)
{
msg_Warn
(
p_this
,
"Submission queue is full, not submitting"
);
goto
end
;
}
switch
(
Handshake
(
p_intf
)
)
{
case
VLC_ENOMEM
:
return
;
msg_Dbg
(
p_this
,
"Song will be submitted."
);
case
VLC_ENOVAR
:
/* username not set */
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
;
#define QUEUE_COPY( a ) \
p_sys->p_queue[p_sys->i_songs].a = p_sys->p_current_song.a
case
VLC_SUCCESS
:
msg_Dbg
(
p_intf
,
"Handshake successfull :)"
);
p_sys
->
b_handshaked
=
true
;
p_sys
->
i_interval
=
0
;
p_sys
->
next_exchange
=
mdate
();
break
;
#define QUEUE_COPY_NULL( a ) \
QUEUE_COPY( a ); \
p_sys->p_current_song.a = NULL
case
VLC_AUDIOSCROBBLER_EFATAL
:
msg_Warn
(
p_intf
,
"Exiting..."
);
return
;
QUEUE_COPY
(
i_l
);
QUEUE_COPY_NULL
(
psz_n
);
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
:
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
;
}
p_sys
->
i_songs
++
;
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 */
char
*
psz_ln
=
strrchr
(
p_sys
->
psz_auth_token
,
'\n'
);
if
(
psz_ln
)
*
psz_ln
=
'\0'
;
end:
DeleteSong
(
&
p_sys
->
p_current_song
);
p_sys
->
b_submit
=
false
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
}
if
(
!
asprintf
(
&
psz_submit
,
"s=%s"
,
p_sys
->
psz_auth_token
)
)
{
/* Out of memory */
return
;
}
/* forge the HTTP POST request */
vlc_mutex_lock
(
&
p_sys
->
lock
);
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
);
/*****************************************************************************
* 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_sys_t
*
p_sys
=
p_intf
->
p_sys
;
...
...
@@ -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_sys_t
*
p_sys
=
p_this
->
p_sys
;
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
;
}
intf_thread_t
*
p_intf
=
(
intf_thread_t
*
)
p_this
;
intf_sys_t
*
p_sys
=
calloc
(
1
,
sizeof
(
intf_sys_t
)
);
/* Send if the user had listen more than 240s OR half the track length */
if
(
(
played_time
<
240
)
&&
(
played_time
<
(
p_sys
->
p_current_song
.
i_l
/
2
)
)
)
{
msg_Dbg
(
p_this
,
"Song not listened long enough, not submitting"
);
goto
end
;
}
if
(
!
p_sys
)
return
VLC_ENOMEM
;
/* Check that all meta are present */
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
;
}
p_intf
->
p_sys
=
p_sys
;
if
(
p_sys
->
i_songs
>=
QUEUE_MAX
)
{
msg_Warn
(
p_this
,
"Submission queue is full, not submitting"
);
goto
end
;
}
vlc_mutex_init
(
&
p_sys
->
lock
);
vlc_cond_init
(
&
p_sys
->
wait
);
msg_Dbg
(
p_this
,
"Song will be submitted."
);
var_AddCallback
(
pl_Get
(
p_intf
),
"item-current"
,
ItemChange
,
p_intf
);
#define QUEUE_COPY( a ) \
p_sys->p_queue[p_sys->i_songs].a = p_sys->p_current_song.a
p_intf
->
pf_run
=
Run
;
#define QUEUE_COPY_NULL( a ) \
QUEUE_COPY( a ); \
p_sys->p_current_song.a = NULL
return
VLC_SUCCESS
;
}
QUEUE_COPY
(
i_l
);
QUEUE_COPY_NULL
(
psz_n
);
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
/*****************************************************************************
* 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
;
p_sys
->
i_songs
++
;
var_DelCallback
(
p_playlist
,
"item-current"
,
ItemChange
,
p_intf
)
;
/* signal the main loop we have something to submit */
vlc_cond_signal
(
&
p_sys
->
wait
);
p_input
=
playlist_CurrentInput
(
p_playlist
);
if
(
p_input
)
{
if
(
p_sys
->
b_state_cb
)
var_DelCallback
(
p_input
,
"intf-event"
,
PlayingChange
,
p_intf
);
vlc_object_release
(
p_input
);
}
end:
DeleteSong
(
&
p_sys
->
p_current_song
);
p_sys
->
b_submit
=
false
;
vlc_mutex_unlock
(
&
p_sys
->
lock
);
int
i
;
for
(
i
=
0
;
i
<
p_sys
->
i_songs
;
i
++
)
DeleteSong
(
&
p_sys
->
p_queue
[
i
]
);
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
*
...
...
@@ -912,105 +768,238 @@ proto:
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
);
}
/*****************************************************************************
* ReadMetaData : Read meta data when parsed by vlc
*****************************************************************************/
static
void
ReadMetaData
(
intf_thread_t
*
p_this
)
static
void
HandleInterval
(
mtime_t
*
next
,
unsigned
int
*
i_interval
)
{
input_thread_t
*
p_input
;
input_item_t
*
p_item
;
if
(
*
i_interval
==
0
)
{
/* 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
)
);
if
(
!
p_input
)
return
;
intf_sys_t
*
p_sys
=
p_intf
->
p_sys
;
p_item
=
input_GetItem
(
p_input
);
if
(
!
p_item
)
/* main loop */
for
(
;;
)
{
vlc_object_release
(
p_input
);
return
;
}
bool
b_wait
=
false
;
#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
(
!
p_sys
->
p_current_song
.
psz_a
)
{
msg_Dbg
(
p_this
,
"No artist.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
if
(
b_wait
)
continue
;
/* holding on until next_exchange */
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_t
,
Title
);
if
(
!
p_sys
->
p_current_song
.
psz_t
)
{
msg_Dbg
(
p_this
,
"No track name.."
);
DeleteSong
(
&
p_sys
->
p_current_song
);
goto
end
;
}
/* handshake if needed */
if
(
!
p_sys
->
b_handshaked
)
{
msg_Dbg
(
p_intf
,
"Handshaking with last.fm ..."
);
/* Now we have read the mandatory meta data, so we can submit that info */
p_sys
->
b_submit
=
true
;
switch
(
Handshake
(
p_intf
)
)
{
case
VLC_ENOMEM
:
return
;
ALLOC_ITEM_META
(
p_sys
->
p_current_song
.
psz_b
,
Album
);
if
(
!
p_sys
->
p_current_song
.
psz_b
)
p_sys
->
p_current_song
.
psz_b
=
calloc
(
1
,
1
);
case
VLC_ENOVAR
:
/* username not set */
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
);
if
(
!
p_sys
->
p_current_song
.
psz_m
)
p_sys
->
p_current_song
.
psz_m
=
calloc
(
1
,
1
);
case
VLC_SUCCESS
:
msg_Dbg
(
p_intf
,
"Handshake successfull :)"
);
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
);
if
(
!
p_sys
->
p_current_song
.
psz_n
)
p_sys
->
p_current_song
.
psz_n
=
calloc
(
1
,
1
);
#undef ALLOC_ITEM_META
case
VLC_EGENERIC
:
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_this
,
"Meta data registered
"
);
msg_Dbg
(
p_intf
,
"Going to submit some data...
"
);
end:
vlc_mutex_unlock
(
&
p_sys
->
lock
);
vlc_object_release
(
p_input
);
}
/* The session may be invalid if there is a trailing \n */
char
*
psz_ln
=
strrchr
(
p_sys
->
psz_auth_token
,
'\n'
);
if
(
psz_ln
)
*
psz_ln
=
'\0'
;
static
void
HandleInterval
(
mtime_t
*
next
,
unsigned
int
*
i_interval
)
{
if
(
*
i_interval
==
0
)
{
/* 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
;
if
(
!
asprintf
(
&
psz_submit
,
"s=%s"
,
p_sys
->
psz_auth_token
)
)
{
/* Out of memory */
return
;
}
/* forge the HTTP POST request */
vlc_mutex_lock
(
&
p_sys
->
lock
);
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
;
}
}
*
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